Filtering Bugfixes (#1220)
* Cleaned up random strings and unified them in one place. * Implemented the ability to disable typeaheads * Refactored disable state to disable controls on filter * Fixed an overflow regression on title * Updated ComicInfo DTO which had some bad properties on it * Cleaned up some code around disabled typeaheads/filters * Fixed typeaheads causing resets to state and mucking up filter presets * Fixed state not refreshing between page loads * Fixed a bad parsing for My Charms Are Wasted on Kuroiwa Medaka - Ch. 37.5 - Volume Extras * Cleanup within the metadata filter to reuse logic and minimize extra loops. * Fixed a timing issue with typeahead and first load for people * Fixed a bug in Publication Status for a given library, which would fail due to not performing some of the query in memory. Removed a custom index on Series table that wasn't used and potentially caused constraint issues. * Added a wiki link for stats collections * Security bump * Fixed the regex
This commit is contained in:
parent
e3aa9abf55
commit
e630e0b2c9
28 changed files with 1856 additions and 291 deletions
|
|
@ -1,10 +1,42 @@
|
|||
import { Injectable } from '@angular/core';
|
||||
import { ActivatedRoute, ActivatedRouteSnapshot } from '@angular/router';
|
||||
import { LibraryType } from 'src/app/_models/library';
|
||||
import { Pagination } from 'src/app/_models/pagination';
|
||||
import { SeriesFilter, SortField } from 'src/app/_models/series-filter';
|
||||
import { SeriesService } from 'src/app/_services/series.service';
|
||||
|
||||
/**
|
||||
* Used to pass state between the filter and the url
|
||||
*/
|
||||
export enum FilterQueryParam {
|
||||
Format = 'format',
|
||||
Genres = 'genres',
|
||||
AgeRating = 'ageRating',
|
||||
PublicationStatus = 'publicationStatus',
|
||||
Tags = 'tags',
|
||||
Languages = 'languages',
|
||||
CollectionTags = 'collectionTags',
|
||||
Libraries = 'libraries',
|
||||
Writers = 'writers',
|
||||
Artists = 'artists',
|
||||
Character = 'character',
|
||||
Colorist = 'colorist',
|
||||
CoverArtists = 'coverArtists',
|
||||
Editor = 'editor',
|
||||
Inker = 'inker',
|
||||
Letterer = 'letterer',
|
||||
Penciller = 'penciller',
|
||||
Publisher = 'publisher',
|
||||
Translator = 'translators',
|
||||
ReadStatus = 'readStatus',
|
||||
SortBy = 'sortBy',
|
||||
Rating = 'rating',
|
||||
Name = 'name',
|
||||
/**
|
||||
* This is a pagination control
|
||||
*/
|
||||
Page = 'page'
|
||||
}
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
|
|
@ -38,10 +70,11 @@ export class FilterUtilitiesService {
|
|||
|
||||
/**
|
||||
* Will fetch current page from route if present
|
||||
* @param ActivatedRouteSnapshot to fetch page from. Must be from component else may get stale data
|
||||
* @returns A default pagination object
|
||||
*/
|
||||
pagination(): Pagination {
|
||||
return {currentPage: parseInt(this.route.snapshot.queryParamMap.get('page') || '1', 10), itemsPerPage: 30, totalItems: 0, totalPages: 1};
|
||||
pagination(snapshot: ActivatedRouteSnapshot): Pagination {
|
||||
return {currentPage: parseInt(snapshot.queryParamMap.get('page') || '1', 10), itemsPerPage: 30, totalItems: 0, totalPages: 1};
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -54,46 +87,44 @@ export class FilterUtilitiesService {
|
|||
urlFromFilter(currentUrl: string, filter: SeriesFilter | undefined) {
|
||||
if (filter === undefined) return currentUrl;
|
||||
let params = '';
|
||||
|
||||
|
||||
|
||||
params += this.joinFilter(filter.formats, 'format');
|
||||
params += this.joinFilter(filter.genres, 'genres');
|
||||
params += this.joinFilter(filter.ageRating, 'ageRating');
|
||||
params += this.joinFilter(filter.publicationStatus, 'publicationStatus');
|
||||
params += this.joinFilter(filter.tags, 'tags');
|
||||
params += this.joinFilter(filter.languages, 'languages');
|
||||
params += this.joinFilter(filter.collectionTags, 'collectionTags');
|
||||
params += this.joinFilter(filter.libraries, 'libraries');
|
||||
params += this.joinFilter(filter.formats, FilterQueryParam.Format);
|
||||
params += this.joinFilter(filter.genres, FilterQueryParam.Genres);
|
||||
params += this.joinFilter(filter.ageRating, FilterQueryParam.AgeRating);
|
||||
params += this.joinFilter(filter.publicationStatus, FilterQueryParam.PublicationStatus);
|
||||
params += this.joinFilter(filter.tags, FilterQueryParam.Tags);
|
||||
params += this.joinFilter(filter.languages, FilterQueryParam.Languages);
|
||||
params += this.joinFilter(filter.collectionTags, FilterQueryParam.CollectionTags);
|
||||
params += this.joinFilter(filter.libraries, FilterQueryParam.Libraries);
|
||||
|
||||
params += this.joinFilter(filter.writers, 'writers');
|
||||
params += this.joinFilter(filter.artists, 'artists');
|
||||
params += this.joinFilter(filter.character, 'character');
|
||||
params += this.joinFilter(filter.colorist, 'colorist');
|
||||
params += this.joinFilter(filter.coverArtist, 'coverArtists');
|
||||
params += this.joinFilter(filter.editor, 'editor');
|
||||
params += this.joinFilter(filter.inker, 'inker');
|
||||
params += this.joinFilter(filter.letterer, 'letterer');
|
||||
params += this.joinFilter(filter.penciller, 'penciller');
|
||||
params += this.joinFilter(filter.publisher, 'publisher');
|
||||
params += this.joinFilter(filter.translators, 'translators');
|
||||
params += this.joinFilter(filter.writers, FilterQueryParam.Writers);
|
||||
params += this.joinFilter(filter.artists, FilterQueryParam.Artists);
|
||||
params += this.joinFilter(filter.character, FilterQueryParam.Character);
|
||||
params += this.joinFilter(filter.colorist, FilterQueryParam.Colorist);
|
||||
params += this.joinFilter(filter.coverArtist, FilterQueryParam.CoverArtists);
|
||||
params += this.joinFilter(filter.editor, FilterQueryParam.Editor);
|
||||
params += this.joinFilter(filter.inker, FilterQueryParam.Inker);
|
||||
params += this.joinFilter(filter.letterer, FilterQueryParam.Letterer);
|
||||
params += this.joinFilter(filter.penciller, FilterQueryParam.Penciller);
|
||||
params += this.joinFilter(filter.publisher, FilterQueryParam.Publisher);
|
||||
params += this.joinFilter(filter.translators, FilterQueryParam.Translator);
|
||||
|
||||
// readStatus (we need to do an additonal check as there is a default case)
|
||||
if (filter.readStatus && filter.readStatus.inProgress !== true && filter.readStatus.notRead !== true && filter.readStatus.read !== true) {
|
||||
params += '&readStatus=' + `${filter.readStatus.inProgress},${filter.readStatus.notRead},${filter.readStatus.read}`;
|
||||
params += `&${FilterQueryParam.ReadStatus}=${filter.readStatus.inProgress},${filter.readStatus.notRead},${filter.readStatus.read}`;
|
||||
}
|
||||
|
||||
// sortBy (additional check to not save to url if default case)
|
||||
if (filter.sortOptions && !(filter.sortOptions.sortField === SortField.SortName && filter.sortOptions.isAscending === true)) {
|
||||
params += '&sortBy=' + filter.sortOptions.sortField + ',' + filter.sortOptions.isAscending;
|
||||
params += `&${FilterQueryParam.SortBy}=${filter.sortOptions.sortField},${filter.sortOptions.isAscending}`;
|
||||
}
|
||||
|
||||
if (filter.rating > 0) {
|
||||
params += '&rating=' + filter.rating;
|
||||
params += `&${FilterQueryParam.Rating}=${filter.rating}`;
|
||||
}
|
||||
|
||||
if (filter.seriesNameQuery !== '') {
|
||||
params += '&name=' + encodeURIComponent(filter.seriesNameQuery);
|
||||
params += `&${FilterQueryParam.Name}=${encodeURIComponent(filter.seriesNameQuery)}`;
|
||||
}
|
||||
|
||||
return currentUrl + params;
|
||||
|
|
@ -102,143 +133,143 @@ export class FilterUtilitiesService {
|
|||
private joinFilter(filterProp: Array<any>, key: string) {
|
||||
let params = '';
|
||||
if (filterProp.length > 0) {
|
||||
params += `&${key}=` + filterProp.join(',');
|
||||
params += `&${key}=${filterProp.join(',')}`;
|
||||
}
|
||||
return params;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new instance of a filterSettings that is populated with filter presets from URL
|
||||
* @param ActivatedRouteSnapshot to fetch page from. Must be from component else may get stale data
|
||||
* @returns The Preset filter and if something was set within
|
||||
*/
|
||||
filterPresetsFromUrl(): [SeriesFilter, boolean] {
|
||||
const snapshot = this.route.snapshot;
|
||||
filterPresetsFromUrl(snapshot: ActivatedRouteSnapshot): [SeriesFilter, boolean] {
|
||||
const filter = this.seriesService.createSeriesFilter();
|
||||
let anyChanged = false;
|
||||
|
||||
const format = snapshot.queryParamMap.get('format');
|
||||
const format = snapshot.queryParamMap.get(FilterQueryParam.Format);
|
||||
if (format !== undefined && format !== null) {
|
||||
filter.formats = [...filter.formats, ...format.split(',').map(item => parseInt(item, 10))];
|
||||
anyChanged = true;
|
||||
}
|
||||
|
||||
const genres = snapshot.queryParamMap.get('genres');
|
||||
const genres = snapshot.queryParamMap.get(FilterQueryParam.Genres);
|
||||
if (genres !== undefined && genres !== null) {
|
||||
filter.genres = [...filter.genres, ...genres.split(',').map(item => parseInt(item, 10))];
|
||||
anyChanged = true;
|
||||
}
|
||||
|
||||
const ageRating = snapshot.queryParamMap.get('ageRating');
|
||||
const ageRating = snapshot.queryParamMap.get(FilterQueryParam.AgeRating);
|
||||
if (ageRating !== undefined && ageRating !== null) {
|
||||
filter.ageRating = [...filter.ageRating, ...ageRating.split(',').map(item => parseInt(item, 10))];
|
||||
anyChanged = true;
|
||||
}
|
||||
|
||||
const publicationStatus = snapshot.queryParamMap.get('publicationStatus');
|
||||
const publicationStatus = snapshot.queryParamMap.get(FilterQueryParam.PublicationStatus);
|
||||
if (publicationStatus !== undefined && publicationStatus !== null) {
|
||||
filter.publicationStatus = [...filter.publicationStatus, ...publicationStatus.split(',').map(item => parseInt(item, 10))];
|
||||
anyChanged = true;
|
||||
}
|
||||
|
||||
const tags = snapshot.queryParamMap.get('tags');
|
||||
const tags = snapshot.queryParamMap.get(FilterQueryParam.Tags);
|
||||
if (tags !== undefined && tags !== null) {
|
||||
filter.tags = [...filter.tags, ...tags.split(',').map(item => parseInt(item, 10))];
|
||||
anyChanged = true;
|
||||
}
|
||||
|
||||
const languages = snapshot.queryParamMap.get('languages');
|
||||
const languages = snapshot.queryParamMap.get(FilterQueryParam.Languages);
|
||||
if (languages !== undefined && languages !== null) {
|
||||
filter.languages = [...filter.languages, ...languages.split(',')];
|
||||
anyChanged = true;
|
||||
}
|
||||
|
||||
const writers = snapshot.queryParamMap.get('writers');
|
||||
const writers = snapshot.queryParamMap.get(FilterQueryParam.Writers);
|
||||
if (writers !== undefined && writers !== null) {
|
||||
filter.writers = [...filter.writers, ...writers.split(',').map(item => parseInt(item, 10))];
|
||||
anyChanged = true;
|
||||
}
|
||||
|
||||
const artists = snapshot.queryParamMap.get('artists');
|
||||
const artists = snapshot.queryParamMap.get(FilterQueryParam.Artists);
|
||||
if (artists !== undefined && artists !== null) {
|
||||
filter.artists = [...filter.artists, ...artists.split(',').map(item => parseInt(item, 10))];
|
||||
anyChanged = true;
|
||||
}
|
||||
|
||||
const character = snapshot.queryParamMap.get('character');
|
||||
const character = snapshot.queryParamMap.get(FilterQueryParam.Character);
|
||||
if (character !== undefined && character !== null) {
|
||||
filter.character = [...filter.character, ...character.split(',').map(item => parseInt(item, 10))];
|
||||
anyChanged = true;
|
||||
}
|
||||
|
||||
const colorist = snapshot.queryParamMap.get('colorist');
|
||||
const colorist = snapshot.queryParamMap.get(FilterQueryParam.Colorist);
|
||||
if (colorist !== undefined && colorist !== null) {
|
||||
filter.colorist = [...filter.colorist, ...colorist.split(',').map(item => parseInt(item, 10))];
|
||||
anyChanged = true;
|
||||
}
|
||||
|
||||
const coverArtists = snapshot.queryParamMap.get('coverArtists');
|
||||
const coverArtists = snapshot.queryParamMap.get(FilterQueryParam.CoverArtists);
|
||||
if (coverArtists !== undefined && coverArtists !== null) {
|
||||
filter.coverArtist = [...filter.coverArtist, ...coverArtists.split(',').map(item => parseInt(item, 10))];
|
||||
anyChanged = true;
|
||||
}
|
||||
|
||||
const editor = snapshot.queryParamMap.get('editor');
|
||||
const editor = snapshot.queryParamMap.get(FilterQueryParam.Editor);
|
||||
if (editor !== undefined && editor !== null) {
|
||||
filter.editor = [...filter.editor, ...editor.split(',').map(item => parseInt(item, 10))];
|
||||
anyChanged = true;
|
||||
}
|
||||
|
||||
const inker = snapshot.queryParamMap.get('inker');
|
||||
const inker = snapshot.queryParamMap.get(FilterQueryParam.Inker);
|
||||
if (inker !== undefined && inker !== null) {
|
||||
filter.inker = [...filter.inker, ...inker.split(',').map(item => parseInt(item, 10))];
|
||||
anyChanged = true;
|
||||
}
|
||||
|
||||
const letterer = snapshot.queryParamMap.get('letterer');
|
||||
const letterer = snapshot.queryParamMap.get(FilterQueryParam.Letterer);
|
||||
if (letterer !== undefined && letterer !== null) {
|
||||
filter.letterer = [...filter.letterer, ...letterer.split(',').map(item => parseInt(item, 10))];
|
||||
anyChanged = true;
|
||||
}
|
||||
|
||||
const penciller = snapshot.queryParamMap.get('penciller');
|
||||
const penciller = snapshot.queryParamMap.get(FilterQueryParam.Penciller);
|
||||
if (penciller !== undefined && penciller !== null) {
|
||||
filter.penciller = [...filter.penciller, ...penciller.split(',').map(item => parseInt(item, 10))];
|
||||
anyChanged = true;
|
||||
}
|
||||
|
||||
const publisher = snapshot.queryParamMap.get('publisher');
|
||||
const publisher = snapshot.queryParamMap.get(FilterQueryParam.Publisher);
|
||||
if (publisher !== undefined && publisher !== null) {
|
||||
filter.publisher = [...filter.publisher, ...publisher.split(',').map(item => parseInt(item, 10))];
|
||||
anyChanged = true;
|
||||
}
|
||||
|
||||
const translators = snapshot.queryParamMap.get('translators');
|
||||
const translators = snapshot.queryParamMap.get(FilterQueryParam.Translator);
|
||||
if (translators !== undefined && translators !== null) {
|
||||
filter.translators = [...filter.translators, ...translators.split(',').map(item => parseInt(item, 10))];
|
||||
anyChanged = true;
|
||||
}
|
||||
|
||||
const libraries = snapshot.queryParamMap.get('libraries');
|
||||
const libraries = snapshot.queryParamMap.get(FilterQueryParam.Libraries);
|
||||
if (libraries !== undefined && libraries !== null) {
|
||||
filter.libraries = [...filter.libraries, ...libraries.split(',').map(item => parseInt(item, 10))];
|
||||
anyChanged = true;
|
||||
}
|
||||
|
||||
const collectionTags = snapshot.queryParamMap.get('collectionTags');
|
||||
const collectionTags = snapshot.queryParamMap.get(FilterQueryParam.CollectionTags);
|
||||
if (collectionTags !== undefined && collectionTags !== null) {
|
||||
filter.collectionTags = [...filter.collectionTags, ...collectionTags.split(',').map(item => parseInt(item, 10))];
|
||||
anyChanged = true;
|
||||
}
|
||||
|
||||
// Rating, seriesName,
|
||||
const rating = snapshot.queryParamMap.get('rating');
|
||||
const rating = snapshot.queryParamMap.get(FilterQueryParam.Rating);
|
||||
if (rating !== undefined && rating !== null && parseInt(rating, 10) > 0) {
|
||||
filter.rating = parseInt(rating, 10);
|
||||
anyChanged = true;
|
||||
}
|
||||
|
||||
/// Read status is encoded as true,true,true
|
||||
const readStatus = snapshot.queryParamMap.get('readStatus');
|
||||
const readStatus = snapshot.queryParamMap.get(FilterQueryParam.ReadStatus);
|
||||
if (readStatus !== undefined && readStatus !== null) {
|
||||
const values = readStatus.split(',').map(i => i === 'true');
|
||||
if (values.length === 3) {
|
||||
|
|
@ -249,7 +280,7 @@ export class FilterUtilitiesService {
|
|||
}
|
||||
}
|
||||
|
||||
const sortBy = snapshot.queryParamMap.get('sortBy');
|
||||
const sortBy = snapshot.queryParamMap.get(FilterQueryParam.SortBy);
|
||||
if (sortBy !== undefined && sortBy !== null) {
|
||||
const values = sortBy.split(',');
|
||||
if (values.length === 1) {
|
||||
|
|
@ -264,7 +295,7 @@ export class FilterUtilitiesService {
|
|||
}
|
||||
}
|
||||
|
||||
const searchNameQuery = snapshot.queryParamMap.get('name');
|
||||
const searchNameQuery = snapshot.queryParamMap.get(FilterQueryParam.Name);
|
||||
if (searchNameQuery !== undefined && searchNameQuery !== null && searchNameQuery !== '') {
|
||||
filter.seriesNameQuery = decodeURIComponent(searchNameQuery);
|
||||
anyChanged = true;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue