mirror of
https://github.com/Kareadita/Kavita.git
synced 2025-07-09 03:04:19 -04:00
Bulk Operations for In Progress and Recently Added (#677)
* Don't log a message about bad match if the file is a cover image * Enable bulk operations for In Progress and Recently Added * Fixed a bad logic case
This commit is contained in:
parent
ef383295f0
commit
98e5cb87ed
@ -73,7 +73,8 @@ namespace API.Services.Tasks.Scanner
|
|||||||
info = Parser.Parser.Parse(path, rootPath, type);
|
info = Parser.Parser.Parse(path, rootPath, type);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (info == null)
|
// If we couldn't match, log. But don't log if the file parses as a cover image
|
||||||
|
if (info == null || !(Parser.Parser.IsImage(path) || Parser.Parser.IsCoverImage(path)))
|
||||||
{
|
{
|
||||||
_logger.LogWarning("[Scanner] Could not parse series from {Path}", path);
|
_logger.LogWarning("[Scanner] Could not parse series from {Path}", path);
|
||||||
return;
|
return;
|
||||||
|
@ -1,14 +1,14 @@
|
|||||||
<ng-container>
|
<app-bulk-operations [actionCallback]="bulkActionCallback"></app-bulk-operations>
|
||||||
<app-card-detail-layout header="In Progress"
|
<app-card-detail-layout header="In Progress"
|
||||||
[isLoading]="isLoading"
|
[isLoading]="isLoading"
|
||||||
[items]="recentlyAdded"
|
[items]="series"
|
||||||
[filters]="filters"
|
[filters]="filters"
|
||||||
[pagination]="pagination"
|
[pagination]="pagination"
|
||||||
(pageChange)="onPageChange($event)"
|
(pageChange)="onPageChange($event)"
|
||||||
(applyFilter)="updateFilter($event)"
|
(applyFilter)="updateFilter($event)"
|
||||||
|
|
||||||
>
|
>
|
||||||
<ng-template #cardItem let-item let-position="idx">
|
<ng-template #cardItem let-item let-position="idx">
|
||||||
<app-series-card [data]="item" [libraryId]="item.libraryId" (reload)="loadPage()"></app-series-card>
|
<app-series-card [data]="item" [libraryId]="item.libraryId" (reload)="loadPage()" (selection)="bulkSelectionService.handleCardSelection('series', position, series.length, $event)" [selected]="bulkSelectionService.isCardSelected('series', position)" [allowSelection]="true"></app-series-card>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
</app-card-detail-layout>
|
</app-card-detail-layout>
|
||||||
</ng-container>
|
|
||||||
|
@ -1,11 +1,15 @@
|
|||||||
import { Component, OnInit } from '@angular/core';
|
import { Component, HostListener, OnInit } from '@angular/core';
|
||||||
import { Title } from '@angular/platform-browser';
|
import { Title } from '@angular/platform-browser';
|
||||||
import { Router, ActivatedRoute } from '@angular/router';
|
import { Router, ActivatedRoute } from '@angular/router';
|
||||||
import { take } from 'rxjs/operators';
|
import { take } from 'rxjs/operators';
|
||||||
|
import { BulkSelectionService } from '../cards/bulk-selection.service';
|
||||||
import { UpdateFilterEvent } from '../cards/card-detail-layout/card-detail-layout.component';
|
import { UpdateFilterEvent } from '../cards/card-detail-layout/card-detail-layout.component';
|
||||||
|
import { KEY_CODES } from '../shared/_services/utility.service';
|
||||||
import { Pagination } from '../_models/pagination';
|
import { Pagination } from '../_models/pagination';
|
||||||
import { Series } from '../_models/series';
|
import { Series } from '../_models/series';
|
||||||
import { FilterItem, SeriesFilter, mangaFormatFilters } from '../_models/series-filter';
|
import { FilterItem, SeriesFilter, mangaFormatFilters } from '../_models/series-filter';
|
||||||
|
import { Action } from '../_services/action-factory.service';
|
||||||
|
import { ActionService } from '../_services/action.service';
|
||||||
import { SeriesService } from '../_services/series.service';
|
import { SeriesService } from '../_services/series.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
@ -16,7 +20,7 @@ import { SeriesService } from '../_services/series.service';
|
|||||||
export class InProgressComponent implements OnInit {
|
export class InProgressComponent implements OnInit {
|
||||||
|
|
||||||
isLoading: boolean = true;
|
isLoading: boolean = true;
|
||||||
recentlyAdded: Series[] = [];
|
series: Series[] = [];
|
||||||
pagination!: Pagination;
|
pagination!: Pagination;
|
||||||
libraryId!: number;
|
libraryId!: number;
|
||||||
filters: Array<FilterItem> = mangaFormatFilters;
|
filters: Array<FilterItem> = mangaFormatFilters;
|
||||||
@ -24,7 +28,8 @@ export class InProgressComponent implements OnInit {
|
|||||||
mangaFormat: null
|
mangaFormat: null
|
||||||
};
|
};
|
||||||
|
|
||||||
constructor(private router: Router, private route: ActivatedRoute, private seriesService: SeriesService, private titleService: Title) {
|
constructor(private router: Router, private route: ActivatedRoute, private seriesService: SeriesService, private titleService: Title,
|
||||||
|
private actionService: ActionService, public bulkSelectionService: BulkSelectionService) {
|
||||||
this.router.routeReuseStrategy.shouldReuseRoute = () => false;
|
this.router.routeReuseStrategy.shouldReuseRoute = () => false;
|
||||||
this.titleService.setTitle('Kavita - In Progress');
|
this.titleService.setTitle('Kavita - In Progress');
|
||||||
if (this.pagination === undefined || this.pagination === null) {
|
if (this.pagination === undefined || this.pagination === null) {
|
||||||
@ -33,6 +38,20 @@ export class InProgressComponent implements OnInit {
|
|||||||
this.loadPage();
|
this.loadPage();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@HostListener('document:keydown.shift', ['$event'])
|
||||||
|
handleKeypress(event: KeyboardEvent) {
|
||||||
|
if (event.key === KEY_CODES.SHIFT) {
|
||||||
|
this.bulkSelectionService.isShiftDown = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@HostListener('document:keyup.shift', ['$event'])
|
||||||
|
handleKeyUp(event: KeyboardEvent) {
|
||||||
|
if (event.key === KEY_CODES.SHIFT) {
|
||||||
|
this.bulkSelectionService.isShiftDown = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ngOnInit() {}
|
ngOnInit() {}
|
||||||
|
|
||||||
seriesClicked(series: Series) {
|
seriesClicked(series: Series) {
|
||||||
@ -61,7 +80,7 @@ export class InProgressComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
this.isLoading = true;
|
this.isLoading = true;
|
||||||
this.seriesService.getInProgress(this.libraryId, this.pagination?.currentPage, this.pagination?.itemsPerPage, this.filter).pipe(take(1)).subscribe(series => {
|
this.seriesService.getInProgress(this.libraryId, this.pagination?.currentPage, this.pagination?.itemsPerPage, this.filter).pipe(take(1)).subscribe(series => {
|
||||||
this.recentlyAdded = series.result;
|
this.series = series.result;
|
||||||
this.pagination = series.pagination;
|
this.pagination = series.pagination;
|
||||||
this.isLoading = false;
|
this.isLoading = false;
|
||||||
window.scrollTo(0, 0);
|
window.scrollTo(0, 0);
|
||||||
@ -73,4 +92,35 @@ export class InProgressComponent implements OnInit {
|
|||||||
return urlParams.get('page');
|
return urlParams.get('page');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bulkActionCallback = (action: Action, data: any) => {
|
||||||
|
const selectedSeriesIndexies = this.bulkSelectionService.getSelectedCardsForSource('series');
|
||||||
|
const selectedSeries = this.series.filter((series, index: number) => selectedSeriesIndexies.includes(index + ''));
|
||||||
|
|
||||||
|
switch (action) {
|
||||||
|
case Action.AddToReadingList:
|
||||||
|
this.actionService.addMultipleSeriesToReadingList(selectedSeries, () => {
|
||||||
|
this.bulkSelectionService.deselectAll();
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
case Action.AddToCollection:
|
||||||
|
this.actionService.addMultipleSeriesToCollectionTag(selectedSeries, () => {
|
||||||
|
this.bulkSelectionService.deselectAll();
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
case Action.MarkAsRead:
|
||||||
|
this.actionService.markMultipleSeriesAsRead(selectedSeries, () => {
|
||||||
|
this.loadPage();
|
||||||
|
this.bulkSelectionService.deselectAll();
|
||||||
|
});
|
||||||
|
|
||||||
|
break;
|
||||||
|
case Action.MarkAsUnread:
|
||||||
|
this.actionService.markMultipleSeriesAsUnread(selectedSeries, () => {
|
||||||
|
this.loadPage();
|
||||||
|
this.bulkSelectionService.deselectAll();
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,6 @@
|
|||||||
(pageChange)="onPageChange($event)"
|
(pageChange)="onPageChange($event)"
|
||||||
>
|
>
|
||||||
<ng-template #cardItem let-item let-position="idx">
|
<ng-template #cardItem let-item let-position="idx">
|
||||||
<app-series-card [data]="item" [libraryId]="libraryId" [suppressLibraryLink]="true" (reload)="loadPage()" (selection)="bulkSelectionService.handleCardSelection('series', position, series.length, $event)" [selected]="bulkSelectionService.isCardSelected('series', position)" [allowSelection]="true"></app-series-card>
|
<app-series-card [data]="item" [libraryId]="libraryId" [suppressLibraryLink]="true" (reload)="loadPage()" (selection)="bulkSelectionService.handleCardSelection('series', position, series.length, $event)" [selected]="bulkSelectionService.isCardSelected('series', position)" [allowSelection]="true"></app-series-card>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
</app-card-detail-layout>
|
</app-card-detail-layout>
|
||||||
|
@ -1,14 +1,13 @@
|
|||||||
<ng-container>
|
<app-bulk-operations [actionCallback]="bulkActionCallback"></app-bulk-operations>
|
||||||
<app-card-detail-layout header="Recently Added"
|
<app-card-detail-layout header="Recently Added"
|
||||||
[isLoading]="isLoading"
|
[isLoading]="isLoading"
|
||||||
[items]="recentlyAdded"
|
[items]="series"
|
||||||
[pagination]="pagination"
|
[pagination]="pagination"
|
||||||
[filters]="filters"
|
[filters]="filters"
|
||||||
(applyFilter)="updateFilter($event)"
|
(applyFilter)="updateFilter($event)"
|
||||||
(pageChange)="onPageChange($event)"
|
(pageChange)="onPageChange($event)"
|
||||||
>
|
>
|
||||||
<ng-template #cardItem let-item let-position="idx">
|
<ng-template #cardItem let-item let-position="idx">
|
||||||
<app-series-card [data]="item" [libraryId]="item.libraryId" (reload)="loadPage()"></app-series-card>
|
<app-series-card [data]="item" [libraryId]="item.libraryId" (reload)="loadPage()" (selection)="bulkSelectionService.handleCardSelection('series', position, series.length, $event)" [selected]="bulkSelectionService.isCardSelected('series', position)" [allowSelection]="true"></app-series-card>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
</app-card-detail-layout>
|
</app-card-detail-layout>
|
||||||
</ng-container>
|
|
@ -1,11 +1,18 @@
|
|||||||
import { Component, OnInit } from '@angular/core';
|
import { Component, HostListener, OnDestroy, OnInit } from '@angular/core';
|
||||||
import { Title } from '@angular/platform-browser';
|
import { Title } from '@angular/platform-browser';
|
||||||
import { ActivatedRoute, Router } from '@angular/router';
|
import { ActivatedRoute, Router } from '@angular/router';
|
||||||
import { take } from 'rxjs/operators';
|
import { Subject } from 'rxjs';
|
||||||
|
import { debounceTime, take, takeUntil, takeWhile } from 'rxjs/operators';
|
||||||
|
import { BulkSelectionService } from '../cards/bulk-selection.service';
|
||||||
import { UpdateFilterEvent } from '../cards/card-detail-layout/card-detail-layout.component';
|
import { UpdateFilterEvent } from '../cards/card-detail-layout/card-detail-layout.component';
|
||||||
|
import { KEY_CODES } from '../shared/_services/utility.service';
|
||||||
|
import { SeriesAddedEvent } from '../_models/events/series-added-event';
|
||||||
import { Pagination } from '../_models/pagination';
|
import { Pagination } from '../_models/pagination';
|
||||||
import { Series } from '../_models/series';
|
import { Series } from '../_models/series';
|
||||||
import { FilterItem, mangaFormatFilters, SeriesFilter } from '../_models/series-filter';
|
import { FilterItem, mangaFormatFilters, SeriesFilter } from '../_models/series-filter';
|
||||||
|
import { Action, ActionFactoryService } from '../_services/action-factory.service';
|
||||||
|
import { ActionService } from '../_services/action.service';
|
||||||
|
import { MessageHubService } from '../_services/message-hub.service';
|
||||||
import { SeriesService } from '../_services/series.service';
|
import { SeriesService } from '../_services/series.service';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -16,10 +23,10 @@ import { SeriesService } from '../_services/series.service';
|
|||||||
templateUrl: './recently-added.component.html',
|
templateUrl: './recently-added.component.html',
|
||||||
styleUrls: ['./recently-added.component.scss']
|
styleUrls: ['./recently-added.component.scss']
|
||||||
})
|
})
|
||||||
export class RecentlyAddedComponent implements OnInit {
|
export class RecentlyAddedComponent implements OnInit, OnDestroy {
|
||||||
|
|
||||||
isLoading: boolean = true;
|
isLoading: boolean = true;
|
||||||
recentlyAdded: Series[] = [];
|
series: Series[] = [];
|
||||||
pagination!: Pagination;
|
pagination!: Pagination;
|
||||||
libraryId!: number;
|
libraryId!: number;
|
||||||
|
|
||||||
@ -28,7 +35,10 @@ export class RecentlyAddedComponent implements OnInit {
|
|||||||
mangaFormat: null
|
mangaFormat: null
|
||||||
};
|
};
|
||||||
|
|
||||||
constructor(private router: Router, private route: ActivatedRoute, private seriesService: SeriesService, private titleService: Title) {
|
onDestroy: Subject<void> = new Subject();
|
||||||
|
|
||||||
|
constructor(private router: Router, private route: ActivatedRoute, private seriesService: SeriesService, private titleService: Title,
|
||||||
|
private actionService: ActionService, public bulkSelectionService: BulkSelectionService, private hubService: MessageHubService) {
|
||||||
this.router.routeReuseStrategy.shouldReuseRoute = () => false;
|
this.router.routeReuseStrategy.shouldReuseRoute = () => false;
|
||||||
this.titleService.setTitle('Kavita - Recently Added');
|
this.titleService.setTitle('Kavita - Recently Added');
|
||||||
if (this.pagination === undefined || this.pagination === null) {
|
if (this.pagination === undefined || this.pagination === null) {
|
||||||
@ -37,7 +47,30 @@ export class RecentlyAddedComponent implements OnInit {
|
|||||||
this.loadPage();
|
this.loadPage();
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit() {}
|
@HostListener('document:keydown.shift', ['$event'])
|
||||||
|
handleKeypress(event: KeyboardEvent) {
|
||||||
|
if (event.key === KEY_CODES.SHIFT) {
|
||||||
|
this.bulkSelectionService.isShiftDown = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@HostListener('document:keyup.shift', ['$event'])
|
||||||
|
handleKeyUp(event: KeyboardEvent) {
|
||||||
|
if (event.key === KEY_CODES.SHIFT) {
|
||||||
|
this.bulkSelectionService.isShiftDown = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
this.hubService.seriesAdded.pipe(takeWhile(event => event.libraryId === this.libraryId), debounceTime(6000), takeUntil(this.onDestroy)).subscribe((event: SeriesAddedEvent) => {
|
||||||
|
this.loadPage();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnDestroy() {
|
||||||
|
this.onDestroy.next();
|
||||||
|
this.onDestroy.complete();
|
||||||
|
}
|
||||||
|
|
||||||
seriesClicked(series: Series) {
|
seriesClicked(series: Series) {
|
||||||
this.router.navigate(['library', this.libraryId, 'series', series.id]);
|
this.router.navigate(['library', this.libraryId, 'series', series.id]);
|
||||||
@ -65,7 +98,7 @@ export class RecentlyAddedComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
this.isLoading = true;
|
this.isLoading = true;
|
||||||
this.seriesService.getRecentlyAdded(this.libraryId, this.pagination?.currentPage, this.pagination?.itemsPerPage, this.filter).pipe(take(1)).subscribe(series => {
|
this.seriesService.getRecentlyAdded(this.libraryId, this.pagination?.currentPage, this.pagination?.itemsPerPage, this.filter).pipe(take(1)).subscribe(series => {
|
||||||
this.recentlyAdded = series.result;
|
this.series = series.result;
|
||||||
this.pagination = series.pagination;
|
this.pagination = series.pagination;
|
||||||
this.isLoading = false;
|
this.isLoading = false;
|
||||||
window.scrollTo(0, 0);
|
window.scrollTo(0, 0);
|
||||||
@ -76,4 +109,35 @@ export class RecentlyAddedComponent implements OnInit {
|
|||||||
const urlParams = new URLSearchParams(window.location.search);
|
const urlParams = new URLSearchParams(window.location.search);
|
||||||
return urlParams.get('page');
|
return urlParams.get('page');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bulkActionCallback = (action: Action, data: any) => {
|
||||||
|
const selectedSeriesIndexies = this.bulkSelectionService.getSelectedCardsForSource('series');
|
||||||
|
const selectedSeries = this.series.filter((series, index: number) => selectedSeriesIndexies.includes(index + ''));
|
||||||
|
|
||||||
|
switch (action) {
|
||||||
|
case Action.AddToReadingList:
|
||||||
|
this.actionService.addMultipleSeriesToReadingList(selectedSeries, () => {
|
||||||
|
this.bulkSelectionService.deselectAll();
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
case Action.AddToCollection:
|
||||||
|
this.actionService.addMultipleSeriesToCollectionTag(selectedSeries, () => {
|
||||||
|
this.bulkSelectionService.deselectAll();
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
case Action.MarkAsRead:
|
||||||
|
this.actionService.markMultipleSeriesAsRead(selectedSeries, () => {
|
||||||
|
this.loadPage();
|
||||||
|
this.bulkSelectionService.deselectAll();
|
||||||
|
});
|
||||||
|
|
||||||
|
break;
|
||||||
|
case Action.MarkAsUnread:
|
||||||
|
this.actionService.markMultipleSeriesAsUnread(selectedSeries, () => {
|
||||||
|
this.loadPage();
|
||||||
|
this.bulkSelectionService.deselectAll();
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user