diff --git a/src/Ombi/ClientApp/src/app/requests-list/components/tv-grid/tv-grid.component.html b/src/Ombi/ClientApp/src/app/requests-list/components/tv-grid/tv-grid.component.html index b9c256985..143a3bf55 100644 --- a/src/Ombi/ClientApp/src/app/requests-list/components/tv-grid/tv-grid.component.html +++ b/src/Ombi/ClientApp/src/app/requests-list/components/tv-grid/tv-grid.component.html @@ -30,6 +30,20 @@ + + + + @@ -78,4 +92,11 @@
+ + + + + + {{'Requests.RequestsTitle' | translate}}
- \ No newline at end of file + + + + + + + diff --git a/src/Ombi/ClientApp/src/app/requests-list/components/tv-grid/tv-grid.component.ts b/src/Ombi/ClientApp/src/app/requests-list/components/tv-grid/tv-grid.component.ts index 5e8521302..9461f31c8 100644 --- a/src/Ombi/ClientApp/src/app/requests-list/components/tv-grid/tv-grid.component.ts +++ b/src/Ombi/ClientApp/src/app/requests-list/components/tv-grid/tv-grid.component.ts @@ -1,14 +1,19 @@ import { Component, AfterViewInit, ViewChild, Output, EventEmitter, ChangeDetectorRef, OnInit } from "@angular/core"; -import { IRequestsViewModel, IChildRequests } from "../../../interfaces"; +import {IRequestsViewModel, IChildRequests, IMovieRequests, IRequestEngineResult} from "../../../interfaces"; import { MatPaginator } from "@angular/material/paginator"; import { MatSort } from "@angular/material/sort"; -import { merge, of as observableOf, Observable } from 'rxjs'; +import { MatTableDataSource } from "@angular/material/table"; +import { SelectionModel } from "@angular/cdk/collections"; + +import {merge, of as observableOf, Observable, forkJoin} from 'rxjs'; import { catchError, map, startWith, switchMap } from 'rxjs/operators'; import { RequestServiceV2 } from "../../../services/requestV2.service"; import { AuthService } from "../../../auth/auth.service"; import { StorageService } from "../../../shared/storage/storage-service"; import { RequestFilterType } from "../../models/RequestFilterType"; +import {NotificationService, RequestService} from "../../../services"; +import {TranslateService} from "@ngx-translate/core"; @Component({ templateUrl: "./tv-grid.component.html", @@ -16,7 +21,7 @@ import { RequestFilterType } from "../../models/RequestFilterType"; styleUrls: ["../requests-list.component.scss"] }) export class TvGridComponent implements OnInit, AfterViewInit { - public dataSource: IChildRequests[] = []; + public dataSource: MatTableDataSource; public resultsLength: number; public isLoadingResults = true; public displayedColumns: string[] = ['series', 'requestedBy', 'status', 'requestStatus', 'requestedDate','actions']; @@ -25,6 +30,8 @@ export class TvGridComponent implements OnInit, AfterViewInit { public defaultSort: string = "requestedDate"; public defaultOrder: string = "desc"; public currentFilter: RequestFilterType = RequestFilterType.All; + public selection = new SelectionModel(true, []); + public RequestFilter = RequestFilterType; public manageOwnRequests: boolean; @@ -40,12 +47,15 @@ export class TvGridComponent implements OnInit, AfterViewInit { @ViewChild(MatSort) sort: MatSort; constructor(private requestService: RequestServiceV2, private auth: AuthService, - private ref: ChangeDetectorRef, private storageService: StorageService) { + private ref: ChangeDetectorRef, private storageService: StorageService, + private notification: NotificationService, + private translateService: TranslateService, + private requestServiceV1: RequestService) { } - public ngOnInit() { - this.isAdmin = this.auth.hasRole("admin") || this.auth.hasRole("poweruser"); + public ngOnInit() { + this.isAdmin = this.auth.hasRole("admin") || this.auth.hasRole("poweruser"); const defaultCount = this.storageService.get(this.storageKeyGridCount); const defaultSort = this.storageService.get(this.storageKey); const defaultOrder = this.storageService.get(this.storageKeyOrder); @@ -66,7 +76,7 @@ export class TvGridComponent implements OnInit, AfterViewInit { public async ngAfterViewInit() { - this.storageService.save(this.storageKeyGridCount, this.gridCount); + this.storageService.save(this.storageKeyGridCount, this.gridCount); this.storageService.save(this.storageKeyCurrentFilter, (+this.currentFilter).toString()); this.paginator.showFirstLastButtons = true; @@ -78,7 +88,7 @@ export class TvGridComponent implements OnInit, AfterViewInit { startWith({}), switchMap((value: any) => { this.isLoadingResults = true; - + if (value.active || value.direction) { this.storageService.save(this.storageKey, value.active); this.storageService.save(this.storageKeyOrder, value.direction); @@ -96,14 +106,14 @@ export class TvGridComponent implements OnInit, AfterViewInit { this.isLoadingResults = false; return observableOf([]); }) - ).subscribe(data => this.dataSource = data); + ).subscribe(data => this.dataSource = new MatTableDataSource(data)); } public openOptions(request: IChildRequests) { - const filter = () => { this.dataSource = this.dataSource.filter((req) => { + const filter = () => { this.dataSource.data = this.dataSource.data.filter((req) => { return req.id !== request.id; })}; - + const onChange = () => { this.ref.detectChanges(); }; @@ -131,4 +141,56 @@ export class TvGridComponent implements OnInit, AfterViewInit { this.currentFilter = type; this.ngAfterViewInit(); } + + public isAllSelected() { + const numSelected = this.selection.selected.length; + const numRows = this.dataSource.data.length; + return numSelected === numRows; + } + + public masterToggle() { + this.isAllSelected() ? + this.selection.clear() : + this.dataSource.data.forEach(row => this.selection.select(row)); + } + + public async bulkDelete() { + if (this.selection.isEmpty()) { + return; + } + let tasks = new Array(); + this.selection.selected.forEach((selected) => { + tasks.push(this.requestServiceV1.deleteChild(selected.id)); + }); + + await Promise.all(tasks); + + this.notification.success(this.translateService.instant('Requests.RequestPanel.Deleted')) + this.selection.clear(); + this.ngAfterViewInit(); + } + + public bulkApprove() { + if (this.selection.isEmpty()) { + return; + } + let tasks = new Array>(); + this.selection.selected.forEach((selected) => { + tasks.push(this.requestServiceV1.approveChild({ id: selected.id })); + }); + + this.isLoadingResults = true; + forkJoin(tasks).subscribe((result: IRequestEngineResult[]) => { + this.isLoadingResults = false; + const failed = result.filter(x => !x.result); + if(failed.length > 0) { + this.notification.error("Some requests failed to approve: " + failed[0].errorMessage); + this.selection.clear(); + return; + } + this.notification.success(this.translateService.instant('Requests.RequestPanel.Approved')); + this.selection.clear(); + this.ngAfterViewInit(); + }) + } }