mirror of https://github.com/Ombi-app/Ombi
Add the Issue Reporting functionality (#1811)
* Added issuesreporting and the ability to add categories to the UI * Added lazy loading!pull/1817/head
parent
438f56eceb
commit
246f1c07cf
@ -0,0 +1,63 @@
|
|||||||
|
import { IIssueCategory, IUser, RequestType } from "./";
|
||||||
|
|
||||||
|
export interface IIssues {
|
||||||
|
id?: number;
|
||||||
|
title: string;
|
||||||
|
requestType: RequestType;
|
||||||
|
providerId: string;
|
||||||
|
subject: string;
|
||||||
|
description: string;
|
||||||
|
issueCategory: IIssueCategory;
|
||||||
|
issueCategoryId: number;
|
||||||
|
status: IssueStatus;
|
||||||
|
resolvedDate?: Date;
|
||||||
|
comments: IIssueComments[];
|
||||||
|
requestId: number | undefined;
|
||||||
|
userReported: IUser | undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum IssueStatus {
|
||||||
|
Pending = 0,
|
||||||
|
InProgress = 1,
|
||||||
|
Resolved = 2,
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IIssueCount {
|
||||||
|
pending: number;
|
||||||
|
inProgress: number;
|
||||||
|
resolved: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IPagenator {
|
||||||
|
first: number;
|
||||||
|
rows: number;
|
||||||
|
page: number;
|
||||||
|
pageCount: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IIssueComments {
|
||||||
|
userId: string;
|
||||||
|
comment: string;
|
||||||
|
movieIssueId: number | undefined;
|
||||||
|
tvIssueId: number | undefined;
|
||||||
|
date: Date;
|
||||||
|
user: IUser;
|
||||||
|
issues: IIssues | undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IIssuesChat {
|
||||||
|
comment: string;
|
||||||
|
date: Date;
|
||||||
|
username: string;
|
||||||
|
adminComment: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface INewIssueComments {
|
||||||
|
comment: string;
|
||||||
|
issueId: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IUpdateStatus {
|
||||||
|
issueId: number;
|
||||||
|
status: IssueStatus;
|
||||||
|
}
|
@ -0,0 +1,76 @@
|
|||||||
|
<div *ngIf="issue">
|
||||||
|
<h1>{{issue.title}} </h1>
|
||||||
|
<div class="col-md-6">
|
||||||
|
<span class="label label-info">{{IssueStatus[issue.status]}}</span>
|
||||||
|
<span class="label label-success">{{issue.issueCategory.value}}</span>
|
||||||
|
|
||||||
|
<h3 *ngIf="issue.userReported?.alias">{{'Issues.ReportedBy' | translate}}: {{issue.userReported.alias}}</h3>
|
||||||
|
<h3 *ngIf="!issue.userReported?.alias">{{'Issues.ReportedBy' | translate}}: {{issue.userReported.userName}}</h3>
|
||||||
|
<h3 *ngIf="issue.subject">{{'Issues.Subject' | translate}}: {{issue.subject}}</h3>
|
||||||
|
<br>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="description" class="control-label" [translate]="'Issues.Description'"></label>
|
||||||
|
<div>
|
||||||
|
<textarea class="form-control-custom form-control" disabled="disabled" [(ngModel)]="issue.description" rows="5" type="text"></textarea>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="row chat-window col-xs-7 col-md-5" id="chat_window_1" style="margin-left:10px;">
|
||||||
|
<div class="col-xs-12 col-md-12">
|
||||||
|
<div class="panel panel-default">
|
||||||
|
<div class="panel-heading top-bar">
|
||||||
|
<div class="col-md-8 col-xs-8">
|
||||||
|
<h3 class="panel-title">
|
||||||
|
<span class="glyphicon glyphicon-comment"></span> {{'Issues.Comments' | translate}}</h3>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div *ngIf="comments" class="panel-body msg_container_base">
|
||||||
|
<div *ngIf="comments.length <= 0" class="row msg_container base_receive">
|
||||||
|
<div class="col-md-10 col-xs-10">
|
||||||
|
<div class="messages msg_sent">
|
||||||
|
<p [translate]="'Issues.NoComments'"></p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div *ngFor="let comment of comments" class="row msg_container" [ngClass]="{'base_sent': comment.adminComment, 'base_receive': !comment.adminComment}">
|
||||||
|
<div class="col-md-10 col-xs-10">
|
||||||
|
<div class="messages msg_sent">
|
||||||
|
<p>{{comment.comment}}</p>
|
||||||
|
<time>{{comment.username}} • {{comment.date | date:'short'}}</time>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div class="panel-footer">
|
||||||
|
<div class="input-group">
|
||||||
|
<input id="btn-input" type="text" class="form-control input-sm chat_input" [(ngModel)]="newComment.comment" [attr.placeholder]="'Issues.WriteMessagePlaceholder' | translate"
|
||||||
|
/>
|
||||||
|
<span class="input-group-btn">
|
||||||
|
<button class="btn btn-primary btn-sm" id="btn-chat" (click)="addComment()" [translate]="'Issues.SendMessageButton'"></button>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-md-12">
|
||||||
|
<div *ngIf="isAdmin && settings">
|
||||||
|
<div *ngIf="issue.status === IssueStatus.Pending && settings.enableInProgress">
|
||||||
|
<button class="btn btn-primary btn-sm" (click)="inProgress()" [translate]="'Issues.MarkInProgress'"></button>
|
||||||
|
</div>
|
||||||
|
<div *ngIf="issue.status === IssueStatus.Pending && !settings.enableInProgress || issue.status == IssueStatus.InProgress">
|
||||||
|
<button class="btn btn-primary btn-sm" (click)="resolve()" [translate]="'Issues.MarkResolved'"></button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
@ -0,0 +1,137 @@
|
|||||||
|
$color:#424242;
|
||||||
|
|
||||||
|
body{
|
||||||
|
height:400px;
|
||||||
|
position: fixed;
|
||||||
|
bottom: 0;
|
||||||
|
}
|
||||||
|
.col-md-2, .col-md-10{
|
||||||
|
padding:0;
|
||||||
|
}
|
||||||
|
.panel{
|
||||||
|
margin-bottom: 0px;
|
||||||
|
}
|
||||||
|
.chat-window{
|
||||||
|
float:right;
|
||||||
|
margin-left:10px;
|
||||||
|
}
|
||||||
|
.chat-window > div > .panel{
|
||||||
|
border-radius: 5px 5px 0 0;
|
||||||
|
}
|
||||||
|
.icon_minim{
|
||||||
|
padding:2px 10px;
|
||||||
|
}
|
||||||
|
.msg_container_base{
|
||||||
|
background: #e5e5e5;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0 10px 10px;
|
||||||
|
max-height:300px;
|
||||||
|
overflow-x:hidden;
|
||||||
|
}
|
||||||
|
.top-bar {
|
||||||
|
background: $color;
|
||||||
|
color: white;
|
||||||
|
padding: 10px;
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
.msg_receive{
|
||||||
|
padding-left:0;
|
||||||
|
margin-left:0;
|
||||||
|
}
|
||||||
|
.msg_sent{
|
||||||
|
padding-bottom:20px !important;
|
||||||
|
margin-right:0;
|
||||||
|
}
|
||||||
|
.messages {
|
||||||
|
background: white;
|
||||||
|
padding: 10px;
|
||||||
|
border-radius: 2px;
|
||||||
|
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2);
|
||||||
|
max-width:100%;
|
||||||
|
color:black;
|
||||||
|
}
|
||||||
|
.messages > p {
|
||||||
|
font-size: 13px;
|
||||||
|
margin: 0 0 0.2rem 0;
|
||||||
|
}
|
||||||
|
.messages > time {
|
||||||
|
font-size: 11px;
|
||||||
|
color: #ccc;
|
||||||
|
}
|
||||||
|
.msg_container {
|
||||||
|
padding: 10px;
|
||||||
|
overflow: hidden;
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
img {
|
||||||
|
display: block;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
.avatar {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
.base_receive > .avatar:after {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
width: 0;
|
||||||
|
height: 0;
|
||||||
|
border: 5px solid #FFF;
|
||||||
|
border-left-color: rgba(0, 0, 0, 0);
|
||||||
|
border-bottom-color: rgba(0, 0, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
.base_sent {
|
||||||
|
justify-content: flex-end;
|
||||||
|
align-items: flex-end;
|
||||||
|
}
|
||||||
|
.base_sent > .avatar:after {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 0;
|
||||||
|
height: 0;
|
||||||
|
border: 5px solid white;
|
||||||
|
border-right-color: transparent;
|
||||||
|
border-top-color: transparent;
|
||||||
|
box-shadow: 0px 1px 0px rgba(0, 0, 0, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.msg_sent > time{
|
||||||
|
float: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
.msg_container_base::-webkit-scrollbar-track
|
||||||
|
{
|
||||||
|
-webkit-box-shadow: inset 0 0 6px rgba(0,0,0,0.3);
|
||||||
|
background-color: #F5F5F5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.msg_container_base::-webkit-scrollbar
|
||||||
|
{
|
||||||
|
width: 12px;
|
||||||
|
background-color: #F5F5F5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.msg_container_base::-webkit-scrollbar-thumb
|
||||||
|
{
|
||||||
|
-webkit-box-shadow: inset 0 0 6px rgba(0,0,0,.3);
|
||||||
|
background-color: #555;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-group.dropup{
|
||||||
|
position:fixed;
|
||||||
|
left:0px;
|
||||||
|
bottom:0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.panel-footer {
|
||||||
|
padding: 10px 15px;
|
||||||
|
background-color: $color;
|
||||||
|
border-top: 1px solid transparent;
|
||||||
|
border-bottom-right-radius: -1;
|
||||||
|
border-bottom-left-radius: -1;
|
||||||
|
}
|
@ -0,0 +1,88 @@
|
|||||||
|
import { Component, OnInit } from "@angular/core";
|
||||||
|
import { ActivatedRoute } from "@angular/router";
|
||||||
|
|
||||||
|
import { AuthService } from "../auth/auth.service";
|
||||||
|
import { IssuesService, NotificationService, SettingsService } from "../services";
|
||||||
|
|
||||||
|
import { IIssues, IIssuesChat, IIssueSettings, INewIssueComments, IssueStatus } from "../interfaces";
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
templateUrl: "issueDetails.component.html",
|
||||||
|
styleUrls: ["./issueDetails.component.scss"],
|
||||||
|
})
|
||||||
|
export class IssueDetailsComponent implements OnInit {
|
||||||
|
|
||||||
|
public issue: IIssues;
|
||||||
|
public comments: IIssuesChat[];
|
||||||
|
public newComment: INewIssueComments = {
|
||||||
|
comment: "",
|
||||||
|
issueId: 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
public IssueStatus = IssueStatus;
|
||||||
|
public isAdmin: boolean;
|
||||||
|
public settings: IIssueSettings;
|
||||||
|
|
||||||
|
private issueId: number;
|
||||||
|
|
||||||
|
constructor(private issueService: IssuesService,
|
||||||
|
private route: ActivatedRoute,
|
||||||
|
private authService: AuthService,
|
||||||
|
private settingsService: SettingsService,
|
||||||
|
private notificationService: NotificationService) {
|
||||||
|
this.route.params
|
||||||
|
.subscribe((params: any) => {
|
||||||
|
this.issueId = parseInt(params.id);
|
||||||
|
});
|
||||||
|
|
||||||
|
this.isAdmin = this.authService.hasRole("Admin") || this.authService.hasRole("PowerUser");
|
||||||
|
this.settingsService.getIssueSettings().subscribe(x => this.settings = x);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ngOnInit() {
|
||||||
|
this.issueService.getIssue(this.issueId).subscribe(x => {
|
||||||
|
this.issue = {
|
||||||
|
comments: x.comments,
|
||||||
|
id: x.id,
|
||||||
|
issueCategory: x.issueCategory,
|
||||||
|
issueCategoryId: x.issueCategoryId,
|
||||||
|
subject: x.subject,
|
||||||
|
description: x.description,
|
||||||
|
status:x.status,
|
||||||
|
resolvedDate:x.resolvedDate,
|
||||||
|
title: x.title,
|
||||||
|
requestType: x.requestType,
|
||||||
|
requestId: x.requestId,
|
||||||
|
providerId: x.providerId,
|
||||||
|
userReported: x.userReported,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
this.loadComments();
|
||||||
|
}
|
||||||
|
|
||||||
|
public addComment() {
|
||||||
|
this.newComment.issueId = this.issueId;
|
||||||
|
this.issueService.addComment(this.newComment).subscribe(x => {
|
||||||
|
this.loadComments();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public inProgress() {
|
||||||
|
this.issueService.updateStatus({issueId: this.issueId, status: IssueStatus.InProgress}).subscribe(x => {
|
||||||
|
this.notificationService.success("Marked issue as In Progress");
|
||||||
|
this.issue.status = IssueStatus.InProgress;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public resolve() {
|
||||||
|
this.issueService.updateStatus({issueId: this.issueId, status: IssueStatus.Resolved}).subscribe(x => {
|
||||||
|
this.notificationService.success("Marked issue as Resolved");
|
||||||
|
this.issue.status = IssueStatus.Resolved;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private loadComments() {
|
||||||
|
this.issueService.getComments(this.issueId).subscribe(x => this.comments = x);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,28 @@
|
|||||||
|
<h1 id="issuesTitle" [translate]="'Issues.Title'"></h1>
|
||||||
|
|
||||||
|
<ngb-tabset *ngIf="count">
|
||||||
|
<ngb-tab *ngIf="count.pending > 0">
|
||||||
|
<ng-template ngbTabTitle>{{'Issues.PendingTitle' | translate}} <span class="badge">{{count.pending}}</span></ng-template>
|
||||||
|
<ng-template ngbTabContent>
|
||||||
|
<div *ngIf="pendingIssues">
|
||||||
|
<issues-table [issues]="pendingIssues" (changePage)="changePagePending($event)" [totalRecords]="count.pending"></issues-table>
|
||||||
|
</div>
|
||||||
|
</ng-template>
|
||||||
|
</ngb-tab>
|
||||||
|
<ngb-tab *ngIf="count.inProgress > 0">
|
||||||
|
<ng-template ngbTabTitle>{{'Issues.InProgressTitle' | translate}} <span class="badge">{{count.inProgress}}</span></ng-template>
|
||||||
|
<ng-template ngbTabContent>
|
||||||
|
<div *ngIf="inProgressIssues">
|
||||||
|
<issues-table [issues]="inProgressIssues" (changePage)="changePageInProg($event)" [totalRecords]="count.inProgress"></issues-table>
|
||||||
|
</div>
|
||||||
|
</ng-template>
|
||||||
|
</ngb-tab>
|
||||||
|
<ngb-tab *ngIf="count.resolved > 0">
|
||||||
|
<ng-template ngbTabTitle>{{'Issues.ResolvedTitle' | translate}} <span class="badge">{{count.resolved}}</span></ng-template>
|
||||||
|
<ng-template ngbTabContent>
|
||||||
|
<div *ngIf="resolvedIssues">
|
||||||
|
<issues-table [issues]="resolvedIssues" (changePage)="changePageResolved($event)" [totalRecords]="count.resolved"></issues-table>
|
||||||
|
</div>
|
||||||
|
</ng-template>
|
||||||
|
</ngb-tab>
|
||||||
|
</ngb-tabset>
|
@ -0,0 +1,65 @@
|
|||||||
|
import { Component, OnInit } from "@angular/core";
|
||||||
|
|
||||||
|
import { IssuesService } from "../services";
|
||||||
|
|
||||||
|
import { IIssueCount, IIssues, IPagenator, IssueStatus } from "../interfaces";
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
templateUrl: "issues.component.html",
|
||||||
|
})
|
||||||
|
export class IssuesComponent implements OnInit {
|
||||||
|
|
||||||
|
public pendingIssues: IIssues[];
|
||||||
|
public inProgressIssues: IIssues[];
|
||||||
|
public resolvedIssues: IIssues[];
|
||||||
|
|
||||||
|
public count: IIssueCount;
|
||||||
|
|
||||||
|
private takeAmount = 10;
|
||||||
|
private pendingSkip = 0;
|
||||||
|
private inProgressSkip = 0;
|
||||||
|
private resolvedSkip = 0;
|
||||||
|
|
||||||
|
constructor(private issueService: IssuesService) { }
|
||||||
|
|
||||||
|
public ngOnInit() {
|
||||||
|
this.getPending();
|
||||||
|
this.getInProg();
|
||||||
|
this.getResolved();
|
||||||
|
this.issueService.getIssuesCount().subscribe(x => this.count = x);
|
||||||
|
}
|
||||||
|
|
||||||
|
public changePagePending(event: IPagenator) {
|
||||||
|
this.pendingSkip = event.first;
|
||||||
|
this.getPending();
|
||||||
|
}
|
||||||
|
|
||||||
|
public changePageInProg(event: IPagenator) {
|
||||||
|
this.inProgressSkip = event.first;
|
||||||
|
this.getInProg();
|
||||||
|
}
|
||||||
|
|
||||||
|
public changePageResolved(event: IPagenator) {
|
||||||
|
this.resolvedSkip = event.first;
|
||||||
|
this.getResolved();
|
||||||
|
}
|
||||||
|
|
||||||
|
private getPending() {
|
||||||
|
this.issueService.getIssuesPage(this.takeAmount, this.pendingSkip, IssueStatus.Pending).subscribe(x => {
|
||||||
|
this.pendingIssues = x;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private getInProg() {
|
||||||
|
this.issueService.getIssuesPage(this.takeAmount, this.inProgressSkip, IssueStatus.InProgress).subscribe(x => {
|
||||||
|
this.inProgressIssues = x;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private getResolved() {
|
||||||
|
this.issueService.getIssuesPage(this.takeAmount, this.resolvedSkip, IssueStatus.Resolved).subscribe(x => {
|
||||||
|
this.resolvedIssues = x;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,55 @@
|
|||||||
|
<table class="table table-striped table-hover table-responsive table-condensed">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th (click)="setOrder('title')">
|
||||||
|
<a [translate]="'Issues.ColumnTitle'"></a>
|
||||||
|
<span *ngIf="order === 'title'">
|
||||||
|
<span [hidden]="reverse"><i class="fa fa-arrow-down" aria-hidden="true"></i></span><span [hidden]="!reverse"><i class="fa fa-arrow-up" aria-hidden="true"></i></span>
|
||||||
|
</span>
|
||||||
|
</th>
|
||||||
|
<th (click)="setOrder('issueCategory.value')">
|
||||||
|
<a [translate]="'Issues.Category'"></a>
|
||||||
|
<span *ngIf="order === 'issueCategory.value'">
|
||||||
|
<span [hidden]="reverse"><i class="fa fa-arrow-down" aria-hidden="true"></i></span><span [hidden]="!reverse"><i class="fa fa-arrow-up" aria-hidden="true"></i></span>
|
||||||
|
</span>
|
||||||
|
</th>
|
||||||
|
<th (click)="setOrder('issue.status')">
|
||||||
|
<a [translate]="'Issues.Status'"></a>
|
||||||
|
<span *ngIf="order === 'issue.status'">
|
||||||
|
<span [hidden]="reverse"><i class="fa fa-arrow-down" aria-hidden="true"></i></span><span [hidden]="!reverse"><i class="fa fa-arrow-up" aria-hidden="true"></i></span>
|
||||||
|
</span>
|
||||||
|
</th>
|
||||||
|
<th (click)="setOrder('issue.reportedUser')">
|
||||||
|
<a [translate]="'Issues.ReportedBy'"></a>
|
||||||
|
<span *ngIf="order === 'issue.reportedUser'">
|
||||||
|
<span [hidden]="reverse"><i class="fa fa-arrow-down" aria-hidden="true"></i></span><span [hidden]="!reverse"><i class="fa fa-arrow-up" aria-hidden="true"></i></span>
|
||||||
|
</span>
|
||||||
|
</th>
|
||||||
|
<th>
|
||||||
|
</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr *ngFor="let issue of issues | orderBy: order : reverse : 'case-insensitive'">
|
||||||
|
<td>
|
||||||
|
{{issue.title}}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{{issue.issueCategory.value}}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{{IssueStatus[issue.status] | humanize}}
|
||||||
|
</td>
|
||||||
|
<td *ngIf="issue.userReported?.alias">
|
||||||
|
{{issue.userReported.alias}}
|
||||||
|
</td>
|
||||||
|
<td *ngIf="!issue.userReported?.alias">
|
||||||
|
{{issue.userReported.userName}}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<a [routerLink]="['/issues/' + issue.id]" class="btn btn-sm btn-info-outline" [translate]="'Issues.Details'"></a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<p-paginator [rows]="rowCount" [totalRecords]="totalRecords" (onPageChange)="paginate($event)"></p-paginator>
|
@ -0,0 +1,40 @@
|
|||||||
|
import { Component, EventEmitter, Input, Output } from "@angular/core";
|
||||||
|
|
||||||
|
import { IIssues, IPagenator, IssueStatus } from "./../interfaces";
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: "issues-table",
|
||||||
|
templateUrl: "issuestable.component.html",
|
||||||
|
})
|
||||||
|
export class IssuesTableComponent {
|
||||||
|
|
||||||
|
@Input() public issues: IIssues[];
|
||||||
|
@Input() public totalRecords: number;
|
||||||
|
|
||||||
|
@Output() public changePage = new EventEmitter<IPagenator>();
|
||||||
|
|
||||||
|
public IssueStatus = IssueStatus;
|
||||||
|
|
||||||
|
public order: string = "id";
|
||||||
|
public reverse = false;
|
||||||
|
|
||||||
|
public rowCount = 10;
|
||||||
|
|
||||||
|
public setOrder(value: string) {
|
||||||
|
if (this.order === value) {
|
||||||
|
this.reverse = !this.reverse;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.order = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public paginate(event: IPagenator) {
|
||||||
|
//event.first = Index of the first record (current index)
|
||||||
|
//event.rows = Number of rows to display in new page
|
||||||
|
//event.page = Index of the new page
|
||||||
|
//event.pageCount = Total number of pages
|
||||||
|
|
||||||
|
this.changePage.emit(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,26 @@
|
|||||||
|
<p-sidebar [(visible)]="visible" position="right" styleClass="ui-sidebar-md side-back" (onHide)="hide()">
|
||||||
|
<div *ngIf="title">
|
||||||
|
|
||||||
|
<h3>Reporting an Issue for "{{title}}"</h3>
|
||||||
|
|
||||||
|
<h4 *ngIf="issueCategory">Issue type: {{issueCategory.value}}</h4>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="subject" class="control-label">Subject</label>
|
||||||
|
<div>
|
||||||
|
<input type="text" [(ngModel)]="issue.subject" class="form-control form-control-custom " id="subject" name="subject"
|
||||||
|
value="{{issue?.subject}}">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="description" class="control-label">Descriptiopn</label>
|
||||||
|
<div>
|
||||||
|
<textarea class="form-control-custom form-control" [(ngModel)]="issue.description" rows="5" type="text"></textarea>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<button type="button" [disabled]="submitted" class="btn btn-primary-outline" (click)="submit()">Submit</button>
|
||||||
|
</div>
|
||||||
|
</p-sidebar>
|
@ -0,0 +1,74 @@
|
|||||||
|
import { Component, EventEmitter, Input, Output } from "@angular/core";
|
||||||
|
|
||||||
|
import { IIssueCategory, IIssues, IssueStatus, RequestType } from "./../interfaces";
|
||||||
|
import { IssuesService, NotificationService } from "./../services";
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: "issue-report",
|
||||||
|
templateUrl: "issues-report.component.html",
|
||||||
|
|
||||||
|
})
|
||||||
|
export class IssuesReportComponent {
|
||||||
|
@Input() public visible: boolean;
|
||||||
|
@Input() public id: number; // RequestId
|
||||||
|
@Input() public title: string;
|
||||||
|
@Input() public issueCategory: IIssueCategory;
|
||||||
|
@Input() public movie: boolean;
|
||||||
|
@Input() public providerId: string;
|
||||||
|
|
||||||
|
@Output() public visibleChange = new EventEmitter<boolean>();
|
||||||
|
|
||||||
|
public submitted: boolean = false;
|
||||||
|
|
||||||
|
get getTitle(): string {
|
||||||
|
return this.title;
|
||||||
|
}
|
||||||
|
|
||||||
|
public issue: IIssues;
|
||||||
|
|
||||||
|
constructor(private issueService: IssuesService,
|
||||||
|
private notification: NotificationService) {
|
||||||
|
this.issue = {
|
||||||
|
subject: "",
|
||||||
|
description: "",
|
||||||
|
issueCategory: { value: "", id: 0 },
|
||||||
|
status: IssueStatus.Pending,
|
||||||
|
resolvedDate: undefined,
|
||||||
|
id: undefined,
|
||||||
|
issueCategoryId: 0,
|
||||||
|
comments: [],
|
||||||
|
requestId: undefined,
|
||||||
|
requestType: RequestType.movie,
|
||||||
|
title: "",
|
||||||
|
providerId: "",
|
||||||
|
userReported: undefined,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public submit() {
|
||||||
|
this.submitted = true;
|
||||||
|
const issue = this.issue;
|
||||||
|
issue.requestId = this.id;
|
||||||
|
issue.issueCategory = this.issueCategory;
|
||||||
|
issue.issueCategoryId = this.issueCategory.id;
|
||||||
|
issue.title = this.title;
|
||||||
|
issue.providerId = this.providerId;
|
||||||
|
if (this.movie) {
|
||||||
|
issue.requestType = RequestType.movie;
|
||||||
|
} else {
|
||||||
|
issue.requestType = RequestType.tvShow;
|
||||||
|
}
|
||||||
|
this.issueService.createIssue(issue).subscribe(x => {
|
||||||
|
if (x) {
|
||||||
|
this.notification.success("Issue Created");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public hide(): void {
|
||||||
|
this.submitted = false;
|
||||||
|
this.visible = !this.visible;
|
||||||
|
this.visibleChange.emit(this.visible);
|
||||||
|
}
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue