Started on the approval panel for tv shows

This commit is contained in:
tidusjar 2019-03-18 22:46:27 +00:00
parent 833544694a
commit b68e9fc080
18 changed files with 183 additions and 134 deletions

View file

@ -131,6 +131,7 @@ namespace Ombi.Core.Engine.V2
item.Available = oldModel.Available; item.Available = oldModel.Available;
item.Approved = oldModel.Approved; item.Approved = oldModel.Approved;
item.SeasonRequests = oldModel.SeasonRequests; item.SeasonRequests = oldModel.SeasonRequests;
item.RequestId = oldModel.RequestId;
return await GetExtraInfo(showInfoTask, item); return await GetExtraInfo(showInfoTask, item);
} }

View file

@ -42,22 +42,11 @@ namespace Ombi.Core.Rule.Rules.Search
} }
if (obj.Type == RequestType.TvShow) if (obj.Type == RequestType.TvShow)
{ {
//var tvRequests = Tv.GetRequest(obj.Id);
//if (tvRequests != null) // Do we already have a request for this?
//{
// obj.Requested = true;
// obj.Approved = tvRequests.ChildRequests.Any(x => x.Approved);
// obj.Available = tvRequests.ChildRequests.Any(x => x.Available);
// return Task.FromResult(Success());
//}
var request = (SearchTvShowViewModel)obj; var request = (SearchTvShowViewModel)obj;
var tvRequests = Tv.GetRequest(obj.Id); var tvRequests = Tv.GetRequest(obj.Id);
if (tvRequests != null) // Do we already have a request for this? if (tvRequests != null) // Do we already have a request for this?
{ {
request.RequestId = tvRequests.Id;
request.Requested = true; request.Requested = true;
request.Approved = tvRequests.ChildRequests.Any(x => x.Approved); request.Approved = tvRequests.ChildRequests.Any(x => x.Approved);

View file

@ -78,7 +78,7 @@ export class DiscoverCardDetailsComponent implements OnInit {
} }
} else if (this.data.type === RequestType.tvShow) { } else if (this.data.type === RequestType.tvShow) {
this.dialog.open(EpisodeRequestComponent, { width: "700px", data: this.tv }) this.dialog.open(EpisodeRequestComponent, { width: "700px", data: this.tv, panelClass: 'modal-panel' })
} }
this.loading = false; this.loading = false;

View file

@ -27,7 +27,7 @@ export class DiscoverCardComponent implements OnInit {
} }
public openDetails(details: IDiscoverCardResult) { public openDetails(details: IDiscoverCardResult) {
const ref = this.dialog.open(DiscoverCardDetailsComponent, { width:"700px", data: details }) const ref = this.dialog.open(DiscoverCardDetailsComponent, { width:"700px", data: details, panelClass: 'modal-panel' })
ref.afterClosed().subscribe(result => { ref.afterClosed().subscribe(result => {
console.log('The dialog was closed'); console.log('The dialog was closed');

View file

@ -41,6 +41,7 @@ export interface ISearchTvResultV2 {
images: IImagesV2; images: IImagesV2;
cast: ICast[]; cast: ICast[];
crew: ICrew[]; crew: ICrew[];
requestId: number;
} }

View file

@ -2,12 +2,13 @@
import { YoutubeTrailerComponent } from "./shared/youtube-trailer.component"; import { YoutubeTrailerComponent } from "./shared/youtube-trailer.component";
import { TvDetailsComponent } from "./tv/tv-details.component"; import { TvDetailsComponent } from "./tv/tv-details.component";
import { MovieInformationPanelComponent } from "./movie/panels/movie-information-panel.component"; import { MovieInformationPanelComponent } from "./movie/panels/movie-information-panel.component";
import { TvInformationPanelComponent } from "./tv/panels/tv-information-panel.component"; import { TvInformationPanelComponent } from "./tv/panels/tv-information-panel/tv-information-panel.component";
import { TopBannerComponent } from "./shared/top-banner/top-banner.component"; import { TopBannerComponent } from "./shared/top-banner/top-banner.component";
import { SocialIconsComponent } from "./shared/social-icons/social-icons.component"; import { SocialIconsComponent } from "./shared/social-icons/social-icons.component";
import { MediaPosterComponent } from "./shared/media-poster/media-poster.component"; import { MediaPosterComponent } from "./shared/media-poster/media-poster.component";
import { CastCarouselComponent } from "./shared/cast-carousel/cast-carousel.component"; import { CastCarouselComponent } from "./shared/cast-carousel/cast-carousel.component";
import { DenyDialogComponent } from "./shared/deny-dialog/deny-dialog.component"; import { DenyDialogComponent } from "./shared/deny-dialog/deny-dialog.component";
import { TvRequestsPanelComponent } from "./tv/panels/tv-requests/tv-requests-panel.component";
export const components: any[] = [ export const components: any[] = [
MovieDetailsComponent, MovieDetailsComponent,
@ -20,6 +21,7 @@ export const components: any[] = [
MediaPosterComponent, MediaPosterComponent,
CastCarouselComponent, CastCarouselComponent,
DenyDialogComponent, DenyDialogComponent,
TvRequestsPanelComponent
]; ];

View file

@ -1,9 +1,9 @@
import { Component, ViewEncapsulation, Input, OnInit } from "@angular/core"; import { Component, ViewEncapsulation, Input, OnInit } from "@angular/core";
import { ISearchTvResultV2 } from "../../../../interfaces/ISearchTvResultV2"; import { ISearchTvResultV2 } from "../../../../../interfaces/ISearchTvResultV2";
@Component({ @Component({
templateUrl: "./tv-information-panel.component.html", templateUrl: "./tv-information-panel.component.html",
styleUrls: ["../../../media-details.component.scss"], styleUrls: ["../../../../media-details.component.scss"],
selector: "tv-information-panel", selector: "tv-information-panel",
encapsulation: ViewEncapsulation.None encapsulation: ViewEncapsulation.None
}) })

View file

@ -0,0 +1,78 @@
<mat-accordion class="mat-elevation-z8">
<mat-expansion-panel *ngFor="let request of tvRequest">
<mat-expansion-panel-header>
<mat-panel-title>
<div *ngIf="request.approved && !request.available">{{'Common.ProcessingRequest' | translate}}</div>
<div *ngIf="request.requested && !request.approved && !request.available">
{{'Common.PendingApproval' | translate}}
</div>
<div *ngIf="!request.requested && !request.available && !request.approved">
{{'Common.NotRequested' | translate}}
</div>
<div *ngIf="request.available">{{'Common.Available' | translate}}
</div>
</mat-panel-title>
<mat-panel-description>
Requested By '{{request.requestedUser.userAlias}}' on
{{request.requestedDate | amLocal | amDateFormat: 'LL' }}
</mat-panel-description>
</mat-expansion-panel-header>
<mat-tab-group *ngFor="let season of request.seasonRequests">
<mat-tab label="{{ 'Requests.Season' | translate }} {{season.seasonNumber}}">
<table mat-table [dataSource]="season.episodes" class="mat-elevation-z8">
<ng-container matColumnDef="number">
<th mat-header-cell *matHeaderCellDef> {{ 'Requests.Number' | translate }} </th>
<td mat-cell *matCellDef="let element"> {{element.episodeNumber}} </td>
</ng-container>
<ng-container matColumnDef="title">
<th mat-header-cell *matHeaderCellDef> {{ 'Requests.GridTitle' | translate }} </th>
<td mat-cell *matCellDef="let element"> {{element.title}} </td>
</ng-container>
<ng-container matColumnDef="airDate">
<th mat-header-cell *matHeaderCellDef> {{ 'Requests.AirDate' | translate }} </th>
<td mat-cell *matCellDef="let element"> {{element.airDate | amLocal | amDateFormat: 'L' }}</td>
</ng-container>
<ng-container matColumnDef="status">
<th mat-header-cell *matHeaderCellDef> {{ 'Requests.GridStatus' | translate }} </th>
<td mat-cell *matCellDef="let ep">
<span *ngIf="request.denied" class="label label-danger" id="deniedLabel"
[translate]="'Common.Denied'">
<i class="fa fa-check" matTooltip="{{request.deniedReason}}"></i>
</span>
<span *ngIf="!request.denied && ep.available" class="label label-success"
id="availableLabel" [translate]="'Common.Available'"></span>
<span *ngIf="!request.denied &&ep.approved && !ep.available" class="label label-info"
id="processingRequestLabel" [translate]="'Common.ProcessingRequest'"></span>
<div *ngIf="!request.denied && !ep.approved">
<div *ngIf="!ep.available"><span class="label label-warning" id="pendingApprovalLabel"
[translate]="'Common.PendingApproval'"></span></div>
</div>
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
</table>
</mat-tab>
</mat-tab-group>
<button mat-raised-button color="accent">Approve</button>
</mat-expansion-panel>
</mat-accordion>

View file

@ -0,0 +1,16 @@
import { Component, ViewEncapsulation, Input, OnInit } from "@angular/core";
import { IChildRequests } from "../../../../../interfaces";
@Component({
templateUrl: "./tv-requests-panel.component.html",
styleUrls: ["./tv-requests-panel.component.scss"],
selector: "tv-requests-panel"
})
export class TvRequestsPanelComponent implements OnInit {
@Input() public tvRequest: IChildRequests[];
public displayedColumns: string[] = ['number', 'title', 'airDate', 'status'];
public ngOnInit(): void {
//
}
}

View file

@ -13,19 +13,21 @@
<div class="col-12 col-lg-3 col-xl-3 media-row"> <div class="col-12 col-lg-3 col-xl-3 media-row">
<social-icons [homepage]="tv.homepage" [tvdbId]="tv.id" [hasTrailer]="tv.trailer" (openTrailer)="openDialog()" <social-icons [homepage]="tv.homepage" [tvdbId]="tv.id" [hasTrailer]="tv.trailer" (openTrailer)="openDialog()"
[imdbId]="tv.imdbId" [available]="tv.available" [plexUrl]="tv.plexUrl" [embyUrl]="tv.embyUrl"></social-icons> [imdbId]="tv.imdbId" [available]="tv.available" [plexUrl]="tv.plexUrl" [embyUrl]="tv.embyUrl">
</social-icons>
</div> </div>
<div class="col-12 col-lg-6 col-xl-6 media-row"> <div class="col-12 col-lg-6 col-xl-6 media-row">
<button *ngIf="!tv.fullyAvailable" mat-raised-button class="btn-spacing" color="primary" (click)="request()"><i <button *ngIf="!tv.fullyAvailable" mat-raised-button class="btn-spacing" color="primary"
class="fa fa-plus"></i> (click)="request()"><i class="fa fa-plus"></i>
{{ 'Common.Request' | translate }}</button> {{ 'Common.Request' | translate }}</button>
<button *ngIf="tv.fullyAvailable" mat-raised-button class="btn-spacing" color="accent" [disabled]> <button *ngIf="tv.fullyAvailable" mat-raised-button class="btn-spacing" color="accent" [disabled]>
<i class="fa fa-check"></i> {{'Common.Available' | translate }}</button> <i class="fa fa-check"></i> {{'Common.Available' | translate }}</button>
<button *ngIf="tv.partlyAvailable && !tv.fullyAvailable" mat-raised-button class="btn-spacing" color="accent" [disabled]> <button *ngIf="tv.partlyAvailable && !tv.fullyAvailable" mat-raised-button class="btn-spacing" color="accent"
[disabled]>
<i class="fa fa-check"></i> {{'Common.PartiallyAvailable' | translate }}</button> <i class="fa fa-check"></i> {{'Common.PartiallyAvailable' | translate }}</button>
</div> </div>
</div> </div>
@ -56,91 +58,38 @@
</div> </div>
</div> </div>
</div>
</div>
<div class="row">
<div class="col-12 col-md-2">
<!--Just some space yo-->
</div> </div>
</div> <div class="col-12 col-md-10">
<div class="row card-spacer media-row">
<div class="col-12 col-md-9">
</div>
</div>
<div class="row card-spacer media-row">
<div class="col-12 col-md-3"></div>
<!-- <div class="col-12 col-md-9">
<mat-accordion> <mat-accordion>
<mat-expansion-panel> <mat-expansion-panel>
<mat-expansion-panel-header> <mat-expansion-panel-header>
<mat-panel-title> <mat-panel-title>
Recommendations Requests
</mat-panel-title> </mat-panel-title>
</mat-expansion-panel-header> </mat-expansion-panel-header>
<tv-requests-panel [tvRequest]="tvRequest"></tv-requests-panel>
<div class="row card-spacer" *ngIf="tv.recommendations.results.length > 0">
<div class="col-md-2" *ngFor="let r of tv.recommendations.results">
<div class="sidebar affixable affix-top preview-poster">
<div class="poster">
<a [routerLink]="'/details/tv/'+r.id">
<img class="real grow" matTooltip="{{r.title}}"
src="https://image.tmdb.org/t/p/w300/{{r.poster_path}}" alt="Poster"
style="display: block;">
</a>
</div>
</div>
</div>
</div>
</mat-expansion-panel> </mat-expansion-panel>
<mat-expansion-panel>
<mat-expansion-panel-header>
<mat-panel-title>
Similar
</mat-panel-title>
</mat-expansion-panel-header>
<div class="row card-spacer" *ngIf="tv.similar.results.length > 0">
<div class="col-md-2" *ngFor="let r of tv.similar.results">
<div class="sidebar affixable affix-top preview-poster">
<div class="poster ">
<a [routerLink]="'/details/tv/'+r.id">
<img class="real grow" matTooltip="{{r.title}}"
src="https://image.tmdb.org/t/p/w300/{{r.poster_path}}" alt="Poster"
style="display: block;">
</a>
</div>
</div>
</div>
</div>
</mat-expansion-panel>
<mat-expansion-panel>
<mat-expansion-panel-header>
<mat-panel-title>
Videos
</mat-panel-title>
</mat-expansion-panel-header>
<div class="row card-spacer" *ngIf="tv.videos.results.length > 0">
<div class="col-md-6" *ngFor="let video of tv.videos.results">
<iframe width="100%" height="315px"
[src]="'https://www.youtube.com/embed/' + video.key | safe" frameborder="0"
allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture"
allowfullscreen></iframe>
</div>
</div>
</mat-expansion-panel>
</mat-accordion> </mat-accordion>
</div> -->
</div> </div>
</div>
</div> </div>

View file

@ -1,11 +1,12 @@
import { Component, ViewEncapsulation } from "@angular/core"; import { Component, ViewEncapsulation } from "@angular/core";
import { ImageService, SearchV2Service, MessageService } from "../../../services"; import { ImageService, SearchV2Service, MessageService, RequestService } from "../../../services";
import { ActivatedRoute } from "@angular/router"; import { ActivatedRoute } from "@angular/router";
import { DomSanitizer } from "@angular/platform-browser"; import { DomSanitizer } from "@angular/platform-browser";
import { ISearchTvResultV2 } from "../../../interfaces/ISearchTvResultV2"; import { ISearchTvResultV2 } from "../../../interfaces/ISearchTvResultV2";
import { MatDialog } from "@angular/material"; import { MatDialog } from "@angular/material";
import { YoutubeTrailerComponent } from "../shared/youtube-trailer.component"; import { YoutubeTrailerComponent } from "../shared/youtube-trailer.component";
import { EpisodeRequestComponent } from "../../../shared/episode-request/episode-request.component"; import { EpisodeRequestComponent } from "../../../shared/episode-request/episode-request.component";
import { IChildRequests } from "../../../interfaces";
@Component({ @Component({
templateUrl: "./tv-details.component.html", templateUrl: "./tv-details.component.html",
@ -14,13 +15,14 @@ import { EpisodeRequestComponent } from "../../../shared/episode-request/episode
}) })
export class TvDetailsComponent { export class TvDetailsComponent {
public tv: ISearchTvResultV2; public tv: ISearchTvResultV2;
public tvRequest: IChildRequests[];
public fromSearch: boolean; public fromSearch: boolean;
private tvdbId: number; private tvdbId: number;
constructor(private searchService: SearchV2Service, private route: ActivatedRoute, constructor(private searchService: SearchV2Service, private route: ActivatedRoute,
private sanitizer: DomSanitizer, private imageService: ImageService, private sanitizer: DomSanitizer, private imageService: ImageService,
public dialog: MatDialog, public messageService: MessageService) { public dialog: MatDialog, public messageService: MessageService, private requestService: RequestService) {
this.route.params.subscribe((params: any) => { this.route.params.subscribe((params: any) => {
this.tvdbId = params.tvdbId; this.tvdbId = params.tvdbId;
this.fromSearch = params.search; this.fromSearch = params.search;
@ -30,19 +32,23 @@ export class TvDetailsComponent {
} }
public async load() { public async load() {
if(this.fromSearch) { if (this.fromSearch) {
this.tv = await this.searchService.getTvInfoWithMovieDbId(this.tvdbId); this.tv = await this.searchService.getTvInfoWithMovieDbId(this.tvdbId);
this.tvdbId = this.tv.id; this.tvdbId = this.tv.id;
} else { } else {
this.tv = await this.searchService.getTvInfo(this.tvdbId); this.tv = await this.searchService.getTvInfo(this.tvdbId);
} }
if(this.tv.requestId) {
this.tvRequest = await this.requestService.getChildRequests(this.tv.requestId).toPromise();
}
const tvBanner = await this.imageService.getTvBanner(this.tvdbId).toPromise(); const tvBanner = await this.imageService.getTvBanner(this.tvdbId).toPromise();
this.tv.background = this.sanitizer.bypassSecurityTrustStyle("url(" + tvBanner + ")"); this.tv.background = this.sanitizer.bypassSecurityTrustStyle("url(" + tvBanner + ")");
} }
public async request() { public async request() {
this.dialog.open(EpisodeRequestComponent, { width: "800px", data: this.tv }) this.dialog.open(EpisodeRequestComponent, { width: "800px", data: this.tv, panelClass: 'modal-panel' })
} }
public openDialog() { public openDialog() {

View file

@ -52,7 +52,7 @@
<ng-container matColumnDef="actions"> <ng-container matColumnDef="actions">
<th mat-header-cell *matHeaderCellDef> </th> <th mat-header-cell *matHeaderCellDef> </th>
<td mat-cell *matCellDef="let element"> <td mat-cell *matCellDef="let element">
<button mat-raised-button color="primary" [routerLink]="'/details/movie/' + element.theMovieDbId">Details</button> <button mat-raised-button color="accent" [routerLink]="'/details/movie/' + element.theMovieDbId">Details</button>
</td> </td>
</ng-container> </ng-container>

View file

@ -2,8 +2,3 @@
margin: auto; margin: auto;
width: 95%; width: 95%;
} }
.table {
width: 100%;
height:100%;
}

View file

@ -57,7 +57,7 @@
<ng-container matColumnDef="actions"> <ng-container matColumnDef="actions">
<th mat-header-cell *matHeaderCellDef> </th> <th mat-header-cell *matHeaderCellDef> </th>
<td mat-cell *matCellDef="let element"> <td mat-cell *matCellDef="let element">
<button mat-raised-button color="primary" [routerLink]="'/details/tv/' + element.parentRequest.tvDbId">Details</button> <button mat-raised-button color="accent" [routerLink]="'/details/tv/' + element.parentRequest.tvDbId">Details</button>
</td> </td>
</ng-container> </ng-container>

View file

@ -10,7 +10,7 @@ import { IssuesReportComponent } from "./issues-report.component";
import { InputSwitchModule, SidebarModule } from "primeng/primeng"; import { InputSwitchModule, SidebarModule } from "primeng/primeng";
import { import {
MatButtonModule, MatNativeDateModule, MatIconModule, MatSidenavModule, MatListModule, MatToolbarModule, MatTooltipModule, MatSelectModule, MatTableModule, MatPaginatorModule, MatSortModule} from '@angular/material'; MatButtonModule, MatNativeDateModule, MatIconModule, MatSidenavModule, MatListModule, MatToolbarModule, MatTooltipModule, MatSelectModule, MatTableModule, MatPaginatorModule, MatSortModule, MatTreeModule} from '@angular/material';
import { MatCardModule, MatInputModule, MatTabsModule, MatAutocompleteModule, MatCheckboxModule, MatExpansionModule, MatDialogModule, MatProgressSpinnerModule, import { MatCardModule, MatInputModule, MatTabsModule, MatAutocompleteModule, MatCheckboxModule, MatExpansionModule, MatDialogModule, MatProgressSpinnerModule,
MatChipsModule } from "@angular/material"; MatChipsModule } from "@angular/material";
import { EpisodeRequestComponent } from "./episode-request/episode-request.component"; import { EpisodeRequestComponent } from "./episode-request/episode-request.component";
@ -47,6 +47,7 @@ import { EpisodeRequestComponent } from "./episode-request/episode-request.compo
MatSelectModule, MatSelectModule,
MatPaginatorModule, MatPaginatorModule,
MatSortModule, MatSortModule,
MatTreeModule,
], ],
entryComponents: [ entryComponents: [
EpisodeRequestComponent EpisodeRequestComponent
@ -62,6 +63,7 @@ import { EpisodeRequestComponent } from "./episode-request/episode-request.compo
EpisodeRequestComponent, EpisodeRequestComponent,
TruncateModule, TruncateModule,
InputSwitchModule, InputSwitchModule,
MatTreeModule,
MomentModule,MatCardModule, MomentModule,MatCardModule,
MatInputModule, MatInputModule,
MatTabsModule, MatTabsModule,

View file

@ -2,6 +2,11 @@
.top-spacing { .top-spacing {
padding-top: 10%; padding-top: 10%;
} }
.modal-panel {
max-height: 100vh !important;
max-width: 100vw !important;
height: 100%;
}
} }
@media (min-width: 979px) { @media (min-width: 979px) {
@ -10,7 +15,8 @@
} }
} }
html, body{ html,
body {
min-height: 100vh; min-height: 100vh;
overflow: auto; overflow: auto;
} }
@ -24,8 +30,8 @@ html, body{
height: 50px; height: 50px;
} }
/* Scrollbar */ /* Scrollbar */
::-webkit-scrollbar { ::-webkit-scrollbar {
width: 7px; width: 7px;
background: rgba(0, 0, 0, 0); background: rgba(0, 0, 0, 0);
@ -52,3 +58,7 @@ html, body{
transform: scale(1.1); transform: scale(1.1);
color: black; color: black;
} }
table {
width: 100%;
}