mirror of https://github.com/Ombi-app/Ombi
parent
73353a6aa5
commit
6d339e7a1c
@ -1,3 +1,3 @@
|
|||||||
<div *ngIf="movie && radarrEnabled" class="text-center">
|
<div *ngIf="movie && radarrEnabled" class="text-center">
|
||||||
<button mat-raised-button color="warn" class="text-center" (click)="openAdvancedOptions();">Advanced Options</button>
|
<button mat-raised-button color="warn" class="text-center" (click)="openAdvancedOptions();">{{'MediaDetails.AdvancedOptions' | translate }}</button>
|
||||||
</div>
|
</div>
|
@ -0,0 +1,72 @@
|
|||||||
|
<div class="mat-elevation-z8">
|
||||||
|
<grid-spinner [loading]="isLoadingResults"></grid-spinner>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- <div class="row"> -->
|
||||||
|
<div class="row justify-content-md-center top-spacing">
|
||||||
|
<div class="btn-group" role="group">
|
||||||
|
<button type="button" (click)="switchFilter(RequestFilter.All)" [attr.color]="currentFilter === RequestFilter.All ? 'accent' : 'primary'" [ngClass]="currentFilter === RequestFilter.All ? 'mat-accent' : 'mat-primary'" mat-raised-button class="btn grow">{{'Requests.AllRequests' | translate}}</button>
|
||||||
|
<button type="button" (click)="switchFilter(RequestFilter.Pending)" [attr.color]="currentFilter === RequestFilter.Pending ? 'accent' : 'primary'" [ngClass]="currentFilter === RequestFilter.Pending ? 'mat-accent' : 'mat-primary'" mat-raised-button class="btn grow">{{'Requests.PendingRequests' | translate}}</button>
|
||||||
|
<button type="button" (click)="switchFilter(RequestFilter.Processing)" [attr.color]="currentFilter === RequestFilter.Processing ? 'accent' : 'primary'" [ngClass]="currentFilter === RequestFilter.Processing ? 'mat-accent' : 'mat-primary'" mat-raised-button
|
||||||
|
class="btn grow">{{'Requests.ProcessingRequests' | translate}}</button>
|
||||||
|
<button type="button" (click)="switchFilter(RequestFilter.Available)" [attr.color]="currentFilter === RequestFilter.Available ? 'accent' : 'primary'" [ngClass]="currentFilter === RequestFilter.Available ? 'mat-accent' : 'mat-primary'" mat-raised-button
|
||||||
|
class="btn grow">{{'Requests.AvailableRequests' | translate}}</button>
|
||||||
|
<button type="button" (click)="switchFilter(RequestFilter.Denied)" [attr.color]="currentFilter === RequestFilter.Denied ? 'accent' : 'primary'" [ngClass]="currentFilter === RequestFilter.Denied ? 'mat-accent' : 'mat-primary'" mat-raised-button class="btn grow">{{'Requests.DeniedRequests' | translate}}</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-2 offset-md-10">
|
||||||
|
<mat-form-field>
|
||||||
|
<mat-select placeholder="{{'Requests.RequestsToDisplay' | translate}}" [(value)]="gridCount" (selectionChange)="ngAfterViewInit()">
|
||||||
|
<mat-option value="10">10</mat-option>
|
||||||
|
<mat-option value="15">15</mat-option>
|
||||||
|
<mat-option value="30">30</mat-option>
|
||||||
|
<mat-option value="100">100</mat-option>
|
||||||
|
</mat-select>
|
||||||
|
</mat-form-field>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- </div> -->
|
||||||
|
<table mat-table [dataSource]="dataSource" class="table" matSort [matSortActive]="defaultSort" matSortDisableClear [matSortDirection]="defaultOrder">
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<ng-container matColumnDef="artistName">
|
||||||
|
<th mat-header-cell *matHeaderCellDef mat-sort-header disableClear> {{ 'Requests.ArtistName' | translate}} </th>
|
||||||
|
<td mat-cell *matCellDef="let element"> {{element.artistName}} </td>
|
||||||
|
</ng-container>
|
||||||
|
<ng-container matColumnDef="title">
|
||||||
|
<th mat-header-cell *matHeaderCellDef mat-sort-header disableClear> {{ 'Requests.AlbumName' | translate}} </th>
|
||||||
|
<td mat-cell *matCellDef="let element"> {{element.title}} ({{element.releaseDate | amLocal | amDateFormat: 'YYYY'}}) </td>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<ng-container matColumnDef="requestedUser.requestedBy">
|
||||||
|
<th mat-header-cell *matHeaderCellDef> {{'Requests.RequestedBy' | translate}} </th>
|
||||||
|
<td mat-cell *matCellDef="let element"> {{element.requestedUser?.userAlias}} </td>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<ng-container matColumnDef="requestedDate">
|
||||||
|
<th mat-header-cell *matHeaderCellDef mat-sort-header disableClear> {{ 'Requests.RequestDate' | translate}} </th>
|
||||||
|
<td mat-cell *matCellDef="let element"> {{element.requestedDate | amLocal | amDateFormat: 'LL'}} </td>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<ng-container matColumnDef="requestStatus">
|
||||||
|
<th mat-header-cell *matHeaderCellDef mat-sort-header disableClear> {{ 'Requests.RequestStatus' | translate}} </th>
|
||||||
|
<td mat-cell *matCellDef="let element"> {{element.requestStatus | translate}} </td>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<ng-container matColumnDef="actions">
|
||||||
|
<th mat-header-cell *matHeaderCellDef> </th>
|
||||||
|
<td mat-cell *matCellDef="let element">
|
||||||
|
<button mat-raised-button color="accent" [routerLink]="'/details/artist/' + element.foreignArtistId">{{ 'Requests.Details' | translate}}</button>
|
||||||
|
<button mat-raised-button color="warn" (click)="openOptions(element)" *ngIf="isAdmin"> {{ 'Requests.Options' | translate}}</button>
|
||||||
|
</td>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<tr mat-header-row *matHeaderRowDef="displayedColumns; sticky: true"></tr>
|
||||||
|
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<mat-paginator [length]="resultsLength" [pageSize]="gridCount"></mat-paginator>
|
||||||
|
</div>
|
@ -0,0 +1,49 @@
|
|||||||
|
@import "~styles/variables.scss";
|
||||||
|
|
||||||
|
.dark .mat-header-cell {
|
||||||
|
background: $accent-dark !important;
|
||||||
|
font-size: 1em;
|
||||||
|
font-weight: bold;
|
||||||
|
color: #303030;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mat-form-field {
|
||||||
|
float:right;
|
||||||
|
margin-right:20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*::ng-deep .dark .mat-form-field-label{
|
||||||
|
font-size: 1.2em;
|
||||||
|
}*/
|
||||||
|
|
||||||
|
::ng-deep .mat-form-field-infix {
|
||||||
|
width: 8em;
|
||||||
|
margin-top:1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
::ng-deep .dark .mat-tab-label-active{
|
||||||
|
background: $accent-dark !important;
|
||||||
|
color: #303030 !important;
|
||||||
|
font-weight:bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
::ng-deep .mat-tab-label{
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
::ng-deep .row {
|
||||||
|
margin-right:0;
|
||||||
|
margin-left:0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 500px) {
|
||||||
|
.justify-content-md-center {
|
||||||
|
justify-content: normal !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 1170px){
|
||||||
|
.justify-content-md-center {
|
||||||
|
justify-content: center !important;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,136 @@
|
|||||||
|
import { Component, AfterViewInit, ViewChild, EventEmitter, Output, ChangeDetectorRef, OnInit } from "@angular/core";
|
||||||
|
import { IRequestsViewModel, IAlbumRequest } from "../../../interfaces";
|
||||||
|
import { MatPaginator } from "@angular/material/paginator";
|
||||||
|
import { MatSort } from "@angular/material/sort";
|
||||||
|
import { merge, Observable, of as observableOf } 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";
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
templateUrl: "./albums-grid.component.html",
|
||||||
|
selector: "albums-grid",
|
||||||
|
styleUrls: ["./albums-grid.component.scss"]
|
||||||
|
})
|
||||||
|
export class AlbumsGridComponent implements OnInit, AfterViewInit {
|
||||||
|
public dataSource: IAlbumRequest[] = [];
|
||||||
|
public resultsLength: number;
|
||||||
|
public isLoadingResults = true;
|
||||||
|
public displayedColumns: string[] = ['artistName', 'title', 'requestedUser.requestedBy', 'requestStatus','requestedDate', 'actions'];
|
||||||
|
public gridCount: string = "15";
|
||||||
|
public isAdmin: boolean;
|
||||||
|
public defaultSort: string = "requestedDate";
|
||||||
|
public defaultOrder: string = "desc";
|
||||||
|
public currentFilter: RequestFilterType = RequestFilterType.All;
|
||||||
|
|
||||||
|
public RequestFilter = RequestFilterType;
|
||||||
|
|
||||||
|
|
||||||
|
private storageKey = "Albums_DefaultRequestListSort";
|
||||||
|
private storageKeyOrder = "Albums_DefaultRequestListSortOrder";
|
||||||
|
private storageKeyGridCount = "Albums_DefaultGridCount";
|
||||||
|
private storageKeyCurrentFilter = "Albums_DefaultFilter";
|
||||||
|
|
||||||
|
@Output() public onOpenOptions = new EventEmitter<{ request: any, filter: any, onChange: any }>();
|
||||||
|
|
||||||
|
@ViewChild(MatPaginator) paginator: MatPaginator;
|
||||||
|
@ViewChild(MatSort) sort: MatSort;
|
||||||
|
|
||||||
|
constructor(private requestService: RequestServiceV2, private ref: ChangeDetectorRef,
|
||||||
|
private auth: AuthService, private storageService: StorageService) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
const defaultFilter = +this.storageService.get(this.storageKeyCurrentFilter);
|
||||||
|
if (defaultSort) {
|
||||||
|
this.defaultSort = defaultSort;
|
||||||
|
}
|
||||||
|
if (defaultOrder) {
|
||||||
|
this.defaultOrder = defaultOrder;
|
||||||
|
}
|
||||||
|
if (defaultCount) {
|
||||||
|
this.gridCount = defaultCount;
|
||||||
|
}
|
||||||
|
if (defaultFilter) {
|
||||||
|
this.currentFilter = defaultFilter;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async ngAfterViewInit() {
|
||||||
|
|
||||||
|
this.storageService.save(this.storageKeyGridCount, this.gridCount);
|
||||||
|
this.storageService.save(this.storageKeyCurrentFilter, (+this.currentFilter).toString());
|
||||||
|
|
||||||
|
// If the user changes the sort order, reset back to the first page.
|
||||||
|
this.sort.sortChange.subscribe(() => this.paginator.pageIndex = 0);
|
||||||
|
this.paginator.showFirstLastButtons = true;
|
||||||
|
|
||||||
|
merge(this.sort.sortChange, this.paginator.page, this.currentFilter)
|
||||||
|
.pipe(
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
return this.loadData();
|
||||||
|
}),
|
||||||
|
map((data: IRequestsViewModel<IAlbumRequest>) => {
|
||||||
|
// Flip flag to show that loading has finished.
|
||||||
|
this.isLoadingResults = false;
|
||||||
|
this.resultsLength = data.total;
|
||||||
|
|
||||||
|
return data.collection;
|
||||||
|
}),
|
||||||
|
catchError((err) => {
|
||||||
|
this.isLoadingResults = false;
|
||||||
|
return observableOf([]);
|
||||||
|
})
|
||||||
|
).subscribe(data => this.dataSource = data);
|
||||||
|
}
|
||||||
|
|
||||||
|
public loadData(): Observable<IRequestsViewModel<IAlbumRequest>> {
|
||||||
|
switch(RequestFilterType[RequestFilterType[this.currentFilter]]) {
|
||||||
|
case RequestFilterType.All:
|
||||||
|
return this.requestService.getAlbumRequests(+this.gridCount, this.paginator.pageIndex * +this.gridCount, this.sort.active, this.sort.direction);
|
||||||
|
case RequestFilterType.Pending:
|
||||||
|
return this.requestService.getAlbumPendingRequests(+this.gridCount, this.paginator.pageIndex * +this.gridCount, this.sort.active, this.sort.direction);
|
||||||
|
case RequestFilterType.Available:
|
||||||
|
return this.requestService.getAlbumAvailableRequests(+this.gridCount, this.paginator.pageIndex * +this.gridCount, this.sort.active, this.sort.direction);
|
||||||
|
case RequestFilterType.Processing:
|
||||||
|
return this.requestService.getAlbumProcessingRequests(+this.gridCount, this.paginator.pageIndex * +this.gridCount, this.sort.active, this.sort.direction);
|
||||||
|
case RequestFilterType.Denied:
|
||||||
|
return this.requestService.getAlbumDeniedRequests(+this.gridCount, this.paginator.pageIndex * +this.gridCount, this.sort.active, this.sort.direction);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public openOptions(request: IAlbumRequest) {
|
||||||
|
const filter = () => {
|
||||||
|
this.dataSource = this.dataSource.filter((req) => {
|
||||||
|
return req.id !== request.id;
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
|
const onChange = () => {
|
||||||
|
this.ref.detectChanges();
|
||||||
|
};
|
||||||
|
|
||||||
|
this.onOpenOptions.emit({ request: request, filter: filter, onChange: onChange });
|
||||||
|
}
|
||||||
|
|
||||||
|
public switchFilter(type: RequestFilterType) {
|
||||||
|
this.currentFilter = type;
|
||||||
|
this.ngAfterViewInit();
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in new issue