mirror of
https://github.com/Ombi-app/Ombi.git
synced 2025-07-12 16:22:55 -07:00
Made a start on the Issues page
This commit is contained in:
parent
03fc7d4c19
commit
c787e58f3b
26 changed files with 244 additions and 86 deletions
|
@ -9,6 +9,7 @@ namespace Ombi.Core.Engine.Interfaces
|
||||||
{
|
{
|
||||||
public interface IMovieEngineV2
|
public interface IMovieEngineV2
|
||||||
{
|
{
|
||||||
|
Task<MovieFullInfoViewModel> GetMovieInfoByRequestId(int requestId, CancellationToken cancellationToken, string langCode = null);
|
||||||
Task<MovieFullInfoViewModel> GetFullMovieInformation(int theMovieDbId, CancellationToken cancellationToken, string langCode = null);
|
Task<MovieFullInfoViewModel> GetFullMovieInformation(int theMovieDbId, CancellationToken cancellationToken, string langCode = null);
|
||||||
Task<IEnumerable<SearchMovieViewModel>> SimilarMovies(int theMovieDbId, string langCode);
|
Task<IEnumerable<SearchMovieViewModel>> SimilarMovies(int theMovieDbId, string langCode);
|
||||||
Task<IEnumerable<SearchMovieViewModel>> PopularMovies();
|
Task<IEnumerable<SearchMovieViewModel>> PopularMovies();
|
||||||
|
|
|
@ -7,6 +7,7 @@ namespace Ombi.Core.Engine.Interfaces
|
||||||
public interface IMusicSearchEngineV2
|
public interface IMusicSearchEngineV2
|
||||||
{
|
{
|
||||||
Task<ArtistInformation> GetArtistInformation(string artistId);
|
Task<ArtistInformation> GetArtistInformation(string artistId);
|
||||||
|
Task<ArtistInformation> GetArtistInformationByRequestId(int requestId);
|
||||||
Task<AlbumArt> GetReleaseGroupArt(string musicBrainzId, CancellationToken token);
|
Task<AlbumArt> GetReleaseGroupArt(string musicBrainzId, CancellationToken token);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -6,5 +6,6 @@ namespace Ombi.Core
|
||||||
public interface ITVSearchEngineV2
|
public interface ITVSearchEngineV2
|
||||||
{
|
{
|
||||||
Task<SearchFullInfoTvShowViewModel> GetShowInformation(int tvdbid);
|
Task<SearchFullInfoTvShowViewModel> GetShowInformation(int tvdbid);
|
||||||
|
Task<SearchFullInfoTvShowViewModel> GetShowByRequest(int requestId);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -48,6 +48,16 @@ namespace Ombi.Core.Engine.V2
|
||||||
return await ProcessSingleMovie(movieInfo);
|
return await ProcessSingleMovie(movieInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<MovieFullInfoViewModel> GetMovieInfoByRequestId(int requestId, CancellationToken cancellationToken, string langCode = null)
|
||||||
|
{
|
||||||
|
langCode = await DefaultLanguageCode(langCode);
|
||||||
|
var request = await RequestService.MovieRequestService.Find(requestId);
|
||||||
|
var movieInfo = await Cache.GetOrAdd(nameof(GetFullMovieInformation) + request.TheMovieDbId + langCode,
|
||||||
|
async () => await MovieApi.GetFullMovieInfo(request.TheMovieDbId, cancellationToken, langCode), DateTime.Now.AddHours(12), cancellationToken);
|
||||||
|
|
||||||
|
return await ProcessSingleMovie(movieInfo);
|
||||||
|
}
|
||||||
|
|
||||||
public async Task<MovieCollectionsViewModel> GetCollection(int collectionId, CancellationToken cancellationToken, string langCode = null)
|
public async Task<MovieCollectionsViewModel> GetCollection(int collectionId, CancellationToken cancellationToken, string langCode = null)
|
||||||
{
|
{
|
||||||
langCode = await DefaultLanguageCode(langCode);
|
langCode = await DefaultLanguageCode(langCode);
|
||||||
|
|
|
@ -118,6 +118,12 @@ namespace Ombi.Core.Engine.V2
|
||||||
|
|
||||||
return new AlbumArt();
|
return new AlbumArt();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<ArtistInformation> GetArtistInformationByRequestId(int requestId)
|
||||||
|
{
|
||||||
|
var request = await RequestService.MusicRequestRepository.Find(requestId);
|
||||||
|
return await GetArtistInformation(request.ForeignArtistId);
|
||||||
|
}
|
||||||
|
|
||||||
private List<BandMember> GetBandMembers(Artist artist)
|
private List<BandMember> GetBandMembers(Artist artist)
|
||||||
{
|
{
|
||||||
|
|
|
@ -21,6 +21,7 @@ using Ombi.Core.Settings;
|
||||||
using Ombi.Core.Settings.Models.External;
|
using Ombi.Core.Settings.Models.External;
|
||||||
using Ombi.Store.Repository;
|
using Ombi.Store.Repository;
|
||||||
using TraktSharp.Entities;
|
using TraktSharp.Entities;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
namespace Ombi.Core.Engine.V2
|
namespace Ombi.Core.Engine.V2
|
||||||
{
|
{
|
||||||
|
@ -48,7 +49,12 @@ namespace Ombi.Core.Engine.V2
|
||||||
private IEmbyContentRepository EmbyContentRepo { get; }
|
private IEmbyContentRepository EmbyContentRepo { get; }
|
||||||
private ITraktApi TraktApi { get; }
|
private ITraktApi TraktApi { get; }
|
||||||
|
|
||||||
|
public async Task<SearchFullInfoTvShowViewModel> GetShowByRequest(int requestId)
|
||||||
|
{
|
||||||
|
var request = await RequestService.TvRequestService.GetChild().Include(x => x.ParentRequest).FirstOrDefaultAsync(x => x.Id == requestId);
|
||||||
|
return await GetShowInformation(request.ParentRequest.TvDbId);
|
||||||
|
}
|
||||||
|
|
||||||
public async Task<SearchFullInfoTvShowViewModel> GetShowInformation(int tvdbid)
|
public async Task<SearchFullInfoTvShowViewModel> GetShowInformation(int tvdbid)
|
||||||
{
|
{
|
||||||
var tvdbshow = await Cache.GetOrAdd(nameof(GetShowInformation) + tvdbid,
|
var tvdbshow = await Cache.GetOrAdd(nameof(GetShowInformation) + tvdbid,
|
||||||
|
@ -60,11 +66,11 @@ namespace Ombi.Core.Engine.V2
|
||||||
var show = await Cache.GetOrAdd("GetTvFullInformation" + tvdbshow.id,
|
var show = await Cache.GetOrAdd("GetTvFullInformation" + tvdbshow.id,
|
||||||
async () => await TvMazeApi.GetTvFullInformation(tvdbshow.id), DateTime.Now.AddHours(12));
|
async () => await TvMazeApi.GetTvFullInformation(tvdbshow.id), DateTime.Now.AddHours(12));
|
||||||
if (show == null)
|
if (show == null)
|
||||||
{
|
{
|
||||||
// We don't have enough information
|
// We don't have enough information
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Setup the task so we can get the data later on if we have a IMDBID
|
// Setup the task so we can get the data later on if we have a IMDBID
|
||||||
Task<TraktShow> traktInfoTask = new Task<TraktShow>(() => null);
|
Task<TraktShow> traktInfoTask = new Task<TraktShow>(() => null);
|
||||||
if (show.externals?.imdb.HasValue() ?? false)
|
if (show.externals?.imdb.HasValue() ?? false)
|
||||||
|
@ -147,7 +153,7 @@ namespace Ombi.Core.Engine.V2
|
||||||
private async Task<SearchFullInfoTvShowViewModel> GetExtraInfo(Task<TraktShow> showInfoTask, SearchFullInfoTvShowViewModel model)
|
private async Task<SearchFullInfoTvShowViewModel> GetExtraInfo(Task<TraktShow> showInfoTask, SearchFullInfoTvShowViewModel model)
|
||||||
{
|
{
|
||||||
var result = await showInfoTask;
|
var result = await showInfoTask;
|
||||||
if(result == null)
|
if (result == null)
|
||||||
{
|
{
|
||||||
return model;
|
return model;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
|
<!-- <p-growl [value]="notificationService.messages" [life]="3000"></p-growl>
|
||||||
<!-- <p-growl [value]="notificationService.messages" [life]="3000"></p-growl>
|
|
||||||
<nav *ngIf="showNav" class="navbar navbar-default navbar-fixed-top">
|
<nav *ngIf="showNav" class="navbar navbar-default navbar-fixed-top">
|
||||||
<div class="container-fluid">
|
<div class="container-fluid">
|
||||||
<div class="navbar-header">
|
<div class="navbar-header">
|
||||||
|
@ -169,10 +168,10 @@
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<app-my-nav [showNav]="showNav" [isAdmin]="isAdmin" [applicationName]="applicationName" [username]="username" (logoutClick)="logOut();"
|
<app-my-nav [showNav]="showNav" [isAdmin]="isAdmin" [applicationName]="applicationName" [username]="username" (logoutClick)="logOut();" (themeChange)="onSetTheme($event)">
|
||||||
(themeChange)="onSetTheme($event)"></app-my-nav>
|
</app-my-nav>
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
|
@ -25,7 +25,6 @@ export class AppComponent implements OnInit {
|
||||||
|
|
||||||
public customizationSettings: ICustomizationSettings;
|
public customizationSettings: ICustomizationSettings;
|
||||||
public customPageSettings: ICustomPage;
|
public customPageSettings: ICustomPage;
|
||||||
public issuesEnabled = false;
|
|
||||||
public user: ILocalUser;
|
public user: ILocalUser;
|
||||||
public showNav: boolean;
|
public showNav: boolean;
|
||||||
public updateAvailable: boolean;
|
public updateAvailable: boolean;
|
||||||
|
@ -90,7 +89,6 @@ export class AppComponent implements OnInit {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
this.settingsService.issueEnabled().subscribe(x => this.issuesEnabled = x);
|
|
||||||
this.settingsService.voteEnabled().subscribe(x => this.voteEnabled = x);
|
this.settingsService.voteEnabled().subscribe(x => this.voteEnabled = x);
|
||||||
|
|
||||||
this.router.events.subscribe((event: NavigationStart) => {
|
this.router.events.subscribe((event: NavigationStart) => {
|
||||||
|
|
|
@ -32,4 +32,5 @@ export interface INavBar {
|
||||||
name: string;
|
name: string;
|
||||||
link: string;
|
link: string;
|
||||||
requiresAdmin: boolean;
|
requiresAdmin: boolean;
|
||||||
|
enabled: boolean;
|
||||||
}
|
}
|
|
@ -1,28 +1,21 @@
|
||||||
<table mat-table
|
<!-- <table mat-table [dataSource]="pendingIssues" multiTemplateDataRows class="mat-elevation-z8">
|
||||||
[dataSource]="pendingIssues" multiTemplateDataRows
|
<ng-container matColumnDef="{{column}}" *ngFor="let column of columnsToDisplay">
|
||||||
class="mat-elevation-z8">
|
<th mat-header-cell *matHeaderCellDef> {{column}} </th>
|
||||||
<ng-container matColumnDef="{{column}}" *ngFor="let column of columnsToDisplay">
|
<td mat-cell *matCellDef="let element"> {{element[column]}} </td>
|
||||||
<th mat-header-cell *matHeaderCellDef> {{column}} </th>
|
</ng-container>
|
||||||
<td mat-cell *matCellDef="let element"> {{element[column]}} </td>
|
|
||||||
</ng-container>
|
|
||||||
|
|
||||||
<!-- Expanded Content Column - The detail row is made up of this one column that spans across all columns -->
|
<ng-container matColumnDef="expandedDetail">
|
||||||
<ng-container matColumnDef="expandedDetail">
|
<td mat-cell *matCellDef="let element" [attr.colspan]="columnsToDisplay.length">
|
||||||
<td mat-cell *matCellDef="let element" [attr.colspan]="columnsToDisplay.length">
|
<div class="example-element-detail" [@detailExpand]="element == expandedElement ? 'expanded' : 'collapsed'">
|
||||||
<div class="example-element-detail"
|
<div class="example-element-diagram">
|
||||||
[@detailExpand]="element == expandedElement ? 'expanded' : 'collapsed'">
|
<div class="example-element-position"> {{element.requestId}} </div>
|
||||||
<div class="example-element-diagram">
|
</div>
|
||||||
<div class="example-element-position"> {{element.requestId}} </div>
|
</div>
|
||||||
</div>
|
</td>
|
||||||
</div>
|
</ng-container>
|
||||||
</td>
|
|
||||||
</ng-container>
|
|
||||||
|
|
||||||
<tr mat-header-row *matHeaderRowDef="columnsToDisplay"></tr>
|
<tr mat-header-row *matHeaderRowDef="columnsToDisplay"></tr>
|
||||||
<tr mat-row *matRowDef="let element; columns: columnsToDisplay;"
|
<tr mat-row *matRowDef="let element; columns: columnsToDisplay;" class="example-element-row" [class.example-expanded-row]="expandedElement === element" (click)="expandedElement = expandedElement === element ? null : element">
|
||||||
class="example-element-row"
|
</tr>
|
||||||
[class.example-expanded-row]="expandedElement === element"
|
<tr mat-row *matRowDef="let row; columns: ['expandedDetail']" class="example-detail-row"></tr>
|
||||||
(click)="expandedElement = expandedElement === element ? null : element">
|
</table> -->
|
||||||
</tr>
|
|
||||||
<tr mat-row *matRowDef="let row; columns: ['expandedDetail']" class="example-detail-row"></tr>
|
|
||||||
</table>
|
|
|
@ -6,6 +6,7 @@ import { IIssueCount, IIssues, IPagenator, IssueStatus } from "../../../interfac
|
||||||
import { COLUMNS } from "./issues-list.constants";
|
import { COLUMNS } from "./issues-list.constants";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
|
selector: "issues-list",
|
||||||
templateUrl: "issues-list.component.html",
|
templateUrl: "issues-list.component.html",
|
||||||
})
|
})
|
||||||
export class IssuesListComponent implements OnInit {
|
export class IssuesListComponent implements OnInit {
|
||||||
|
|
|
@ -1,28 +1,25 @@
|
||||||
<h1 id="issuesTitle" [translate]="'Issues.Title'"></h1>
|
<div class="small-middle-container">
|
||||||
|
<mat-tab-group>
|
||||||
<ngb-tabset *ngIf="count">
|
<mat-tab label="{{'Issues.PendingTitle' | translate}}">
|
||||||
<ngb-tab *ngIf="count.pending > 0">
|
<ng-template matTabContent>
|
||||||
<ng-template ngbTabTitle>{{'Issues.PendingTitle' | translate}} <span class="badge">{{count.pending}}</span></ng-template>
|
<div *ngIf="pendingIssues">
|
||||||
<ng-template ngbTabContent>
|
<issues-table [issues]="pendingIssues" (changePage)="changePagePending($event)" [totalRecords]="count.pending"></issues-table>
|
||||||
<div *ngIf="pendingIssues">
|
</div>
|
||||||
<issues-table [issues]="pendingIssues" (changePage)="changePagePending($event)" [totalRecords]="count.pending"></issues-table>
|
</ng-template>
|
||||||
</div>
|
</mat-tab>
|
||||||
</ng-template>
|
<mat-tab *ngIf="inProgressIssues.length > 0" label="{{'Issues.InProgressTitle' | translate}}">
|
||||||
</ngb-tab>
|
<ng-template matTabContent>
|
||||||
<ngb-tab *ngIf="count.inProgress > 0">
|
<div *ngIf="inProgressIssues">
|
||||||
<ng-template ngbTabTitle>{{'Issues.InProgressTitle' | translate}} <span class="badge">{{count.inProgress}}</span></ng-template>
|
<issues-table [issues]="inProgressIssues" (changePage)="changePageInProg($event)" [totalRecords]="count.inProgress"></issues-table>
|
||||||
<ng-template ngbTabContent>
|
</div>
|
||||||
<div *ngIf="inProgressIssues">
|
</ng-template>
|
||||||
<issues-table [issues]="inProgressIssues" (changePage)="changePageInProg($event)" [totalRecords]="count.inProgress"></issues-table>
|
</mat-tab>
|
||||||
</div>
|
<mat-tab label="{{'Issues.ResolvedTitle' | translate}}">
|
||||||
</ng-template>
|
<ng-template matTabContent>
|
||||||
</ngb-tab>
|
<div *ngIf="resolvedIssues">
|
||||||
<ngb-tab *ngIf="count.resolved > 0">
|
<issues-table [issues]="resolvedIssues" (changePage)="changePageResolved($event)" [totalRecords]="count.resolved"></issues-table>
|
||||||
<ng-template ngbTabTitle>{{'Issues.ResolvedTitle' | translate}} <span class="badge">{{count.resolved}}</span></ng-template>
|
</div>
|
||||||
<ng-template ngbTabContent>
|
</ng-template>
|
||||||
<div *ngIf="resolvedIssues">
|
</mat-tab>
|
||||||
<issues-table [issues]="resolvedIssues" (changePage)="changePageResolved($event)" [totalRecords]="count.resolved"></issues-table>
|
</mat-tab-group>
|
||||||
</div>
|
</div>
|
||||||
</ng-template>
|
|
||||||
</ngb-tab>
|
|
||||||
</ngb-tabset>
|
|
4
src/Ombi/ClientApp/src/app/issues/issues.component.scss
Normal file
4
src/Ombi/ClientApp/src/app/issues/issues.component.scss
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
.small-middle-container {
|
||||||
|
margin: auto;
|
||||||
|
width: 95%;
|
||||||
|
}
|
|
@ -6,6 +6,7 @@ import { IIssueCount, IIssues, IPagenator, IssueStatus } from "../interfaces";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
templateUrl: "issues.component.html",
|
templateUrl: "issues.component.html",
|
||||||
|
styleUrls: ['issues.component.scss']
|
||||||
})
|
})
|
||||||
export class IssuesComponent implements OnInit {
|
export class IssuesComponent implements OnInit {
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,7 @@ import { IssuesListComponent } from "./components/issues-list/issues-list.compon
|
||||||
import * as fromComponents from "./components";
|
import * as fromComponents from "./components";
|
||||||
|
|
||||||
const routes: Routes = [
|
const routes: Routes = [
|
||||||
{ path: "", component: IssuesListComponent, canActivate: [AuthGuard] },
|
{ path: "", component: IssuesComponent, canActivate: [AuthGuard] },
|
||||||
{ path: ":id", component: IssueDetailsComponent, canActivate: [AuthGuard] },
|
{ path: ":id", component: IssueDetailsComponent, canActivate: [AuthGuard] },
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,68 @@
|
||||||
<table class="table table-striped table-hover table-responsive table-condensed">
|
<table mat-table [dataSource]="issues" class="table" matSort matSortDisableClear>
|
||||||
|
|
||||||
|
|
||||||
|
<ng-container matColumnDef="title">
|
||||||
|
<th mat-header-cell *matHeaderCellDef mat-sort-header disableClear> {{ 'Issues.ColumnTitle' | translate}} </th>
|
||||||
|
<td mat-cell *matCellDef="let element"> {{element.title}} </td>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<ng-container matColumnDef="category">
|
||||||
|
<th mat-header-cell *matHeaderCellDef mat-sort-header disableClear> {{ 'Issues.Category' | translate}} </th>
|
||||||
|
<td mat-cell *matCellDef="let element"> {{element.issueCategory.value}} </td>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<ng-container matColumnDef="subject">
|
||||||
|
<th mat-header-cell *matHeaderCellDef mat-sort-header disableClear> {{ 'Issues.Subject' | translate}} </th>
|
||||||
|
<td mat-cell *matCellDef="let element"> {{element.subject}} </td>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<ng-container matColumnDef="status">
|
||||||
|
<th mat-header-cell *matHeaderCellDef mat-sort-header disableClear> {{ 'Issues.Status' | translate}} </th>
|
||||||
|
<td mat-cell *matCellDef="let element"> {{IssueStatus[element.status] | humanize}} </td>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<ng-container matColumnDef="reportedBy">
|
||||||
|
<th mat-header-cell *matHeaderCellDef mat-sort-header disableClear> {{ 'Issues.ReportedBy' | translate}} </th>
|
||||||
|
<td mat-cell *matCellDef="let element"> {{element.userReported.userAlias}} </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="status">
|
||||||
|
<th mat-header-cell *matHeaderCellDef mat-sort-header disableClear> {{ 'Requests.Status' | translate}} </th>
|
||||||
|
<td mat-cell *matCellDef="let element"> {{element.status}} </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 *ngIf="element.requestType === 1" mat-raised-button color="accent" [routerLink]="'/details/movie/request/' + element.requestId">{{ 'Issues.Details' | translate}}</button>
|
||||||
|
<button *ngIf="element.requestType === 0" mat-raised-button color="accent" [routerLink]="'/details/tv/' + element.requestId">{{ 'Issues.Details' | translate}}</button>
|
||||||
|
<button *ngIf="element.requestType === 2" mat-raised-button color="accent" [routerLink]="'/details/artist/' + element.requestId">{{ 'Issues.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>
|
||||||
|
|
||||||
|
<!-- <table class="table table-striped table-hover table-responsive table-condensed">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th (click)="setOrder('title', $event)">
|
<th (click)="setOrder('title', $event)">
|
||||||
|
@ -52,4 +116,4 @@
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
<p-paginator [rows]="rowCount" [totalRecords]="totalRecords" (onPageChange)="paginate($event)"></p-paginator>
|
<p-paginator [rows]="rowCount" [totalRecords]="totalRecords" (onPageChange)="paginate($event)"></p-paginator> -->
|
|
@ -13,6 +13,7 @@ export class IssuesTableComponent {
|
||||||
|
|
||||||
@Output() public changePage = new EventEmitter<IPagenator>();
|
@Output() public changePage = new EventEmitter<IPagenator>();
|
||||||
|
|
||||||
|
public displayedColumns = ["title", "category", "subject", "status", "reportedBy", "actions"]
|
||||||
public IssueStatus = IssueStatus;
|
public IssueStatus = IssueStatus;
|
||||||
|
|
||||||
public order: string = "id";
|
public order: string = "id";
|
||||||
|
|
|
@ -30,14 +30,36 @@ export class MovieDetailsComponent {
|
||||||
public dialog: MatDialog, private requestService: RequestService,
|
public dialog: MatDialog, private requestService: RequestService,
|
||||||
public messageService: MessageService, private auth: AuthService) {
|
public messageService: MessageService, private auth: AuthService) {
|
||||||
this.route.params.subscribe((params: any) => {
|
this.route.params.subscribe((params: any) => {
|
||||||
this.theMovidDbId = params.movieDbId;
|
|
||||||
this.load();
|
this.theMovidDbId = params.movieDbId;
|
||||||
|
if (params.requestId) {
|
||||||
|
this.load(+params.requestId);
|
||||||
|
} else {
|
||||||
|
this.load(undefined);
|
||||||
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public load() {
|
public async load(requestId: number|undefined) {
|
||||||
|
|
||||||
this.isAdmin = this.auth.hasRole("admin") || this.auth.hasRole("poweruser");
|
this.isAdmin = this.auth.hasRole("admin") || this.auth.hasRole("poweruser");
|
||||||
|
|
||||||
|
if (requestId) {
|
||||||
|
var result = await this.searchService.getFullMovieDetailsByRequestId(requestId);
|
||||||
|
this.theMovidDbId = result.id
|
||||||
|
|
||||||
|
this.movie = result;
|
||||||
|
if (this.movie.requestId > 0) {
|
||||||
|
// Load up this request
|
||||||
|
this.hasRequest = true;
|
||||||
|
this.movieRequest = await this.requestService.getMovieRequest(this.movie.requestId);
|
||||||
|
}
|
||||||
|
this.imageService.getMovieBanner(this.theMovidDbId.toString()).subscribe(x => {
|
||||||
|
this.movie.background = this.sanitizer.bypassSecurityTrustStyle
|
||||||
|
("url(" + x + ")");
|
||||||
|
});
|
||||||
|
} else {
|
||||||
this.searchService.getFullMovieDetails(this.theMovidDbId).subscribe(async x => {
|
this.searchService.getFullMovieDetails(this.theMovidDbId).subscribe(async x => {
|
||||||
this.movie = x;
|
this.movie = x;
|
||||||
if (this.movie.requestId > 0) {
|
if (this.movie.requestId > 0) {
|
||||||
|
@ -50,7 +72,7 @@ export class MovieDetailsComponent {
|
||||||
("url(" + x + ")");
|
("url(" + x + ")");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async request() {
|
public async request() {
|
||||||
|
@ -87,7 +109,7 @@ export class MovieDetailsComponent {
|
||||||
public async issue() {
|
public async issue() {
|
||||||
const dialogRef = this.dialog.open(NewIssueComponent, {
|
const dialogRef = this.dialog.open(NewIssueComponent, {
|
||||||
width: '500px',
|
width: '500px',
|
||||||
data: {requestId: this.movieRequest ? this.movieRequest.id : null, requestType: RequestType.movie, imdbid: this.movie.imdbId}
|
data: {requestId: this.movieRequest ? this.movieRequest.id : null, requestType: RequestType.movie, imdbid: this.movie.imdbId, title: this.movie.title}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,4 +10,5 @@ export interface IIssueDialogData {
|
||||||
requestType: RequestType;
|
requestType: RequestType;
|
||||||
requestId: number;
|
requestId: number;
|
||||||
imdbId: string;
|
imdbId: string;
|
||||||
|
title: string;
|
||||||
}
|
}
|
|
@ -31,7 +31,7 @@ export class NewIssueComponent implements OnInit {
|
||||||
comments: [],
|
comments: [],
|
||||||
requestId: data.requestId,
|
requestId: data.requestId,
|
||||||
requestType: data.requestType,
|
requestType: data.requestType,
|
||||||
title: "",
|
title: data.title,
|
||||||
providerId: data.imdbId,
|
providerId: data.imdbId,
|
||||||
userReported: undefined,
|
userReported: undefined,
|
||||||
};
|
};
|
||||||
|
|
|
@ -18,6 +18,7 @@ import { ArtistDetailsComponent } from "./components/artist/artist-details.compo
|
||||||
|
|
||||||
const routes: Routes = [
|
const routes: Routes = [
|
||||||
{ path: "movie/:movieDbId", component: MovieDetailsComponent, canActivate: [AuthGuard] },
|
{ path: "movie/:movieDbId", component: MovieDetailsComponent, canActivate: [AuthGuard] },
|
||||||
|
{ path: "movie/request/:requestId", component: MovieDetailsComponent, canActivate: [AuthGuard] },
|
||||||
{ path: "tv/:tvdbId/:search", component: TvDetailsComponent, canActivate: [AuthGuard] },
|
{ path: "tv/:tvdbId/:search", component: TvDetailsComponent, canActivate: [AuthGuard] },
|
||||||
{ path: "tv/:tvdbId", component: TvDetailsComponent, canActivate: [AuthGuard] },
|
{ path: "tv/:tvdbId", component: TvDetailsComponent, canActivate: [AuthGuard] },
|
||||||
{ path: "artist/:artistId", component: ArtistDetailsComponent, canActivate: [AuthGuard] },
|
{ path: "artist/:artistId", component: ArtistDetailsComponent, canActivate: [AuthGuard] },
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
<mat-toolbar>{{applicationName}}</mat-toolbar>
|
<mat-toolbar>{{applicationName}}</mat-toolbar>
|
||||||
<mat-nav-list>
|
<mat-nav-list>
|
||||||
<span *ngFor="let nav of navItems">
|
<span *ngFor="let nav of navItems">
|
||||||
<a *ngIf="nav.requiresAdmin && isAdmin || !nav.requiresAdmin" mat-list-item [routerLink]="nav.link"
|
<a *ngIf="(nav.requiresAdmin && isAdmin || !nav.requiresAdmin) && nav.enabled" mat-list-item [routerLink]="nav.link"
|
||||||
[routerLinkActive]="getTheme()">
|
[routerLinkActive]="getTheme()">
|
||||||
<mat-icon aria-label="Side nav toggle icon">{{nav.icon}}</mat-icon>
|
<mat-icon aria-label="Side nav toggle icon">{{nav.icon}}</mat-icon>
|
||||||
{{nav.name | translate}}
|
{{nav.name | translate}}
|
||||||
|
|
|
@ -4,6 +4,7 @@ import { Observable } from 'rxjs';
|
||||||
import { map } from 'rxjs/operators';
|
import { map } from 'rxjs/operators';
|
||||||
import { INavBar } from '../interfaces/ICommon';
|
import { INavBar } from '../interfaces/ICommon';
|
||||||
import { StorageService } from '../shared/storage/storage-service';
|
import { StorageService } from '../shared/storage/storage-service';
|
||||||
|
import { SettingsService } from '../services';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-my-nav',
|
selector: 'app-my-nav',
|
||||||
|
@ -24,27 +25,33 @@ export class MyNavComponent implements OnInit {
|
||||||
@Output() public logoutClick = new EventEmitter();
|
@Output() public logoutClick = new EventEmitter();
|
||||||
@Output() public themeChange = new EventEmitter<string>();
|
@Output() public themeChange = new EventEmitter<string>();
|
||||||
public theme: string;
|
public theme: string;
|
||||||
|
public issuesEnabled: boolean = false;
|
||||||
|
public navItems: INavBar[];
|
||||||
|
|
||||||
constructor(private breakpointObserver: BreakpointObserver,
|
constructor(private breakpointObserver: BreakpointObserver,
|
||||||
|
private settingsService: SettingsService,
|
||||||
private store: StorageService) {
|
private store: StorageService) {
|
||||||
}
|
}
|
||||||
|
|
||||||
public ngOnInit(): void {
|
public async ngOnInit() {
|
||||||
|
|
||||||
|
this.issuesEnabled = await this.settingsService.issueEnabled().toPromise();
|
||||||
|
console.log("issues enabled: " + this.issuesEnabled);
|
||||||
this.theme = this.store.get("theme");
|
this.theme = this.store.get("theme");
|
||||||
if(!this.theme) {
|
if(!this.theme) {
|
||||||
this.store.save("theme","dark");
|
this.store.save("theme","dark");
|
||||||
}
|
}
|
||||||
|
this.navItems = [
|
||||||
|
{ name: "NavigationBar.Discover", icon: "find_replace", link: "/discover", requiresAdmin: false, enabled: true },
|
||||||
|
{ name: "NavigationBar.Requests", icon: "list", link: "/requests-list", requiresAdmin: false, enabled: true },
|
||||||
|
{ name: "NavigationBar.Issues", icon: "notification_important", link: "/issues", requiresAdmin: false, enabled: this.issuesEnabled },
|
||||||
|
{ name: "NavigationBar.UserManagement", icon: "account_circle", link: "/usermanagement", requiresAdmin: true, enabled: true },
|
||||||
|
{ name: "NavigationBar.Calendar", icon: "calendar_today", link: "/calendar", requiresAdmin: false, enabled: true },
|
||||||
|
{ name: "NavigationBar.Settings", icon: "settings", link: "/Settings/About", requiresAdmin: true, enabled: true },
|
||||||
|
{ name: "NavigationBar.UserPreferences", icon: "person", link: "/user-preferences", requiresAdmin: false, enabled: true },
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
public navItems: INavBar[] = [
|
|
||||||
{ name: "NavigationBar.Discover", icon: "find_replace", link: "/discover", requiresAdmin: false },
|
|
||||||
{ name: "NavigationBar.Requests", icon: "list", link: "/requests-list", requiresAdmin: false },
|
|
||||||
{ name: "NavigationBar.UserManagement", icon: "account_circle", link: "/usermanagement", requiresAdmin: true },
|
|
||||||
{ name: "NavigationBar.Calendar", icon: "calendar_today", link: "/calendar", requiresAdmin: false },
|
|
||||||
{ name: "NavigationBar.Settings", icon: "settings", link: "/Settings/About", requiresAdmin: true },
|
|
||||||
{ name: "NavigationBar.UserPreferences", icon: "person", link: "/user-preferences", requiresAdmin: false },
|
|
||||||
]
|
|
||||||
|
|
||||||
public logOut() {
|
public logOut() {
|
||||||
this.logoutClick.emit();
|
this.logoutClick.emit();
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,6 +23,11 @@ export class SearchV2Service extends ServiceHelpers {
|
||||||
public getFullMovieDetails(theMovieDbId: number): Observable<ISearchMovieResultV2> {
|
public getFullMovieDetails(theMovieDbId: number): Observable<ISearchMovieResultV2> {
|
||||||
return this.http.get<ISearchMovieResultV2>(`${this.url}/Movie/${theMovieDbId}`);
|
return this.http.get<ISearchMovieResultV2>(`${this.url}/Movie/${theMovieDbId}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public getFullMovieDetailsByRequestId(requestId: number): Promise<ISearchMovieResultV2> {
|
||||||
|
return this.http.get<ISearchMovieResultV2>(`${this.url}/Movie/request/${requestId}`).toPromise();
|
||||||
|
}
|
||||||
|
|
||||||
public getFullMovieDetailsPromise(theMovieDbId: number): Promise<ISearchMovieResultV2> {
|
public getFullMovieDetailsPromise(theMovieDbId: number): Promise<ISearchMovieResultV2> {
|
||||||
return this.http.get<ISearchMovieResultV2>(`${this.url}/Movie/${theMovieDbId}`).toPromise();
|
return this.http.get<ISearchMovieResultV2>(`${this.url}/Movie/${theMovieDbId}`).toPromise();
|
||||||
}
|
}
|
||||||
|
|
|
@ -246,7 +246,7 @@ namespace Ombi.Controllers.V1
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Deletes a comment on a issue
|
/// Deletes a comment on a issue
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[HttpDelete("comments/{id:int}")]
|
[HttpDelete("comments/{id}")]
|
||||||
[PowerUser]
|
[PowerUser]
|
||||||
public async Task<bool> DeleteComment(int id)
|
public async Task<bool> DeleteComment(int id)
|
||||||
{
|
{
|
||||||
|
@ -256,6 +256,16 @@ namespace Ombi.Controllers.V1
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[HttpDelete("{id}")]
|
||||||
|
[PowerUser]
|
||||||
|
public async Task<bool> DeleteIssue(int id)
|
||||||
|
{
|
||||||
|
var issue = await _issues.GetAll().FirstOrDefaultAsync(x => x.Id == id);
|
||||||
|
|
||||||
|
await _issues.Delete(issue);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
[HttpPost("status")]
|
[HttpPost("status")]
|
||||||
public async Task<bool> UpdateStatus([FromBody] IssueStateViewModel model)
|
public async Task<bool> UpdateStatus([FromBody] IssueStateViewModel model)
|
||||||
{
|
{
|
||||||
|
|
|
@ -61,6 +61,15 @@ namespace Ombi.Controllers.V2
|
||||||
return await _movieEngineV2.GetFullMovieInformation(movieDbId, Request.HttpContext.RequestAborted);
|
return await _movieEngineV2.GetFullMovieInformation(movieDbId, Request.HttpContext.RequestAborted);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns details for a single movie
|
||||||
|
/// </summary>
|
||||||
|
[HttpGet("movie/request/{requestId}")]
|
||||||
|
public async Task<MovieFullInfoViewModel> GetMovieByRequest(int requestId)
|
||||||
|
{
|
||||||
|
return await _movieEngineV2.GetMovieInfoByRequestId(requestId, Request.HttpContext.RequestAborted);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns basic information about the provided collection
|
/// Returns basic information about the provided collection
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -83,6 +92,17 @@ namespace Ombi.Controllers.V2
|
||||||
return await _tvEngineV2.GetShowInformation(tvdbid);
|
return await _tvEngineV2.GetShowInformation(tvdbid);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns details for a single show
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>TVMaze is the TV Show Provider</remarks>
|
||||||
|
///
|
||||||
|
[HttpGet("tv/request/{requestId}")]
|
||||||
|
public async Task<SearchFullInfoTvShowViewModel> GetTvInfoByRequest(int requestId)
|
||||||
|
{
|
||||||
|
return await _tvEngineV2.GetShowByRequest(requestId);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns details for a single show
|
/// Returns details for a single show
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -357,6 +377,14 @@ namespace Ombi.Controllers.V2
|
||||||
return await _musicEngine.GetArtistInformation(artistId);
|
return await _musicEngine.GetArtistInformation(artistId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[HttpGet("artist/request/{requestId}")]
|
||||||
|
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||||
|
[ProducesDefaultResponseType]
|
||||||
|
public async Task<ArtistInformation> GetArtistInformationByRequestId(int requestId)
|
||||||
|
{
|
||||||
|
return await _musicEngine.GetArtistInformationByRequestId(requestId);
|
||||||
|
}
|
||||||
|
|
||||||
[HttpGet("releasegroupart/{musicBrainzId}")]
|
[HttpGet("releasegroupart/{musicBrainzId}")]
|
||||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||||
[ProducesDefaultResponseType]
|
[ProducesDefaultResponseType]
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue