mirror of
https://github.com/Kareadita/Kavita.git
synced 2025-07-31 14:33:50 -04:00
Filtering Bugs (#447)
# Fixed - Fixed: Fixed an issue with filtering, after applying a filter, the cards on screen did not update with the correct information - Fixed: Pagination is now slighlty smaller (only 8 pages) as on mobile, it was cutting off screen. # Changed - Changed: During library scan and series updates, Series names for Epubs will now trim excess white space =============================================== * Fixed issue where some formats could get returned with another format filter. * Filtering was not properly flushing DOM on filter change, updated trackbyidentity to account for filter * One more fix for the filtering bug * Made pagination UI slightly smaller to better fit on mobile phones. Trim() series names for Epub files and Trim() on series update for appropriate fields. * Removed a no longer needed animation.
This commit is contained in:
parent
55dd9e7f1e
commit
58856c0d70
@ -133,10 +133,10 @@ namespace API.Controllers
|
|||||||
{
|
{
|
||||||
return BadRequest("A series already exists in this library with this name. Series Names must be unique to a library.");
|
return BadRequest("A series already exists in this library with this name. Series Names must be unique to a library.");
|
||||||
}
|
}
|
||||||
series.Name = updateSeries.Name;
|
series.Name = updateSeries.Name.Trim();
|
||||||
series.LocalizedName = updateSeries.LocalizedName;
|
series.LocalizedName = updateSeries.LocalizedName.Trim();
|
||||||
series.SortName = updateSeries.SortName;
|
series.SortName = updateSeries.SortName.Trim();
|
||||||
series.Summary = updateSeries.Summary;
|
series.Summary = updateSeries.Summary.Trim();
|
||||||
|
|
||||||
_unitOfWork.SeriesRepository.Update(series);
|
_unitOfWork.SeriesRepository.Update(series);
|
||||||
|
|
||||||
|
@ -1,10 +1,12 @@
|
|||||||
using System.Collections.Generic;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using API.Comparators;
|
using API.Comparators;
|
||||||
using API.DTOs;
|
using API.DTOs;
|
||||||
using API.DTOs.Filtering;
|
using API.DTOs.Filtering;
|
||||||
using API.Entities;
|
using API.Entities;
|
||||||
|
using API.Entities.Enums;
|
||||||
using API.Extensions;
|
using API.Extensions;
|
||||||
using API.Helpers;
|
using API.Helpers;
|
||||||
using API.Interfaces;
|
using API.Interfaces;
|
||||||
@ -78,8 +80,9 @@ namespace API.Data
|
|||||||
|
|
||||||
public async Task<PagedList<SeriesDto>> GetSeriesDtoForLibraryIdAsync(int libraryId, int userId, UserParams userParams, FilterDto filter)
|
public async Task<PagedList<SeriesDto>> GetSeriesDtoForLibraryIdAsync(int libraryId, int userId, UserParams userParams, FilterDto filter)
|
||||||
{
|
{
|
||||||
|
var formats = filter.GetSqlFilter();
|
||||||
var query = _context.Series
|
var query = _context.Series
|
||||||
.Where(s => s.LibraryId == libraryId && (filter.MangaFormat == null || s.Format == filter.MangaFormat))
|
.Where(s => s.LibraryId == libraryId && formats.Contains(s.Format))
|
||||||
.OrderBy(s => s.SortName)
|
.OrderBy(s => s.SortName)
|
||||||
.ProjectTo<SeriesDto>(_mapper.ConfigurationProvider)
|
.ProjectTo<SeriesDto>(_mapper.ConfigurationProvider)
|
||||||
.AsNoTracking();
|
.AsNoTracking();
|
||||||
@ -307,6 +310,8 @@ namespace API.Data
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public async Task<PagedList<SeriesDto>> GetRecentlyAdded(int libraryId, int userId, UserParams userParams, FilterDto filter)
|
public async Task<PagedList<SeriesDto>> GetRecentlyAdded(int libraryId, int userId, UserParams userParams, FilterDto filter)
|
||||||
{
|
{
|
||||||
|
var formats = filter.GetSqlFilter();
|
||||||
|
|
||||||
if (libraryId == 0)
|
if (libraryId == 0)
|
||||||
{
|
{
|
||||||
var userLibraries = _context.Library
|
var userLibraries = _context.Library
|
||||||
@ -317,7 +322,7 @@ namespace API.Data
|
|||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
var allQuery = _context.Series
|
var allQuery = _context.Series
|
||||||
.Where(s => userLibraries.Contains(s.LibraryId) && (filter.MangaFormat == null || s.Format == filter.MangaFormat))
|
.Where(s => userLibraries.Contains(s.LibraryId) && formats.Contains(s.Format))
|
||||||
.AsNoTracking()
|
.AsNoTracking()
|
||||||
.OrderByDescending(s => s.Created)
|
.OrderByDescending(s => s.Created)
|
||||||
.ProjectTo<SeriesDto>(_mapper.ConfigurationProvider)
|
.ProjectTo<SeriesDto>(_mapper.ConfigurationProvider)
|
||||||
@ -327,7 +332,7 @@ namespace API.Data
|
|||||||
}
|
}
|
||||||
|
|
||||||
var query = _context.Series
|
var query = _context.Series
|
||||||
.Where(s => s.LibraryId == libraryId && (filter.MangaFormat == null || s.Format == filter.MangaFormat))
|
.Where(s => s.LibraryId == libraryId && formats.Contains(s.Format))
|
||||||
.AsNoTracking()
|
.AsNoTracking()
|
||||||
.OrderByDescending(s => s.Created)
|
.OrderByDescending(s => s.Created)
|
||||||
.ProjectTo<SeriesDto>(_mapper.ConfigurationProvider)
|
.ProjectTo<SeriesDto>(_mapper.ConfigurationProvider)
|
||||||
@ -346,9 +351,9 @@ namespace API.Data
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public async Task<PagedList<SeriesDto>> GetInProgress(int userId, int libraryId, UserParams userParams, FilterDto filter)
|
public async Task<PagedList<SeriesDto>> GetInProgress(int userId, int libraryId, UserParams userParams, FilterDto filter)
|
||||||
{
|
{
|
||||||
|
var formats = filter.GetSqlFilter();
|
||||||
var series = _context.Series
|
var series = _context.Series
|
||||||
.Where(s => filter.MangaFormat == null || s.Format == filter.MangaFormat)
|
.Where(s => formats.Contains(s.Format))
|
||||||
.Join(_context.AppUserProgresses, s => s.Id, progress => progress.SeriesId, (s, progress) => new
|
.Join(_context.AppUserProgresses, s => s.Id, progress => progress.SeriesId, (s, progress) => new
|
||||||
{
|
{
|
||||||
Series = s,
|
Series = s,
|
||||||
@ -367,14 +372,16 @@ namespace API.Data
|
|||||||
series = series.Where(s => s.AppUserId == userId
|
series = series.Where(s => s.AppUserId == userId
|
||||||
&& s.PagesRead > 0
|
&& s.PagesRead > 0
|
||||||
&& s.PagesRead < s.Series.Pages
|
&& s.PagesRead < s.Series.Pages
|
||||||
&& userLibraries.Contains(s.Series.LibraryId));
|
&& userLibraries.Contains(s.Series.LibraryId)
|
||||||
|
&& formats.Contains(s.Series.Format));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
series = series.Where(s => s.AppUserId == userId
|
series = series.Where(s => s.AppUserId == userId
|
||||||
&& s.PagesRead > 0
|
&& s.PagesRead > 0
|
||||||
&& s.PagesRead < s.Series.Pages
|
&& s.PagesRead < s.Series.Pages
|
||||||
&& s.Series.LibraryId == libraryId);
|
&& s.Series.LibraryId == libraryId
|
||||||
|
&& formats.Contains(s.Series.Format));
|
||||||
}
|
}
|
||||||
|
|
||||||
var retSeries = series
|
var retSeries = series
|
||||||
|
28
API/Extensions/FilterDtoExtensions.cs
Normal file
28
API/Extensions/FilterDtoExtensions.cs
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using API.DTOs.Filtering;
|
||||||
|
using API.Entities.Enums;
|
||||||
|
|
||||||
|
namespace API.Extensions
|
||||||
|
{
|
||||||
|
public static class FilterDtoExtensions
|
||||||
|
{
|
||||||
|
private static IList<MangaFormat> _allFormats = Enum.GetValues<MangaFormat>();
|
||||||
|
|
||||||
|
public static IList<MangaFormat> GetSqlFilter(this FilterDto filter)
|
||||||
|
{
|
||||||
|
var format = filter.MangaFormat;
|
||||||
|
if (format != null)
|
||||||
|
{
|
||||||
|
return new List<MangaFormat>()
|
||||||
|
{
|
||||||
|
(MangaFormat) format
|
||||||
|
};
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return _allFormats;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -323,10 +323,10 @@ namespace API.Services
|
|||||||
Edition = string.Empty,
|
Edition = string.Empty,
|
||||||
Format = MangaFormat.Epub,
|
Format = MangaFormat.Epub,
|
||||||
Filename = Path.GetFileName(filePath),
|
Filename = Path.GetFileName(filePath),
|
||||||
Title = specialName,
|
Title = specialName.Trim(),
|
||||||
FullFilePath = filePath,
|
FullFilePath = filePath,
|
||||||
IsSpecial = false,
|
IsSpecial = false,
|
||||||
Series = series,
|
Series = series.Trim(),
|
||||||
Volumes = seriesIndex.Split(".")[0]
|
Volumes = seriesIndex.Split(".")[0]
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -342,10 +342,10 @@ namespace API.Services
|
|||||||
Edition = string.Empty,
|
Edition = string.Empty,
|
||||||
Format = MangaFormat.Epub,
|
Format = MangaFormat.Epub,
|
||||||
Filename = Path.GetFileName(filePath),
|
Filename = Path.GetFileName(filePath),
|
||||||
Title = epubBook.Title,
|
Title = epubBook.Title.Trim(),
|
||||||
FullFilePath = filePath,
|
FullFilePath = filePath,
|
||||||
IsSpecial = false,
|
IsSpecial = false,
|
||||||
Series = epubBook.Title,
|
Series = epubBook.Title.Trim(),
|
||||||
Volumes = Parser.Parser.DefaultVolume
|
Volumes = Parser.Parser.DefaultVolume
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,12 @@
|
|||||||
<div class="container-fluid" style="padding-top: 10px">
|
<div class="container-fluid" style="padding-top: 10px">
|
||||||
<div class="row no-gutters">
|
<div class="row no-gutters pb-2">
|
||||||
<div class="col mr-auto">
|
<div class="col mr-auto">
|
||||||
<h2 style="display: inline-block">
|
<h2 style="display: inline-block">
|
||||||
<span *ngIf="actions.length > 0" class="">
|
<span *ngIf="actions.length > 0" class="">
|
||||||
<app-card-actionables (actionHandler)="performAction($event)" [actions]="actions" [labelBy]="header"></app-card-actionables>
|
<app-card-actionables (actionHandler)="performAction($event)" [actions]="actions" [labelBy]="header"></app-card-actionables>
|
||||||
</span> {{header}} <span class="badge badge-primary badge-pill" attr.aria-label="{{pagination.totalItems}} total items" *ngIf="pagination != undefined">{{pagination.totalItems}}</span>
|
</span> {{header}}
|
||||||
|
<!-- NOTE: On mobile the pill can eat up a lot of space, we can hide it and move to the filter section if user is interested -->
|
||||||
|
<span class="badge badge-primary badge-pill" attr.aria-label="{{pagination.totalItems}} total items" *ngIf="pagination != undefined">{{pagination.totalItems}}</span>
|
||||||
</h2>
|
</h2>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -24,6 +26,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<ng-container [ngTemplateOutlet]="paginationTemplate" [ngTemplateOutletContext]="{ id: 'top' }"></ng-container>
|
<ng-container [ngTemplateOutlet]="paginationTemplate" [ngTemplateOutletContext]="{ id: 'top' }"></ng-container>
|
||||||
|
|
||||||
@ -45,13 +48,12 @@
|
|||||||
<div class="d-flex justify-content-center" *ngIf="pagination && items.length > 0">
|
<div class="d-flex justify-content-center" *ngIf="pagination && items.length > 0">
|
||||||
<ngb-pagination
|
<ngb-pagination
|
||||||
*ngIf="pagination.totalPages > 1"
|
*ngIf="pagination.totalPages > 1"
|
||||||
[maxSize]="10"
|
[maxSize]="8"
|
||||||
[rotate]="true"
|
[rotate]="true"
|
||||||
[ellipses]="false"
|
[ellipses]="false"
|
||||||
[(page)]="pagination.currentPage"
|
[(page)]="pagination.currentPage"
|
||||||
[pageSize]="pagination.itemsPerPage"
|
[pageSize]="pagination.itemsPerPage"
|
||||||
(pageChange)="onPageChange($event)"
|
(pageChange)="onPageChange($event)"
|
||||||
[boundaryLinks]="true"
|
|
||||||
[collectionSize]="pagination.totalItems">
|
[collectionSize]="pagination.totalItems">
|
||||||
|
|
||||||
<ng-template ngbPaginationPages let-page let-pages="pages" *ngIf="pagination.totalItems / pagination.itemsPerPage > 20">
|
<ng-template ngbPaginationPages let-page let-pages="pages" *ngIf="pagination.totalItems / pagination.itemsPerPage > 20">
|
||||||
|
@ -66,7 +66,7 @@ export class CardDetailLayoutComponent implements OnInit {
|
|||||||
constructor() { }
|
constructor() { }
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
this.trackByIdentity = (index: number, item: any) => `${this.header}_${this.pagination?.currentPage}_${index}`;
|
this.trackByIdentity = (index: number, item: any) => `${this.header}_${this.pagination?.currentPage}_${this.filterForm.get('filter')?.value}_${item.id}_${index}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
onPageChange(page: number) {
|
onPageChange(page: number) {
|
||||||
|
@ -8,10 +8,7 @@
|
|||||||
|
|
||||||
@import '~swiper/swiper.scss';
|
@import '~swiper/swiper.scss';
|
||||||
|
|
||||||
// Custom animation for ng-lazyload-image
|
|
||||||
img.ng-lazyloaded {
|
|
||||||
//animation: fadein .5s; // I think it might look better without animation
|
|
||||||
}
|
|
||||||
@keyframes fadein {
|
@keyframes fadein {
|
||||||
from { opacity: 0; }
|
from { opacity: 0; }
|
||||||
to { opacity: 1; }
|
to { opacity: 1; }
|
||||||
@ -114,3 +111,9 @@ body {
|
|||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Debug styles
|
||||||
|
.redlines * {
|
||||||
|
outline: 1px solid red;
|
||||||
|
outline-offset: -1px;
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user