Smart Filter Encoding Fix (#2387)
This commit is contained in:
parent
b6d4938e22
commit
9894a2623c
133 changed files with 677 additions and 471 deletions
|
@ -1,8 +1,15 @@
|
|||
export interface Pagination {
|
||||
export class Pagination {
|
||||
currentPage: number;
|
||||
itemsPerPage: number;
|
||||
totalItems: number;
|
||||
totalPages: number;
|
||||
|
||||
constructor() {
|
||||
this.currentPage = 0;
|
||||
this.itemsPerPage = 0;
|
||||
this.totalItems = 0;
|
||||
this.totalPages = 0;
|
||||
}
|
||||
}
|
||||
|
||||
export class PaginatedResult<T> {
|
||||
|
|
|
@ -1,16 +1,14 @@
|
|||
import {HttpClient} from '@angular/common/http';
|
||||
import {Injectable} from '@angular/core';
|
||||
import {map, tap} from 'rxjs/operators';
|
||||
import {of, ReplaySubject, switchMap} from 'rxjs';
|
||||
import {tap} from 'rxjs/operators';
|
||||
import {of} from 'rxjs';
|
||||
import {environment} from 'src/environments/environment';
|
||||
import {Genre} from '../_models/metadata/genre';
|
||||
import {AgeRating} from '../_models/metadata/age-rating';
|
||||
import {AgeRatingDto} from '../_models/metadata/age-rating-dto';
|
||||
import {Language} from '../_models/metadata/language';
|
||||
import {PublicationStatusDto} from '../_models/metadata/publication-status-dto';
|
||||
import {Person, PersonRole} from '../_models/metadata/person';
|
||||
import {Tag} from '../_models/tag';
|
||||
import {TextResonse} from '../_types/text-response';
|
||||
import {FilterComparison} from '../_models/metadata/v2/filter-comparison';
|
||||
import {FilterField} from '../_models/metadata/v2/filter-field';
|
||||
import {Router} from "@angular/router";
|
||||
|
@ -93,10 +91,6 @@ export class MetadataService {
|
|||
return this.httpClient.get<Array<Person>>(this.baseUrl + 'metadata/people-by-role?role=' + role);
|
||||
}
|
||||
|
||||
// getChapterSummary(chapterId: number) {
|
||||
// return this.httpClient.get<string>(this.baseUrl + 'metadata/chapter-summary?chapterId=' + chapterId, TextResonse);
|
||||
// }
|
||||
|
||||
createDefaultFilterDto(): SeriesFilterV2 {
|
||||
return {
|
||||
statements: [] as FilterStatement[],
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
<h6 subtitle *ngIf="pagination">{{t('series-count', {num: pagination.totalItems | number})}}</h6>
|
||||
</app-side-nav-companion-bar>
|
||||
<app-bulk-operations [actionCallback]="bulkActionCallback"></app-bulk-operations>
|
||||
<app-card-detail-layout
|
||||
<app-card-detail-layout *ngIf="filter"
|
||||
[isLoading]="loadingSeries"
|
||||
[items]="series"
|
||||
[trackByIdentity]="trackByIdentity"
|
||||
|
|
|
@ -47,7 +47,7 @@ export class AllSeriesComponent implements OnInit {
|
|||
title: string = translate('all-series.title');
|
||||
series: Series[] = [];
|
||||
loadingSeries = false;
|
||||
pagination!: Pagination;
|
||||
pagination: Pagination = new Pagination();
|
||||
filter: SeriesFilterV2 | undefined = undefined;
|
||||
filterSettings: FilterSettings = new FilterSettings();
|
||||
filterOpen: EventEmitter<boolean> = new EventEmitter();
|
||||
|
@ -113,20 +113,18 @@ export class AllSeriesComponent implements OnInit {
|
|||
|
||||
this.router.routeReuseStrategy.shouldReuseRoute = () => false;
|
||||
|
||||
this.title = this.route.snapshot.queryParamMap.get('title') || this.title;
|
||||
this.titleService.setTitle('Kavita - ' + this.title);
|
||||
this.filterUtilityService.filterPresetsFromUrl(this.route.snapshot).subscribe(filter => {
|
||||
this.filter = filter;
|
||||
|
||||
this.pagination = this.filterUtilityService.pagination(this.route.snapshot);
|
||||
this.title = this.route.snapshot.queryParamMap.get('title') || this.filter.name || this.title;
|
||||
this.titleService.setTitle('Kavita - ' + this.title);
|
||||
|
||||
this.filter = this.filterUtilityService.filterPresetsFromUrlV2(this.route.snapshot);
|
||||
if (this.filter.statements.length === 0) {
|
||||
this.filter!.statements.push(this.filterUtilityService.createSeriesV2DefaultStatement());
|
||||
}
|
||||
this.filterActiveCheck = this.filterUtilityService.createSeriesV2Filter();
|
||||
this.filterActiveCheck!.statements.push(this.filterUtilityService.createSeriesV2DefaultStatement());
|
||||
this.filterSettings.presetsV2 = this.filter;
|
||||
this.filterActiveCheck = this.filterUtilityService.createSeriesV2Filter();
|
||||
this.filterActiveCheck!.statements.push(this.filterUtilityService.createSeriesV2DefaultStatement());
|
||||
this.filterSettings.presetsV2 = this.filter;
|
||||
|
||||
this.cdRef.markForCheck();
|
||||
this.cdRef.markForCheck();
|
||||
});
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
|
@ -155,16 +153,20 @@ export class AllSeriesComponent implements OnInit {
|
|||
if (data.filterV2 === undefined) return;
|
||||
this.filter = data.filterV2;
|
||||
|
||||
if (!data.isFirst) {
|
||||
this.filterUtilityService.updateUrlFromFilterV2(this.pagination, this.filter);
|
||||
if (data.isFirst) {
|
||||
this.loadPage();
|
||||
return;
|
||||
}
|
||||
|
||||
this.loadPage();
|
||||
this.filterUtilityService.updateUrlFromFilter(this.filter).subscribe((encodedFilter) => {
|
||||
this.loadPage();
|
||||
});
|
||||
}
|
||||
|
||||
loadPage() {
|
||||
this.filterActive = !this.utilityService.deepEqual(this.filter, this.filterActiveCheck);
|
||||
this.loadingSeries = true;
|
||||
this.title = this.route.snapshot.queryParamMap.get('title') || this.filter?.name || translate('all-series.title');
|
||||
this.cdRef.markForCheck();
|
||||
this.seriesService.getAllSeriesV2(undefined, undefined, this.filter!).pipe(take(1)).subscribe(series => {
|
||||
this.series = series.result;
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
<h6 subtitle>{{t('series-count', {num: series.length | number})}}</h6>
|
||||
</app-side-nav-companion-bar>
|
||||
<app-bulk-operations [actionCallback]="bulkActionCallback"></app-bulk-operations>
|
||||
<app-card-detail-layout
|
||||
<app-card-detail-layout *ngIf="filter"
|
||||
[isLoading]="loadingBookmarks"
|
||||
[items]="series"
|
||||
[filterSettings]="filterSettings"
|
||||
|
|
|
@ -26,7 +26,7 @@ import { ImageService } from 'src/app/_services/image.service';
|
|||
import { JumpbarService } from 'src/app/_services/jumpbar.service';
|
||||
import { ReaderService } from 'src/app/_services/reader.service';
|
||||
import { SeriesService } from 'src/app/_services/series.service';
|
||||
import { DecimalPipe } from '@angular/common';
|
||||
import {DecimalPipe, NgIf} from '@angular/common';
|
||||
import { CardItemComponent } from '../../../cards/card-item/card-item.component';
|
||||
import { CardDetailLayoutComponent } from '../../../cards/card-detail-layout/card-detail-layout.component';
|
||||
import { BulkOperationsComponent } from '../../../cards/bulk-operations/bulk-operations.component';
|
||||
|
@ -36,12 +36,12 @@ import {SeriesFilterV2} from "../../../_models/metadata/v2/series-filter-v2";
|
|||
import {Title} from "@angular/platform-browser";
|
||||
|
||||
@Component({
|
||||
selector: 'app-bookmarks',
|
||||
templateUrl: './bookmarks.component.html',
|
||||
styleUrls: ['./bookmarks.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
standalone: true,
|
||||
imports: [SideNavCompanionBarComponent, BulkOperationsComponent, CardDetailLayoutComponent, CardItemComponent, DecimalPipe, TranslocoDirective]
|
||||
selector: 'app-bookmarks',
|
||||
templateUrl: './bookmarks.component.html',
|
||||
styleUrls: ['./bookmarks.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
standalone: true,
|
||||
imports: [SideNavCompanionBarComponent, BulkOperationsComponent, CardDetailLayoutComponent, CardItemComponent, DecimalPipe, TranslocoDirective, NgIf]
|
||||
})
|
||||
export class BookmarksComponent implements OnInit {
|
||||
|
||||
|
@ -54,7 +54,7 @@ export class BookmarksComponent implements OnInit {
|
|||
actions: ActionItem<Series>[] = [];
|
||||
jumpbarKeys: Array<JumpKey> = [];
|
||||
|
||||
pagination!: Pagination;
|
||||
pagination: Pagination = new Pagination();
|
||||
filter: SeriesFilterV2 | undefined = undefined;
|
||||
filterSettings: FilterSettings = new FilterSettings();
|
||||
filterOpen: EventEmitter<boolean> = new EventEmitter();
|
||||
|
@ -73,20 +73,23 @@ export class BookmarksComponent implements OnInit {
|
|||
private router: Router, private readonly cdRef: ChangeDetectorRef,
|
||||
private filterUtilityService: FilterUtilitiesService, private route: ActivatedRoute,
|
||||
private jumpbarService: JumpbarService, private titleService: Title) {
|
||||
this.filter = this.filterUtilityService.filterPresetsFromUrlV2(this.route.snapshot);
|
||||
if (this.filter.statements.length === 0) {
|
||||
this.filter!.statements.push(this.filterUtilityService.createSeriesV2DefaultStatement());
|
||||
}
|
||||
this.filterActiveCheck = this.filterUtilityService.createSeriesV2Filter();
|
||||
this.filterActiveCheck!.statements.push(this.filterUtilityService.createSeriesV2DefaultStatement());
|
||||
this.filterSettings.presetsV2 = this.filter;
|
||||
this.filterSettings.statementLimit = 1;
|
||||
|
||||
this.filterUtilityService.filterPresetsFromUrl(this.route.snapshot).subscribe(filter => {
|
||||
this.filter = filter;
|
||||
|
||||
this.filterActiveCheck = this.filterUtilityService.createSeriesV2Filter();
|
||||
this.filterActiveCheck!.statements.push(this.filterUtilityService.createSeriesV2DefaultStatement());
|
||||
this.filterSettings.presetsV2 = this.filter;
|
||||
this.filterSettings.statementLimit = 1;
|
||||
|
||||
this.cdRef.markForCheck();
|
||||
});
|
||||
|
||||
this.titleService.setTitle('Kavita - ' + translate('bookmarks.title'));
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.actions = this.actionFactoryService.getBookmarkActions(this.handleAction.bind(this));
|
||||
this.pagination = this.filterUtilityService.pagination(this.route.snapshot);
|
||||
}
|
||||
|
||||
|
||||
|
@ -142,7 +145,7 @@ export class BookmarksComponent implements OnInit {
|
|||
this.readerService.clearMultipleBookmarks(seriesIds).subscribe(() => {
|
||||
this.toastr.success(this.translocoService.translate('bookmarks.delete-success'));
|
||||
this.bulkSelectionService.deselectAll();
|
||||
this.loadBookmarks();
|
||||
this.loadPage();
|
||||
});
|
||||
break;
|
||||
default:
|
||||
|
@ -150,7 +153,7 @@ export class BookmarksComponent implements OnInit {
|
|||
}
|
||||
}
|
||||
|
||||
loadBookmarks() {
|
||||
loadPage() {
|
||||
this.loadingBookmarks = true;
|
||||
this.cdRef.markForCheck();
|
||||
|
||||
|
@ -210,11 +213,13 @@ export class BookmarksComponent implements OnInit {
|
|||
if (data.filterV2 === undefined) return;
|
||||
this.filter = data.filterV2;
|
||||
|
||||
if (!data.isFirst) {
|
||||
this.filterUtilityService.updateUrlFromFilterV2(this.pagination, this.filter);
|
||||
if (data.isFirst) {
|
||||
this.loadPage();
|
||||
return;
|
||||
}
|
||||
|
||||
this.loadBookmarks();
|
||||
this.filterUtilityService.updateUrlFromFilter(this.filter).subscribe((encodedFilter) => {
|
||||
this.loadPage();
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -170,7 +170,7 @@ export class BulkSelectionService {
|
|||
|
||||
private applyFilter(action: ActionItem<any>, allowedActions: Array<Action>) {
|
||||
|
||||
var ret = false;
|
||||
let ret = false;
|
||||
if (action.action === Action.Submenu || allowedActions.includes(action.action)) {
|
||||
// Do something
|
||||
ret = true;
|
||||
|
|
|
@ -22,8 +22,8 @@
|
|||
</div>
|
||||
<app-bulk-operations [actionCallback]="bulkActionCallback"></app-bulk-operations>
|
||||
|
||||
<app-card-detail-layout
|
||||
header="Series"
|
||||
<app-card-detail-layout *ngIf="filter"
|
||||
[header]="t('series-header')"
|
||||
[isLoading]="isLoading"
|
||||
[items]="series"
|
||||
[pagination]="pagination"
|
||||
|
|
|
@ -72,7 +72,7 @@ export class CollectionDetailComponent implements OnInit, AfterContentChecked {
|
|||
collectionTag!: CollectionTag;
|
||||
isLoading: boolean = true;
|
||||
series: Array<Series> = [];
|
||||
pagination!: Pagination;
|
||||
pagination: Pagination = new Pagination();
|
||||
collectionTagActions: ActionItem<CollectionTag>[] = [];
|
||||
filter: SeriesFilterV2 | undefined = undefined;
|
||||
filterSettings: FilterSettings = new FilterSettings();
|
||||
|
@ -168,19 +168,19 @@ export class CollectionDetailComponent implements OnInit, AfterContentChecked {
|
|||
}
|
||||
const tagId = parseInt(routeId, 10);
|
||||
|
||||
this.pagination = this.filterUtilityService.pagination(this.route.snapshot);
|
||||
this.filterUtilityService.filterPresetsFromUrl(this.route.snapshot).subscribe(filter => {
|
||||
this.filter = filter;
|
||||
|
||||
this.filter = this.filterUtilityService.filterPresetsFromUrlV2(this.route.snapshot);
|
||||
if (this.filter.statements.filter(stmt => stmt.field === FilterField.Libraries).length === 0) {
|
||||
this.filter!.statements.push({field: FilterField.CollectionTags, value: tagId + '', comparison: FilterComparison.Equal});
|
||||
}
|
||||
this.filterActiveCheck = this.filterUtilityService.createSeriesV2Filter();
|
||||
this.filterActiveCheck!.statements.push({field: FilterField.CollectionTags, value: tagId + '', comparison: FilterComparison.Equal});
|
||||
this.filterSettings.presetsV2 = this.filter;
|
||||
if (this.filter.statements.filter(stmt => stmt.field === FilterField.CollectionTags).length === 0) {
|
||||
this.filter!.statements.push({field: FilterField.CollectionTags, value: tagId + '', comparison: FilterComparison.Equal});
|
||||
}
|
||||
this.filterActiveCheck = this.filterUtilityService.createSeriesV2Filter();
|
||||
this.filterActiveCheck!.statements.push({field: FilterField.CollectionTags, value: tagId + '', comparison: FilterComparison.Equal});
|
||||
this.filterSettings.presetsV2 = this.filter;
|
||||
this.cdRef.markForCheck();
|
||||
|
||||
this.cdRef.markForCheck();
|
||||
|
||||
this.updateTag(tagId);
|
||||
this.updateTag(tagId);
|
||||
});
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
|
@ -252,11 +252,14 @@ export class CollectionDetailComponent implements OnInit, AfterContentChecked {
|
|||
if (data.filterV2 === undefined) return;
|
||||
this.filter = data.filterV2;
|
||||
|
||||
if (!data.isFirst) {
|
||||
this.filterUtilityService.updateUrlFromFilterV2(this.pagination, this.filter);
|
||||
if (data.isFirst) {
|
||||
this.loadPage();
|
||||
return;
|
||||
}
|
||||
|
||||
this.loadPage();
|
||||
this.filterUtilityService.updateUrlFromFilter(this.filter).subscribe((encodedFilter) => {
|
||||
this.loadPage();
|
||||
});
|
||||
}
|
||||
|
||||
handleCollectionActionCallback(action: ActionItem<CollectionTag>, collectionTag: CollectionTag) {
|
||||
|
@ -284,4 +287,5 @@ export class CollectionDetailComponent implements OnInit, AfterContentChecked {
|
|||
});
|
||||
}
|
||||
|
||||
protected readonly undefined = undefined;
|
||||
}
|
||||
|
|
|
@ -147,7 +147,10 @@ export class DashboardComponent implements OnInit {
|
|||
s.api = this.seriesService.getRecentlyUpdatedSeries();
|
||||
break;
|
||||
case StreamType.SmartFilter:
|
||||
s.api = this.seriesService.getAllSeriesV2(0, 20, this.filterUtilityService.decodeSeriesFilter(s.smartFilterEncoded!))
|
||||
s.api = this.filterUtilityService.decodeFilter(s.smartFilterEncoded!).pipe(
|
||||
switchMap(filter => {
|
||||
return this.seriesService.getAllSeriesV2(0, 20, filter);
|
||||
}))
|
||||
.pipe(map(d => d.result), takeUntilDestroyed(this.destroyRef), shareReplay({bufferSize: 1, refCount: true}));
|
||||
break;
|
||||
case StreamType.MoreInGenre:
|
||||
|
@ -195,7 +198,7 @@ export class DashboardComponent implements OnInit {
|
|||
filter.sortOptions.sortField = SortField.LastChapterAdded;
|
||||
filter.sortOptions.isAscending = false;
|
||||
}
|
||||
this.filterUtilityService.applyFilterWithParams(['all-series'], filter, params)
|
||||
this.filterUtilityService.applyFilterWithParams(['all-series'], filter, params).subscribe();
|
||||
} else if (sectionTitle.toLowerCase() === 'on deck') {
|
||||
const params: any = {};
|
||||
params['page'] = 1;
|
||||
|
@ -208,7 +211,7 @@ export class DashboardComponent implements OnInit {
|
|||
filter.sortOptions.sortField = SortField.LastChapterAdded;
|
||||
filter.sortOptions.isAscending = false;
|
||||
}
|
||||
this.filterUtilityService.applyFilterWithParams(['all-series'], filter, params)
|
||||
this.filterUtilityService.applyFilterWithParams(['all-series'], filter, params).subscribe();
|
||||
} else if (sectionTitle.toLowerCase() === 'newly added series') {
|
||||
const params: any = {};
|
||||
params['page'] = 1;
|
||||
|
@ -218,14 +221,14 @@ export class DashboardComponent implements OnInit {
|
|||
filter.sortOptions.sortField = SortField.Created;
|
||||
filter.sortOptions.isAscending = false;
|
||||
}
|
||||
this.filterUtilityService.applyFilterWithParams(['all-series'], filter, params)
|
||||
this.filterUtilityService.applyFilterWithParams(['all-series'], filter, params).subscribe();
|
||||
} else if (sectionTitle.toLowerCase() === 'more in genre') {
|
||||
const params: any = {};
|
||||
params['page'] = 1;
|
||||
params['title'] = translate('more-in-genre-title', {genre: this.genre?.title});
|
||||
const filter = this.filterUtilityService.createSeriesV2Filter();
|
||||
filter.statements.push({field: FilterField.Genres, value: this.genre?.id + '', comparison: FilterComparison.MustContains});
|
||||
this.filterUtilityService.applyFilterWithParams(['all-series'], filter, params)
|
||||
this.filterUtilityService.applyFilterWithParams(['all-series'], filter, params).subscribe();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
<h6 subtitle class="subtitle-with-actionables" *ngIf="active.fragment === ''">{{t('common.series-count', {num: pagination.totalItems | number})}} </h6>
|
||||
</app-side-nav-companion-bar>
|
||||
<app-bulk-operations [actionCallback]="bulkActionCallback"></app-bulk-operations>
|
||||
<app-card-detail-layout
|
||||
<app-card-detail-layout *ngIf="filter"
|
||||
[isLoading]="loadingSeries"
|
||||
[items]="series"
|
||||
[pagination]="pagination"
|
||||
|
|
|
@ -60,9 +60,9 @@ export class LibraryDetailComponent implements OnInit {
|
|||
libraryName = '';
|
||||
series: Series[] = [];
|
||||
loadingSeries = false;
|
||||
pagination!: Pagination;
|
||||
pagination: Pagination = {currentPage: 0, totalPages: 0, totalItems: 0, itemsPerPage: 0};
|
||||
actions: ActionItem<Library>[] = [];
|
||||
filterV2: SeriesFilterV2 | undefined = undefined;
|
||||
filter: SeriesFilterV2 | undefined = undefined;
|
||||
filterSettings: FilterSettings = new FilterSettings();
|
||||
filterOpen: EventEmitter<boolean> = new EventEmitter();
|
||||
filterActive: boolean = false;
|
||||
|
@ -158,19 +158,20 @@ export class LibraryDetailComponent implements OnInit {
|
|||
|
||||
this.actions = this.actionFactoryService.getLibraryActions(this.handleAction.bind(this));
|
||||
|
||||
this.pagination = this.filterUtilityService.pagination(this.route.snapshot);
|
||||
this.filterV2 = this.filterUtilityService.filterPresetsFromUrlV2(this.route.snapshot);
|
||||
this.filterUtilityService.filterPresetsFromUrl(this.route.snapshot).subscribe(filter => {
|
||||
this.filter = filter;
|
||||
|
||||
if (this.filterV2.statements.filter(stmt => stmt.field === FilterField.Libraries).length === 0) {
|
||||
this.filterV2!.statements.push({field: FilterField.Libraries, value: this.libraryId + '', comparison: FilterComparison.Equal});
|
||||
}
|
||||
if (this.filter.statements.filter(stmt => stmt.field === FilterField.Libraries).length === 0) {
|
||||
this.filter!.statements.push({field: FilterField.Libraries, value: this.libraryId + '', comparison: FilterComparison.Equal});
|
||||
}
|
||||
|
||||
this.filterActiveCheck = this.filterUtilityService.createSeriesV2Filter();
|
||||
this.filterActiveCheck.statements.push({field: FilterField.Libraries, value: this.libraryId + '', comparison: FilterComparison.Equal});
|
||||
this.filterActiveCheck = this.filterUtilityService.createSeriesV2Filter();
|
||||
this.filterActiveCheck.statements.push({field: FilterField.Libraries, value: this.libraryId + '', comparison: FilterComparison.Equal});
|
||||
|
||||
this.filterSettings.presetsV2 = this.filterV2;
|
||||
this.filterSettings.presetsV2 = this.filter;
|
||||
|
||||
this.cdRef.markForCheck();
|
||||
this.cdRef.markForCheck();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
@ -179,7 +180,7 @@ export class LibraryDetailComponent implements OnInit {
|
|||
if (event.event === EVENTS.SeriesAdded) {
|
||||
const seriesAdded = event.payload as SeriesAddedEvent;
|
||||
if (seriesAdded.libraryId !== this.libraryId) return;
|
||||
if (!this.utilityService.deepEqual(this.filterV2, this.filterActiveCheck)) {
|
||||
if (!this.utilityService.deepEqual(this.filter, this.filterActiveCheck)) {
|
||||
this.loadPage();
|
||||
return;
|
||||
}
|
||||
|
@ -199,7 +200,7 @@ export class LibraryDetailComponent implements OnInit {
|
|||
} else if (event.event === EVENTS.SeriesRemoved) {
|
||||
const seriesRemoved = event.payload as SeriesRemovedEvent;
|
||||
if (seriesRemoved.libraryId !== this.libraryId) return;
|
||||
if (!this.utilityService.deepEqual(this.filterV2, this.filterActiveCheck)) {
|
||||
if (!this.utilityService.deepEqual(this.filter, this.filterActiveCheck)) {
|
||||
this.loadPage();
|
||||
return;
|
||||
}
|
||||
|
@ -257,21 +258,24 @@ export class LibraryDetailComponent implements OnInit {
|
|||
|
||||
updateFilter(data: FilterEvent) {
|
||||
if (data.filterV2 === undefined) return;
|
||||
this.filterV2 = data.filterV2;
|
||||
this.filter = data.filterV2;
|
||||
|
||||
if (!data.isFirst) {
|
||||
this.filterUtilityService.updateUrlFromFilterV2(this.pagination, this.filterV2);
|
||||
if (data.isFirst) {
|
||||
this.loadPage();
|
||||
return;
|
||||
}
|
||||
|
||||
this.loadPage();
|
||||
this.filterUtilityService.updateUrlFromFilter(this.filter).subscribe((encodedFilter) => {
|
||||
this.loadPage();
|
||||
});
|
||||
}
|
||||
|
||||
loadPage() {
|
||||
this.loadingSeries = true;
|
||||
this.filterActive = !this.utilityService.deepEqual(this.filterV2, this.filterActiveCheck);
|
||||
this.filterActive = !this.utilityService.deepEqual(this.filter, this.filterActiveCheck);
|
||||
this.cdRef.markForCheck();
|
||||
|
||||
this.seriesService.getSeriesForLibraryV2(undefined, undefined, this.filterV2)
|
||||
this.seriesService.getSeriesForLibraryV2(undefined, undefined, this.filter)
|
||||
.subscribe(series => {
|
||||
this.series = series.result;
|
||||
this.pagination = series.pagination;
|
||||
|
@ -282,4 +286,5 @@ export class LibraryDetailComponent implements OnInit {
|
|||
}
|
||||
|
||||
trackByIdentity = (index: number, item: Series) => `${item.id}_${item.name}_${item.localizedName}_${item.pagesRead}`;
|
||||
protected readonly undefined = undefined;
|
||||
}
|
||||
|
|
|
@ -136,7 +136,7 @@ export class NavHeaderComponent implements OnInit {
|
|||
filter.statements = [statement];
|
||||
params['page'] = 1;
|
||||
this.clearSearch();
|
||||
this.filterUtilityService.applyFilterWithParams(['all-series'], filter, params);
|
||||
this.filterUtilityService.applyFilterWithParams(['all-series'], filter, params).subscribe();
|
||||
}
|
||||
|
||||
goToOther(field: FilterField, value: string) {
|
||||
|
|
|
@ -234,6 +234,6 @@ export class ReadingListDetailComponent implements OnInit {
|
|||
}
|
||||
|
||||
goToCharacter(character: Person) {
|
||||
this.filterUtilityService.applyFilter(['all-series'], FilterField.Characters, FilterComparison.Contains, character.id + '');
|
||||
this.filterUtilityService.applyFilter(['all-series'], FilterField.Characters, FilterComparison.Contains, character.id + '').subscribe();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -123,5 +123,4 @@ export class ReadingListsComponent implements OnInit {
|
|||
handleClick(list: ReadingList) {
|
||||
this.router.navigateByUrl('lists/' + list.id);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -24,12 +24,12 @@ export class MetadataDetailComponent {
|
|||
@ContentChild('titleTemplate') titleTemplate!: TemplateRef<any>;
|
||||
@ContentChild('itemTemplate') itemTemplate?: TemplateRef<any>;
|
||||
|
||||
private readonly filterUtilitiesService = inject(FilterUtilitiesService);
|
||||
private readonly filterUtilityService = inject(FilterUtilitiesService);
|
||||
protected readonly TagBadgeCursor = TagBadgeCursor;
|
||||
|
||||
|
||||
goTo(queryParamName: FilterField, filter: any) {
|
||||
if (queryParamName === FilterField.None) return;
|
||||
this.filterUtilitiesService.applyFilter(['library', this.libraryId], queryParamName, FilterComparison.Equal, filter);
|
||||
this.filterUtilityService.applyFilter(['library', this.libraryId], queryParamName, FilterComparison.Equal, filter).subscribe();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -102,7 +102,7 @@ export class SeriesMetadataDetailComponent implements OnChanges {
|
|||
|
||||
goTo(queryParamName: FilterField, filter: any) {
|
||||
this.filterUtilityService.applyFilter(['library', this.series.libraryId], queryParamName,
|
||||
FilterComparison.Equal, filter);
|
||||
FilterComparison.Equal, filter).subscribe();
|
||||
}
|
||||
|
||||
navigate(basePage: string, id: number) {
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
import {Injectable} from '@angular/core';
|
||||
import {ActivatedRouteSnapshot, Params, Router} from '@angular/router';
|
||||
import {Pagination} from 'src/app/_models/pagination';
|
||||
import {SortField, SortOptions} from 'src/app/_models/metadata/series-filter';
|
||||
import {MetadataService} from "../../_services/metadata.service";
|
||||
import {SeriesFilterV2} from "../../_models/metadata/v2/series-filter-v2";
|
||||
|
@ -8,245 +7,93 @@ import {FilterStatement} from "../../_models/metadata/v2/filter-statement";
|
|||
import {FilterCombination} from "../../_models/metadata/v2/filter-combination";
|
||||
import {FilterField} from "../../_models/metadata/v2/filter-field";
|
||||
import {FilterComparison} from "../../_models/metadata/v2/filter-comparison";
|
||||
import {HttpClient} from "@angular/common/http";
|
||||
import {TextResonse} from "../../_types/text-response";
|
||||
import {environment} from "../../../environments/environment";
|
||||
import {map, tap} from "rxjs/operators";
|
||||
import {of, switchMap} from "rxjs";
|
||||
|
||||
const sortOptionsKey = 'sortOptions=';
|
||||
const statementsKey = 'stmts=';
|
||||
const limitToKey = 'limitTo=';
|
||||
const combinationKey = 'combination=';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class FilterUtilitiesService {
|
||||
|
||||
constructor(private metadataService: MetadataService, private router: Router) {}
|
||||
private apiUrl = environment.apiUrl;
|
||||
|
||||
applyFilter(page: Array<any>, filter: FilterField, comparison: FilterComparison, value: string) {
|
||||
const dto: SeriesFilterV2 = {
|
||||
statements: [this.metadataService.createDefaultFilterStatement(filter, comparison, value + '')],
|
||||
combination: FilterCombination.Or,
|
||||
limitTo: 0
|
||||
};
|
||||
constructor(private metadataService: MetadataService, private router: Router, private http: HttpClient) {}
|
||||
|
||||
const url = this.urlFromFilterV2(page.join('/') + '?', dto);
|
||||
return this.router.navigateByUrl(url);
|
||||
}
|
||||
|
||||
applyFilterWithParams(page: Array<any>, filter: SeriesFilterV2, extraParams: Params) {
|
||||
let url = this.urlFromFilterV2(page.join('/') + '?', filter);
|
||||
url += Object.keys(extraParams).map(k => `&${k}=${extraParams[k]}`).join('');
|
||||
return this.router.navigateByUrl(url, extraParams);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the window location with a custom url based on filter and pagination objects
|
||||
* @param pagination
|
||||
* @param filter
|
||||
*/
|
||||
updateUrlFromFilterV2(pagination: Pagination, filter: SeriesFilterV2 | undefined) {
|
||||
const params = '?page=' + pagination.currentPage + '&';
|
||||
|
||||
const url = this.urlFromFilterV2(window.location.href.split('?')[0] + params, filter);
|
||||
window.history.replaceState(window.location.href, '', this.replacePaginationOnUrl(url, pagination));
|
||||
}
|
||||
|
||||
|
||||
private replacePaginationOnUrl(url: string, pagination: Pagination) {
|
||||
return url.replace(/page=\d+/i, 'page=' + pagination.currentPage);
|
||||
}
|
||||
|
||||
/**
|
||||
* Will fetch current page from route if present
|
||||
* @param snapshot to fetch page from. Must be from component else may get stale data
|
||||
* @param itemsPerPage If you want pagination, pass non-zero number
|
||||
* @returns A default pagination object
|
||||
*/
|
||||
pagination(snapshot: ActivatedRouteSnapshot, itemsPerPage: number = 0): Pagination {
|
||||
return {currentPage: parseInt(snapshot.queryParamMap.get('page') || '1', 10), itemsPerPage, totalItems: 0, totalPages: 1};
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the current url with query params for the filter
|
||||
* @param currentUrl Full url, with ?page=1 as a minimum
|
||||
* @param filter Filter to build url off
|
||||
* @returns current url with query params added
|
||||
*/
|
||||
urlFromFilterV2(currentUrl: string, filter: SeriesFilterV2 | undefined) {
|
||||
if (filter === undefined) return currentUrl;
|
||||
|
||||
return currentUrl + this.encodeSeriesFilter(filter);
|
||||
}
|
||||
|
||||
encodeSeriesFilter(filter: SeriesFilterV2) {
|
||||
const encodedStatements = this.encodeFilterStatements(filter.statements);
|
||||
const encodedSortOptions = filter.sortOptions ? `${sortOptionsKey}${this.encodeSortOptions(filter.sortOptions)}` : '';
|
||||
const encodedLimitTo = `${limitToKey}${filter.limitTo}`;
|
||||
|
||||
return `${this.encodeName(filter.name)}${encodedStatements}&${encodedSortOptions}&${encodedLimitTo}&${combinationKey}${filter.combination}`;
|
||||
}
|
||||
|
||||
encodeName(name: string | undefined) {
|
||||
if (name === undefined || name === '') return '';
|
||||
return `name=${encodeURIComponent(name)}&`
|
||||
}
|
||||
|
||||
|
||||
encodeSortOptions(sortOptions: SortOptions) {
|
||||
return `sortField=${sortOptions.sortField},isAscending=${sortOptions.isAscending}`;
|
||||
}
|
||||
|
||||
encodeFilterStatements(statements: Array<FilterStatement>) {
|
||||
if (statements.length === 0) return '';
|
||||
return statementsKey + encodeURIComponent(statements.map(statement => {
|
||||
const encodedComparison = `comparison=${statement.comparison}`;
|
||||
const encodedField = `field=${statement.field}`;
|
||||
const encodedValue = `value=${encodeURIComponent(statement.value)}`;
|
||||
|
||||
return `${encodedComparison}&${encodedField}&${encodedValue}`;
|
||||
}).join(','));
|
||||
}
|
||||
|
||||
decodeSeriesFilter(encodedFilter: string) {
|
||||
const filter = this.metadataService.createDefaultFilterDto();
|
||||
|
||||
if (encodedFilter.includes('name=')) {
|
||||
filter.name = decodeURIComponent(encodedFilter).split('name=')[1].split('&')[0];
|
||||
}
|
||||
|
||||
const stmtsStartIndex = encodedFilter.indexOf(statementsKey);
|
||||
let endIndex = encodedFilter.indexOf('&' + sortOptionsKey);
|
||||
if (endIndex < 0) {
|
||||
endIndex = encodedFilter.indexOf('&' + limitToKey);
|
||||
}
|
||||
|
||||
if (stmtsStartIndex !== -1 || endIndex !== -1) {
|
||||
// +1 is for the =
|
||||
const stmtsEncoded = encodedFilter.substring(stmtsStartIndex + statementsKey.length, endIndex);
|
||||
filter.statements = this.decodeFilterStatements(stmtsEncoded);
|
||||
}
|
||||
|
||||
if (encodedFilter.includes(sortOptionsKey)) {
|
||||
const optionsStartIndex = encodedFilter.indexOf('&' + sortOptionsKey);
|
||||
const endIndex = encodedFilter.indexOf('&' + limitToKey);
|
||||
const sortOptionsEncoded = encodedFilter.substring(optionsStartIndex + sortOptionsKey.length + 1, endIndex);
|
||||
const sortOptions = this.decodeSortOptions(sortOptionsEncoded);
|
||||
if (sortOptions) {
|
||||
filter.sortOptions = sortOptions;
|
||||
}
|
||||
}
|
||||
|
||||
if (encodedFilter.includes(limitToKey)) {
|
||||
const limitTo = decodeURIComponent(encodedFilter).split(limitToKey)[1].split('&')[0];
|
||||
filter.limitTo = parseInt(limitTo, 10);
|
||||
}
|
||||
|
||||
if (encodedFilter.includes(combinationKey)) {
|
||||
const combo = decodeURIComponent(encodedFilter).split(combinationKey)[1].split('&')[0];;
|
||||
filter.combination = parseInt(combo, 10) as FilterCombination;
|
||||
}
|
||||
|
||||
return filter;
|
||||
encodeFilter(filter: SeriesFilterV2 | undefined) {
|
||||
return this.http.post<string>(this.apiUrl + 'filter/encode', filter, TextResonse);
|
||||
}
|
||||
|
||||
decodeFilter(encodedFilter: string) {
|
||||
return this.http.post<SeriesFilterV2>(this.apiUrl + 'filter/decode', {encodedFilter}).pipe(map(filter => {
|
||||
if (filter == null) {
|
||||
filter = this.metadataService.createDefaultFilterDto();
|
||||
filter.statements.push(this.createSeriesV2DefaultStatement());
|
||||
}
|
||||
|
||||
filterPresetsFromUrlV2(snapshot: ActivatedRouteSnapshot): SeriesFilterV2 {
|
||||
const filter = this.metadataService.createDefaultFilterDto();
|
||||
if (!window.location.href.includes('?')) return filter;
|
||||
return filter;
|
||||
}))
|
||||
}
|
||||
|
||||
const queryParams = snapshot.queryParams;
|
||||
updateUrlFromFilter(filter: SeriesFilterV2 | undefined) {
|
||||
return this.encodeFilter(filter).pipe(tap(encodedFilter => {
|
||||
window.history.replaceState(window.location.href, '', window.location.href.split('?')[0]+ '?' + encodedFilter);
|
||||
}));
|
||||
}
|
||||
|
||||
if (queryParams.name) {
|
||||
filter.name = queryParams.name;
|
||||
}
|
||||
filterPresetsFromUrl(snapshot: ActivatedRouteSnapshot) {
|
||||
const filter = this.metadataService.createDefaultFilterDto();
|
||||
filter.statements.push(this.createSeriesV2DefaultStatement());
|
||||
if (!window.location.href.includes('?')) return of(filter);
|
||||
|
||||
const fullUrl = window.location.href.split('?')[1];
|
||||
const stmtsStartIndex = fullUrl.indexOf(statementsKey);
|
||||
let endIndex = fullUrl.indexOf('&' + sortOptionsKey);
|
||||
if (endIndex < 0) {
|
||||
endIndex = fullUrl.indexOf('&' + limitToKey);
|
||||
}
|
||||
return this.decodeFilter(window.location.href.split('?')[1]);
|
||||
}
|
||||
|
||||
if (stmtsStartIndex !== -1 || endIndex !== -1) {
|
||||
// +1 is for the =
|
||||
const stmtsEncoded = fullUrl.substring(stmtsStartIndex + statementsKey.length, endIndex);
|
||||
filter.statements = this.decodeFilterStatements(stmtsEncoded);
|
||||
}
|
||||
/**
|
||||
* Applies and redirects to the passed page with the filter encoded
|
||||
* @param page
|
||||
* @param filter
|
||||
* @param comparison
|
||||
* @param value
|
||||
*/
|
||||
applyFilter(page: Array<any>, filter: FilterField, comparison: FilterComparison, value: string) {
|
||||
const dto = this.createSeriesV2Filter();
|
||||
dto.statements.push(this.metadataService.createDefaultFilterStatement(filter, comparison, value + ''));
|
||||
|
||||
if (queryParams.sortOptions) {
|
||||
const optionsStartIndex = fullUrl.indexOf('&' + sortOptionsKey);
|
||||
const endIndex = fullUrl.indexOf('&' + limitToKey);
|
||||
const sortOptionsEncoded = fullUrl.substring(optionsStartIndex + sortOptionsKey.length + 1, endIndex);
|
||||
const sortOptions = this.decodeSortOptions(sortOptionsEncoded);
|
||||
if (sortOptions) {
|
||||
filter.sortOptions = sortOptions;
|
||||
}
|
||||
}
|
||||
return this.encodeFilter(dto).pipe(switchMap(encodedFilter => {
|
||||
return this.router.navigateByUrl(page.join('/') + '?' + encodedFilter);
|
||||
}));
|
||||
}
|
||||
|
||||
if (queryParams.limitTo) {
|
||||
filter.limitTo = parseInt(queryParams.limitTo, 10);
|
||||
}
|
||||
applyFilterWithParams(page: Array<any>, filter: SeriesFilterV2, extraParams: Params) {
|
||||
return this.encodeFilter(filter).pipe(switchMap(encodedFilter => {
|
||||
let url = page.join('/') + '?' + encodedFilter;
|
||||
url += Object.keys(extraParams).map(k => `&${k}=${extraParams[k]}`).join('');
|
||||
|
||||
if (queryParams.combination) {
|
||||
filter.combination = parseInt(queryParams.combination, 10) as FilterCombination;
|
||||
}
|
||||
return this.router.navigateByUrl(url, extraParams);
|
||||
}));
|
||||
}
|
||||
|
||||
return filter;
|
||||
}
|
||||
|
||||
decodeSortOptions(encodedSortOptions: string): SortOptions | null {
|
||||
const parts = decodeURIComponent(encodedSortOptions).split(',');
|
||||
const sortFieldPart = parts.find(part => part.startsWith('sortField='));
|
||||
const isAscendingPart = parts.find(part => part.startsWith('isAscending='));
|
||||
|
||||
if (sortFieldPart && isAscendingPart) {
|
||||
const sortField = parseInt(sortFieldPart.split('=')[1], 10) as SortField;
|
||||
const isAscending = isAscendingPart.split('=')[1].toLowerCase() === 'true';
|
||||
return {sortField, isAscending};
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
decodeFilterStatements(encodedStatements: string): FilterStatement[] {
|
||||
const statementStrings = decodeURIComponent(encodedStatements).split(',').map(s => decodeURIComponent(s));
|
||||
return statementStrings.map(statementString => {
|
||||
const parts = statementString.split(',');
|
||||
if (parts === null || parts.length < 3) return null;
|
||||
|
||||
const comparisonStartToken = parts.find(part => part.startsWith('comparison='));
|
||||
if (!comparisonStartToken) return null;
|
||||
const comparison = parseInt(comparisonStartToken.split('=')[1], 10) as FilterComparison;
|
||||
|
||||
const fieldStartToken = parts.find(part => part.startsWith('field='));
|
||||
if (!fieldStartToken) return null;
|
||||
const field = parseInt(fieldStartToken.split('=')[1], 10) as FilterField;
|
||||
|
||||
const valueStartToken = parts.find(part => part.startsWith('value='));
|
||||
if (!valueStartToken) return null;
|
||||
const value = decodeURIComponent(valueStartToken.split('=')[1]);
|
||||
return {comparison, field, value};
|
||||
}).filter(o => o != null) as FilterStatement[];
|
||||
}
|
||||
|
||||
createSeriesV2Filter(): SeriesFilterV2 {
|
||||
return {
|
||||
combination: FilterCombination.And,
|
||||
statements: [],
|
||||
limitTo: 0,
|
||||
sortOptions: {
|
||||
isAscending: true,
|
||||
sortField: SortField.SortName
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
createSeriesV2DefaultStatement(): FilterStatement {
|
||||
return {
|
||||
comparison: FilterComparison.Equal,
|
||||
value: '',
|
||||
field: FilterField.SeriesName
|
||||
}
|
||||
}
|
||||
createSeriesV2Filter(): SeriesFilterV2 {
|
||||
return {
|
||||
combination: FilterCombination.And,
|
||||
statements: [],
|
||||
limitTo: 0,
|
||||
sortOptions: {
|
||||
isAscending: true,
|
||||
sortField: SortField.SortName
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
createSeriesV2DefaultStatement(): FilterStatement {
|
||||
return {
|
||||
comparison: FilterComparison.Equal,
|
||||
value: '',
|
||||
field: FilterField.SeriesName
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -115,7 +115,7 @@ export class ServerStatsComponent {
|
|||
ref.componentInstance.items = genres.map(t => t.title);
|
||||
ref.componentInstance.title = translate('server-stats.genres');
|
||||
ref.componentInstance.clicked = (item: string) => {
|
||||
this.filterUtilityService.applyFilter(['all-series'], FilterField.Genres, FilterComparison.Contains, genres.filter(g => g.title === item)[0].id + '');
|
||||
this.filterUtilityService.applyFilter(['all-series'], FilterField.Genres, FilterComparison.Contains, genres.filter(g => g.title === item)[0].id + '').subscribe();
|
||||
};
|
||||
});
|
||||
}
|
||||
|
@ -126,7 +126,7 @@ export class ServerStatsComponent {
|
|||
ref.componentInstance.items = tags.map(t => t.title);
|
||||
ref.componentInstance.title = translate('server-stats.tags');
|
||||
ref.componentInstance.clicked = (item: string) => {
|
||||
this.filterUtilityService.applyFilter(['all-series'], FilterField.Tags, FilterComparison.Contains, tags.filter(g => g.title === item)[0].id + '');
|
||||
this.filterUtilityService.applyFilter(['all-series'], FilterField.Tags, FilterComparison.Contains, tags.filter(g => g.title === item)[0].id + '').subscribe();
|
||||
};
|
||||
});
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
<div [ngStyle]="{'height': ScrollingBlockHeight}" class="main-container container-fluid pt-2" #scrollingBlock>
|
||||
<app-bulk-operations [actionCallback]="bulkActionCallback"></app-bulk-operations>
|
||||
|
||||
<app-card-detail-layout
|
||||
<app-card-detail-layout *ngIf="filter"
|
||||
[isLoading]="isLoading"
|
||||
[items]="series"
|
||||
[pagination]="pagination"
|
||||
|
|
|
@ -56,7 +56,7 @@ export class WantToReadComponent implements OnInit, AfterContentChecked {
|
|||
|
||||
isLoading: boolean = true;
|
||||
series: Array<Series> = [];
|
||||
pagination!: Pagination;
|
||||
pagination: Pagination = new Pagination();
|
||||
filter: SeriesFilterV2 | undefined = undefined;
|
||||
filterSettings: FilterSettings = new FilterSettings();
|
||||
refresh: EventEmitter<void> = new EventEmitter();
|
||||
|
@ -106,17 +106,15 @@ export class WantToReadComponent implements OnInit, AfterContentChecked {
|
|||
this.router.routeReuseStrategy.shouldReuseRoute = () => false;
|
||||
this.titleService.setTitle('Kavita - ' + translate('want-to-read.title'));
|
||||
|
||||
this.pagination = this.filterUtilityService.pagination(this.route.snapshot);
|
||||
this.filterUtilityService.filterPresetsFromUrl(this.route.snapshot).subscribe(filter => {
|
||||
this.filter = filter;
|
||||
|
||||
this.filter = this.filterUtilityService.filterPresetsFromUrlV2(this.route.snapshot);
|
||||
if (this.filter.statements.length === 0) {
|
||||
this.filter!.statements.push(this.filterUtilityService.createSeriesV2DefaultStatement());
|
||||
}
|
||||
this.filterActiveCheck = this.filterUtilityService.createSeriesV2Filter();
|
||||
this.filterActiveCheck!.statements.push(this.filterUtilityService.createSeriesV2DefaultStatement());
|
||||
this.filterSettings.presetsV2 = this.filter;
|
||||
this.filterActiveCheck = this.filterUtilityService.createSeriesV2Filter();
|
||||
this.filterActiveCheck!.statements.push(this.filterUtilityService.createSeriesV2DefaultStatement());
|
||||
this.filterSettings.presetsV2 = this.filter;
|
||||
|
||||
this.cdRef.markForCheck();
|
||||
this.cdRef.markForCheck();
|
||||
});
|
||||
|
||||
this.hubService.messages$.pipe(takeUntilDestroyed(this.destroyRef)).subscribe((event) => {
|
||||
if (event.event === EVENTS.SeriesRemoved) {
|
||||
|
@ -187,11 +185,14 @@ export class WantToReadComponent implements OnInit, AfterContentChecked {
|
|||
if (data.filterV2 === undefined) return;
|
||||
this.filter = data.filterV2;
|
||||
|
||||
if (!data.isFirst) {
|
||||
this.filterUtilityService.updateUrlFromFilterV2(this.pagination, this.filter);
|
||||
if (data.isFirst) {
|
||||
this.loadPage();
|
||||
return;
|
||||
}
|
||||
|
||||
this.loadPage();
|
||||
this.filterUtilityService.updateUrlFromFilter(this.filter).subscribe((encodedFilter) => {
|
||||
this.loadPage();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1299,7 +1299,8 @@
|
|||
"collection-detail": {
|
||||
"no-data": "There are no items. Try adding a series.",
|
||||
"no-data-filtered": "No items match your current filter.",
|
||||
"title-alt": "Kavita - {{collectionName}} Collection"
|
||||
"title-alt": "Kavita - {{collectionName}} Collection",
|
||||
"series-header": "Series"
|
||||
},
|
||||
|
||||
"all-collections": {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue