Merge pull request #4019 from Ombi-app/develop-test2

Redesign of the wizard
Movie Details improvements and some CSS fixes
pull/4029/head^2 v4.0.1067
Jamie 3 years ago committed by GitHub
commit 91b65f321f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -0,0 +1,26 @@
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.DependencyInjection;
using Ombi.Core.Settings;
using Ombi.Settings.Settings.Models;
using System.Threading.Tasks;
namespace Ombi.Attributes
{
public class WizardActionFilter : IAsyncActionFilter
{
public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
{
var settingsService = context.HttpContext.RequestServices.GetRequiredService<ISettingsService<OmbiSettings>>();
var settings = await settingsService.GetSettingsAsync();
if (!settings.Wizard)
{
await next();
return;
}
context.Result = new UnauthorizedResult();
}
}
}

@ -29,7 +29,10 @@
"src/styles/_imports.scss",
"node_modules/bootstrap/scss/bootstrap.scss",
"node_modules/primeng/resources/themes/md-dark-deeppurple/theme.css",
"node_modules/font-awesome/scss/font-awesome.scss",
"node_modules/@fortawesome/fontawesome-free/scss/fontawesome.scss",
"node_modules/@fortawesome/fontawesome-free/scss/regular.scss",
"node_modules/@fortawesome/fontawesome-free/scss/solid.scss",
"node_modules/@fortawesome/fontawesome-free/scss/brands.scss",
"node_modules/primeng/resources/primeng.min.css",
"node_modules/primeicons/primeicons.css",
"node_modules/please-wait/src/please-wait.scss",

@ -24,6 +24,7 @@
"@angularclass/hmr": "^2.1.3",
"@aspnet/signalr": "^1.1.0",
"@auth0/angular-jwt": "^2.1.0",
"@fortawesome/fontawesome-free": "^5.15.2",
"@fullcalendar/core": "^4.2.0",
"@fullcalendar/daygrid": "^4.4.0",
"@fullcalendar/interaction": "^4.2.0",
@ -39,7 +40,6 @@
"chart.js": "2.9.4",
"core-js": "^2.5.4",
"eventemitter2": "^5.0.1",
"font-awesome": "^4.7.0",
"fullcalendar": "^4.0.0-alpha.4",
"jquery": "3.3.1",
"lodash": "^4.17.20",

@ -45,7 +45,7 @@
<ul *ngIf="customizationSettings.recentlyAddedPage" class="nav navbar-nav">
<li id="RecentlyAdded" [routerLinkActive]="['active']">
<a [routerLink]="['/recentlyadded']">
<i class="fa fa-check"></i> {{ 'NavigationBar.RecentlyAdded' | translate }}</a>
<i class="fas fa-check"></i> {{ 'NavigationBar.RecentlyAdded' | translate }}</a>
</li>
</ul>
</div>

@ -5,7 +5,7 @@
<div class="form-group">
<label for="Ip" class="control-label">Page Title
<i *ngIf="form.get('title').hasError('required')" class="fa fa-exclamation-circle error-text" pTooltip="Title is required"></i>
<i *ngIf="form.get('title').hasError('required')" class="fas fa-exclamation-circle error-text" pTooltip="Title is required"></i>
</label>
<input type="text" class="form-control form-control-custom " id="Ip" name="Ip" formControlName="title" [ngClass]="{'form-error': form.get('title').hasError('required')}">
@ -14,7 +14,7 @@
<div class="form-group">
<label for="Ip" class="control-label">Font Awesome Icon
<i *ngIf="form.get('fontAwesomeIcon').hasError('required')" class="fa fa-exclamation-circle error-text" pTooltip="Font Awesome Icon is required"></i>
<i *ngIf="form.get('fontAwesomeIcon').hasError('required')" class="fas fa-exclamation-circle error-text" pTooltip="Font Awesome Icon is required"></i>
</label>
<input type="text" class="form-control form-control-custom " id="fontAwesomeIcon" name="fontAwesomeIcon" formControlName="fontAwesomeIcon" [ngClass]="{'form-error': form.get('fontAwesomeIcon').hasError('required')}">

@ -16,35 +16,35 @@
<span *ngIf="movie">
<a *ngIf="movie.plexUrl" class="media-icons" href="{{movie.plexUrl}}" target="_blank">
<i matTooltip=" {{'Search.ViewOnPlex' | translate}}"
class="fa fa-play-circle fa-2x grow"></i>
class="fas fa-play-circle fa-2x grow"></i>
</a>
<a *ngIf="movie.embyUrl" class="media-icons" href="{{movie.embyUrl}}" target="_blank">
<i matTooltip=" {{'Search.ViewOnEmby' | translate}}"
class="fa fa-play-circle fa-2x grow"></i>
class="fas fa-play-circle fa-2x grow"></i>
</a>
<a *ngIf="movie.jellyfinUrl" class="media-icons" href="{{movie.jellyfinUrl}}" target="_blank">
<i matTooltip=" {{'Search.ViewOnJellyfin' | translate}}"
class="fa fa-play-circle fa-2x grow"></i>
class="fas fa-play-circle fa-2x grow"></i>
</a>
</span>
<span *ngIf="tv">
<a *ngIf="tv.plexUrl" class="media-icons" href="{{tv.plexUrl}}" target="_blank">
<i matTooltip=" {{'Search.ViewOnPlex' | translate}}"
class="fa fa-play-circle fa-2x grow"></i>
class="fas fa-play-circle fa-2x grow"></i>
</a>
<a *ngIf="tv.embyUrl" class="media-icons" href="{{tv.embyUrl}}" target="_blank">
<i matTooltip=" {{'Search.ViewOnEmby' | translate}}"
class="fa fa-play-circle fa-2x grow"></i>
class="fas fa-play-circle fa-2x grow"></i>
</a>
<a *ngIf="tv.jellyfinUrl" class="media-icons" href="{{tv.jellyfinUrl}}" target="_blank">
<i matTooltip=" {{'Search.ViewOnJellyfin' | translate}}"
class="fa fa-play-circle fa-2x grow"></i>
class="fas fa-play-circle fa-2x grow"></i>
</a>
</span>
<a class="media-icons" (click)="close()">
<i class="fa fa-window-close fa-2x grow"></i>
<i class="fas fa-window-close fa-2x grow"></i>
</a>
</div>
@ -123,14 +123,14 @@
<span *ngIf="!movie.available">
<span *ngIf="movie.requested || movie.approved; then requestedBtn else notRequestedBtn"></span>
<ng-template #requestedBtn>
<button mat-raised-button class="btn-spacing btn-orange" [disabled]><i class="fa fa-check"></i>
<button mat-raised-button class="btn-spacing btn-orange" [disabled]><i class="fas fa-check"></i>
{{ 'Common.Requested' | translate }}</button>
</ng-template>
<ng-template #notRequestedBtn>
<button mat-raised-button class="btn-spacing" color="primary" (click)="request()">
<i *ngIf="movie.requestProcessing" class="fa fa-circle-o-notch fa-spin fa-fw"></i> <i
*ngIf="!movie.requestProcessing && !movie.processed" class="fa fa-plus"></i>
<i *ngIf="movie.processed && !movie.requestProcessing" class="fa fa-check"></i> {{
<i *ngIf="movie.requestProcessing" class="fas fa-circle-notch fa-spin fa-fw"></i> <i
*ngIf="!movie.requestProcessing && !movie.processed" class="fas fa-plus"></i>
<i *ngIf="movie.processed && !movie.requestProcessing" class="fas fa-check"></i> {{
'Common.Request' | translate }}</button>
</ng-template>
</span>
@ -140,27 +140,27 @@
<div *ngIf="!tv.fullyAvailable" class="dropdown">
<button mat-raised-button class="btn-orange btn-spacing" type="button" (click)="request()">
<i class="fa fa-plus"></i>
<i class="fas fa-plus"></i>
{{ 'Common.Request' | translate }}
<span class="caret"></span>
</button>
</div>
<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="fas fa-check"></i> {{'Common.Available' | translate }}</button>
<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="fas fa-check"></i> {{'Common.PartiallyAvailable' | translate }}</button>
<span *ngIf="tv.available">
<a *ngIf="tv.plexUrl" mat-raised-button style="text-align: right" class="btn-spacing btn-greem"
href="{{tv.plexUrl}}" target="_blank"><i class="fa fa-eye"></i> {{'Search.ViewOnPlex' |
href="{{tv.plexUrl}}" target="_blank"><i class="far fa-eye"></i> {{'Search.ViewOnPlex' |
translate}}</a>
<a *ngIf="tv.embyUrl" mat-raised-button class="btn-green btn-spacing" href="{{tv.embyUrl}}"
target="_blank"><i class="fa fa-eye"></i> {{'Search.ViewOnEmby' |
target="_blank"><i class="far fa-eye"></i> {{'Search.ViewOnEmby' |
translate}}</a>
<a *ngIf="tv.jellyfinUrl" mat-raised-button class="btn-green btn-spacing" href="{{tv.jellyfinUrl}}"
target="_blank"><i class="fa fa-eye"></i> {{'Search.ViewOnJellyfin' |
target="_blank"><i class="far fa-eye"></i> {{'Search.ViewOnJellyfin' |
translate}}</a>
</span>
<button mat-raised-button class="btn-green btn-spacing" (click)="openDetails()"> {{

@ -6,7 +6,7 @@
{{RequestType[result.type] | humanize}}
</div>
<div class="{{getStatusClass()}} top-right">
<span>{{getAvailbilityStatus()}}</span>
<span class="indicator"></span><span class="indicator-text">{{getAvailbilityStatus()}}</span>
</div>
</div>
<img [routerLink]="generateDetailsLink()" id="cardImage" src="{{result.posterPath}}" class="image"
@ -22,7 +22,7 @@
<div class="col-12">
<button mat-raised-button class="btn-green full-width poster-request-btn" (click)="request($event)">
<mat-icon *ngIf="!loading">cloud_download</mat-icon>
<i *ngIf="loading" class="fa fa-spinner fa-pulse fa-2x fa-fw" aria-hidden="true"></i>
<i *ngIf="loading" class="fas fa-spinner fa-pulse fa-2x fa-fw" aria-hidden="true"></i>
</button>
</div>
</div>

@ -159,17 +159,27 @@ small {
}
/* common */
.top-right span {
.top-right{
display:flex;
}
.top-right span.indicator, span.indicator-text {
display: none;
background-color: transparent;
color: #fff;
text-shadow: 0 1px 1px rgba(0,0,0,.2);
text-align: right;
font-size: 14px;
}
.top-right span.indicator{
padding-right: 0px;
}
.top-right span.indicator-text{
padding-right: 1em;
}
.top-right span:before{
.top-right span.indicator:before{
content: '';
width: 10px;
height: 10px;
@ -179,29 +189,29 @@ small {
margin-right:5px;
}
.top-right.available span{
.top-right.available span.indicator, span.indicator-text{
display:block;
}
.top-right.available span:before{
.top-right.available span.indicator:before{
display: inline-block;
background-color: #1DE9B6;
}
.top-right.approved span {
.top-right.approved span.indicator, span.indicator-text {
display: block;
}
.top-right.approved span:before{
.top-right.approved span.indicator:before{
display: inline-block;
background-color: #ff5722;
}
.top-right.requested span {
.top-right.requested span.indicator, span.indicator-text {
display: block;
}
.top-right.requested span:before{
.top-right.requested span.indicator:before{
display: inline-block;
background-color: #ffd740;
}
@ -212,4 +222,18 @@ small {
a.poster-overlay:hover{
text-decoration: none;
}
@media screen and (max-width: 400px){
.ellipsis{
display:none;
}
.top-right span.indicator-text{
display:none;
}
.top-right span.indicator{
padding-right:1em;
}
}

@ -9,4 +9,9 @@ h2{
margin-top:40px;
margin-left:40px;
font-size: 24px;
}
::ng-deep .p-carousel-item{
min-height:290px;
max-height:290px;
}

@ -118,14 +118,14 @@
*ngIf="movie.requested || movie.approved; then requestedBtn else notRequestedBtn"></span>
<ng-template #requestedBtn>
<button mat-raised-button class="btn-spacing btn-orange" [disabled]><i
class="fa fa-check"></i>
class="fas fa-check"></i>
{{ 'Common.Requested' | translate }}</button>
</ng-template>
<ng-template #notRequestedBtn>
<button mat-raised-button class="btn-spacing" color="primary" (click)="request()">
<i *ngIf="movie.requestProcessing" class="fa fa-circle-o-notch fa-spin fa-fw"></i>
<i *ngIf="!movie.requestProcessing && !movie.processed" class="fa fa-plus"></i>
<i *ngIf="movie.processed && !movie.requestProcessing" class="fa fa-check"></i> {{
<i *ngIf="movie.requestProcessing" class="fas fa-circle-notch fa-spin fa-fw"></i>
<i *ngIf="!movie.requestProcessing && !movie.processed" class="fas fa-plus"></i>
<i *ngIf="movie.processed && !movie.requestProcessing" class="fas fa-check"></i> {{
'Common.Request' | translate }}</button>
</ng-template>
</span>
@ -135,7 +135,7 @@
<div *ngIf="!tv.fullyAvailable" class="dropdown">
<button mat-raised-button class="btn-orange btn-spacing" type="button" (click)="request()">
<i class="fa fa-plus"></i>
<i class="fas fa-plus"></i>
{{ 'Common.Request' | translate }}
<span class="caret"></span>
</button>
@ -143,21 +143,21 @@
<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="fas fa-check"></i> {{'Common.Available' | translate }}</button>
<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="fas fa-check"></i> {{'Common.PartiallyAvailable' | translate }}</button>
<span *ngIf="tv.available">
<a *ngIf="tv.plexUrl" mat-raised-button style="text-align: right"
class="btn-spacing btn-greem" href="{{tv.plexUrl}}" target="_blank"><i
class="fa fa-eye"></i> {{'Search.ViewOnPlex' |
class="far fa-eye"></i> {{'Search.ViewOnPlex' |
translate}}</a>
<a *ngIf="tv.embyUrl" mat-raised-button class="btn-green btn-spacing" href="{{tv.embyUrl}}"
target="_blank"><i class="fa fa-eye"></i> {{'Search.ViewOnEmby' |
target="_blank"><i class="far fa-eye"></i> {{'Search.ViewOnEmby' |
translate}}</a>
<a *ngIf="tv.jellyfinUrl" mat-raised-button class="btn-green btn-spacing" href="{{tv.jellyfinUrl}}"
target="_blank"><i class="fa fa-eye"></i> {{'Search.ViewOnJellyfin' |
target="_blank"><i class="far fa-eye"></i> {{'Search.ViewOnJellyfin' |
translate}}</a>
</span>
</div>

@ -9,7 +9,7 @@
</div>
<div *ngIf="!discoverResults || discoverResults.length === 0">
<div class="row justify-content-md-center top-spacing loading-spinner">
<h1> {{'Discovery.NoSearch' | translate}} <i class="fa fa-frown-o" aria-hidden="true"></i></h1>
<h1> {{'Discovery.NoSearch' | translate}} <i class="far fa-frown" aria-hidden="true"></i></h1>
</div>
</div>
</div>

@ -14,6 +14,8 @@ export interface IPlexOAuthViewModel {
export interface IPlexOAuthAccessToken {
accessToken: string;
success: boolean;
error: string;
}
export interface IPlexUser {

@ -61,7 +61,7 @@
<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"> <i *ngIf="isAdmin" style="float:right;" class="fa fa-times" aria-hidden="true" (click)="deleteComment(comment.id)"></i>
<div class="messages msg_sent"> <i *ngIf="isAdmin" style="float:right;" class="fas fa-times" aria-hidden="true" (click)="deleteComment(comment.id)"></i>
<p>{{comment.comment}}</p>
<time>{{comment.username}} • {{comment.date | amLocal | amDateFormat: 'l LT'}}</time>
</div>

@ -13,21 +13,21 @@
</div>
<div class="col-md-4 col-md-push-3 vcenter">
<div *ngIf="landingPageSettings.noticeEnabled">
<h3><i class="fa fa-bell-o"></i>&nbsp;<b>Notice</b></h3>
<h3><i class="far fa-bell"></i>&nbsp;<b>Notice</b></h3>
<span [innerHtml]="landingPageSettings.noticeText"></span>
</div>
<br>
<div *ngIf="!mediaServerStatus">
<i class="fa fa-spinner fa-spin fa-3x fa-fw"></i>
<i class="fas fa-spinner fa-spin fa-3x fa-fw"></i>
</div>
<div *ngIf="mediaServerStatus">
<div *ngIf="mediaServerStatus.fullyAvailable">
<h3 class="online"><i class="fa fa-check-circle "></i> {{ 'LandingPage.OnlineHeading' | translate }}</h3>
<h3 class="online"><i class="fas fa-check-circle "></i> {{ 'LandingPage.OnlineHeading' | translate }}</h3>
<span [translate]="'LandingPage.OnlineParagraph'"></span>
<p [translate]="'LandingPage.CheckPageForUpdates'"></p>
</div>
<div *ngIf="mediaServerStatus.partiallyDown">
<h3 class="partial"><i class="fa fa-exclamation-triangle "></i> {{ 'LandingPage.PartiallyOnlineHeading' | translate }}</h3>
<h3 class="partial"><i class="fas fa-exclamation-triangle "></i> {{ 'LandingPage.PartiallyOnlineHeading' | translate }}</h3>
<span [translate]="'LandingPage.PartiallyOnlineParagraph'"></span>
<p *ngIf="mediaServerStatus.serversUnavailable > 1" [translate]="'LandingPage.MultipleServersUnavailable'" [translateParams]="{serversUnavailable: mediaServerStatus.serversUnavailable, totalServers: mediaServerStatus.totalServers}"></p>
<p *ngIf="mediaServerStatus.serversUnavailable == 1" [translate]="'LandingPage.SingleServerUnavailable'" [translateParams]="{serversUnavailable: mediaServerStatus.serversUnavailable, totalServers: mediaServerStatus.totalServers}">There is {{mediaServerStatus.serversUnavailable}} server offline out of {{mediaServerStatus.totalServers}}.</p>
@ -35,7 +35,7 @@
</div>
<div *ngIf="mediaServerStatus.completelyDown">
<h3 class="offline"><i class="fa fa-times "></i> {{ 'LandingPage.OfflineHeading' | translate }}</h3>
<h3 class="offline"><i class="fas fa-times "></i> {{ 'LandingPage.OfflineHeading' | translate }}</h3>
<span [translate]="'LandingPage.OfflineParagraph'"></span>
<p [translate]="'LandingPage.CheckPageForUpdates'"></p>
</div>

@ -40,7 +40,7 @@
<button id="sign-in" mat-raised-button color="primary" type="submit" (click)="loginWithOmbi = true">{{'Login.SignInWith' | translate:appNameTranslate}}</button>
<button id="sign-plex" mat-raised-button color="accent" type="button" (click)="oauth()">
<span *ngIf="!oauthLoading">{{'Login.SignInWithPlex' | translate}}</span>
<span *ngIf="oauthLoading"><i class="fa fa-circle-o-notch fa-spin fa-fw"></i></span>
<span *ngIf="oauthLoading"><i class="fas fa-circle-notch fa-spin fa-fw"></i></span>
</button>
</div>
</mat-card-content>

@ -23,12 +23,12 @@
<div class="col-12 col-lg-6 col-xl-6 media-row">
<button mat-raised-button *ngIf="selectedAlbums.length === 0" class="btn-spacing" color="primary" (click)="requestAllAlbums()">
<i class="fa fa-plus"></i> {{ 'MediaDetails.RequestAllAlbums' | translate }}</button>
<i class="fas fa-plus"></i> {{ 'MediaDetails.RequestAllAlbums' | translate }}</button>
<button mat-raised-button *ngIf="selectedAlbums.length > 0" class="btn-spacing" color="primary" (click)="requestAllAlbums()">
<i class="fa fa-plus"></i> {{ 'MediaDetails.RequestSelectedAlbums' | translate }}</button>
<i class="fas fa-plus"></i> {{ 'MediaDetails.RequestSelectedAlbums' | translate }}</button>
<button mat-raised-button *ngIf="selectedAlbums.length > 0" class="btn-spacing" color="accent" (click)="clearSelection()">
<i class="fa fa-minus"></i> {{ 'MediaDetails.ClearSelection' | translate }}</button>
<i class="fas fa-minus"></i> {{ 'MediaDetails.ClearSelection' | translate }}</button>
@ -39,39 +39,39 @@
<ng-template #requestedBtn>
<button mat-raised-button *ngIf="!hasRequest || hasRequest && movieRequest && !movieRequest.denied"
class="btn-spacing" color="warn" [disabled]><i class="fa fa-check"></i>
class="btn-spacing" color="warn" [disabled]><i class="fas fa-check"></i>
{{ 'Common.Requested' | translate }}</button>
</ng-template>
<ng-template #notRequestedBtn>
<button mat-raised-button class="btn-spacing" color="primary" (click)="request()">
<i *ngIf="movie.requestProcessing" class="fa fa-circle-o-notch fa-spin fa-fw"></i> <i
*ngIf="!movie.requestProcessing && !movie.processed" class="fa fa-plus"></i>
<i *ngIf="movie.processed && !movie.requestProcessing" class="fa fa-check"></i> {{
<i *ngIf="movie.requestProcessing" class="fas fa-circle-notch fa-spin fa-fw"></i> <i
*ngIf="!movie.requestProcessing && !movie.processed" class="fas fa-plus"></i>
<i *ngIf="movie.processed && !movie.requestProcessing" class="fas fa-check"></i> {{
'Common.Request' | translate }}</button>
</ng-template>
</span> -->
<!-- <span *ngIf="isAdmin && hasRequest">
<button (click)="approve()" mat-raised-button class="btn-spacing" color="accent">
<i class="fa fa-plus"></i> {{ 'Common.Approve' | translate }}
<i class="fas fa-plus"></i> {{ 'Common.Approve' | translate }}
</button>
<button *ngIf="!movie.available" (click)="markAvailable()" mat-raised-button class="btn-spacing"
color="accent">
<i class="fa fa-plus"></i> {{ 'Requests.MarkAvailable' | translate }}
<i class="fas fa-plus"></i> {{ 'Requests.MarkAvailable' | translate }}
</button>
<button *ngIf="movieRequest && !movieRequest.denied" mat-raised-button class="btn-spacing" color="warn"
(click)="deny()">
<i class="fa fa-times"></i> {{
<i class="fas fa-times"></i> {{
'Requests.Deny' | translate }}</button>
<button *ngIf="movieRequest && movieRequest.denied" [matTooltip]="movieRequest.deniedReason"
mat-raised-button class="btn-spacing" color="warn">
<i class="fa fa-times"></i> {{
<i class="fas fa-times"></i> {{
'MediaDetails.Denied' | translate }}</button>
</span> -->
<!-- <button *ngIf="(hasRequest && movieRequest) || movie.available" mat-raised-button class="btn-spacing"
color="danger" (click)="issue()">
<i class="fa fa-exclamation"></i> {{
<i class="fas fa-exclamation"></i> {{
'Requests.ReportIssue' | translate }}</button> -->

@ -32,68 +32,71 @@
<section id="info-wrapper">
<div class="small-middle-container">
<div class="row justify-content-center justify-content-sm-start">
<media-poster [posterPath]="'https://image.tmdb.org/t/p/w300/' + movie.posterPath"></media-poster>
<div class="row justify-content-center justify-content-sm-start header-container">
<div class="details-poster-container">
<media-poster [posterPath]="'https://image.tmdb.org/t/p/w300/' + movie.posterPath"></media-poster>
</div>
<!--Next to poster-->
<div class="col-12 col-lg-9 col-xl-9 media-row">
<span *ngIf="movie.available">
<a *ngIf="movie.plexUrl" href="{{movie.plexUrl}}" mat-raised-button target="_blank" class="btn-spacing viewon-btn plex">
{{'Search.ViewOnPlex' | translate}}
<i class="fa fa-play-circle fa-2x"></i>
</a>
<a *ngIf="movie.embyUrl" href="{{movie.embyUrl}}" mat-raised-button target="_blank" class="btn-spacing viewon-btn emby">
{{'Search.ViewOnEmby' | translate}}
<i class="fa fa-play-circle fa-2x"></i>
</a>
<a *ngIf="movie.jellyfinUrl" href="{{movie.jellyfinUrl}}" mat-raised-button target="_blank" class="btn-spacing viewon-btn jellyfinUrl">
{{'Search.ViewOnJellyfin' | translate}}
<i class="fa fa-play-circle fa-2x"></i>
</a>
</span>
<button mat-raised-button class="btn-green btn-spacing" *ngIf="movie.available && !movie.plexUrl && !movie.embyUrl && !movie.jellyfinUrl"> {{
'Common.Available' | translate }}</button>
<span *ngIf="!movie.available">
<span *ngIf="movie.requested || movie.approved; then requestedBtn else notRequestedBtn"></span>
<ng-template #requestedBtn>
<button mat-raised-button *ngIf="!hasRequest || hasRequest && movieRequest && !movieRequest.denied" class="btn-spacing" color="warn" [disabled]>
<i class="fa fa-check"></i>
{{ 'Common.Requested' | translate }}
<div class="details-button-container">
<div class="col-12 media-row">
<span *ngIf="movie.available">
<a *ngIf="movie.plexUrl" href="{{movie.plexUrl}}" mat-raised-button target="_blank" class="btn-spacing viewon-btn plex">
{{'Search.ViewOnPlex' | translate}}
<i class="far fa-play-circle fa-2x"></i>
</a>
<a *ngIf="movie.embyUrl" href="{{movie.embyUrl}}" mat-raised-button target="_blank" class="btn-spacing viewon-btn emby">
{{'Search.ViewOnEmby' | translate}}
<i class="far fa-play-circle fa-2x"></i>
</a>
<a *ngIf="movie.jellyfinUrl" href="{{movie.jellyfinUrl}}" mat-raised-button target="_blank" class="btn-spacing viewon-btn jellyfinUrl">
{{'Search.ViewOnJellyfin' | translate}}
<i class="far fa-play-circle fa-2x"></i>
</a>
</span>
<button mat-raised-button class="btn-green btn-spacing" *ngIf="movie.available && !movie.plexUrl && !movie.embyUrl && !movie.jellyfinUrl"> {{
'Common.Available' | translate }}</button>
<span *ngIf="!movie.available">
<span *ngIf="movie.requested || movie.approved; then requestedBtn else notRequestedBtn"></span>
<ng-template #requestedBtn>
<button mat-raised-button *ngIf="!hasRequest || hasRequest && movieRequest && !movieRequest.denied" class="btn-spacing" color="warn" [disabled]>
<i class="fas fa-check"></i>
{{ 'Common.Requested' | translate }}
</button>
</ng-template>
<ng-template #notRequestedBtn>
<button mat-raised-button class="btn-spacing" color="primary" (click)="request()">
<i *ngIf="movie.requestProcessing" class="fas fa-circle-notch fa-spin fa-fw"></i>
<i *ngIf="!movie.requestProcessing && !movie.processed" class="fas fa-plus"></i>
<i *ngIf="movie.processed && !movie.requestProcessing" class="fas fa-check"></i>
{{'Common.Request' | translate }}
</button>
</ng-template>
</span>
<span *ngIf="isAdmin && hasRequest">
<button *ngIf="!movie.approved" (click)="approve()" mat-raised-button class="btn-spacing" color="accent">
<i class="fas fa-plus"></i> {{ 'Common.Approve' | translate }}
</button>
</ng-template>
<ng-template #notRequestedBtn>
<button mat-raised-button class="btn-spacing" color="primary" (click)="request()">
<i *ngIf="movie.requestProcessing" class="fa fa-circle-o-notch fa-spin fa-fw"></i>
<i *ngIf="!movie.requestProcessing && !movie.processed" class="fa fa-plus"></i>
<i *ngIf="movie.processed && !movie.requestProcessing" class="fa fa-check"></i>
{{'Common.Request' | translate }}
<button *ngIf="!movie.available" (click)="markAvailable()" mat-raised-button class="btn-spacing"
color="accent">
<i class="fas fa-plus"></i> {{ 'Requests.MarkAvailable' | translate }}
</button>
</ng-template>
</span>
<span *ngIf="isAdmin && hasRequest">
<button *ngIf="!movie.approved" (click)="approve()" mat-raised-button class="btn-spacing" color="accent">
<i class="fa fa-plus"></i> {{ 'Common.Approve' | translate }}
</button>
<button *ngIf="!movie.available" (click)="markAvailable()" mat-raised-button class="btn-spacing"
color="accent">
<i class="fa fa-plus"></i> {{ 'Requests.MarkAvailable' | translate }}
</button>
<button *ngIf="movieRequest && !movieRequest.denied && !movie.available" mat-raised-button class="btn-spacing" color="warn" (click)="deny()">
<i class="fa fa-times"></i> {{'Requests.Deny' | translate }}
<button *ngIf="movieRequest && !movieRequest.denied && !movie.available" mat-raised-button class="btn-spacing" color="warn" (click)="deny()">
<i class="fas fa-times"></i> {{'Requests.Deny' | translate }}
</button>
<button *ngIf="movieRequest && movieRequest.denied" [matTooltip]="movieRequest.deniedReason" mat-raised-button class="btn-spacing" color="warn">
<i class="fas fa-times"></i> {{'MediaDetails.Denied' | translate }}
</button>
</span>
<button mat-raised-button class="btn-spacing" color="danger" (click)="issue()">
<i class="fas fa-exclamation"></i> {{'Requests.ReportIssue' | translate }}
</button>
<button *ngIf="movieRequest && movieRequest.denied" [matTooltip]="movieRequest.deniedReason" mat-raised-button class="btn-spacing" color="warn">
<i class="fa fa-times"></i> {{'MediaDetails.Denied' | translate }}
<button *ngIf="movie.belongsToCollection" [routerLink]="'/discover/collection/' + movie.belongsToCollection.id" mat-raised-button class="btn-spacing">
<i class="fas fa-list"></i> {{'MediaDetails.ViewCollection' | translate}}
</button>
</span>
<button mat-raised-button class="btn-spacing" color="danger" (click)="issue()">
<i class="fa fa-exclamation"></i> {{'Requests.ReportIssue' | translate }}
</button>
<button *ngIf="movie.belongsToCollection" [routerLink]="'/discover/collection/' + movie.belongsToCollection.id" mat-raised-button class="btn-spacing">
<i class="fa fa-list"></i> {{'MediaDetails.ViewCollection' | translate}}
</button>
</div>
</div>
</div>
@ -125,6 +128,28 @@
</div>
</div>
<!-- <div class="row card-spacer" *ngIf="movie.videos?.results?.length > 0">
<div class="col-md-6" *ngFor="let video of movie.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> -->
<div class="row" *ngIf="movie.videos?.results?.length > 0">
<div class="col-12">
<mat-card class="mat-elevation-z8">
<mat-card-header>Trailers</mat-card-header>
<mat-card-content>
<p-carousel class="no-indicator" [numVisible]="2" [numScroll]="10" [page]="0" [value]="movie.videos?.results">
<ng-template let-result pTemplate="item">
<iframe width="98%" height="315px" [src]="'https://www.youtube.com/embed/' + result.key | safe" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
</ng-template>
</p-carousel>
</mat-card-content>
</mat-card>
</div>
</div>
<div class="row">
<div class="col-12">
<div class="issuesPanel">
@ -172,20 +197,6 @@
</div>
</div>
</mat-expansion-panel>
<mat-expansion-panel>
<mat-expansion-panel-header>
<mat-panel-title>
{{'MediaDetails.VideosTitle' | translate}}
</mat-panel-title>
</mat-expansion-panel-header>
<div class="row card-spacer" *ngIf="movie.videos?.results?.length > 0">
<div class="col-md-6" *ngFor="let video of movie.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>
</div>
</div>

@ -1,32 +1,32 @@
<div class="social-icons-container-inner">
<a *ngIf="homepage" class="media-icons" href="{{homepage}}" target="_blank">
<i matTooltip="Homepage" class="fa fa-home fa-2x grow-social"></i>
<i matTooltip="Homepage" class="sfa-home fa-2x grow-social"></i>
</a>
<a *ngIf="theMoviedbId" href="https://www.themoviedb.org/movie/{{theMoviedbId}}" class="media-icons"
target="_blank">
<i matTooltip="The Movie DB" class="fa fa-film fa-2x grow-social"></i>
<i matTooltip="The Movie DB" class="fas fa-film fa-2x grow-social"></i>
</a>
<a *ngIf="tvdbId" href="https://www.thetvdb.com/?id={{tvdbId}}&tab=series" class="media-icons" target="_blank">
<i matTooltip="The TV DB" class="fa fa-tv fa-2x grow-social"></i>
<i matTooltip="The TV DB" class="fas fa-tv fa-2x grow-social"></i>
</a>
<a *ngIf="hasTrailer" class="media-icons youtube" (click)="openDialog()">
<i matTooltip="Trailer" class="fa fa-youtube-play fa-2x grow-social"></i>
<i matTooltip="Trailer" class="fab fa-youtube fa-2x grow-social"></i>
</a>
<a *ngIf="imdbId" class="media-icons imdb" [href]="doNotAppend ? imdbid : 'https://imdb.com/title/' + imdbId" target="_blank">
<i matTooltip="Imdb" class="fa fa-imdb fa-2x grow-social"></i>
<i matTooltip="Imdb" class="fab fa-imdb fa-2x grow-social"></i>
</a>
<a *ngIf="twitter" class="media-icons" [href]="doNotAppend ? twitter : 'https://twitter.com/' + twitter" target="_blank">
<i matTooltip="Twitter" class="fa fa-twitter fa-2x grow-social"></i>
<i matTooltip="Twitter" class="fab fa-twitter fa-2x grow-social"></i>
</a>
<a *ngIf="facebook" class="media-icons" [href]="doNotAppend ? facebook : 'https://facebook.com/' + facebook" target="_blank">
<i matTooltip="Facebook" class="fa fa-facebook fa-2x grow-social"></i>
<i matTooltip="Facebook" class="fab fa-facebook fa-2x grow-social"></i>
</a> <a *ngIf="instagram" class="media-icons" [href]="doNotAppend ? instagram : 'https://instagram.com/' + instagram" target="_blank">
<i matTooltip="Instagram" class="fa fa-instagram fa-2x grow-social"></i>
<i matTooltip="Instagram" class="fab fa-instagram fa-2x grow-social"></i>
</a>
<!-- Setting/Configuration admin area -->
<button *ngIf="isAdmin" mat-icon-button [matMenuTriggerFor]="menu">
<mat-icon>settings</mat-icon>
<button *ngIf="isAdmin" mat-icon-button [matMenuTriggerFor]="menu" class="admin-cog">
<i class="fas fa-cog fa-2x "></i>
</button>
<mat-menu #menu="matMenu">
<button mat-menu-item (click)="openRequestOnBehalf()" [disabled]="!canRequestOnBehalf">

@ -4,3 +4,7 @@ a.media-icons:hover{
color:$ombi-active;
}
button.admin-cog{
margin-left:40px;
color:$ombi-active;
}

@ -1,7 +1,8 @@
<section id="summary-wrapper">
<div class="full-screenshot enabled" [style.background-image]="background"></div>
<div class="shadow-base" [ngClass]="available ? 'available-bottom-border' : ''"></div>
<div class="full-screenshot enabled overlay"></div>
<!--<div class="shadow-base" [ngClass]="available ? 'available-bottom-border' : ''"></div>-->
<div class="container summary">
<div class="container title-top-banner">

@ -8,7 +8,14 @@
margin-left:0px;
}}
@media (min-width:2400px){
.title-top-banner{
padding-left:390px;
margin-left:0px;
}}
@media (max-width:571px){
.title-top-banner{
text-align:center;
top:50px;
}}

@ -4,7 +4,7 @@
<div *ngIf="tv">
<div *ngIf="tv.id === 0; else main">
<div class="small-middle-container no-info">
<h1><i class="fa fa-frown-o" aria-hidden="true"></i></h1>
<h1><i class="far fa-frown-o" aria-hidden="true"></i></h1>
<h3> {{ 'MediaDetails.NotEnoughInfo' | translate }}</h3>
</div>
</div>
@ -37,18 +37,18 @@
<div class="col-12 col-lg-5 col-xl-5 media-row">
<!-- <button *ngIf="!tv.fullyAvailable" mat-raised-button class="btn-spacing" color="primary"
(click)="request()"><i class="fa fa-plus"></i>
(click)="request()"><i class="fas fa-plus"></i>
{{ 'Common.Request' | translate }}</button> -->
<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="fas fa-check"></i> {{'Common.Available' | translate }}</button>
<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="fas fa-check"></i> {{'Common.PartiallyAvailable' | translate }}</button>
<button mat-raised-button class="btn-spacing" color="danger" (click)="issue()">
<i class="fa fa-exclamation"></i> {{
<i class="fas fa-exclamation"></i> {{
'Requests.ReportIssue' | translate }}</button>
</div>

@ -14,12 +14,6 @@
}
}
@media (max-width: 767px) {
#summary-wrapper {
height: 350px !important;
}
}
#summary-wrapper .full-screenshot,
.summary-wrapper .full-screenshot,
#watching-wrapper .full-screenshot,
@ -43,7 +37,7 @@
background-size: cover;
background-position: 50% 10%;
transition: all .5s;
height: 300px;
height: 600px;
color: #fff;
position: relative;
}
@ -85,7 +79,7 @@
#summary-wrapper .summary .container,
.summary-wrapper .summary .container {
position: absolute;
bottom: 0;
bottom: 300px;
left: 0;
right: 0;
}
@ -176,7 +170,8 @@
}
.media-row {
padding-top: 2%;
padding-top: 56px;
padding-left: 26px;
}
.cast-profile-img {
@ -235,7 +230,7 @@
text-align:right;
display:flex;
justify-content: flex-end;
padding-right:2em;
padding-right:2.5%
}
.viewon-btn {
@ -255,3 +250,27 @@
border: 1px solid #00a4dc;
color: #00a4dc;
}
::ng-deep .p-carousel-indicators {
display: none !important;
}
#info-wrapper{
margin-top:-200px;
}
.full-screenshot.enabled.overlay{
background-image: linear-gradient(to bottom, transparent, 50%, $ombi-background-primary);
}
.row.justify-content-center.justify-content-sm-start.header-container{
flex-wrap: nowrap;
}
.details-button-container{
width:100%;
}
.info-wrapper .row{
flex-wrap:wrap;
}

@ -29,7 +29,7 @@
<mat-icon *ngIf="nav.icon" aria-label="Side nav toggle icon" [style]="nav.style">{{nav.icon}}
</mat-icon>
<i *ngIf="nav.faIcon" class="fa fa-lg {{nav.faIcon}}"
<i *ngIf="nav.faIcon" class="far fa-lg {{nav.faIcon}}"
style="padding-left: 5px; padding-right: 5px;" aria-hidden="true"></i>
&nbsp;{{nav.name | translate}}
</a>

@ -87,7 +87,7 @@ export class MyNavComponent implements OnInit {
// { name: "NavigationBar.Calendar", icon: "calendar_today", link: "/calendar", requiresAdmin: false, enabled: true },
{ name: "NavigationBar.Donate", icon: "attach_money", link: "https://www.paypal.me/PlexRequestsNet", externalLink: true, requiresAdmin: true, enabled: true, toolTip: true, style: "color:red;", toolTipMessage: 'NavigationBar.DonateTooltip', faIcon: null },
{ name: "NavigationBar.Donate", icon: "attach_money", link: customizationSettings.customDonationUrl, externalLink: true, requiresAdmin: false, enabled: customizationSettings.enableCustomDonations, toolTip: true, toolTipMessage: customizationSettings.customDonationMessage, faIcon: null },
{ name: "NavigationBar.FeatureSuggestion", icon: null, link: "https://features.ombi.io/", externalLink: true, requiresAdmin: true, enabled: true, toolTip: true, toolTipMessage: 'NavigationBar.FeatureSuggestionTooltip', faIcon: "fa-lightbulb-o" },
{ name: "NavigationBar.FeatureSuggestion", icon: null, link: "https://features.ombi.io/", externalLink: true, requiresAdmin: true, enabled: true, toolTip: true, toolTipMessage: 'NavigationBar.FeatureSuggestionTooltip', faIcon: "fa-lightbulb" },
{ name: "NavigationBar.Settings", icon: "settings", link: "/Settings/About", requiresAdmin: true, enabled: true, faIcon: null },
{ name: "NavigationBar.UserPreferences", icon: "person", link: "/user-preferences", requiresAdmin: false, enabled: true, faIcon: null },
];

@ -4,13 +4,13 @@
(keyup)="search($event)">
<span class="input-group-btn">
<button id="filterBtn" class="btn btn-sm btn-info-outline" (click)="filterDisplay = !filterDisplay">
<i class="fa fa-filter"></i> {{ 'Requests.Filter' | translate }}
<i class="fas fa-filter"></i> {{ 'Requests.Filter' | translate }}
</button>
<button class="btn btn-sm btn-primary-outline dropdown-toggle" type="button" data-toggle="dropdown"
aria-haspopup="true" aria-expanded="true">
<i class="fa fa-sort"></i> {{ 'Requests.Sort' | translate }}
<i class="fas fa-sort"></i> {{ 'Requests.Sort' | translate }}
<span class="caret"></span>
</button>
<ul class="dropdown-menu" aria-labelledby="dropdownMenu2">
@ -93,7 +93,7 @@
</div>
<div *ngIf="request.denied" id="requestDenied">
{{ 'Requests.Denied' | translate }}
<i style="color:red;" class="fa fa-check" pTooltip="{{request.deniedReason}}"></i>
<i style="color:red;" class="fas fa-check" pTooltip="{{request.deniedReason}}"></i>
</div>
@ -124,11 +124,11 @@
<a *ngIf="request.showSubscribe && !request.subscribed" style="color:white" (click)="subscribe(request)"
pTooltip="Subscribe for notifications">
<i class="fa fa-rss"></i>
<i class="fas fa-rss"></i>
</a>
<a *ngIf="request.showSubscribe && request.subscribed" style="color:red" (click)="unSubscribe(request)"
pTooltip="Unsubscribe notification">
<i class="fa fa-rss"></i>
<i class="fas fa-rss"></i>
</a>
</div>
</div>
@ -137,14 +137,14 @@
<form>
<button (click)="approve(request)" style="text-align: right" class="btn btn-sm btn-success-outline approve"
type="submit">
<i class="fa fa-plus"></i> {{ 'Common.Approve' | translate }}
<i class="fas fa-plus"></i> {{ 'Common.Approve' | translate }}
</button>
</form>
<!--Radarr Root Folder-->
<div *ngIf="radarrRootFolders?.length > 1" class="btn-group btn-split" id="rootFolderBtn">
<button type="button" class="btn btn-sm btn-warning-outline">
<i class="fa fa-plus"></i> {{ 'Requests.ChangeRootFolder' | translate }}
<i class="fas fa-plus"></i> {{ 'Requests.ChangeRootFolder' | translate }}
</button>
<button type="button" class="btn btn-warning-outline dropdown-toggle" data-toggle="dropdown"
aria-haspopup="true" aria-expanded="false">
@ -161,7 +161,7 @@
<!--Radarr Quality Profiles -->
<div *ngIf="radarrProfiles?.length > 1" class="btn-group btn-split" id="changeQualityBtn">
<button type="button" class="btn btn-sm btn-warning-outline">
<i class="fa fa-plus"></i> {{ 'Requests.ChangeQualityProfile' | translate }}
<i class="fas fa-plus"></i> {{ 'Requests.ChangeQualityProfile' | translate }}
</button>
<button type="button" class="btn btn-warning-outline dropdown-toggle" data-toggle="dropdown"
aria-haspopup="true" aria-expanded="false">
@ -177,7 +177,7 @@
<div *ngIf="!request.denied" id="denyBtn">
<button type="button" (click)="deny(request)" class="btn btn-sm btn-danger-outline deny">
<i class="fa fa-times"></i> {{ 'Requests.Deny' | translate }}
<i class="fas fa-times"></i> {{ 'Requests.Deny' | translate }}
</button>
</div>
</div>
@ -186,11 +186,11 @@
<form id="markBtnGroup">
<button id="unavailableBtn" *ngIf="request.available" (click)="changeAvailability(request, false)"
style="text-align: right" value="false" class="btn btn-sm btn-info-outline change">
<i class="fa fa-minus"></i> {{ 'Requests.MarkUnavailable' | translate }}
<i class="fas fa-minus"></i> {{ 'Requests.MarkUnavailable' | translate }}
</button>
<button id="availableBtn" *ngIf="!request.available" (click)="changeAvailability(request, true)"
style="text-align: right" value="true" class="btn btn-sm btn-success-outline change">
<i class="fa fa-plus"></i> {{ 'Requests.MarkAvailable' | translate }}
<i class="fas fa-plus"></i> {{ 'Requests.MarkAvailable' | translate }}
</button>
</form>
@ -200,14 +200,14 @@
<div *ngIf="isAdmin || isRequestUser(request)">
<form>
<button id="removeBtn" (click)="removeRequest(request)" style="text-align: right" class="btn btn-sm btn-danger-outline delete">
<i class="fa fa-minus"></i> {{ 'Requests.Remove' | translate }}
<i class="fas fa-minus"></i> {{ 'Requests.Remove' | translate }}
</button>
</form>
</div>
<div class="dropdown" *ngIf="issueCategories && issuesEnabled" id="issuesBtn">
<button class="btn btn-sm btn-primary-outline dropdown-toggle" type="button" data-toggle="dropdown"
aria-haspopup="true" aria-expanded="true">
<i class="fa fa-plus"></i> {{ 'Requests.ReportIssue' | translate }}
<i class="fas fa-plus"></i> {{ 'Requests.ReportIssue' | translate }}
<span class="caret"></span>
</button>
<ul class="dropdown-menu" aria-labelledby="dropdownMenu1">
@ -284,5 +284,5 @@
</div>
<button class="btn btn-sm btn-primary-outline" (click)="clearFilter($event)">
<i class="fa fa-filter"></i> {{ 'Filter.ClearFilter' | translate }}</button>
<i class="fas fa-filter"></i> {{ 'Filter.ClearFilter' | translate }}</button>
</p-sidebar>

@ -4,13 +4,13 @@
(keyup)="search($event)">
<span class="input-group-btn">
<button id="filterBtn" class="btn btn-sm btn-info-outline" (click)="filterDisplay = !filterDisplay">
<i class="fa fa-filter"></i> {{ 'Requests.Filter' | translate }}
<i class="fas fa-filter"></i> {{ 'Requests.Filter' | translate }}
</button>
<button class="btn btn-sm btn-primary-outline dropdown-toggle" type="button" data-toggle="dropdown"
aria-haspopup="true" aria-expanded="true">
<i class="fa fa-sort"></i> {{ 'Requests.Sort' | translate }}
<i class="fas fa-sort"></i> {{ 'Requests.Sort' | translate }}
<span class="caret"></span>
</button>
<ul class="dropdown-menu" aria-labelledby="dropdownMenu2">
@ -91,7 +91,7 @@
[translate]="'Common.ProcessingRequest'"></span>
<span *ngIf="request.denied" class="label label-danger" id="requestDeclinedLabel" [translate]="'Common.RequestDenied'"></span>
<span *ngIf="request.deniedReason" title="{{request.deniedReason}}">
<i class="fa fa-info-circle"></i>
<i class="fas fa-info-circle"></i>
</span>
<span *ngIf="!request.approved && !request.availble && !request.denied" id="pendingApprovalLabel"
class="label label-warning" [translate]="'Common.PendingApproval'"></span>
@ -99,7 +99,7 @@
</div>
<div *ngIf="request.denied" id="requestDenied">
{{ 'Requests.Denied' | translate }}
<i style="color:red;" class="fa fa-check" pTooltip="{{request.deniedReason}}"></i>
<i style="color:red;" class="fas fa-check" pTooltip="{{request.deniedReason}}"></i>
</div>
@ -125,10 +125,10 @@
<div class="col-md-2 col-md-push-6">
<a *ngIf="request.showSubscribe && !request.subscribed" style="color:white" (click)="subscribe(request)" pTooltip="Subscribe for notifications">
<i class="fa fa-rss"></i>
<i class="fas fa-rss"></i>
</a>
<a *ngIf="request.showSubscribe && request.subscribed" style="color:red" (click)="unSubscribe(request)" pTooltip="Unsubscribe notification">
<i class="fa fa-rss"></i>
<i class="fas fa-rss"></i>
</a>
</div>
</div> -->
@ -137,14 +137,14 @@
<form class="col-md-6">
<button (click)="approve(request)" style="text-align: right" class="btn btn-sm btn-success-outline approve"
type="submit">
<i class="fa fa-plus"></i> {{ 'Common.Approve' | translate }}
<i class="fas fa-plus"></i> {{ 'Common.Approve' | translate }}
</button>
</form>
<!--Radarr Root Folder-->
<!-- <div *ngIf="radarrRootFolders" class="btn-group btn-split" id="rootFolderBtn">
<button type="button" class="btn btn-sm btn-warning-outline">
<i class="fa fa-plus"></i> {{ 'Requests.ChangeRootFolder' | translate }}
<i class="fas fa-plus"></i> {{ 'Requests.ChangeRootFolder' | translate }}
</button>
<button type="button" class="btn btn-warning-outline dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<span class="caret"></span>
@ -160,7 +160,7 @@
<!--Radarr Quality Profiles -->
<!-- <div *ngIf="radarrProfiles" class="btn-group btn-split" id="changeQualityBtn">
<button type="button" class="btn btn-sm btn-warning-outline">
<i class="fa fa-plus"></i> {{ 'Requests.ChangeQualityProfile' | translate }}
<i class="fas fa-plus"></i> {{ 'Requests.ChangeQualityProfile' | translate }}
</button>
<button type="button" class="btn btn-warning-outline dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<span class="caret"></span>
@ -175,7 +175,7 @@
<div *ngIf="!request.denied" id="denyBtn" class="col-md-6">
<button type="button" (click)="deny(request)" class="btn btn-sm btn-danger-outline deny">
<i class="fa fa-times"></i> {{ 'Requests.Deny' | translate }}
<i class="fas fa-times"></i> {{ 'Requests.Deny' | translate }}
</button>
</div>
</div>
@ -184,11 +184,11 @@
<form id="markBtnGroup">
<button id="unavailableBtn" *ngIf="request.available" (click)="changeAvailability(request, false)"
style="text-align: right" value="false" class="btn btn-sm btn-info-outline change">
<i class="fa fa-minus"></i> {{ 'Requests.MarkUnavailable' | translate }}
<i class="fas fa-minus"></i> {{ 'Requests.MarkUnavailable' | translate }}
</button>
<button id="availableBtn" *ngIf="!request.available" (click)="changeAvailability(request, true)"
style="text-align: right" value="true" class="btn btn-sm btn-success-outline change">
<i class="fa fa-plus"></i> {{ 'Requests.MarkAvailable' | translate }}
<i class="fas fa-plus"></i> {{ 'Requests.MarkAvailable' | translate }}
</button>
</form>
@ -198,14 +198,14 @@
<div *ngIf="isAdmin || isRequestUser(request)">
<form id="removeBtn">
<button (click)="removeRequest(request)" style="text-align: right" class="btn btn-sm btn-danger-outline delete">
<i class="fa fa-minus"></i> {{ 'Requests.Remove' | translate }}
<i class="fas fa-minus"></i> {{ 'Requests.Remove' | translate }}
</button>
</form>
</div>
<div class="dropdown" *ngIf="issueCategories && issuesEnabled" id="issuesBtn">
<button class="btn btn-sm btn-primary-outline dropdown-toggle" type="button" data-toggle="dropdown"
aria-haspopup="true" aria-expanded="true">
<i class="fa fa-plus"></i> {{ 'Requests.ReportIssue' | translate }}
<i class="fas fa-plus"></i> {{ 'Requests.ReportIssue' | translate }}
<span class="caret"></span>
</button>
<ul class="dropdown-menu" aria-labelledby="dropdownMenu1">
@ -274,7 +274,7 @@
</div>
<button class="btn btn-sm btn-primary-outline" (click)="clearFilter($event)">
<i class="fa fa-filter"></i> {{ 'Filter.ClearFilter' | translate }}</button>
<i class="fas fa-filter"></i> {{ 'Filter.ClearFilter' | translate }}</button>
</p-sidebar>

@ -3,14 +3,14 @@
<ul id="nav-tabs" class="nav nav-tabs" role="tablist">
<li role="presentation" class="active">
<a id="movieTabButton" aria-controls="home" role="tab" data-toggle="tab" (click)="selectMovieTab()" href="#movieTab"><i class="fa fa-film"></i> {{ 'Requests.MoviesTab' | translate }}</a>
<a id="movieTabButton" aria-controls="home" role="tab" data-toggle="tab" (click)="selectMovieTab()" href="#movieTab"><i class="fas fa-film"></i> {{ 'Requests.MoviesTab' | translate }}</a>
</li>
<li role="presentation">
<a id="tvTabButton" aria-controls="profile" role="tab" data-toggle="tab" (click)="selectTvTab()" href="#tvTab"><i class="fa fa-television"></i> {{ 'Requests.TvTab' | translate }}</a>
<a id="tvTabButton" aria-controls="profile" role="tab" data-toggle="tab" (click)="selectTvTab()" href="#tvTab"><i class="fas fa-tv"></i> {{ 'Requests.TvTab' | translate }}</a>
</li>
<li role="presentation" *ngIf="musicEnabled">
<a id="albumTabButton" aria-controls="profile" role="tab" data-toggle="tab" (click)="selectMusicTab()" href="#albumTab"><i class="fa fa-music"></i> {{ 'Requests.MusicTab' | translate }}</a>
<a id="albumTabButton" aria-controls="profile" role="tab" data-toggle="tab" (click)="selectMusicTab()" href="#albumTab"><i class="fas fa-music"></i> {{ 'Requests.MusicTab' | translate }}</a>
</li>
</ul>

@ -16,29 +16,29 @@
<div class="col-md-1 col-md-push-9">
<button id="subscribeBtn" *ngIf="child.showSubscribe && !child.subscribed" (click)="subscribe(child)"
class="btn btn-sm btn-primary-outline" pTooltip="Subscribe for notifications" type="submit"><i
class="fa fa-rss"></i> Subscribe</button>
class="fas fa-rss"></i> Subscribe</button>
<button id="subscribeBtn" *ngIf="child.showSubscribe && child.subscribed" (click)="unSubscribe(child)"
class="btn btn-sm btn-danger-outline" pTooltip="UnSubscribe for notifications" type="submit"><i
class="fa fa-rss"></i> UnSubscribe</button>
class="fas fa-rss"></i> UnSubscribe</button>
<div *ngIf="isAdmin">
<button id="approveBtn" *ngIf="child.canApprove && !child.approved" (click)="approve(child)" class="btn btn-sm btn-success-outline"
type="submit"><i class="fa fa-plus"></i> {{ 'Common.Approve' | translate }}</button>
type="submit"><i class="fas fa-plus"></i> {{ 'Common.Approve' | translate }}</button>
<button id="unavailableBtn" *ngIf="child.available" (click)="changeAvailability(child, false)"
style="text-align: right" value="false" class="btn btn-sm btn-info-outline change"><i class="fa fa-minus"></i>
style="text-align: right" value="false" class="btn btn-sm btn-info-outline change"><i class="fas fa-minus"></i>
{{ 'Requests.MarkUnavailable' | translate }}</button>
<button id="availableBtn" *ngIf="!child.available" (click)="changeAvailability(child, true)" style="text-align: right"
value="true" class="btn btn-sm btn-success-outline change"><i class="fa fa-plus"></i> {{
value="true" class="btn btn-sm btn-success-outline change"><i class="fas fa-plus"></i> {{
'Requests.MarkAvailable' | translate }}</button>
<button id="denyBtn" *ngIf="!child.denied" type="button" (click)="deny(child)" class="btn btn-sm btn-danger-outline deny">
<i class="fa fa-times"></i> {{ 'Requests.Deny' | translate }}</button>
<i class="fas fa-times"></i> {{ 'Requests.Deny' | translate }}</button>
</div>
<div *ngIf="isAdmin || isRequestUser(child)">
<button id="removeBtn" type="button" (click)="removeRequest(child)" class="btn btn-sm btn-danger-outline deny"><i
class="fa fa-times"></i> {{ 'Requests.Remove' | translate }}</button>
class="fas fa-times"></i> {{ 'Requests.Remove' | translate }}</button>
</div>
@ -91,7 +91,7 @@
<td>
<span *ngIf="child.denied" class="label label-danger" id="deniedLabel"
[translate]="'Common.Denied'">
<i style="color:red;" class="fa fa-check" pTooltip="{{child.deniedReason}}"></i>
<i style="color:red;" class="fas fa-check" pTooltip="{{child.deniedReason}}"></i>
</span>
<span *ngIf="!child.denied && ep.available" class="label label-success" id="availableLabel"
[translate]="'Common.Available'"></span>

@ -47,12 +47,12 @@
<div class="col-sm-3 col-sm-push-3 small-padding">
<button style="text-align: right" class="btn btn-sm btn-success-outline" (click)="openClosestTab(node,$event)">
<i class="fa fa-plus"></i> View</button>
<i class="fas fa-plus"></i> View</button>
<div *ngIf="isAdmin">
<!--Sonarr Root Folder-->
<div *ngIf="sonarrRootFolders?.length > 1" class="btn-group btn-split" id="rootFolderBtn">
<button type="button" class="btn btn-sm btn-warning-outline">
<i class="fa fa-plus"></i> {{ 'Requests.ChangeRootFolder' | translate }}
<i class="fas fa-plus"></i> {{ 'Requests.ChangeRootFolder' | translate }}
</button>
<button type="button" class="btn btn-warning-outline dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<span class="caret"></span>
@ -68,7 +68,7 @@
<!--Sonarr Quality Profiles -->
<div *ngIf="sonarrProfiles?.length > 1" class="btn-group btn-split" id="changeQualityBtn">
<button type="button" class="btn btn-sm btn-warning-outline">
<i class="fa fa-plus"></i> {{ 'Requests.ChangeQualityProfile' | translate }}
<i class="fas fa-plus"></i> {{ 'Requests.ChangeQualityProfile' | translate }}
</button>
<button type="button" class="btn btn-warning-outline dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<span class="caret"></span>
@ -84,7 +84,7 @@
</div>
<div class="dropdown" *ngIf="issueCategories && issuesEnabled" id="issueBtn">
<button class="btn btn-sm btn-primary-outline dropdown-toggle" type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true">
<i class="fa fa-plus"></i> {{ 'Requests.ReportIssue' | translate }}
<i class="fas fa-plus"></i> {{ 'Requests.ReportIssue' | translate }}
<span class="caret"></span>
</button>
<ul class="dropdown-menu" aria-labelledby="dropdownMenu1">

@ -5,7 +5,7 @@
<div class="btn-group" role="group">
<a href="#" class="btn btn-sm btn-primary-outline dropdown-toggle" data-toggle="dropdown" aria-expanded="false">
{{ 'Search.Suggestions' | translate }}
<i class="fa fa-chevron-down"></i>
<i class="fa-list fa-chevron-down"></i>
</a>
<ul class="dropdown-menu">
<li><a (click)="popularMovies()" [translate]="'Search.Movies.PopularMovies'"></a></li>
@ -15,7 +15,7 @@
</ul>
<button class="btn btn-sm btn-primary-outline" (click)="refineOpen()">
{{ 'Search.Refine' | translate }}
<i class="fa" [ngClass]="{'fa-chevron-down': !refineSearchEnabled, 'fa-chevron-up': refineSearchEnabled}"></i>
<i class="fas" [ngClass]="{'fa-chevron-down': !refineSearchEnabled, 'fa-chevron-up': refineSearchEnabled}"></i>
</button>
</div>
</ng-template>
@ -28,7 +28,7 @@
<div class="search-button-container-inline">
<ng-template [ngTemplateOutlet]="FilterRef"></ng-template>
</div>
<i class="fa fa-search"></i>
<i class="fas fa-search"></i>
</div>
</div>
@ -77,7 +77,7 @@
<!-- Movie content -->
<div id="movieList">
<div *ngIf="searchApplied && movieResults?.length <= 0" class='no-search-results'>
<i class='fa fa-film no-search-results-icon'></i>
<i class='fas fa-film no-search-results-icon'></i>
<div class='no-search-results-text' [translate]="'Search.NoResults'"></div>
</div>
@ -132,50 +132,50 @@
<div class="col-sm-2 small-padding">
<div *ngIf="result.available">
<button style="text-align: right" class="btn btn-success-outline disabled" disabled><i class="fa fa-check"></i>
<button style="text-align: right" class="btn btn-success-outline disabled" disabled><i class="fas fa-check"></i>
{{ 'Common.Available' | translate }}</button>
</div>
<div *ngIf="!result.available">
<div *ngIf="result.requested || result.approved; then requestedBtn else notRequestedBtn"></div>
<ng-template #requestedBtn>
<button style="text-align: right" class="btn btn-primary-outline disabled" [disabled]><i
class="fa fa-check"></i> {{ 'Common.Requested' | translate }}</button>
class="fas fa-check"></i> {{ 'Common.Requested' | translate }}</button>
</ng-template>
<ng-template #notRequestedBtn>
<button id="{{result.id}}" style="text-align: right" class="btn btn-primary-outline"
(click)="request(result)">
<i *ngIf="result.requestProcessing" class="fa fa-circle-o-notch fa-spin fa-fw"></i> <i
*ngIf="!result.requestProcessing && !result.processed" class="fa fa-plus"></i>
<i *ngIf="result.processed && !result.requestProcessing" class="fa fa-check"></i> {{
<i *ngIf="result.requestProcessing" class="fas fa-circle-notch fa-spin fa-fw"></i> <i
*ngIf="!result.requestProcessing && !result.processed" class="fas fa-plus"></i>
<i *ngIf="result.processed && !result.requestProcessing" class="fas fa-check"></i> {{
'Common.Request' | translate }}</button>
</ng-template>
</div>
<div *ngIf="result.requested">
<a *ngIf="result.showSubscribe && !result.subscribed" style="text-align: right" class="btn btn btn-success-outline"
(click)="subscribe(result)" pTooltip="Subscribe for notifications when this movie becomes available">
<i class="fa fa-rss"></i> Subscribe</a>
<i class="fas fa-rss"></i> Subscribe</a>
<a *ngIf="result.showSubscribe && result.subscribed" style="text-align: right;" class="btn btn btn-warning-outline"
(click)="unSubscribe(result)" pTooltip="Unsubscribe notifications when this movie becomes available">
<i class="fa fa-rss"></i> Unsubscribe</a>
<i class="fas fa-rss"></i> Unsubscribe</a>
</div>
<button style="text-align: right" class="btn btn-sm btn-info-outline" (click)="similarMovies(result.id)">
<i class="fa fa-eye"></i> {{ 'Search.Similar' | translate }}</button>
<i class="far fa-eye"></i> {{ 'Search.Similar' | translate }}</button>
<br />
<div *ngIf="result.available">
<a *ngIf="result.plexUrl" style="text-align: right" class="btn btn-sm btn-success-outline" href="{{result.plexUrl}}"
target="_blank"><i class="fa fa-eye"></i> {{'Search.ViewOnPlex' | translate}}</a>
target="_blank"><i class="far fa-eye"></i> {{'Search.ViewOnPlex' | translate}}</a>
<a *ngIf="result.embyUrl" style="text-align: right" id="embybtn" class="btn btn-sm btn-success-outline"
href="{{result.embyUrl}}" target="_blank"><i class="fa fa-eye"></i> {{'Search.ViewOnEmby' |
href="{{result.embyUrl}}" target="_blank"><i class="far fa-eye"></i> {{'Search.ViewOnEmby' |
translate}}</a>
<a *ngIf="result.jellyfinUrl" style="text-align: right" id="jellyfinbtn" class="btn btn-sm btn-success-outline"
href="{{result.jellyfinUrl}}" target="_blank"><i class="fa fa-eye"></i> {{'Search.ViewOnJellyfin' |
href="{{result.jellyfinUrl}}" target="_blank"><i class="far fa-eye"></i> {{'Search.ViewOnJellyfin' |
translate}}</a>
</div>
<div class="dropdown" *ngIf="result.available && issueCategories && issuesEnabled">
<button class="btn btn-sm btn-primary-outline dropdown-toggle" type="button" data-toggle="dropdown"
aria-haspopup="true" aria-expanded="true">
<i class="fa fa-plus"></i> {{'Requests.ReportIssue' | translate}}
<i class="fas fa-plus"></i> {{'Requests.ReportIssue' | translate}}
<span class="caret"></span>
</button>
<ul class="dropdown-menu" aria-labelledby="dropdownMenu1">

@ -6,7 +6,7 @@
<div class="btn-group">
<a href="#" class="btn btn-sm btn-primary-outline dropdown-toggle" data-toggle="dropdown" aria-expanded="false">
Suggestions
<i class="fa fa-chevron-down"></i>
<i class="fas fa-chevron-down"></i>
</a>
<ul class="dropdown-menu">
<li>
@ -23,7 +23,7 @@
</li>
</ul>
</div>
<i id="movieSearchButton" class="fa fa-search"></i>
<i id="movieSearchButton" class="fas fa-search"></i>
</div>
</div>
<br />
@ -31,7 +31,7 @@
<!-- Movie content -->
<div id="movieList">
<div *ngIf="searchApplied && movieResults?.length <= 0" class='no-search-results'>
<i class='fa fa-film no-search-results-icon'></i>
<i class='fas fa-film no-search-results-icon'></i>
<div class='no-search-results-text'>Sorry, we didn't find any results!</div>
</div>
@ -108,13 +108,13 @@
<div *ngIf="result.available">
<button style="text-align: right" class="btn btn-success-outline disabled" disabled>
<i class="fa fa-check"></i> Available</button>
<i class="fas fa-check"></i> Available</button>
<div *ngIf="result.plexUrl">
<br/>
<br/>
<a style="text-align: right" class="btn btn-sm btn-primary-outline" href="{{result.plexUrl}}" target="_blank">
<i class="fa fa-eye"></i> View In Plex</a>
<i class="far fa-eye"></i> View In Plex</a>
</div>
</div>
@ -122,20 +122,20 @@
<div *ngIf="result.requested || result.approved; then requestedBtn else notRequestedBtn"></div>
<ng-template #requestedBtn>
<button style="text-align: right" class="btn btn-primary-outline disabled" [disabled]>
<i class="fa fa-check"></i> Requested</button>
<i class="fas fa-check"></i> Requested</button>
</ng-template>
<ng-template #notRequestedBtn>
<button id="{{result.id}}" style="text-align: right" class="btn btn-primary-outline" (click)="request(result)">
<i *ngIf="result.requestProcessing" class="fa fa-circle-o-notch fa-spin fa-fw"></i>
<i *ngIf="!result.requestProcessing && !result.processed" class="fa fa-plus"></i>
<i *ngIf="result.processed && !result.requestProcessing" class="fa fa-check"></i>Request</button>
<i *ngIf="result.requestProcessing" class="fas fa-circle-notch fa-spin fa-fw"></i>
<i *ngIf="!result.requestProcessing && !result.processed" class="fas fa-plus"></i>
<i *ngIf="result.processed && !result.requestProcessing" class="fas fa-check"></i>Request</button>
</ng-template>
</div>
<br/>
<div *ngIf="result.available">
<a *ngIf="result.plexUrl" style="text-align: right" class="btn btn-sm btn-success-outline" href="{{result.plexUrl}}" target="_blank">
<i class="fa fa-eye"></i> View On Plex</a>
<i class="far fa-eye"></i> View On Plex</a>
</div>

@ -71,25 +71,25 @@
<!-- <div class="row" *ngIf="result.requested">
<div class="col-md-2 col-md-push-10">
<a *ngIf="result.showSubscribe && !result.subscribed" style="color:white" (click)="subscribe(result)" pTooltip="Subscribe for notifications"> <i class="fa fa-rss"></i></a>
<a *ngIf="result.showSubscribe && result.subscribed" style="color:red" (click)="unSubscribe(result)" pTooltip="Unsubscribe notification"> <i class="fa fa-rss"></i></a>
<a *ngIf="result.showSubscribe && !result.subscribed" style="color:white" (click)="subscribe(result)" pTooltip="Subscribe for notifications"> <i class="fas fa-rss"></i></a>
<a *ngIf="result.showSubscribe && result.subscribed" style="color:red" (click)="unSubscribe(result)" pTooltip="Unsubscribe notification"> <i class="fas fa-rss"></i></a>
</div>
</div> -->
<div *ngIf="result.fullyAvailable">
<button style="text-align: right" class="btn btn-success-outline disabled" disabled>
<i class="fa fa-check"></i> {{ 'Common.Available' | translate }}</button>
<i class="fas fa-check"></i> {{ 'Common.Available' | translate }}</button>
</div>
<div *ngIf="!result.fullyAvailable">
<div *ngIf="result.requested || result.approved || result.monitored; then requestedBtn else notRequestedBtn"></div>
<ng-template #requestedBtn>
<button style="text-align: right" class="btn btn-primary-outline disabled" [disabled]>
<i class="fa fa-check"></i> {{ 'Common.Requested' | translate }}</button>
<i class="fas fa-check"></i> {{ 'Common.Requested' | translate }}</button>
</ng-template>
<ng-template #notRequestedBtn>
<button style="text-align: right" class="btn btn-primary-outline" (click)="request(result)">
<i *ngIf="result.requestProcessing" class="fa fa-circle-o-notch fa-spin fa-fw"></i>
<i *ngIf="!result.requestProcessing && !result.processed" class="fa fa-plus"></i>
<i *ngIf="result.processed && !result.requestProcessing" class="fa fa-check"></i> {{ 'Common.Request'
<i *ngIf="result.requestProcessing" class="fas fa-circle-notch fa-spin fa-fw"></i>
<i *ngIf="!result.requestProcessing && !result.processed" class="fas fa-plus"></i>
<i *ngIf="result.processed && !result.requestProcessing" class="fas fa-check"></i> {{ 'Common.Request'
| translate }}</button>
</ng-template>
</div>
@ -98,7 +98,7 @@
<div class="dropdown" *ngIf="(result.partiallyAvailable || result.fullyAvailable) && issueCategories && issuesEnabled">
<button class="btn btn-sm btn-primary-outline dropdown-toggle" type="button" data-toggle="dropdown" aria-haspopup="true"
aria-expanded="true">
<i class="fa fa-plus"></i> Report Issue
<i class="fas fa-plus"></i> Report Issue
<span class="caret"></span>
</button>
<ul class="dropdown-menu" aria-labelledby="dropdownMenu1">

@ -47,15 +47,15 @@
<div class="row" *ngIf="result.requested">
<div class="col-md-2 col-md-push-10">
<!-- <a *ngIf="result.showSubscribe && !result.subscribed" style="color:white" (click)="subscribe(result)" pTooltip="Subscribe for notifications"> <i class="fa fa-rss"></i></a>
<a *ngIf="result.showSubscribe && result.subscribed" style="color:red" (click)="unSubscribe(result)" pTooltip="Unsubscribe notification"> <i class="fa fa-rss"></i></a> -->
<!-- <a *ngIf="result.showSubscribe && !result.subscribed" style="color:white" (click)="subscribe(result)" pTooltip="Subscribe for notifications"> <i class="fas fa-rss"></i></a>
<a *ngIf="result.showSubscribe && result.subscribed" style="color:red" (click)="unSubscribe(result)" pTooltip="Unsubscribe notification"> <i class="fas fa-rss"></i></a> -->
</div>
</div>
<button style="text-align: right" class="btn btn-info-outline" [disabled]="searchingAlbums" (click)="viewAllAlbums()">
<i class="fa fa-eye"></i> View Albums</button>
<i class="far fa-eye"></i> View Albums</button>
</div>
<!-- <button style="text-align: right" class="btn btn-sm btn-info-outline" (click)="similarMovies(result.id)"> <i class="fa fa-eye"></i> {{ 'Search.Similar' | translate }}</button> -->
<!-- <button style="text-align: right" class="btn btn-sm btn-info-outline" (click)="similarMovies(result.id)"> <i class="far fa-eye"></i> {{ 'Search.Similar' | translate }}</button> -->
<br/>

@ -3,7 +3,7 @@
<div class="input-group">
<input id="search" type="text" placeholder="{{ 'Search.SearchBarPlaceholder' | translate }}" class="form-control form-control-custom form-control-search form-control-withbuttons" (keyup)="search($event)">
<div class="input-group-addon right-radius">
<i class="fa fa-search"></i>
<i class="fas fa-search"></i>
</div>
</div>
<div class="form-group">
@ -20,11 +20,11 @@
<br />
<div id="movieList">
<div *ngIf="searchApplied && artistResult?.length <= 0 && !searchAlbum" class='no-search-results'>
<i class='fa fa-music no-search-results-icon'></i>
<i class='fas fa-music no-search-results-icon'></i>
<div class='no-search-results-text' [translate]="'Search.NoResults'"></div>
</div>
<div *ngIf="searchApplied && albumResult?.length <= 0 && searchAlbum" class='no-search-results'>
<i class='fa fa-music no-search-results-icon'></i>
<i class='fas fa-music no-search-results-icon'></i>
<div class='no-search-results-text' [translate]="'Search.NoResults'"></div>
</div>

@ -7,14 +7,14 @@
<ul id="nav-tabs" class="nav nav-tabs nav-justified" role="tablist">
<li role="presentation" class="active">
<a id="movieTabButton" href="#MoviesTab" aria-controls="home" role="tab" data-toggle="tab" (click)="selectMovieTab()"><i class="fa fa-film"></i> {{ 'Search.MoviesTab' | translate }}</a>
<a id="movieTabButton" href="#MoviesTab" aria-controls="home" role="tab" data-toggle="tab" (click)="selectMovieTab()"><i class="fas fa-film"></i> {{ 'Search.MoviesTab' | translate }}</a>
</li>
<li role="presentation">
<a id="tvTabButton" href="#TvShowTab" aria-controls="profile" role="tab" data-toggle="tab" (click)="selectTvTab()"><i class="fa fa-television"></i> {{ 'Search.TvTab' | translate }}</a>
<a id="tvTabButton" href="#TvShowTab" aria-controls="profile" role="tab" data-toggle="tab" (click)="selectTvTab()"><i class="fas fa-tv"></i> {{ 'Search.TvTab' | translate }}</a>
</li>
<li role="presentation" *ngIf="musicEnabled">
<a id="tvTabButton" href="#MusicTab" aria-controls="profile" role="tab" data-toggle="tab" (click)="selectMusicTab()"><i class="fa fa-music"></i> {{ 'Search.MusicTab' | translate }}</a>
<a id="tvTabButton" href="#MusicTab" aria-controls="profile" role="tab" data-toggle="tab" (click)="selectMusicTab()"><i class="fas fa-music"></i> {{ 'Search.MusicTab' | translate }}</a>
</li>
</ul>

@ -4,7 +4,7 @@
<div class="btn-group" role="group">
<a href="#" class="btn btn-sm btn-primary-outline dropdown-toggle" data-toggle="dropdown" aria-expanded="false">
{{ 'Search.Suggestions' | translate }}
<i class="fa fa-chevron-down"></i>
<i class="fas fa-chevron-down"></i>
</a>
<ul class="dropdown-menu">
<li>
@ -31,7 +31,7 @@
<div class="search-button-container-inline">
<ng-template [ngTemplateOutlet]="FilterRef"></ng-template>
</div>
<i id="tvSearchButton" class="fa fa-search"></i>
<i id="tvSearchButton" class="fas fa-search"></i>
</div>
</div>
@ -49,7 +49,7 @@
<div id="tvList">
<div *ngIf="searchApplied && tvResults?.length <= 0" class='no-search-results'>
<i class='fa fa-film no-search-results-icon'></i>
<i class='fas fa-film no-search-results-icon'></i>
<div class='no-search-results-text'>{{ 'Search.NoResults' | translate }}</div>
</div>
<div *ngIf="tvResults" >
@ -107,7 +107,7 @@
<div class="col-sm-2 small-padding">
<div *ngIf="!node.fullyAvailable" class="dropdown">
<button class="btn btn-primary-outline dropdown-toggle" type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true">
<i class="fa fa-plus"></i> {{ 'Common.Request' | translate }}
<i class="fas fa-plus"></i> {{ 'Common.Request' | translate }}
<span class="caret"></span>
</button>
<ul class="dropdown-menu" aria-labelledby="dropdownMenu1">
@ -128,29 +128,29 @@
<div *ngIf="node.fullyAvailable">
<button style="text-align: right" class="btn btn-success-outline disabled" disabled>
<i class="fa fa-check"></i> {{ 'Common.Available' | translate }}
<i class="fas fa-check"></i> {{ 'Common.Available' | translate }}
</button>
</div>
<br />
<div *ngIf="node.plexUrl && node.available">
<a style="text-align: right" class="btn btn-sm btn-success-outline" href="{{node.plexUrl}}" target="_blank">
<i class="fa fa-eye"></i> {{ 'Search.ViewOnPlex' | translate }}
<i class="far fa-eye"></i> {{ 'Search.ViewOnPlex' | translate }}
</a>
</div>
<div *ngIf="node.embyUrl && node.available">
<a style="text-align: right" id="embybtn" class="btn btn-sm btn-success-outline" href="{{node.embyUrl}}" target="_blank">
<i class="fa fa-eye"></i> {{ 'Search.ViewOnEmby' | translate }}
<i class="far fa-eye"></i> {{ 'Search.ViewOnEmby' | translate }}
</a>
</div>
<div *ngIf="node.jellyfinUrl && node.available">
<a style="text-align: right" id="jellyfinbtn" class="btn btn-sm btn-success-outline" href="{{node.jellyfinUrl}}" target="_blank">
<i class="fa fa-eye"></i> {{ 'Search.ViewOnJellyfin' | translate }}
<i class="far fa-eye"></i> {{ 'Search.ViewOnJellyfin' | translate }}
</a>
</div>
<div class="dropdown" *ngIf="issueCategories && issuesEnabled">
<button class="btn btn-sm btn-primary-outline dropdown-toggle" type="button" data-toggle="dropdown" aria-haspopup="true"
aria-expanded="true">
<i class="fa fa-plus"></i> {{ 'Requests.ReportIssue' | translate }}
<i class="fas fa-plus"></i> {{ 'Requests.ReportIssue' | translate }}
<span class="caret"></span>
</button>
<ul class="dropdown-menu" aria-labelledby="dropdownMenu1">

@ -62,7 +62,7 @@
</div>
<div class="md-form-field" style="display:inline;margin-left:20px;">
<button mat-raised-button id="profiles" (click)="getProfiles(form)" class="mat-stroked-button load">
Load Quality Profiles <span *ngIf="profilesRunning" class="fa fa-spinner fa-spin"></span></button>
Load Quality Profiles <span *ngIf="profilesRunning" class="fas fa-spinner fa-spin"></span></button>
</div>
</div>
</div>

@ -19,7 +19,7 @@
</td>
<td>{{RequestType[v.type] | humanize}}</td>
<td class="vcenter">{{v.retryCount}}</td>
<td class="vcenter"> <i [pTooltip]="v.error" class="fa fa-info-circle"></i></td>
<td class="vcenter"> <i [pTooltip]="v.error" class="fas fa-info-circle"></i></td>
<td class="vcenter"><button type="button" class="mat-focus-indicator mat-flat-button mat-button-base mat-warn" (click)="remove(v)">Remove</button></td>
</tr>
</tbody>

@ -56,7 +56,7 @@
<div class="md-form-field">
<div class="md-form-field" style="display:inline;">
<button mat-raised-button type="button" (click)="getProfiles(form)" color="primary">Load Profiles <span
*ngIf="profilesRunning" class="fa fa-spinner fa-spin"></span></button>
*ngIf="profilesRunning" class="fas fa-spinner fa-spin"></span></button>
</div>
<div class="md-form-field" style="margin-top:1em;"></div>
<mat-form-field appearance="outline" floatLabel=always>
@ -72,7 +72,7 @@
<div class="md-form-field">
<div class="md-form-field" style="display:inline;">
<button mat-raised-button type="button" (click)="getRootFolders(form)" color="primary">Load Root Folders <span
*ngIf="rootFoldersRunning" class="fa fa-spinner fa-spin"></span></button>
*ngIf="rootFoldersRunning" class="fas fa-spinner fa-spin"></span></button>
</div>
<div class="md-form-field" style="margin-top:1em;"></div>
@ -90,7 +90,7 @@
<div class="md-form-field">
<div class="md-form-field" style="display:inline;">
<button mat-raised-button type="button" (click)="getMetadataProfiles(form)" color="primary">Load Metadata <span
*ngIf="metadataRunning" class="fa fa-spinner fa-spin"></span></button></div>
*ngIf="metadataRunning" class="fas fa-spinner fa-spin"></span></button></div>
<div class="md-form-field" style="margin-top:1em;"></div>
</div>
<mat-form-field appearance="outline" floatLabel=always>

@ -22,7 +22,7 @@
<div class="form-group">
<label for="applicationToken" class="control-label">Application Token
<i class="fa fa-question-circle" pTooltip="Optional authentication token. Will be sent as 'Access-Token' header."></i>
<i class="far fa-question-circle" pTooltip="Optional authentication token. Will be sent as 'Access-Token' header."></i>
</label>
<input type="text" class="form-control form-control-custom " id="applicationToken" name="applicationToken" [ngClass]="{'form-error': form.get('applicationToken').hasError('required')}" formControlName="applicationToken" pTooltip="Enter your Application token from Webhook.">

@ -16,7 +16,7 @@
<mat-label>Api Key</mat-label>
<input matInput id="ApiKey" name="ApiKey" formControlName="apiKey" readonly="readonly">
<button type="button" matSuffix (click)="refreshApiKey()" style="display:inline-block;">
<mat-icon class="fa fa-refresh"></mat-icon>
<mat-icon class="fas fa-sync"></mat-icon>
</button>
</mat-form-field>

@ -102,7 +102,7 @@
<div>
<button mat-raised-button (click)="loadLibraries(server)"
class="mat-focus-indicator mat-stroked-button mat-button-base">Load Libraries
<i class="fa fa-film"></i>
<i class="fas fa-film"></i>
</button>
</div>
</div>
@ -143,7 +143,7 @@
<div>
<button mat-raised-button id="requestToken" (click)="requestServers(server)"
class="mat-stroked-button">Load Servers
<i class="fa fa-key"></i>
<i class="fas fa-key"></i>
</button>
</div>
</div>

@ -59,7 +59,7 @@
<label for="username" class="control-label"><h3>Radarr Interface</h3></label>
<div class="md-form-field">
<div class="md-form-field" style="display:inline;">
<button mat-raised-button (click)="getProfiles(form)" color="primary">Load Profiles <span *ngIf="profilesRunning" class="fa fa-spinner fa-spin"></span></button>
<button mat-raised-button (click)="getProfiles(form)" color="primary">Load Profiles <span *ngIf="profilesRunning" class="fas fa-spinner fa-spin"></span></button>
</div>
<div class="md-form-field" style="margin-top:1em;"></div>
<mat-form-field appearance="outline" >
@ -74,7 +74,7 @@
</div>
<div class="md-form-field">
<div class="md-form-field" style="display:inline;">
<button mat-raised-button (click)="getRootFolders(form)" color="primary">Load Root Folders <span *ngIf="rootFoldersRunning" class="fa fa-spinner fa-spin"></span></button>
<button mat-raised-button (click)="getRootFolders(form)" color="primary">Load Root Folders <span *ngIf="rootFoldersRunning" class="fas fa-spinner fa-spin"></span></button>
</div>
<div class="md-form-field" style="margin-top:1em;"></div>
<mat-form-field appearance="outline" >

@ -1,5 +1,5 @@

<button mat-button [matMenuTriggerFor]="configurationmenu"><i class="fa fa-cogs" aria-hidden="true"></i> Configuration</button>
<button mat-button [matMenuTriggerFor]="configurationmenu"><i class="fas fa-wrench" aria-hidden="true"></i> Configuration</button>
<mat-menu #configurationmenu="matMenu">
<button mat-menu-item [routerLink]="['/Settings/Ombi']">General</button>
<button mat-menu-item [routerLink]="['/Settings/Customization']">Customization</button>
@ -11,33 +11,33 @@
<button mat-menu-item [routerLink]="['/Settings/TheMovieDb']">The Movie Database</button>
</mat-menu>
<button mat-button [matMenuTriggerFor]="mediaservermenu"><i class="fa fa-server" aria-hidden="true"></i> Media Server</button>
<button mat-button [matMenuTriggerFor]="mediaservermenu"><i class="fas fa-server" aria-hidden="true"></i> Media Server</button>
<mat-menu #mediaservermenu="matMenu">
<button mat-menu-item [routerLink]="['/Settings/Plex']">Plex</button>
<button mat-menu-item [routerLink]="['/Settings/Emby']">Emby</button>
<button mat-menu-item [routerLink]="['/Settings/Jellyfin']">Jellyfin</button>
</mat-menu>
<button mat-button [matMenuTriggerFor]="tvmenu"><i class="fa fa-television" aria-hidden="true"></i> TV</button>
<button mat-button [matMenuTriggerFor]="tvmenu"><i class="fas fa-tv" aria-hidden="true"></i> TV</button>
<mat-menu #tvmenu="matMenu">
<button mat-menu-item [routerLink]="['/Settings/Sonarr']">Sonarr</button>
<button mat-menu-item [routerLink]="['/Settings/DogNzb']">DogNzb</button>
<button mat-menu-item [routerLink]="['/Settings/SickRage']">SickRage</button>
</mat-menu>
<button mat-button [matMenuTriggerFor]="movieMenu"><i class="fa fa-film" aria-hidden="true"></i> Movies</button>
<button mat-button [matMenuTriggerFor]="movieMenu"><i class="fas fa-film" aria-hidden="true"></i> Movies</button>
<mat-menu #movieMenu="matMenu">
<button mat-menu-item [routerLink]="['/Settings/CouchPotato']">CouchPotato</button>
<button mat-menu-item [routerLink]="['/Settings/DogNzb']">DogNzb</button>
<button mat-menu-item [routerLink]="['/Settings/Radarr']">Radarr</button>
</mat-menu>
<button mat-button [matMenuTriggerFor]="musicMenu"><i class="fa fa-music" aria-hidden="true"></i> Music</button>
<button mat-button [matMenuTriggerFor]="musicMenu"><i class="fas fa-music" aria-hidden="true"></i> Music</button>
<mat-menu #musicMenu="matMenu">
<button mat-menu-item [routerLink]="['/Settings/Lidarr']">Lidarr</button>
</mat-menu>
<button mat-button [matMenuTriggerFor]="notificationMenu"><i class="fa fa-bell-o" aria-hidden="true"></i> Notifications</button>
<button mat-button [matMenuTriggerFor]="notificationMenu"><i class="fas fa-bell" aria-hidden="true"></i> Notifications</button>
<mat-menu #notificationMenu="matMenu">
<button mat-menu-item [routerLink]="['/Settings/CloudMobile']">Mobile</button>
<button mat-menu-item [routerLink]="['/Settings/Mobile']">Legacy Mobile</button>
@ -55,7 +55,7 @@
<button mat-menu-item [routerLink]="['/Settings/Webhook']">Webhook</button>
</mat-menu>
<button mat-button [matMenuTriggerFor]="systemMenu"><i class="fa fa-tachometer" aria-hidden="true"></i> System</button>
<button mat-button [matMenuTriggerFor]="systemMenu"><i class="fas fa-sliders-h" aria-hidden="true"></i> System</button>
<mat-menu #systemMenu="matMenu">
<button mat-menu-item [routerLink]="['/Settings/About']">About</button>
<button mat-menu-item [routerLink]="['/Settings/FailedRequests']">Failed Requests</button>

@ -61,7 +61,7 @@
<div id="profiles">
<div class="md-form-field" style="display:inline;">
<button mat-raised-button id="profiles" (click)="getProfiles(form)" class="mat-stroked-button">
Load Qualities <span *ngIf="profilesRunning" class="fa fa-spinner fa-spin"></span></button>
Load Qualities <span *ngIf="profilesRunning" class="fas fa-spinner fa-spin"></span></button>
<div class="md-form-field" style="margin-top:1em;"></div>
</div>
<div class="md-form-field" style="display:contents;">
@ -93,7 +93,7 @@
<div id="rootFolders">
<div class="md-form-field" style="display:inline">
<button mat-raised-button id="rootFolder" (click)="getRootFolders(form)" class="mat-stroked-button">
Load Folders <span *ngIf="rootFoldersRunning" class="fa fa-spinner fa-spin"></span></button><div class="md-form-field" style="margin-top:1em;"></div>
Load Folders <span *ngIf="rootFoldersRunning" class="fas fa-spinner fa-spin"></span></button><div class="md-form-field" style="margin-top:1em;"></div>
</div>
<div class="md-form-field" style="display:contents;">
<mat-form-field appearance="outline">
@ -122,12 +122,12 @@
<div class="form-group col-md-12" *ngIf="form.controls.v3.value">
<label for="select" class="control-label">Language Profiles
<i *ngIf="form.get('languageProfile').hasError('required')" class="fa fa-exclamation-circle error-text" pTooltip="A Language Profile is required"></i>
<i *ngIf="form.get('languageProfile').hasError('required')" class="fas fa-exclamation-circle error-text" pTooltip="A Language Profile is required"></i>
</label>
<div id="langaugeProfile">
<div class="md-form-field" style="display:inline">
<button type="button" mat-raised-button (click)="getLanguageProfiles(form)" class="mat-stroked-button">Load
Languages <span *ngIf="langRunning" class="fa fa-spinner fa-spin"> </span></button><div class="md-form-field" style="margin-top:1em;"></div>
Languages <span *ngIf="langRunning" class="fas fa-spinner fa-spin"> </span></button><div class="md-form-field" style="margin-top:1em;"></div>
</div>
<div class="md-form-field" style="display:contents;">
<mat-form-field appearance="outline">

@ -6,12 +6,12 @@
<li role="presentation" class="active">
<a id="currentVotes" href="#currentVotes" aria-controls="home" role="tab" data-toggle="tab" (click)="selectCurrentTab()"><i
class="fa fa-meh-o"></i> {{ 'Votes.VotesTab' | translate }}</a>
class="far fa-meh"></i> {{ 'Votes.VotesTab' | translate }}</a>
</li>
<li role="presentation">
<a id="completedVotes" href="#completedVotes" aria-controls="profile" role="tab" data-toggle="tab" (click)="selectCompletedVotesTab()"><i
class="fa fa-smile-o"></i> {{ 'Votes.CompletedVotesTab' | translate }}</a>
class="far fa-smile"></i> {{ 'Votes.CompletedVotesTab' | translate }}</a>
</li>
</ul>
@ -32,9 +32,9 @@
<tbody>
<tr *ngFor="let vm of currentVotes">
<td class="vcenter">
<button id="{{vm.requestId}}upvote" class="btn btn-info-outline col-md-6" (click)="upvote(vm)"><i class="fa fa-thumbs-o-up"
<button id="{{vm.requestId}}upvote" class="btn btn-info-outline col-md-6" (click)="upvote(vm)"><i class="far fa-thumbs-up"
aria-hidden="true"></i></button>
<button id="{{vm.requestId}}downvote" class="btn btn-info-outline col-md-6" (click)="downvote(vm)" ><i class="fa fa-thumbs-o-down"
<button id="{{vm.requestId}}downvote" class="btn btn-info-outline col-md-6" (click)="downvote(vm)" ><i class="far fa-thumbs-down"
aria-hidden="true"></i></button>
</td>
<td style="width: 10%"> <img *ngIf="vm.image" class="img-responsive poster" style="max-width: 100%;
@ -66,10 +66,10 @@
<tr *ngFor="let vm of completedVotes">
<td class="vcenter">
<button id="{{vm.requestId}}upvote" class="btn btn-info-outline col-md-6" [ngClass]="{'btn-success-outline': vm.myVote == VoteType.Upvote, 'btn-info-outline': vm.myVote != VoteType.Upvote}"
(click)="upvote(vm)" [disabled]="vm.myVote == VoteType.Upvote"><i class="fa fa-thumbs-o-up"
(click)="upvote(vm)" [disabled]="vm.myVote == VoteType.Upvote"><i class="far fa-thumbs-up"
aria-hidden="true"></i></button>
<button id="{{vm.requestId}}downvote" class="btn btn-info-outline col-md-6" [ngClass]="{'btn-danger-outline': vm.myVote == VoteType.Downvote, 'btn-info-outline': vm.myVote != VoteType.Downvote}"
(click)="downvote(vm)" [disabled]="vm.myVote == VoteType.Downvote"><i class="fa fa-thumbs-o-down"
(click)="downvote(vm)" [disabled]="vm.myVote == VoteType.Downvote"><i class="far fa-thumbs-down"
aria-hidden="true"></i></button>
</td>
<td style="width: 10%"> <img *ngIf="vm.image" class="img-responsive poster" style="max-width: 100%;

@ -1,12 +1,22 @@

<small>This account will be used to configure your settings and also manage all of the requests.</small>
<div>
<mat-form-field>
<input matInput type="text" id="adminUsername" name="Username" [(ngModel)]="user.username" placeholder="Username">
</mat-form-field>
</div> <div>
<mat-form-field>
<input type="password" matInput id="adminPassword" name="Password" [(ngModel)]="user.password" placeholder="Password">
</mat-form-field>
<div class="mediaserver-container">
<div class="left-container mediaserver">
<i class="fas fa-user-shield text-logo"></i>
</div>
<div class="right-container mediaserver">
<div class="right-container-content mediaserver">
<h1>Protect your Ombi</h1>
<small>Create an Admin account to make sure you are always able to access your Ombi.</small>
<div>
<mat-form-field>
<input matInput type="text" id="adminUsername" name="Username" [(ngModel)]="user.username" placeholder="Username">
</mat-form-field>
</div> <div>
<mat-form-field>
<input type="password" matInput id="adminPassword" name="Password" [(ngModel)]="user.password" placeholder="Password">
</mat-form-field>
</div>
<small class="important">You'll need to configure e-mail to reset your password!</small>
</div>
</div>
</div>

@ -4,6 +4,7 @@ import { ICreateWizardUser } from "../../interfaces";
@Component({
selector: "wizard-local-admin",
templateUrl: "./createadmin.component.html",
styleUrls: ["../welcome/welcome.component.scss"]
})
export class CreateAdminComponent {

@ -1,31 +1,40 @@

<div *ngIf="embySettings">
<div *ngIf="embySettings.servers">
<div *ngFor="let server of embySettings.servers">
<div>
<mat-form-field>
<input type="text" matInput [(ngModel)]="server.ip" id="Ip" name="Ip" placeholder="Emby Hostname or IP Address">
</mat-form-field>
</div>
<div class="mediaserver-container">
<div class="left-container mediaserver">
<img src="https://emby.media/resources/logowhite_1881.png">
</div>
<div class="right-container mediaserver">
<div class="right-container-content mediaserver">
<H1 class="wizard-title">Emby Configuration</H1>
<div *ngIf="embySettings">
<div *ngIf="embySettings.servers">
<div *ngFor="let server of embySettings.servers">
<div>
<mat-form-field>
<input type="text" matInput [(ngModel)]="server.ip" id="Ip" name="Ip" placeholder="Emby Hostname or IP Address">
</mat-form-field>
</div>
<div>
<div>
<mat-form-field>
<input type="text" matInput [(ngModel)]="server.port" id="portNumber" name="Port" value="{{server.port}}">
</mat-form-field>
</div>
<div>
<mat-slide-toggle [(ngModel)]="server.ssl">Enable SSL</mat-slide-toggle>
</div>
<div>
<mat-form-field>
<input type="text" matInput [(ngModel)]="server.apiKey" id="apiKey" name="ApiKey" placeholder="Emby API Key">
</mat-form-field>
</div>
<div style="text-align: center; margin-top: 20px">
<a (click)="save()" id="embyApiKeySave" mat-raised-button color="primary">Save <div id="spinner"></div></a>
<mat-form-field>
<input type="text" matInput [(ngModel)]="server.port" id="portNumber" name="Port" value="{{server.port}}">
</mat-form-field>
</div>
<div>
<mat-slide-toggle [(ngModel)]="server.ssl">Enable SSL</mat-slide-toggle>
</div>
<div>
<mat-form-field>
<input type="text" matInput [(ngModel)]="server.apiKey" id="apiKey" name="ApiKey" placeholder="Emby API Key">
</mat-form-field>
</div>
<div style="text-align: center; margin-top: 20px">
<button (click)="save()" id="embyApiKeySave" mat-raised-button color="accent" type="button" class="viewon-btn emby">Save</button><div id="spinner"></div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>

@ -8,6 +8,7 @@ import { IEmbySettings } from "../../interfaces";
@Component({
selector: "wizard-emby",
templateUrl: "./emby.component.html",
styleUrls: ["../welcome/welcome.component.scss"],
})
export class EmbyComponent implements OnInit {

@ -1,31 +1,40 @@

<div *ngIf="jellyfinSettings">
<div *ngIf="jellyfinSettings.servers">
<div *ngFor="let server of jellyfinSettings.servers">
<div>
<mat-form-field>
<input type="text" matInput [(ngModel)]="server.ip" id="Ip" name="Ip" placeholder="Jellyfin Hostname or IP Address">
</mat-form-field>
</div>
<div class="mediaserver-container">
<div class="left-container mediaserver">
<img src="https://jellyfin.org/images/banner-dark.svg">
</div>
<div class="right-container mediaserver">
<div class="right-container-content mediaserver">
<H1 class="wizard-title">Jellyfin Configuration</H1>
<div *ngIf="jellyfinSettings">
<div *ngIf="jellyfinSettings.servers">
<div *ngFor="let server of jellyfinSettings.servers">
<div>
<mat-form-field>
<input type="text" matInput [(ngModel)]="server.ip" id="Ip" name="Ip" placeholder="Jellyfin Hostname or IP Address">
</mat-form-field>
</div>
<div>
<div>
<mat-form-field>
<input type="text" matInput [(ngModel)]="server.port" id="portNumber" name="Port" value="{{server.port}}">
</mat-form-field>
</div>
<div>
<mat-slide-toggle [(ngModel)]="server.ssl">Enable SSL</mat-slide-toggle>
</div>
<div>
<mat-form-field>
<input type="text" matInput [(ngModel)]="server.apiKey" id="apiKey" name="ApiKey" placeholder="Jellyfin API Key">
</mat-form-field>
</div>
<div style="text-align: center; margin-top: 20px">
<a (click)="save()" id="jellyfinApiKeySave" mat-raised-button color="primary">Save <div id="spinner"></div></a>
<mat-form-field>
<input type="text" matInput [(ngModel)]="server.port" id="portNumber" name="Port" value="{{server.port}}">
</mat-form-field>
</div>
<div>
<mat-slide-toggle [(ngModel)]="server.ssl">Enable SSL</mat-slide-toggle>
</div>
<div>
<mat-form-field>
<input type="text" matInput [(ngModel)]="server.apiKey" id="apiKey" name="ApiKey" placeholder="Jellyfin API Key">
</mat-form-field>
</div>
<div style="text-align: center; margin-top: 20px">
<button (click)="save()" id="jellyfinApiKeySave" mat-raised-button color="accent" type="button" class="viewon-btn jellyfin">Save</button><div id="spinner"></div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>

@ -8,6 +8,7 @@ import { IJellyfinSettings } from "../../interfaces";
@Component({
selector: "wizard-jellyfin",
templateUrl: "./jellyfin.component.html",
styleUrls: ["../welcome/welcome.component.scss"]
})
export class JellyfinComponent implements OnInit {

@ -0,0 +1,5 @@
export interface IOmbiConfigModel {
applicationName: string;
applicationUrl: string;
logo: string;
}

@ -0,0 +1,28 @@
<div class="mediaserver-container">
<div class="left-container mediaserver">
<i class="fas fa-user-astronaut text-logo"></i>
</div>
<div class="right-container mediaserver">
<div class="right-container-content mediaserver">
<h1 *ngIf="!config.applicationName">Customize your Ombi</h1>
<h1 *ngIf="config.applicationName">Customize your {{config.applicationName}}</h1>
<div>
<mat-form-field>
<input type="text" matInput id="applicationname" name="Application Name" [(ngModel)]="config.applicationName" placeholder="Application Name">
</mat-form-field>
</div>
<div>
<mat-form-field>
<input matInput type="text" id="applicationurl" name="Application URL" [(ngModel)]="config.applicationUrl" placeholder="Application URL">
</mat-form-field>
</div>
<div>
<mat-form-field>
<mat-label>Custom Logo</mat-label>
<input matInput type="url" id="customlogo" name="Custom Logo" [(ngModel)]="config.logo" placeholder="Input the URL of your custom logo">
</mat-form-field>
</div>
</div>
</div>
</div>

@ -0,0 +1,13 @@
import { Component, Input } from "@angular/core";
import { IOmbiConfigModel } from "../models/OmbiConfigModel";
import { WizardService } from "../services/wizard.service";
@Component({
selector: "wizard-ombi",
templateUrl: "./ombiconfig.component.html",
styleUrls: ["../welcome/welcome.component.scss"]
})
export class OmbiConfigComponent {
@Input() public config: IOmbiConfigModel;
}

@ -1,24 +1,38 @@
<div class="form-group">
<div>
<mat-form-field>
<input matInput type="text" [(ngModel)]="login" id="username" placeholder="Username">
</mat-form-field>
</div>
<div>
<mat-form-field>
<input matInput type="password" [(ngModel)]="password" placeholder="Password">
</mat-form-field>
</div>
</div>
<small>Please note we do not store this information, we only store your Plex Authorization Token that will allow Ombi to view your media and users</small>
<div class="form-group">
<div style="text-align: center; margin-top: 20px">
<button (click)="requestAuthToken()" mat-raised-button color="primary" >Request Token <i class="fa fa-key"></i></button>
<div class="mediaserver-container" >
<div class="left-container mediaserver">
<img src="https://www.plex.tv/wp-content/themes/plex/assets/img/plex-logo.svg">
</div>
</div>
<p class="text-center">OR</p>
<div class="form-group">
<div style="text-align: center; margin-top: 20px">
<button (click)="oauth()" mat-raised-button color="accent" type="button">Continue With Plex</button>
<div class="right-container mediaserver">
<div class="right-container-content mediaserver">
<H1 class="wizard-title">Plex Configuration</H1>
<div class="form-group">
<div>
<mat-form-field>
<input matInput type="text" [(ngModel)]="login" id="username" placeholder="Username" [disabled]="completed">
</mat-form-field>
</div>
<div>
<mat-form-field>
<input matInput type="password" [(ngModel)]="password" placeholder="Password" [disabled]="completed">
</mat-form-field>
</div>
</div>
<small>Please note we do not store this information, we only store your Plex Authorization Token that will allow Ombi to view your media and users</small>
<div class="plex-buttons">
<div class="form-group">
<div style="text-align: center; margin-top: 20px">
<button (click)="requestAuthToken()" mat-raised-button color="primary" class="viewon-btn standard" [disabled]="completed">Request Token <i class="fas fa-key"></i></button>
</div>
</div>
<p class="text-center space-or">OR</p>
<div class="form-group">
<div style="text-align: center; margin-top: 20px">
<button (click)="oauth()" mat-raised-button color="accent" type="button" class="viewon-btn plex" [disabled]="completed">
<i *ngIf="oauthLoading" class="fas fa-circle-notch fa-spin fa-fw"></i>
Login With Plex</button>
</div>
</div>
</div>
</div>
</div>
</div>

@ -9,12 +9,15 @@ import { StorageService } from "../../shared/storage/storage-service";
@Component({
selector: "wizard-plex",
templateUrl: "./plex.component.html",
styleUrls: ["../welcome/welcome.component.scss"],
})
export class PlexComponent implements OnInit, OnDestroy {
public login: string;
public password: string;
public pinTimer: any;
public completed: boolean;
public oauthLoading: boolean;
private clientId: string;
@ -42,7 +45,7 @@ export class PlexComponent implements OnInit, OnDestroy {
usePlexAdminAccount: true,
}).subscribe(y => {
if (y.result) {
this.router.navigate(["login"]);
this.notificationService.success("Created your Plex User!");
} else {
this.notificationService.error("Could not get the Plex Admin Information");
if (y.errors.length > 0) {
@ -56,6 +59,7 @@ export class PlexComponent implements OnInit, OnDestroy {
}
public oauth() {
this.oauthLoading = true;
const oAuthWindow = window.open(window.location.toString(), "_blank", `toolbar=0,
location=0,
status=0,
@ -68,20 +72,24 @@ export class PlexComponent implements OnInit, OnDestroy {
this.authService.login({ usePlexOAuth: true, password: "", rememberMe: true, username: "", plexTvPin: pin }).subscribe(x => {
oAuthWindow!.location.replace(x.url);
this.pinTimer = setInterval(() => {
// this.notify.info("Authenticating", "Loading... Please Wait");
this.getPinResult(x.pinId);
}, 10000);
}, 3000);
});
});
}
public getPinResult(pinId: number) {
this.plexOauth.oAuth(pinId).subscribe(x => {
if (!x.accessToken) {
if(!x.success) {
this.oauthLoading = false;
clearInterval(this.pinTimer);
this.notificationService.error(`Error From Plex: ${x.error}`)
}
return;
// RETURN
}
this.identityService.createWizardUser({
@ -92,10 +100,14 @@ export class PlexComponent implements OnInit, OnDestroy {
if (u.result) {
this.authService.oAuth(pinId).subscribe(c => {
this.store.save("id_token", c.access_token);
this.router.navigate(["login"]);
this.completed = true;
this.notificationService.success("Created your Plex User!");
this.oauthLoading = false;
clearInterval(this.pinTimer);
});
} else {
this.oauthLoading = false;
if (u.errors.length > 0) {
console.log(u.errors[0]);
}

@ -0,0 +1,19 @@
import { PlatformLocation, APP_BASE_HREF } from "@angular/common";
import { HttpClient } from "@angular/common/http";
import { Injectable, Inject } from "@angular/core";
import { Observable } from "rxjs";
import { ICustomizationSettings } from "../../interfaces";
import { ServiceHelpers } from "../../services";
import { IOmbiConfigModel } from "../models/OmbiConfigModel";
@Injectable()
export class WizardService extends ServiceHelpers {
constructor(public http: HttpClient, @Inject(APP_BASE_HREF) href:string) {
super(http, "/api/v2/wizard/", href);
}
public addOmbiConfig(config: IOmbiConfigModel): Observable<ICustomizationSettings> {
return this.http.post<ICustomizationSettings>(`${this.url}config`, config, {headers: this.headers});
}
}

@ -1,67 +1,87 @@
<div class="container">
<div class="wizard-background">
<div class="container wizard-inner">
<mat-horizontal-stepper linear #stepper>
<mat-step >
<form >
<ng-template matStepLabel>Welcome</ng-template>
<p>Welcome to Ombi, this wizard will quickly take you through the inital setup!</p>
<div>
<button mat-button matStepperNext>Next</button>
<div class="welcome-container">
<div class="left-container logo">
OMBI
</div>
<div class="right-container">
<div class="right-container-content">
<h1>Welcome to Ombi!</h1>
<p>This wizard will quickly take you through the inital setup!</p>
<p>If you encounter any problems, please reach out on the following platforms:</p>
<br />
<div class="social-media">
<ul class="fa-ul">
<li><a href="https://discord.gg/Sa7wNWb" target="_blank"><span class="fa-li"><i class="fab fa-discord"></i></span>Ombi Discord</a>
<li><a href="https://github.com/Ombi-app/Ombi" target="_blank"><span class="fa-li"><i class="fab fa-github"></i></span>Ombi Github</a>
<li><a href="https://docs.ombi.app/" target="_blank"><span class="fa-li"><i class="fas fa-book"></i></span>Ombi Documentation</a>
</ul>
</div>
</div>
</div>
</div>
<div class="welcome-buttons">
<button mat-button matStepperNext class="mat-raised-button mat-accent">Next</button>
</div>
</form>
</mat-step>
<mat-step [optional]="true">
<form >
<ng-template matStepLabel>Plex</ng-template>
<wizard-plex></wizard-plex>
<div>
<button mat-button matStepperPrevious>Back</button>
<button mat-button matStepperNext>Next</button>
</div>
</form>
</mat-step>
<mat-step [optional]="true">
<form >
<ng-template matStepLabel>Emby</ng-template>
<wizard-emby></wizard-emby>
<div>
<button mat-button matStepperPrevious>Back</button>
<button mat-button matStepperNext>Next</button>
</div>
</form>
</mat-step>
<mat-step [optional]="true">
<form >
<ng-template matStepLabel>Jellyfin</ng-template>
<wizard-jellyfin></wizard-jellyfin>
<div>
<button mat-button matStepperPrevious>Back</button>
<button mat-button matStepperNext>Next</button>
</div>
</form>
</mat-step>
<mat-step>
<form >
<ng-template matStepLabel>Create a local admin</ng-template>
<wizard-local-admin [user]="localUser"></wizard-local-admin>
<div>
<button mat-button matStepperPrevious>Back</button>
<button mat-button matStepperNext>Next</button>
</div>
</form>
</mat-step>
<form >
<ng-template matStepLabel>Media Server</ng-template>
<mat-tab-group>
<mat-tab label="Plex"><wizard-plex></wizard-plex></mat-tab>
<mat-tab label="Emby"><wizard-emby></wizard-emby></mat-tab>
<mat-tab label="Jellyfin"><wizard-jellyfin></wizard-jellyfin></mat-tab>
</mat-tab-group>
<button mat-button matStepperPrevious class="mat-raised-button mat-error left">Back</button>
<button mat-button matStepperNext class="mat-raised-button mat-accent right">Next</button>
</form>
</mat-step>
<mat-step>
<form>
<ng-template matStepLabel>Create a local admin</ng-template>
<wizard-local-admin [user]="localUser"></wizard-local-admin>
<div>
<button mat-button matStepperPrevious class="mat-raised-button mat-error left">Back</button>
<button mat-button matStepperNext class="mat-raised-button mat-accent right">Next</button>
</div>
</form>
</mat-step>
<mat-step [optional]="true">
<form >
<ng-template matStepLabel>Ombi config</ng-template>
<wizard-ombi [config]="config"></wizard-ombi>
<div>
<button mat-button matStepperPrevious class="mat-raised-button mat-error left">Back</button>
<button mat-button matStepperNext class="mat-raised-button mat-accent right">Next</button>
</div>
</form>
</mat-step>
<mat-step>
<ng-template matStepLabel>Done</ng-template>
All setup! Press Finish to continue and login to Ombi!
<div class="mediaserver-container">
<div class="left-container mediaserver">
<i class="fas fa-check text-logo"></i>
</div>
<div class="right-container mediaserver">
<div class="right-container-content mediaserver">
<h1>All setup!</h1>
Press Finish to continue and login to Ombi!
</div>
</div>
</div>
<div>
<button mat-button matStepperPrevious (click)="createUser()">Finish</button>
<button mat-button (click)="stepper.reset()">Reset</button>
<button mat-button matStepperPrevious (click)="createUser()" class="mat-raised-button mat-accent right">Finish</button>
<button mat-button (click)="stepper.reset()" class="mat-raised-button mat-error left">Reset</button>
</div>
</mat-step>
</mat-horizontal-stepper>
</div>
</div>
</div>

@ -0,0 +1,172 @@
@import "~styles/variables.scss";
.welcome-container{
display:flex;
height:100%;
width:100%;
}
.welcome-container .logo{
font-family: Montserrat,sans-serif;
text-transform: uppercase;
color: #62d2fa;
font-weight: 700;
font-size: 5em;
display:flex;
justify-content: center;
align-items: center;
height:300px;
}
.left-container{
width:30%;
}
.right-container{
width:60%;
float:right;
}
.right-container-content{
width:100%;
}
.welcome-container .right-container{
display:flex;
align-items: center;
justify-content: center;
}
.welcome-buttons{
float:right;
}
.fab:before {
font-family: 'Font Awesome 5 Brands';
}
.social-media .fab{
font-family: Roboto, "Helvetica Neue", sans-serif;
}
.fas:before {
font-family:"Font Awesome 5 Free";
font-weight:800;
}
.social-media .fas{
font-family: Roboto, "Helvetica Neue", sans-serif;
font-weight:400;
}
.social-media a{
color: #FFF;
}
.social-media{
display:grid;
}
.fa-ul {
list-style-type: none;
margin-left: 2.5em;
padding-left: 0;
}
.fa-li {
left: -2em;
position: absolute;
text-align: center;
width: 2em;
line-height: inherit;
}
.social-media ul li{
font-size:16px;
padding:5px;
}
.left-container.mediaserver img{
object-fit: contain;
width: 100%;
}
.left-container.mediaserver{
display:flex;
justify-content: center;
align-items: center;
height:300px;
padding:20px;
}
.right-container.mediaserver{
display:flex;
justify-content: center;
align-items:center;
}
.right-container-content .mediaserver{
display:block;
}
.mediaserver-container{
display:flex;
height:100%;
width:100%;
justify-content: space-between;
}
.plex-buttons{
display:flex;
justify-content: center;
align-items: center;
}
p.space-or{
padding:20px;
margin-top:20px;
}
.viewon-btn.plex {
border: 1px solid #e5a00d;
color: #e5a00d;
}
.viewon-btn {
background-color: transparent;
text-decoration: none;
}
.viewon-btn.standard {
border: 1px solid #FFF;
}
.viewon-btn.emby {
border: 1px solid #52B54B;
color: #52B54B;
}
.viewon-btn.jellyfin {
border: 1px solid #A45FC4;
color: #A45FC4;
}
.text-logo{
font-size:12em;
}
.left{
float:left;
}
.right{
float:right;
}
small.important{
color:red;
}
h1.wizard-title{
margin-top:30px;
}

@ -1,35 +1,53 @@
import { Component, OnInit } from "@angular/core";
import { AfterViewInit, Component, OnInit, ViewChild } from "@angular/core";
import { Router } from "@angular/router";
import { ICreateWizardUser } from "../../interfaces";
import { IdentityService, NotificationService } from "../../services";
import { IOmbiConfigModel } from "../models/OmbiConfigModel";
import { WizardService } from "../services/wizard.service";
import { MatHorizontalStepper } from'@angular/material/stepper';
import { StepperSelectionEvent } from "@angular/cdk/stepper";
@Component({
templateUrl: "./welcome.component.html",
styleUrls: ["./welcome.component.scss"],
})
export class WelcomeComponent implements OnInit {
@ViewChild('stepper', {static: false}) public stepper: MatHorizontalStepper;
public localUser: ICreateWizardUser;
constructor(private router: Router,
private identityService: IdentityService, private notificationService: NotificationService) { }
public config: IOmbiConfigModel;
constructor(private router: Router, private identityService: IdentityService,
private notificationService: NotificationService, private WizardService: WizardService) { }
public ngOnInit(): void {
public ngOnInit(): void {
this.localUser = {
password:"",
username:"",
usePlexAdminAccount:false
}
this.config = {
applicationName: null,
applicationUrl: null,
logo: null
};
}
public createUser() {
this.identityService.createWizardUser(this.localUser).subscribe(x => {
if (x.result) {
this.WizardService.addOmbiConfig(this.config).subscribe(config => {
if(config != null) {
this.identityService.createWizardUser(this.localUser).subscribe(x => {
if (x.result) {
// save the config
this.router.navigate(["login"]);
} else {
if (x.errors.length > 0) {
this.notificationService.error(x.errors[0]);
this.stepper.previous();
}
}
});
}
}, configErr => this.notificationService.error(configErr));
}
}

@ -11,12 +11,14 @@ import { JellyfinComponent } from "./jellyfin/jellyfin.component";
import { MediaServerComponent } from "./mediaserver/mediaserver.component";
import { PlexComponent } from "./plex/plex.component";
import { WelcomeComponent } from "./welcome/welcome.component";
import { OmbiConfigComponent } from "./ombiconfig/ombiconfig.component";
import { EmbyService } from "../services";
import { JellyfinService } from "../services";
import { PlexService } from "../services";
import { IdentityService } from "../services";
import { PlexOAuthService } from "../services";
import { WizardService } from "./services/wizard.service";
import { SharedModule } from "../shared/shared.module";
@ -27,6 +29,7 @@ const routes: Routes = [
{ path: "Emby", component: EmbyComponent},
{ path: "Jellyfin", component: JellyfinComponent},
{ path: "CreateAdmin", component: CreateAdminComponent},
{ path: "OmbiConfig", component: OmbiConfigComponent},
];
@NgModule({
imports: [
@ -44,6 +47,7 @@ const routes: Routes = [
CreateAdminComponent,
EmbyComponent,
JellyfinComponent,
OmbiConfigComponent,
],
exports: [
RouterModule,
@ -54,6 +58,7 @@ const routes: Routes = [
EmbyService,
JellyfinService,
PlexOAuthService,
WizardService,
],
})

@ -37,6 +37,7 @@
.mat-flat-button.mat-accent, .mat-raised-button.mat-accent, .mat-fab.mat-accent, .mat-mini-fab.mat-accent{
color: $ombi-active-text;
background-color: $ombi-active;
}
.mat-menu-panel{
@ -100,3 +101,43 @@
background: $ombi-background-accent;
}
}
.mat-tooltip{
background: $ombi-background-accent;
}
//Wizard CSS
.mat-stepper-horizontal, .mat-stepper-vertical{
background: $ombi-background-accent;
}
.wizard-background{
background-color: $ombi-background-primary;
width:100%;
height:100vh;
display:flex;
align-items:center;
justify-content: center;
}
.wizard-inner{
color:#FFF;
min-height: 450px;
}
.wizard-inner .mat-stepper-horizontal {
min-height: 450px;
}
.mat-step-header .mat-step-icon{
background-color:$ombi-active;
color: $ombi-active-text;
}
.mat-tab-group.mat-primary .mat-ink-bar, .mat-tab-nav-bar.mat-primary .mat-ink-bar{
background-color: $ombi-active;
}
.mat-flat-button, .mat-raised-button, .mat-fab, .mat-mini-fab{
background-color: $ombi-active;
}

@ -9,10 +9,10 @@
.ui-carousel-viewport {
border:0 !important;
background-color:transparent !important;
background-color:transparent !important;
}
.ui-carousel .ui-carousel-header {
background-color:transparent !important;
border: 0 !important;
}
border: 0 !important;
}

@ -1126,6 +1126,11 @@
lodash "^4.17.13"
to-fast-properties "^2.0.0"
"@fortawesome/fontawesome-free@^5.15.2":
version "5.15.2"
resolved "https://registry.yarnpkg.com/@fortawesome/fontawesome-free/-/fontawesome-free-5.15.2.tgz#218cd7276ab4f9ab57cc3d2efa2697e6a579f25d"
integrity sha512-7l/AX41m609L/EXI9EKH3Vs3v0iA8tKlIOGtw+kgcoanI7p+e4I4GYLqW3UXWiTnjSFymKSmTTPKYrivzbxxqA==
"@fullcalendar/core@^4.2.0":
version "4.4.0"
resolved "https://registry.yarnpkg.com/@fullcalendar/core/-/core-4.4.0.tgz#79dbc0cca836ce628a07e739a456da11ff141373"
@ -3841,10 +3846,6 @@ follow-redirects@^1.0.0:
dependencies:
debug "=3.1.0"
font-awesome@^4.7.0:
version "4.7.0"
resolved "https://registry.yarnpkg.com/font-awesome/-/font-awesome-4.7.0.tgz#8fa8cf0411a1a31afd07b06d2902bb9fc815a133"
for-in@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80"

@ -139,7 +139,7 @@ namespace Ombi.Controllers.V1
public async Task<SaveWizardResult> CreateWizardUser([FromBody] CreateUserWizardModel user)
{
var users = UserManager.Users;
if (users.Any(x => x.NormalizedUserName != "API"))
if (users.Any(x => x.UserType == UserType.LocalUser))
{
// No one should be calling this. Only the wizard
return new SaveWizardResult { Result = false, Errors = new List<string> { "Looks like there is an existing user!" } };
@ -169,7 +169,7 @@ namespace Ombi.Controllers.V1
ImportPlexAdmin = true
});
return await SaveWizardUser(user, adminUser);
return await SaveWizardUser(user, adminUser, false);
}
var userToCreate = new OmbiUser
@ -179,10 +179,10 @@ namespace Ombi.Controllers.V1
StreamingCountry = "US"
};
return await SaveWizardUser(user, userToCreate);
return await SaveWizardUser(user, userToCreate, true);
}
private async Task<SaveWizardResult> SaveWizardUser(CreateUserWizardModel user, OmbiUser userToCreate)
private async Task<SaveWizardResult> SaveWizardUser(CreateUserWizardModel user, OmbiUser userToCreate, bool completeWizard)
{
IdentityResult result;
var retVal = new SaveWizardResult();
@ -210,10 +210,13 @@ namespace Ombi.Controllers.V1
_log.LogInformation("Added the Admin role");
}
// Update the wizard flag
var settings = await OmbiSettings.GetSettingsAsync();
settings.Wizard = true;
await OmbiSettings.SaveSettingsAsync(settings);
if (completeWizard)
{
// Update the wizard flag
var settings = await OmbiSettings.GetSettingsAsync();
settings.Wizard = true;
await OmbiSettings.SaveSettingsAsync(settings);
}
}
if (!result.Succeeded)
{

@ -0,0 +1,54 @@
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Ombi.Attributes;
using Ombi.Core.Settings;
using Ombi.Helpers;
using Ombi.Models.V2;
using Ombi.Settings.Settings.Models;
using System.Threading.Tasks;
namespace Ombi.Controllers.V2
{
[ServiceFilter(typeof(WizardActionFilter))]
[AllowAnonymous]
public class WizardController : V2Controller
{
private ISettingsService<CustomizationSettings> _customizationSettings { get; }
public WizardController(ISettingsService<CustomizationSettings> customizationSettings)
{
_customizationSettings = customizationSettings;
}
[HttpPost("config")]
[ApiExplorerSettings(IgnoreApi =true)]
public async Task<IActionResult> OmbiConfig([FromBody] OmbiConfigModel config)
{
if (config == null)
{
return BadRequest();
}
var settings = await _customizationSettings.GetSettingsAsync();
if (config.ApplicationName.HasValue())
{
settings.ApplicationName = config.ApplicationName;
}
if(config.ApplicationUrl.HasValue())
{
settings.ApplicationUrl = config.ApplicationUrl;
}
if(config.Logo.HasValue())
{
settings.Logo = config.Logo;
}
await _customizationSettings.SaveSettingsAsync(settings);
return new OkObjectResult(settings);
}
}
}

@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Ombi.Models.V2
{
public class OmbiConfigModel
{
public string ApplicationName { get; set; }
public string ApplicationUrl { get; set; }
public string Logo { get; set; }
}
}

@ -30,6 +30,7 @@ using Newtonsoft.Json;
using ILogger = Serilog.ILogger;
using Microsoft.AspNetCore.Diagnostics.HealthChecks;
using Ombi.HealthChecks;
using Ombi.Attributes;
namespace Ombi
{
@ -97,6 +98,7 @@ namespace Ombi
services.RegisterApplicationDependencies(); // Ioc and EF
services.AddSwagger();
services.AddAppSettingsValues(Configuration);
services.AddScoped<WizardActionFilter>();
services.AddCors(o => o.AddPolicy("MyPolicy", builder =>
{

Loading…
Cancel
Save