Fixed bug where deletes of artifact groupings would not cascade
This commit is contained in:
56
OpenArchival.Blazor.ArchiveSearch/ArchiveSearchBar.razor
Normal file
56
OpenArchival.Blazor.ArchiveSearch/ArchiveSearchBar.razor
Normal file
@@ -0,0 +1,56 @@
|
||||
@using MudBlazor
|
||||
@namespace OpenArchival.Blazor.ArchiveSearch
|
||||
|
||||
<Microsoft.AspNetCore.Components.Forms.EditForm Model="this" OnSubmit="OnSubmit">
|
||||
<MudTextField FullWidth="true"
|
||||
AutoFocus="string.IsNullOrEmpty(SearchTerms)"
|
||||
Placeholder="Search"
|
||||
T="string"
|
||||
Variant="Variant.Outlined"
|
||||
Adornment="Adornment.Start"
|
||||
AdornmentIcon="@Icons.Material.Filled.Search"
|
||||
Class="mt-5"
|
||||
@bind-Value="SearchTerms"
|
||||
/>
|
||||
|
||||
<MudExpansionPanel Text="Filter...">
|
||||
<MudText Typo="Typo.caption">Choose which data the serach bar will search on:</MudText>
|
||||
<MudDivider></MudDivider>
|
||||
|
||||
<MudRadioGroup T="ArchiveSearchFilterType" @bind-SelectedOption="SelectedFilter">
|
||||
<MudRadio Option="ArchiveSearchFilterType.All" T="ArchiveSearchFilterType">All</MudRadio>
|
||||
<MudRadio Option="ArchiveSearchFilterType.Tags" T="ArchiveSearchFilterType">Tags</MudRadio>
|
||||
<MudRadio Option="ArchiveSearchFilterType.Defects" T="ArchiveSearchFilterType">Defects</MudRadio>
|
||||
<MudRadio Option="ArchiveSearchFilterType.ListedNames" T="ArchiveSearchFilterType">Listed Names</MudRadio>
|
||||
<MudRadio Option="ArchiveSearchFilterType.Title" T="ArchiveSearchFilterType">Title</MudRadio>
|
||||
<MudRadio Option="ArchiveSearchFilterType.Description" T="ArchiveSearchFilterType">Description</MudRadio>
|
||||
<MudRadio Option="ArchiveSearchFilterType.Filenames" T="ArchiveSearchFilterType">Filenames</MudRadio>
|
||||
<MudRadio Option="ArchiveSearchFilterType.ArtifactTranscriptions" T="ArchiveSearchFilterType">Artifact Transcriptions</MudRadio>
|
||||
</MudRadioGroup>
|
||||
</MudExpansionPanel>
|
||||
</Microsoft.AspNetCore.Components.Forms.EditForm>
|
||||
@code {
|
||||
[Parameter]
|
||||
public string SearchTerms { get; set; } = "";
|
||||
|
||||
[Parameter]
|
||||
public EventCallback<string> SearchTermsChanged { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public ArchiveSearchFilterType SelectedFilter { get; set; } = ArchiveSearchFilterType.All;
|
||||
|
||||
[Parameter]
|
||||
public EventCallback<ArchiveSearchFilterType> SelectedFilterChanged { get; set; }
|
||||
|
||||
private async Task HandleSearchKeyDown(Microsoft.AspNetCore.Components.Web.KeyboardEventArgs args)
|
||||
{
|
||||
if (args.Key == "Enter")
|
||||
{
|
||||
await SearchTermsChanged.InvokeAsync(SearchTerms);
|
||||
}
|
||||
}
|
||||
private async Task OnSubmit(Microsoft.AspNetCore.Components.Forms.EditContext args)
|
||||
{
|
||||
await SearchTermsChanged.InvokeAsync(SearchTerms);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
@page
|
||||
@model OpenArchival.Blazor.ArchiveSearch.MyFeature.Pages.Page1Model
|
||||
|
||||
<!DOCTYPE html>
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<meta name="viewport" content="width=device-width" />
|
||||
<title>Page1</title>
|
||||
</head>
|
||||
<body>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,12 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.RazorPages;
|
||||
|
||||
namespace OpenArchival.Blazor.ArchiveSearch.MyFeature.Pages;
|
||||
|
||||
public class Page1Model : PageModel
|
||||
{
|
||||
public void OnGet()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
132
OpenArchival.Blazor.ArchiveSearch/ArtifactGroupingSearch.cs
Normal file
132
OpenArchival.Blazor.ArchiveSearch/ArtifactGroupingSearch.cs
Normal file
@@ -0,0 +1,132 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Internal;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using MudBlazor;
|
||||
using Npgsql.EntityFrameworkCore.PostgreSQL;
|
||||
using NpgsqlTypes;
|
||||
using OpenArchival.DataAccess;
|
||||
using OpenArchival.DataAccess;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing.Printing;
|
||||
using System.Linq;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace OpenArchival.Blazor.ArchiveSearch;
|
||||
|
||||
public enum ArchiveSearchFilterType
|
||||
{
|
||||
All,
|
||||
Tags,
|
||||
Defects,
|
||||
ListedNames,
|
||||
Title,
|
||||
Description,
|
||||
Filenames,
|
||||
ArtifactTranscriptions
|
||||
}
|
||||
|
||||
public class ArtifactGroupingSearch
|
||||
{
|
||||
|
||||
public int TotalResults { get; set; }
|
||||
|
||||
public int TotalPages { get; set; }
|
||||
|
||||
public int PageSize { get; set; } = 20;
|
||||
|
||||
public int CurrentPage { get; set; }
|
||||
|
||||
public List<ArtifactGrouping> SearchResults { get; set; } = [];
|
||||
|
||||
private string _searchTerms { get; set; }
|
||||
|
||||
private IDbContextFactory<ApplicationDbContext> _contextFactory { get; set; }
|
||||
|
||||
private Expression<Func<ArtifactGrouping, bool>> _currentFilterPredicate;
|
||||
|
||||
private ArchiveSearchFilterType _selectedFilter = ArchiveSearchFilterType.All;
|
||||
|
||||
public ArtifactGroupingSearch(IDbContextFactory<ApplicationDbContext> contextFactory)
|
||||
{
|
||||
_contextFactory = contextFactory;
|
||||
}
|
||||
|
||||
public async Task Search(string Terms, ArchiveSearchFilterType filter, int page = 1)
|
||||
{
|
||||
_searchTerms = Terms;
|
||||
_selectedFilter = filter;
|
||||
|
||||
// Determine which filter expression to use based on the radio button selection
|
||||
switch (_selectedFilter)
|
||||
{
|
||||
case ArchiveSearchFilterType.Tags:
|
||||
_currentFilterPredicate = x => x.TagsSearchVector.Matches(_searchTerms);
|
||||
break;
|
||||
case ArchiveSearchFilterType.Title:
|
||||
_currentFilterPredicate = x => x.TitleSearchVector.Matches(_searchTerms);
|
||||
break;
|
||||
case ArchiveSearchFilterType.Description:
|
||||
_currentFilterPredicate = x => x.DescriptionSearchVector.Matches(_searchTerms);
|
||||
break;
|
||||
case ArchiveSearchFilterType.Defects:
|
||||
_currentFilterPredicate = x => x.DefectsSearchVector.Matches(_searchTerms);
|
||||
break;
|
||||
case ArchiveSearchFilterType.Filenames:
|
||||
_currentFilterPredicate = x => x.FilenamesSearchVector.Matches(_searchTerms);
|
||||
break;
|
||||
case ArchiveSearchFilterType.ArtifactTranscriptions:
|
||||
_currentFilterPredicate = x => x.FileContentSearchVector.Matches(_searchTerms);
|
||||
break;
|
||||
case ArchiveSearchFilterType.ListedNames:
|
||||
_currentFilterPredicate = x => x.ListedNamesSearchVector.Matches(_searchTerms);
|
||||
break;
|
||||
case ArchiveSearchFilterType.All:
|
||||
default:
|
||||
_currentFilterPredicate = x => x.AllSearchVector.Matches(_searchTerms);
|
||||
break;
|
||||
}
|
||||
|
||||
// Get the total count using the chosen filter
|
||||
await using var context = await _contextFactory.CreateDbContextAsync();
|
||||
TotalResults = await context.ArtifactGroupings.Where(_currentFilterPredicate).CountAsync();
|
||||
TotalPages = (int)Math.Ceiling(TotalResults / (double)PageSize);
|
||||
|
||||
// Load the first page with the chosen filter
|
||||
await LoadPageAsync(page);
|
||||
}
|
||||
|
||||
public async Task LoadPageAsync(int page)
|
||||
{
|
||||
CurrentPage = page;
|
||||
|
||||
if (_currentFilterPredicate == null) // Don't run if no search has been performed
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
await using var context = await _contextFactory.CreateDbContextAsync();
|
||||
|
||||
// The query uses the dynamically set filter predicate
|
||||
SearchResults = await context.ArtifactGroupings
|
||||
.Where(_currentFilterPredicate)
|
||||
.Include(x => x.ChildArtifactEntries)
|
||||
.ThenInclude(x => x.Files)
|
||||
.Include(x=>x.Category)
|
||||
.OrderBy(x => x.Id)
|
||||
.Skip((CurrentPage - 1) * PageSize)
|
||||
.Take(PageSize)
|
||||
.ToListAsync();
|
||||
|
||||
}
|
||||
|
||||
public void ClearResults()
|
||||
{
|
||||
SearchResults.Clear();
|
||||
TotalResults = 0;
|
||||
TotalPages = 0;
|
||||
}
|
||||
}
|
||||
@@ -12,33 +12,12 @@
|
||||
@using System.Linq.Expressions
|
||||
|
||||
@using OpenArchival.Blazor.ArtifactGroupingDisplay
|
||||
@using OpenArchival.Blazor.ArchiveSearch
|
||||
@* ^^^ Add this using statement to access your component and enum ^^^ *@
|
||||
|
||||
<MudAutocomplete FullWidth="true"
|
||||
AutoFocus="string.IsNullOrEmpty(SearchTerms)"
|
||||
Placeholder="Search"
|
||||
T="string"
|
||||
Variant="Variant.Outlined"
|
||||
AdornmentIcon="@Icons.Material.Filled.Search"
|
||||
Class="mt-5"
|
||||
@bind-Text="@SearchTerms"
|
||||
OnKeyDown="HandleSearchKeyDown" />
|
||||
<ArchiveSearchBar @bind-SelectedFilter="_selectedFilter"
|
||||
SearchTermsChanged="OnSearchSubmittedAsync" />
|
||||
|
||||
<MudExpansionPanel Text="Filter...">
|
||||
<MudText Typo="Typo.caption"></MudText>
|
||||
<MudDivider></MudDivider>
|
||||
|
||||
<MudRadioGroup T="SearchFilterType" @bind-SelectedOption="_selectedFilter">
|
||||
<MudRadio Option="SearchFilterType.All" T="SearchFilterType">All</MudRadio>
|
||||
<MudRadio Option="SearchFilterType.Tags" T="SearchFilterType">Tags</MudRadio>
|
||||
<MudRadio Option="SearchFilterType.Defects" T="SearchFilterType">Defects</MudRadio>
|
||||
<MudRadio Option="SearchFilterType.ListedNames" T="SearchFilterType">Listed Names</MudRadio>
|
||||
<MudRadio Option="SearchFilterType.Title" T="SearchFilterType">Title</MudRadio>
|
||||
<MudRadio Option="SearchFilterType.Description" T="SearchFilterType">Description</MudRadio>
|
||||
<MudRadio Option="SearchFilterType.Filenames" T="SearchFilterType">Filenames</MudRadio>
|
||||
<MudRadio Option="SearchFilterType.ArtifactTranscriptions" T="SearchFilterType">Artifact Transcriptions</MudRadio>
|
||||
</MudRadioGroup>
|
||||
|
||||
</MudExpansionPanel>
|
||||
@if (_totalResults > 0)
|
||||
{
|
||||
<MudGrid Justify="Justify.FlexStart" Class="mt-1 ml-1 mb-2">
|
||||
@@ -46,6 +25,7 @@
|
||||
<MudButton Class="ml-1" StartIcon="@Icons.Material.Filled.Clear" OnClick="OnClearResults" Variant="Variant.Filled" Color="Color.Primary" Size="Size.Small">Clear</MudButton>
|
||||
</MudGrid>
|
||||
}
|
||||
|
||||
@if (_artifactGroupings.Count > 0)
|
||||
{
|
||||
<MudGrid>
|
||||
@@ -58,9 +38,10 @@
|
||||
</MudGrid>
|
||||
|
||||
<MudPaper Class="d-flex justify-center py-2 mt-4" Elevation="0">
|
||||
<MudPagination Count="_totalPages" Page="_currentPage" SelectedPageChanged="OnPageChangedAsync" />
|
||||
@* === HERE IS THE FIX === *@
|
||||
<MudPagination Count="_totalPages" Selected="_currentPage" SelectedChanged="OnPageChangedAsync" />
|
||||
</MudPaper>
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@foreach (SearchPageSliderEntry entry in _sliderEntries)
|
||||
@@ -73,22 +54,12 @@ else
|
||||
@inject ILogger<SearchArchive> Logger;
|
||||
@inject NavigationManager NavigationManager;
|
||||
@code {
|
||||
public enum SearchFilterType
|
||||
{
|
||||
All,
|
||||
Tags,
|
||||
Defects,
|
||||
ListedNames,
|
||||
Title,
|
||||
Description,
|
||||
Filenames,
|
||||
ArtifactTranscriptions
|
||||
}
|
||||
|
||||
[Parameter]
|
||||
public string SearchTerms { get; set; } = "";
|
||||
|
||||
private SearchFilterType _selectedFilter = SearchFilterType.All;
|
||||
// This enum is now defined in your ArchiveSearchBar component/namespace
|
||||
private ArchiveSearchFilterType _selectedFilter = ArchiveSearchFilterType.All;
|
||||
|
||||
private List<ArtifactGrouping> _artifactGroupings { get; set; } = [];
|
||||
private int _currentPage { get; set; } = 1;
|
||||
private int _totalPages { get; set; } = 0;
|
||||
@@ -108,17 +79,22 @@ else
|
||||
}
|
||||
|
||||
await using var context = await ContextFactory.CreateDbContextAsync();
|
||||
_sliderEntries = await context.SearchPageSliderEntries.Include(e=>e.FilterTags).ToListAsync();
|
||||
_sliderEntries = await context.SearchPageSliderEntries.Include(e => e.FilterTags).ToListAsync();
|
||||
}
|
||||
|
||||
private async Task HandleSearchKeyDown(Microsoft.AspNetCore.Components.Web.KeyboardEventArgs args)
|
||||
/// <summary>
|
||||
/// Called by the ArchiveSearchBar component's 'SearchTermsChanged' event.
|
||||
/// </summary>
|
||||
private async Task OnSearchSubmittedAsync(string searchTerms)
|
||||
{
|
||||
if (args.Key != "Enter" || string.IsNullOrWhiteSpace(SearchTerms))
|
||||
if (string.IsNullOrWhiteSpace(searchTerms))
|
||||
{
|
||||
OnClearResults(null);
|
||||
return;
|
||||
}
|
||||
|
||||
NavigationManager.NavigateTo($"/search/{SearchTerms}");
|
||||
SearchTerms = searchTerms;
|
||||
NavigationManager.NavigateTo($"/search/{Uri.EscapeDataString(SearchTerms)}", replace: true);
|
||||
await PerformSearchAsync();
|
||||
}
|
||||
|
||||
@@ -127,31 +103,31 @@ else
|
||||
/// </summary>
|
||||
private async Task PerformSearchAsync()
|
||||
{
|
||||
// Determine which filter expression to use based on the radio button selection
|
||||
// Determine which filter expression to use
|
||||
switch (_selectedFilter)
|
||||
{
|
||||
case SearchFilterType.Tags:
|
||||
case ArchiveSearchFilterType.Tags:
|
||||
_currentFilterPredicate = x => x.TagsSearchVector.Matches(SearchTerms);
|
||||
break;
|
||||
case SearchFilterType.Title:
|
||||
case ArchiveSearchFilterType.Title:
|
||||
_currentFilterPredicate = x => x.TitleSearchVector.Matches(SearchTerms);
|
||||
break;
|
||||
case SearchFilterType.Description:
|
||||
case ArchiveSearchFilterType.Description:
|
||||
_currentFilterPredicate = x => x.DescriptionSearchVector.Matches(SearchTerms);
|
||||
break;
|
||||
case SearchFilterType.Defects:
|
||||
case ArchiveSearchFilterType.Defects:
|
||||
_currentFilterPredicate = x => x.DefectsSearchVector.Matches(SearchTerms);
|
||||
break;
|
||||
case SearchFilterType.Filenames:
|
||||
case ArchiveSearchFilterType.Filenames:
|
||||
_currentFilterPredicate = x => x.FilenamesSearchVector.Matches(SearchTerms);
|
||||
break;
|
||||
case SearchFilterType.ArtifactTranscriptions:
|
||||
case ArchiveSearchFilterType.ArtifactTranscriptions:
|
||||
_currentFilterPredicate = x => x.FileContentSearchVector.Matches(SearchTerms);
|
||||
break;
|
||||
case SearchFilterType.ListedNames:
|
||||
_currentFilterPredicate = x => x.ListedNamesSearchVector.Matches(SearchTerms);
|
||||
case ArchiveSearchFilterType.ListedNames:
|
||||
_currentFilterPredicate = x => x.ListedNamesSearchVector.Matches(SearchTerms);
|
||||
break;
|
||||
case SearchFilterType.All:
|
||||
case ArchiveSearchFilterType.All:
|
||||
default:
|
||||
_currentFilterPredicate = x => x.AllSearchVector.Matches(SearchTerms);
|
||||
break;
|
||||
@@ -187,20 +163,26 @@ else
|
||||
|
||||
// The query uses the dynamically set filter predicate
|
||||
_artifactGroupings = await context.ArtifactGroupings
|
||||
.Where(_currentFilterPredicate)
|
||||
.Include(x => x.ChildArtifactEntries)
|
||||
.ThenInclude(x => x.Files)
|
||||
.OrderBy(x => x.Id)
|
||||
.Skip((_currentPage - 1) * PageSize)
|
||||
.Take(PageSize)
|
||||
.ToListAsync();
|
||||
.Where(_currentFilterPredicate)
|
||||
.Include(x => x.ChildArtifactEntries)
|
||||
.ThenInclude(x => x.Files)
|
||||
.OrderBy(x => x.Id)
|
||||
.Skip((_currentPage - 1) * PageSize)
|
||||
.Take(PageSize)
|
||||
.ToListAsync();
|
||||
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
private void OnClearResults(Microsoft.AspNetCore.Components.Web.MouseEventArgs args)
|
||||
{
|
||||
_totalResults = 0;
|
||||
_artifactGroupings.Clear();
|
||||
_currentPage = 1;
|
||||
_totalPages = 0;
|
||||
SearchTerms = "";
|
||||
|
||||
NavigationManager.NavigateTo("/search", replace: true);
|
||||
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user