add all search results to collection (#150)
This commit is contained in:
@@ -1,7 +0,0 @@
|
|||||||
using ErsatzTV.Core.Search;
|
|
||||||
using MediatR;
|
|
||||||
|
|
||||||
namespace ErsatzTV.Application.Search.Queries
|
|
||||||
{
|
|
||||||
public record QuerySearchIndex(string Query) : IRequest<SearchResult>;
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
using MediatR;
|
||||||
|
|
||||||
|
namespace ErsatzTV.Application.Search.Queries
|
||||||
|
{
|
||||||
|
public record QuerySearchIndexAllItems(string Query) : IRequest<SearchResultAllItemsViewModel>;
|
||||||
|
}
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using ErsatzTV.Core.Interfaces.Search;
|
||||||
|
using LanguageExt;
|
||||||
|
using MediatR;
|
||||||
|
|
||||||
|
namespace ErsatzTV.Application.Search.Queries
|
||||||
|
{
|
||||||
|
public class
|
||||||
|
QuerySearchIndexAllItemsHandler : IRequestHandler<QuerySearchIndexAllItems, SearchResultAllItemsViewModel>
|
||||||
|
{
|
||||||
|
private readonly ISearchIndex _searchIndex;
|
||||||
|
|
||||||
|
public QuerySearchIndexAllItemsHandler(ISearchIndex searchIndex) => _searchIndex = searchIndex;
|
||||||
|
|
||||||
|
public async Task<SearchResultAllItemsViewModel> Handle(
|
||||||
|
QuerySearchIndexAllItems request,
|
||||||
|
CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
List<int> movieIds = await _searchIndex.Search($"type:movie AND ({request.Query})", 0, 0)
|
||||||
|
.Map(result => result.Items.Map(i => i.Id).ToList());
|
||||||
|
List<int> showIds = await _searchIndex.Search($"type:show AND ({request.Query})", 0, 0)
|
||||||
|
.Map(result => result.Items.Map(i => i.Id).ToList());
|
||||||
|
List<int> musicVideoIds = await _searchIndex.Search($"type:music_video AND ({request.Query})", 0, 0)
|
||||||
|
.Map(result => result.Items.Map(i => i.Id).ToList());
|
||||||
|
|
||||||
|
return new SearchResultAllItemsViewModel(movieIds, showIds, musicVideoIds);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
using System.Threading;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using ErsatzTV.Core.Interfaces.Search;
|
|
||||||
using ErsatzTV.Core.Search;
|
|
||||||
using MediatR;
|
|
||||||
|
|
||||||
namespace ErsatzTV.Application.Search.Queries
|
|
||||||
{
|
|
||||||
public class QuerySearchIndexHandler : IRequestHandler<QuerySearchIndex, SearchResult>
|
|
||||||
{
|
|
||||||
private readonly ISearchIndex _searchIndex;
|
|
||||||
|
|
||||||
public QuerySearchIndexHandler(ISearchIndex searchIndex) => _searchIndex = searchIndex;
|
|
||||||
|
|
||||||
public Task<SearchResult> Handle(QuerySearchIndex request, CancellationToken cancellationToken) =>
|
|
||||||
_searchIndex.Search(request.Query, 0, 100);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace ErsatzTV.Application.Search
|
||||||
|
{
|
||||||
|
public record SearchResultAllItemsViewModel(List<int> MovieIds, List<int> ShowIds, List<int> MusicVideoIds);
|
||||||
|
}
|
||||||
@@ -138,7 +138,7 @@ namespace ErsatzTV.Infrastructure.Search
|
|||||||
|
|
||||||
using DirectoryReader reader = _writer.GetReader(true);
|
using DirectoryReader reader = _writer.GetReader(true);
|
||||||
var searcher = new IndexSearcher(reader);
|
var searcher = new IndexSearcher(reader);
|
||||||
int hitsLimit = skip + limit;
|
int hitsLimit = limit == 0 ? searcher.IndexReader.MaxDoc : skip + limit;
|
||||||
using var analyzer = new StandardAnalyzer(AppLuceneVersion);
|
using var analyzer = new StandardAnalyzer(AppLuceneVersion);
|
||||||
QueryParser parser = !string.IsNullOrWhiteSpace(searchField)
|
QueryParser parser = !string.IsNullOrWhiteSpace(searchField)
|
||||||
? new QueryParser(AppLuceneVersion, searchField, analyzer)
|
? new QueryParser(AppLuceneVersion, searchField, analyzer)
|
||||||
@@ -148,13 +148,21 @@ namespace ErsatzTV.Infrastructure.Search
|
|||||||
var filter = new DuplicateFilter(TitleAndYearField);
|
var filter = new DuplicateFilter(TitleAndYearField);
|
||||||
var sort = new Sort(new SortField(SortTitleField, SortFieldType.STRING));
|
var sort = new Sort(new SortField(SortTitleField, SortFieldType.STRING));
|
||||||
TopFieldDocs topDocs = searcher.Search(query, filter, hitsLimit, sort, true, true);
|
TopFieldDocs topDocs = searcher.Search(query, filter, hitsLimit, sort, true, true);
|
||||||
IEnumerable<ScoreDoc> selectedHits = topDocs.ScoreDocs.Skip(skip).Take(limit);
|
IEnumerable<ScoreDoc> selectedHits = topDocs.ScoreDocs.Skip(skip);
|
||||||
|
|
||||||
|
if (limit > 0)
|
||||||
|
{
|
||||||
|
selectedHits = selectedHits.Take(limit);
|
||||||
|
}
|
||||||
|
|
||||||
var searchResult = new SearchResult(
|
var searchResult = new SearchResult(
|
||||||
selectedHits.Map(d => ProjectToSearchItem(searcher.Doc(d.Doc))).ToList(),
|
selectedHits.Map(d => ProjectToSearchItem(searcher.Doc(d.Doc))).ToList(),
|
||||||
topDocs.TotalHits);
|
topDocs.TotalHits);
|
||||||
|
|
||||||
searchResult.PageMap = GetSearchPageMap(searcher, query, filter, sort, limit);
|
if (limit > 0)
|
||||||
|
{
|
||||||
|
searchResult.PageMap = GetSearchPageMap(searcher, query, filter, sort, limit);
|
||||||
|
}
|
||||||
|
|
||||||
return searchResult.AsTask();
|
return searchResult.AsTask();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -94,21 +94,28 @@ namespace ErsatzTV.Pages
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async Task AddSelectionToCollection()
|
protected Task AddSelectionToCollection() => AddItemsToCollection(
|
||||||
|
_selectedItems.OfType<MovieCardViewModel>().Map(m => m.MovieId).ToList(),
|
||||||
|
_selectedItems.OfType<TelevisionShowCardViewModel>().Map(s => s.TelevisionShowId).ToList(),
|
||||||
|
_selectedItems.OfType<MusicVideoCardViewModel>().Map(mv => mv.MusicVideoId).ToList());
|
||||||
|
|
||||||
|
protected async Task AddItemsToCollection(
|
||||||
|
List<int> movieIds,
|
||||||
|
List<int> showIds,
|
||||||
|
List<int> musicVideoIds,
|
||||||
|
string entityName = "selected items")
|
||||||
{
|
{
|
||||||
|
int count = movieIds.Count + showIds.Count + musicVideoIds.Count;
|
||||||
|
|
||||||
var parameters = new DialogParameters
|
var parameters = new DialogParameters
|
||||||
{ { "EntityType", _selectedItems.Count.ToString() }, { "EntityName", "selected items" } };
|
{ { "EntityType", count.ToString() }, { "EntityName", entityName } };
|
||||||
var options = new DialogOptions { CloseButton = true, MaxWidth = MaxWidth.ExtraSmall };
|
var options = new DialogOptions { CloseButton = true, MaxWidth = MaxWidth.ExtraSmall };
|
||||||
|
|
||||||
IDialogReference dialog = Dialog.Show<AddToCollectionDialog>("Add To Collection", parameters, options);
|
IDialogReference dialog = Dialog.Show<AddToCollectionDialog>("Add To Collection", parameters, options);
|
||||||
DialogResult result = await dialog.Result;
|
DialogResult result = await dialog.Result;
|
||||||
if (!result.Cancelled && result.Data is MediaCollectionViewModel collection)
|
if (!result.Cancelled && result.Data is MediaCollectionViewModel collection)
|
||||||
{
|
{
|
||||||
var request = new AddItemsToCollection(
|
var request = new AddItemsToCollection(collection.Id, movieIds, showIds, musicVideoIds);
|
||||||
collection.Id,
|
|
||||||
_selectedItems.OfType<MovieCardViewModel>().Map(m => m.MovieId).ToList(),
|
|
||||||
_selectedItems.OfType<TelevisionShowCardViewModel>().Map(s => s.TelevisionShowId).ToList(),
|
|
||||||
_selectedItems.OfType<MusicVideoCardViewModel>().Map(mv => mv.MusicVideoId).ToList());
|
|
||||||
|
|
||||||
Either<BaseError, Unit> addResult = await Mediator.Send(request);
|
Either<BaseError, Unit> addResult = await Mediator.Send(request);
|
||||||
addResult.Match(
|
addResult.Match(
|
||||||
@@ -120,7 +127,7 @@ namespace ErsatzTV.Pages
|
|||||||
Right: _ =>
|
Right: _ =>
|
||||||
{
|
{
|
||||||
Snackbar.Add(
|
Snackbar.Add(
|
||||||
$"Added {_selectedItems.Count} items to collection {collection.Name}",
|
$"Added {count} items to collection {collection.Name}",
|
||||||
Severity.Success);
|
Severity.Success);
|
||||||
ClearSelection();
|
ClearSelection();
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
@using ErsatzTV.Application.MediaCards
|
@using ErsatzTV.Application.MediaCards
|
||||||
@using ErsatzTV.Application.MediaCollections
|
@using ErsatzTV.Application.MediaCollections
|
||||||
@using ErsatzTV.Application.MediaCollections.Commands
|
@using ErsatzTV.Application.MediaCollections.Commands
|
||||||
|
@using ErsatzTV.Application.Search
|
||||||
@using ErsatzTV.Application.Search.Queries
|
@using ErsatzTV.Application.Search.Queries
|
||||||
@using Microsoft.AspNetCore.WebUtilities
|
@using Microsoft.AspNetCore.WebUtilities
|
||||||
@using Microsoft.Extensions.Primitives
|
@using Microsoft.Extensions.Primitives
|
||||||
@@ -33,33 +34,41 @@
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
<MudText>@_query</MudText>
|
<MudText Style="margin-bottom: auto; margin-top: auto">@_query</MudText>
|
||||||
if (_movies.Count > 0)
|
if (_movies.Count > 0)
|
||||||
{
|
{
|
||||||
<MudLink Class="ml-4" Href="@(NavigationManager.Uri.Split("#").Head() + "#movies")">@_movies.Count Movies</MudLink>
|
<MudLink Class="ml-4" Href="@(NavigationManager.Uri.Split("#").Head() + "#movies")" Style="margin-bottom: auto; margin-top: auto">@_movies.Count Movies</MudLink>
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
<MudText Class="ml-4">0 Movies</MudText>
|
<MudText Class="ml-4" Style="margin-bottom: auto; margin-top: auto">0 Movies</MudText>
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_shows.Count > 0)
|
if (_shows.Count > 0)
|
||||||
{
|
{
|
||||||
<MudLink Class="ml-4" Href="@(NavigationManager.Uri.Split("#").Head() + "#shows")">@_shows.Count Shows</MudLink>
|
<MudLink Class="ml-4" Href="@(NavigationManager.Uri.Split("#").Head() + "#shows")" Style="margin-bottom: auto; margin-top: auto">@_shows.Count Shows</MudLink>
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
<MudText Class="ml-4">0 Shows</MudText>
|
<MudText Class="ml-4" Style="margin-bottom: auto; margin-top: auto">0 Shows</MudText>
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_musicVideos.Count > 0)
|
if (_musicVideos.Count > 0)
|
||||||
{
|
{
|
||||||
<MudLink Class="ml-4" Href="@(NavigationManager.Uri.Split("#").Head() + "#music_videos")">@_musicVideos.Count Music Videos</MudLink>
|
<MudLink Class="ml-4" Href="@(NavigationManager.Uri.Split("#").Head() + "#music_videos")" Style="margin-bottom: auto; margin-top: auto">@_musicVideos.Count Music Videos</MudLink>
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
<MudText Class="ml-4">0 Music Videos</MudText>
|
<MudText Class="ml-4" Style="margin-bottom: auto; margin-top: auto">0 Music Videos</MudText>
|
||||||
}
|
}
|
||||||
|
<div style="margin-left: auto">
|
||||||
|
<MudButton Variant="Variant.Filled"
|
||||||
|
Color="Color.Primary"
|
||||||
|
StartIcon="@Icons.Material.Filled.Add"
|
||||||
|
OnClick="@AddAllToCollection">
|
||||||
|
Add All To Collection
|
||||||
|
</MudButton>
|
||||||
|
</div>
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
</MudPaper>
|
</MudPaper>
|
||||||
@@ -276,4 +285,10 @@
|
|||||||
return uri;
|
return uri;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task AddAllToCollection(MouseEventArgs _)
|
||||||
|
{
|
||||||
|
SearchResultAllItemsViewModel results = await Mediator.Send(new QuerySearchIndexAllItems(_query));
|
||||||
|
await AddItemsToCollection(results.MovieIds, results.ShowIds, results.MusicVideoIds, "search results");
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -70,7 +70,7 @@
|
|||||||
|
|
||||||
if (MemoryCache.TryGetValue("AddToCollectionDialog.SelectedCollectionId", out int id))
|
if (MemoryCache.TryGetValue("AddToCollectionDialog.SelectedCollectionId", out int id))
|
||||||
{
|
{
|
||||||
_selectedCollection = _collections.SingleOrDefault(c => c.Id == id);
|
_selectedCollection = _collections.SingleOrDefault(c => c.Id == id) ?? _newCollection;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user