diff --git a/src/Ombi/ClientApp/src/app/media-details/components/movie/movie-details.component.ts b/src/Ombi/ClientApp/src/app/media-details/components/movie/movie-details.component.ts
index f0a2423e5..06a1cf0e4 100644
--- a/src/Ombi/ClientApp/src/app/media-details/components/movie/movie-details.component.ts
+++ b/src/Ombi/ClientApp/src/app/media-details/components/movie/movie-details.component.ts
@@ -12,7 +12,7 @@ import { NewIssueComponent } from "../shared/new-issue/new-issue.component";
import { MovieAdvancedOptionsComponent } from "./panels/movie-advanced-options/movie-advanced-options.component";
import { RequestServiceV2 } from "../../../services/requestV2.service";
import { RequestBehalfComponent } from "../shared/request-behalf/request-behalf.component";
-import { Observable, forkJoin } from "rxjs";
+import { forkJoin } from "rxjs";
@Component({
templateUrl: "./movie-details.component.html",
diff --git a/src/Ombi/ClientApp/src/app/requests-list/components/movies-grid/movies-grid.component.html b/src/Ombi/ClientApp/src/app/requests-list/components/movies-grid/movies-grid.component.html
index 90a3e8784..4a8c17f7c 100644
--- a/src/Ombi/ClientApp/src/app/requests-list/components/movies-grid/movies-grid.component.html
+++ b/src/Ombi/ClientApp/src/app/requests-list/components/movies-grid/movies-grid.component.html
@@ -30,6 +30,20 @@
+
+
+
+
+ |
+
+
+
+ |
+
{{ 'Requests.RequestsTitle' | translate}} |
@@ -71,4 +85,11 @@
-
\ No newline at end of file
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Ombi/ClientApp/src/app/requests-list/components/movies-grid/movies-grid.component.ts b/src/Ombi/ClientApp/src/app/requests-list/components/movies-grid/movies-grid.component.ts
index 93cf37a64..c73084c2b 100644
--- a/src/Ombi/ClientApp/src/app/requests-list/components/movies-grid/movies-grid.component.ts
+++ b/src/Ombi/ClientApp/src/app/requests-list/components/movies-grid/movies-grid.component.ts
@@ -1,14 +1,18 @@
import { Component, AfterViewInit, ViewChild, EventEmitter, Output, ChangeDetectorRef, OnInit } from "@angular/core";
-import { IMovieRequests, IRequestsViewModel } from "../../../interfaces";
+import { IMovieRequests, IRequestEngineResult, IRequestsViewModel } from "../../../interfaces";
import { MatPaginator } from "@angular/material/paginator";
import { MatSort } from "@angular/material/sort";
-import { merge, Observable, of as observableOf } from 'rxjs';
+import { merge, Observable, of as observableOf, 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 { SelectionModel } from "@angular/cdk/collections";
+import { NotificationService, RequestService } from "../../../services";
+import { TranslateService } from "@ngx-translate/core";
+import { MatTableDataSource } from "@angular/material/table";
@Component({
templateUrl: "./movies-grid.component.html",
@@ -16,7 +20,7 @@ import { RequestFilterType } from "../../models/RequestFilterType";
styleUrls: ["./movies-grid.component.scss"]
})
export class MoviesGridComponent implements OnInit, AfterViewInit {
- public dataSource: IMovieRequests[] = [];
+ public dataSource: MatTableDataSource;
public resultsLength: number;
public isLoadingResults = true;
public displayedColumns: string[] = ['title', 'requestedUser.requestedBy', 'status', 'requestStatus','requestedDate', 'actions'];
@@ -25,6 +29,7 @@ export class MoviesGridComponent implements OnInit, AfterViewInit {
public defaultSort: string = "requestedDate";
public defaultOrder: string = "desc";
public currentFilter: RequestFilterType = RequestFilterType.All;
+ public selection = new SelectionModel(true, []);
public RequestFilter = RequestFilterType;
@@ -40,13 +45,17 @@ export class MoviesGridComponent implements OnInit, AfterViewInit {
@ViewChild(MatSort) sort: MatSort;
constructor(private requestService: RequestServiceV2, private ref: ChangeDetectorRef,
- private auth: AuthService, private storageService: StorageService) {
+ private auth: AuthService, private storageService: StorageService,
+ private requestServiceV1: RequestService, private notification: NotificationService,
+ private translateService: TranslateService) {
}
-
- public ngOnInit() {
- this.isAdmin = this.auth.hasRole("admin") || this.auth.hasRole("poweruser");
+ public ngOnInit() {
+ this.isAdmin = this.auth.hasRole("admin") || this.auth.hasRole("poweruser");
+ if (this.isAdmin) {
+ this.displayedColumns.unshift('select');
+ }
const defaultCount = this.storageService.get(this.storageKeyGridCount);
const defaultSort = this.storageService.get(this.storageKey);
const defaultOrder = this.storageService.get(this.storageKeyOrder);
@@ -96,7 +105,7 @@ export class MoviesGridComponent implements OnInit, AfterViewInit {
this.isLoadingResults = false;
return observableOf([]);
})
- ).subscribe(data => this.dataSource = data);
+ ).subscribe(data => this.dataSource = new MatTableDataSource(data));
}
public loadData(): Observable> {
@@ -117,9 +126,9 @@ export class MoviesGridComponent implements OnInit, AfterViewInit {
public openOptions(request: IMovieRequests) {
const filter = () => {
- this.dataSource = this.dataSource.filter((req) => {
- return req.id !== request.id;
- })
+ this.dataSource.data = this.dataSource.data.filter((req) => {
+ return req.id !== request.id;
+ });
};
const onChange = () => {
@@ -133,4 +142,56 @@ export class MoviesGridComponent 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.removeMovieRequestAsync(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.approveMovie({ 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();
+ })
+ }
+}
\ No newline at end of file
diff --git a/src/Ombi/ClientApp/src/app/requests-list/components/requests-list.component.scss b/src/Ombi/ClientApp/src/app/requests-list/components/requests-list.component.scss
index 1c6a9f617..78fd3f91f 100644
--- a/src/Ombi/ClientApp/src/app/requests-list/components/requests-list.component.scss
+++ b/src/Ombi/ClientApp/src/app/requests-list/components/requests-list.component.scss
@@ -62,4 +62,11 @@
::ng-deep table.requests button{
margin:5px;
-}
\ No newline at end of file
+}
+
+::ng-deep .floating-fab {
+ position: fixed;
+ right: 3%;
+ bottom: 6%;
+ z-index: 10;
+}
diff --git a/src/Ombi/ClientApp/src/styles/shared.scss b/src/Ombi/ClientApp/src/styles/shared.scss
index 2dd922173..7184d96fb 100644
--- a/src/Ombi/ClientApp/src/styles/shared.scss
+++ b/src/Ombi/ClientApp/src/styles/shared.scss
@@ -137,4 +137,4 @@ table {
::ng-deep .mat-form-field.mat-focused .mat-form-field-label {
color: $accent;
-}
+}
\ No newline at end of file
diff --git a/src/Ombi/wwwroot/translations/en.json b/src/Ombi/wwwroot/translations/en.json
index c75a74a99..0efb3fe88 100644
--- a/src/Ombi/wwwroot/translations/en.json
+++ b/src/Ombi/wwwroot/translations/en.json
@@ -180,7 +180,9 @@
"RequestPanel": {
"Delete":"Delete Request",
"Approve":"Approve Request",
- "ChangeAvailability":"Mark Available"
+ "ChangeAvailability":"Mark Available",
+ "Deleted": "Successfully deleted selected items",
+ "Approved": "Successfully approved selected items"
}
},
"Issues": {