Merge pull request #2332 from MattJeanes/feature/angular6-webpack4

[WIP] Update to Angular 6/Webpack 4
pull/2411/head
Jamie 6 years ago committed by GitHub
commit 9bc95d9ebb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -1,10 +1,10 @@
#tool "nuget:?package=GitVersion.CommandLine"
#addin "Cake.Gulp"
#addin "nuget:?package=Cake.Npm&version=0.13.0"
#addin "SharpZipLib"
#addin nuget:?package=Cake.Compression&version=0.1.4
#addin "Cake.Incubator"
#addin "Cake.Yarn"
//////////////////////////////////////////////////////////////////////
// ARGUMENTS
@ -122,36 +122,19 @@ Task("SetVersionInfo")
Task("NPM")
.Does(() => {
var settings = new NpmInstallSettings {
LogLevel = NpmLogLevel.Silent,
WorkingDirectory = webProjDir,
Production = true
};
NpmInstall(settings);
Yarn.FromPath(webProjDir).Install();
});
Task("Gulp Publish")
.IsDependentOn("NPM")
.Does(() => {
var runScriptSettings = new NpmRunScriptSettings {
ScriptName="publish",
WorkingDirectory = webProjDir,
};
NpmRunScript(runScriptSettings);
.Does(() => {
Yarn.FromPath(webProjDir).RunScript("publish");
});
Task("TSLint")
.Does(() =>
{
var settings = new NpmRunScriptSettings {
WorkingDirectory = webProjDir,
ScriptName = "lint"
};
NpmRunScript(settings);
Yarn.FromPath(webProjDir).RunScript("lint");
});
Task("PrePublish")

@ -29,7 +29,10 @@ namespace Ombi.Core.Tests.Rule.Search
{
ProviderId = "123"
});
var search = new SearchMovieViewModel();
var search = new SearchMovieViewModel()
{
TheMovieDbId = "123",
};
var result = await Rule.Execute(search);
Assert.True(result.Success);

@ -1,23 +1,10 @@
/wwwroot/css/**
/wwwroot/fonts/**
/wwwroot/lib/**
/wwwroot/maps/**
/wwwroot/dist/**
/wwwroot/*.js.map
/wwwroot/*.js
# dependencies
/node_modules
/bower_components
# misc
node_modules
bin
obj
wwwroot/dist
*.log
/.sass-cache
/connect.lock
/coverage/*
/libpeerconnection.log
npm-debug.log
testem.log
#/typings
/systemjs.config.js*
/Logs/**
**.db

@ -4,7 +4,7 @@
"version": "2.0.0",
"tasks": [
{
"taskName": "restore",
"label": "restore",
"command": "npm",
"type": "shell",
"args": [
@ -14,7 +14,16 @@
"problemMatcher": []
},
{
"taskName": "build",
"label": "clean",
"command": "dotnet",
"type": "shell",
"args": [
"clean"
],
"problemMatcher": "$msCompile"
},
{
"label": "build",
"command": "dotnet",
"type": "shell",
"args": [
@ -27,7 +36,7 @@
"problemMatcher": "$msCompile"
},
{
"taskName": "lint",
"label": "lint",
"type": "shell",
"command": "npm",
"args": [

@ -1,7 +1,7 @@
import { animate, style, transition, trigger } from "@angular/animations";
import { AnimationEntryMetadata } from "@angular/core";
import { AnimationTriggerMetadata } from "@angular/animations";
export const fadeInOutAnimation: AnimationEntryMetadata = trigger("fadeInOut", [
export const fadeInOutAnimation: AnimationTriggerMetadata = trigger("fadeInOut", [
transition(":enter", [ // :enter is alias to 'void => *'
style({ opacity: 0 }),
animate(1000, style({ opacity: 1 })),

@ -1,12 +1,12 @@
import {CommonModule, PlatformLocation} from "@angular/common";
import {HttpClient, HttpClientModule} from "@angular/common/http";
import {NgModule} from "@angular/core";
import {FormsModule, ReactiveFormsModule} from "@angular/forms";
import {HttpModule} from "@angular/http";
import {MatButtonModule, MatCardModule, MatInputModule, MatTabsModule} from "@angular/material";
import {BrowserModule} from "@angular/platform-browser";
import {BrowserAnimationsModule} from "@angular/platform-browser/animations";
import {RouterModule, Routes} from "@angular/router";
import { CommonModule, PlatformLocation } from "@angular/common";
import { HttpClient, HttpClientModule } from "@angular/common/http";
import { NgModule } from "@angular/core";
import { FormsModule, ReactiveFormsModule } from "@angular/forms";
import { HttpModule } from "@angular/http";
import { MatButtonModule, MatCardModule, MatInputModule, MatTabsModule } from "@angular/material";
import { BrowserModule } from "@angular/platform-browser";
import { BrowserAnimationsModule } from "@angular/platform-browser/animations";
import { RouterModule, Routes } from "@angular/router";
import { JwtModule } from "@auth0/angular-jwt";
@ -15,7 +15,7 @@ import { TranslateLoader, TranslateModule } from "@ngx-translate/core";
import { TranslateHttpLoader } from "@ngx-translate/http-loader";
import { CookieService } from "ng2-cookies";
import { GrowlModule } from "primeng/components/growl/growl";
import { ButtonModule, CaptchaModule, ConfirmationService, ConfirmDialogModule, DataTableModule,DialogModule, SharedModule, SidebarModule, TooltipModule } from "primeng/primeng";
import { ButtonModule, CaptchaModule, ConfirmationService, ConfirmDialogModule, DataTableModule, DialogModule, SharedModule, SidebarModule, TooltipModule } from "primeng/primeng";
// Components
import { AppComponent } from "./app.component";
@ -67,6 +67,14 @@ export function HttpLoaderFactory(http: HttpClient, platformLocation: PlatformLo
return new TranslateHttpLoader(http, "/translations/", `.json?v=${version}`);
}
export function JwtTokenGetter() {
const token = localStorage.getItem("id_token");
if (!token) {
return "";
}
return token;
}
@NgModule({
imports: [
RouterModule.forRoot(routes),
@ -89,18 +97,12 @@ export function HttpLoaderFactory(http: HttpClient, platformLocation: PlatformLo
CaptchaModule,
TooltipModule,
ConfirmDialogModule,
CommonModule,
CommonModule,
JwtModule.forRoot({
config: {
tokenGetter: () => {
const token = localStorage.getItem("id_token");
if (!token) {
return "";
}
return token;
},
tokenGetter: JwtTokenGetter,
},
}),
}),
TranslateModule.forRoot({
loader: {
provide: TranslateLoader,
@ -119,7 +121,7 @@ export function HttpLoaderFactory(http: HttpClient, platformLocation: PlatformLo
TokenResetPasswordComponent,
CookieComponent,
LoginOAuthComponent,
],
],
providers: [
NotificationService,
AuthService,

@ -1,8 +1,8 @@
import { PlatformLocation } from "@angular/common";
import { PlatformLocation } from "@angular/common";
import { HttpClient } from "@angular/common/http";
import { Injectable } from "@angular/core";
import { JwtHelperService } from "@auth0/angular-jwt";
import { Observable } from "rxjs/Rx";
import { Observable } from "rxjs";
import { ServiceHelpers } from "../services";
import { ILocalUser, IUserLogin } from "./IUserLogin";

@ -1,5 +1,5 @@
import { Component, OnInit } from "@angular/core";
import { NguCarousel } from "@ngu/carousel";
import { NguCarouselConfig } from "@ngu/carousel";
import { ImageService, RecentlyAddedService } from "../services";
import { IRecentlyAddedMovies, IRecentlyAddedTvShows } from "./../interfaces";
@ -43,7 +43,7 @@ export class RecentlyAddedComponent implements OnInit {
public groupTv: boolean = false;
// https://github.com/sheikalthaf/ngu-carousel
public carouselTile: NguCarousel;
public carouselTile: NguCarouselConfig;
constructor(private recentlyAddedService: RecentlyAddedService,
private imageService: ImageService) {}

@ -1,15 +1,12 @@
import { PlatformLocation } from "@angular/common";
import { PlatformLocation } from "@angular/common";
import { Component, Input, OnInit } from "@angular/core";
import { DomSanitizer } from "@angular/platform-browser";
import "rxjs/add/operator/debounceTime";
import "rxjs/add/operator/distinctUntilChanged";
import "rxjs/add/operator/map";
import { Subject } from "rxjs/Subject";
import { Subject } from "rxjs";
import { debounceTime, distinctUntilChanged } from "rxjs/operators";
import { AuthService } from "../auth/auth.service";
import { NotificationService, RadarrService, RequestService } from "../services";
import { FilterType, IFilter, IIssueCategory, IMovieRequests, IPagenator, IRadarrProfile, IRadarrRootFolder, OrderType } from "../interfaces";
import { NotificationService, RadarrService, RequestService } from "../services";
@Component({
selector: "movie-requests",
@ -40,32 +37,33 @@ export class MovieRequestsComponent implements OnInit {
public orderType: OrderType = OrderType.RequestedDateDesc;
public OrderType = OrderType;
public totalMovies: number = 100;
private currentlyLoaded: number;
private amountToLoad: number;
constructor(private requestService: RequestService,
private auth: AuthService,
private notificationService: NotificationService,
private radarrService: RadarrService,
private sanitizer: DomSanitizer,
private readonly platformLocation: PlatformLocation) {
this.searchChanged
.debounceTime(600) // Wait Xms after the last event before emitting last event
.distinctUntilChanged() // only emit if value is different from previous value
.subscribe(x => {
this.searchText = x as string;
if (this.searchText === "") {
this.resetSearch();
return;
}
this.requestService.searchMovieRequests(this.searchText)
.subscribe(m => {
this.setOverrides(m);
this.movieRequests = m;
});
});
constructor(
private requestService: RequestService,
private auth: AuthService,
private notificationService: NotificationService,
private radarrService: RadarrService,
private sanitizer: DomSanitizer,
private readonly platformLocation: PlatformLocation) {
this.searchChanged.pipe(
debounceTime(600), // Wait Xms after the last event before emitting last event
distinctUntilChanged(), // only emit if value is different from previous value
).subscribe(x => {
this.searchText = x as string;
if (this.searchText === "") {
this.resetSearch();
return;
}
this.requestService.searchMovieRequests(this.searchText)
.subscribe(m => {
this.setOverrides(m);
this.movieRequests = m;
});
});
this.defaultPoster = "../../../images/default_movie_poster.png";
const base = this.platformLocation.getBaseHrefFromDOM();
if (base) {
@ -75,7 +73,7 @@ export class MovieRequestsComponent implements OnInit {
public ngOnInit() {
this.amountToLoad = 10;
this.currentlyLoaded = 10;
this.currentlyLoaded = 10;
this.filter = {
availabilityFilter: FilterType.None,
statusFilter: FilterType.None,
@ -85,7 +83,7 @@ export class MovieRequestsComponent implements OnInit {
}
public paginate(event: IPagenator) {
const skipAmount = event.first;
const skipAmount = event.first;
this.loadRequests(this.amountToLoad, skipAmount);
}
@ -102,7 +100,7 @@ export class MovieRequestsComponent implements OnInit {
public changeAvailability(request: IMovieRequests, available: boolean) {
request.available = available;
if(available) {
if (available) {
this.requestService.markMovieAvailable({ id: request.id }).subscribe(x => {
if (x.result) {
this.notificationService.success(
@ -173,7 +171,7 @@ export class MovieRequestsComponent implements OnInit {
this.filterDisplay = false;
this.filter.availabilityFilter = FilterType.None;
this.filter.statusFilter = FilterType.None;
this.resetSearch();
}
@ -199,11 +197,11 @@ export class MovieRequestsComponent implements OnInit {
el.className = "active";
this.orderType = value;
this.loadInit();
}
public subscribe(request: IMovieRequests) {
}
public subscribe(request: IMovieRequests) {
request.subscribed = true;
this.requestService.subscribeToMovie(request.id)
.subscribe(x => {
@ -238,10 +236,10 @@ export class MovieRequestsComponent implements OnInit {
}
private loadRequests(amountToLoad: number, currentlyLoaded: number) {
this.requestService.getMovieRequests(amountToLoad, currentlyLoaded, this.orderType, this.filter)
this.requestService.getMovieRequests(amountToLoad, currentlyLoaded, this.orderType, this.filter)
.subscribe(x => {
this.setOverrides(x.collection);
if(!this.movieRequests) {
if (!this.movieRequests) {
this.movieRequests = [];
}
this.movieRequests = x.collection;
@ -364,6 +362,6 @@ export class MovieRequestsComponent implements OnInit {
private setBackground(req: IMovieRequests): void {
req.backgroundPath = this.sanitizer.bypassSecurityTrustStyle
("url(" + "https://image.tmdb.org/t/p/w1280" + req.background + ")");
("url(" + "https://image.tmdb.org/t/p/w1280" + req.background + ")");
}
}

@ -17,111 +17,111 @@
[infiniteScrollDistance]="1"
[infiniteScrollThrottle]="100"
(scrolled)="loadMore()">-->
<div>
<div>
<p-treeTable [value]="tvRequests">
<ng-template let-col let-node="rowData" pTemplate="header">
Results
</ng-template>
<ng-template let-col let-node="rowData" pTemplate="body">
<!--This is the section that holds the parent level results set-->
<div *ngIf="!node.leaf">
<div class="row">
<div class="myBg backdrop" [style.background-image]="node?.data?.background"></div>
<div class="tint" style="background-image: linear-gradient(to bottom, rgba(0,0,0,0.6) 0%,rgba(0,0,0,0.6) 100%);"></div>
<p-column>
<ng-template let-col let-node="rowData" pTemplate="header">
Results
</ng-template>
<ng-template let-col let-node="rowData" pTemplate="body">
<!--This is the section that holds the parent level results set-->
<div *ngIf="!node.leaf">
<div class="row">
<div class="myBg backdrop" [style.background-image]="node?.data?.background"></div>
<div class="tint" style="background-image: linear-gradient(to bottom, rgba(0,0,0,0.6) 0%,rgba(0,0,0,0.6) 100%);"></div>
<div class="col-sm-2 small-padding">
<div class="col-sm-2 small-padding" >
<img class="img-responsive poster" src="{{node.data.posterPath || null}}" alt="poster">
<img class="img-responsive poster" src="{{node.data.posterPath || null}}" alt="poster">
</div>
<div class="col-sm-5 small-padding">
<div>
<a href="http://www.imdb.com/title/{{node.data.imdbId}}/" target="_blank">
<h4 class="request-title">{{node.data.title}} ({{node.data.releaseDate | date: 'yyyy'}})</h4>
</a>
</div>
<br />
<div>
<span>Status: </span>
<span class="label label-success">{{node.data.status}}</span>
</div>
<div class="col-sm-5 small-padding">
<div>
<a href="http://www.imdb.com/title/{{node.data.imdbId}}/" target="_blank">
<h4 class="request-title">{{node.data.title}} ({{node.data.releaseDate | date: 'yyyy'}})</h4>
</a>
</div>
<br />
<div>
<span>Status: </span>
<span class="label label-success">{{node.data.status}}</span>
</div>
<div>Release Date: {{node.data.releaseDate | date}}</div>
<div *ngIf="isAdmin">
<div *ngIf="node.data.qualityOverrideTitle" class="quality-override">{{ 'Requests.QualityOverride' | translate }}
<span>{{node.data.qualityOverrideTitle}} </span>
</div>
<div *ngIf="node.data.rootPathOverrideTitle" class="root-override">{{ 'Requests.RootFolderOverride' | translate }}
<span>{{node.data.rootPathOverrideTitle}} </span>
</div>
<div>Release Date: {{node.data.releaseDate | date}}</div>
<div *ngIf="isAdmin">
<div *ngIf="node.data.qualityOverrideTitle" class="quality-override">{{ 'Requests.QualityOverride' | translate }}
<span>{{node.data.qualityOverrideTitle}} </span>
</div>
<div *ngIf="node.data.rootPathOverrideTitle" class="root-override">{{ 'Requests.RootFolderOverride' | translate }}
<span>{{node.data.rootPathOverrideTitle}} </span>
</div>
<br />
</div>
<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($event)"><i class="fa fa-plus"></i> View</button>
<div *ngIf="isAdmin">
<!--Sonarr Root Folder-->
<div *ngIf="sonarrRootFolders" 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 }}
</button>
<button type="button" class="btn btn-warning-outline dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<span class="caret"></span>
<span class="sr-only">Toggle Dropdown</span>
</button>
<ul class="dropdown-menu">
<li *ngFor="let folder of sonarrRootFolders">
<a href="#" (click)="selectRootFolder(node.data, folder, $event)">{{folder.path}}</a>
</li>
</ul>
</div>
<!--Sonarr Quality Profiles -->
<div *ngIf="sonarrProfiles" 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 }}
</button>
<button type="button" class="btn btn-warning-outline dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<span class="caret"></span>
<span class="sr-only">Toggle Dropdown</span>
</button>
<ul class="dropdown-menu">
<li *ngFor="let profile of sonarrProfiles">
<a href="#" (click)="selectQualityProfile(node.data, profile, $event)">{{profile.name}}</a>
</li>
</ul>
</div>
<br />
</div>
<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($event)">
<i class="fa fa-plus"></i> View</button>
<div *ngIf="isAdmin">
<!--Sonarr Root Folder-->
<div *ngIf="sonarrRootFolders" 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 }}
</button>
<button type="button" class="btn btn-warning-outline dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<span class="caret"></span>
<span class="sr-only">Toggle Dropdown</span>
</button>
<ul class="dropdown-menu">
<li *ngFor="let folder of sonarrRootFolders">
<a href="#" (click)="selectRootFolder(node.data, folder, $event)">{{folder.path}}</a>
</li>
</ul>
</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 }}
<!--Sonarr Quality Profiles -->
<div *ngIf="sonarrProfiles" 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 }}
</button>
<button type="button" class="btn btn-warning-outline dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<span class="caret"></span>
<span class="sr-only">Toggle Dropdown</span>
</button>
<ul class="dropdown-menu" aria-labelledby="dropdownMenu1">
<li *ngFor="let cat of issueCategories"><a [routerLink]="" (click)="reportIssue(cat, node.data)">{{cat.value}}</a></li>
<ul class="dropdown-menu">
<li *ngFor="let profile of sonarrProfiles">
<a href="#" (click)="selectQualityProfile(node.data, profile, $event)">{{profile.name}}</a>
</li>
</ul>
</div>
</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 }}
<span class="caret"></span>
</button>
<ul class="dropdown-menu" aria-labelledby="dropdownMenu1">
<li *ngFor="let cat of issueCategories">
<a [routerLink]="" (click)="reportIssue(cat, node.data)">{{cat.value}}</a>
</li>
</ul>
</div>
</div>
</div>
<!--This is the section that holds the child seasons if they want to specify specific episodes-->
<div *ngIf="node.leaf">
<tvrequests-children [childRequests]="node.data" [isAdmin] ="isAdmin"
(requestDeleted)="childRequestDeleted($event)"></tvrequests-children>
</div>
</ng-template>
</p-column>
</div>
<!--This is the section that holds the child seasons if they want to specify specific episodes-->
<div *ngIf="node.leaf">
<tvrequests-children [childRequests]="node.data" [isAdmin]="isAdmin" (requestDeleted)="childRequestDeleted($event)"></tvrequests-children>
</div>
</ng-template>
</p-treeTable>
<p-paginator [rows]="10" [totalRecords]="totalTv" (onPageChange)="paginate($event)"></p-paginator>
</div>
<issue-report [movie]="false" [visible]="issuesBarVisible" [title]="issueRequest?.title"
[issueCategory]="issueCategorySelected" [id]="issueRequest?.id" [providerId]="issueProviderId" (visibleChange)="issuesBarVisible = $event;"></issue-report>
<issue-report [movie]="false" [visible]="issuesBarVisible" [title]="issueRequest?.title" [issueCategory]="issueCategorySelected"
[id]="issueRequest?.id" [providerId]="issueProviderId" (visibleChange)="issuesBarVisible = $event;"></issue-report>

@ -1,21 +1,14 @@
import { PlatformLocation } from "@angular/common";
import { PlatformLocation } from "@angular/common";
import { Component, Input, OnInit } from "@angular/core";
import { DomSanitizer } from "@angular/platform-browser";
import "rxjs/add/operator/debounceTime";
import "rxjs/add/operator/distinctUntilChanged";
import "rxjs/add/operator/map";
import { Subject } from "rxjs/Subject";
import { ImageService } from "./../services/image.service";
import "rxjs/add/operator/debounceTime";
import "rxjs/add/operator/distinctUntilChanged";
import "rxjs/add/operator/map";
import { TreeNode } from "primeng/primeng";
import { Subject } from "rxjs";
import { debounceTime, distinctUntilChanged } from "rxjs/operators";
import { AuthService } from "../auth/auth.service";
import { IIssueCategory, IPagenator, ISonarrProfile, ISonarrRootFolder, ITvRequests } from "../interfaces";
import { NotificationService, RequestService, SonarrService } from "../services";
import { TreeNode } from "primeng/primeng";
import { IIssueCategory, IPagenator, ISonarrProfile, ISonarrRootFolder, ITvRequests } from "../interfaces";
import { ImageService } from "./../services/image.service";
@Component({
selector: "tv-requests",
@ -46,29 +39,30 @@ export class TvRequestsComponent implements OnInit {
private currentlyLoaded: number;
private amountToLoad: number;
constructor(private requestService: RequestService,
private auth: AuthService,
private sanitizer: DomSanitizer,
private imageService: ImageService,
private sonarrService: SonarrService,
private notificationService: NotificationService,
private readonly platformLocation: PlatformLocation) {
this.searchChanged
.debounceTime(600) // Wait Xms after the last event before emitting last event
.distinctUntilChanged() // only emit if value is different from previous value
.subscribe(x => {
this.searchText = x as string;
if (this.searchText === "") {
this.resetSearch();
return;
}
this.requestService.searchTvRequestsTree(this.searchText)
.subscribe(m => {
this.tvRequests = m;
this.tvRequests.forEach((val) => this.loadBackdrop(val));
this.tvRequests.forEach((val) => this.setOverride(val.data));
});
});
constructor(
private requestService: RequestService,
private auth: AuthService,
private sanitizer: DomSanitizer,
private imageService: ImageService,
private sonarrService: SonarrService,
private notificationService: NotificationService,
private readonly platformLocation: PlatformLocation) {
this.searchChanged.pipe(
debounceTime(600), // Wait Xms after the last event before emitting last event
distinctUntilChanged(), // only emit if value is different from previous value
).subscribe(x => {
this.searchText = x as string;
if (this.searchText === "") {
this.resetSearch();
return;
}
this.requestService.searchTvRequestsTree(this.searchText)
.subscribe(m => {
this.tvRequests = m;
this.tvRequests.forEach((val) => this.loadBackdrop(val));
this.tvRequests.forEach((val) => this.setOverride(val.data));
});
});
this.defaultPoster = "../../../images/default_tv_poster.png";
const base = this.platformLocation.getBaseHrefFromDOM();
if (base) {
@ -118,7 +112,7 @@ export class TvRequestsComponent implements OnInit {
this.currentlyLoaded = 10;
this.tvRequests = [];
this.isAdmin = this.auth.hasRole("admin") || this.auth.hasRole("poweruser");
this.loadInit();
}
@ -126,10 +120,10 @@ export class TvRequestsComponent implements OnInit {
const skipAmount = event.first;
this.requestService.getTvRequestsTree(this.amountToLoad, skipAmount)
.subscribe(x => {
this.tvRequests = x;
this.currentlyLoaded = this.currentlyLoaded + this.amountToLoad;
});
.subscribe(x => {
this.tvRequests = x;
this.currentlyLoaded = this.currentlyLoaded + this.amountToLoad;
});
}
public search(text: any) {
@ -211,13 +205,13 @@ export class TvRequestsComponent implements OnInit {
this.setDefaults(val);
this.loadBackdrop(val);
this.setOverride(val.data);
});
});
});
});
if(this.isAdmin) {
if (this.isAdmin) {
this.sonarrService.getQualityProfilesWithoutSettings()
.subscribe(x => this.sonarrProfiles = x);
this.sonarrService.getRootFoldersWithoutSettings()
.subscribe(x => this.sonarrRootFolders = x);
}
@ -240,9 +234,9 @@ export class TvRequestsComponent implements OnInit {
("url(https://image.tmdb.org/t/p/w1280" + val.data.background + ")");
} else {
this.imageService.getTvBanner(val.data.tvDbId).subscribe(x => {
if(x) {
if (x) {
val.data.background = this.sanitizer.bypassSecurityTrustStyle
("url(" + x + ")");
("url(" + x + ")");
}
});
}

@ -1,11 +1,9 @@
import { PlatformLocation } from "@angular/common";
import { PlatformLocation } from "@angular/common";
import { Component, Input, OnInit } from "@angular/core";
import { DomSanitizer } from "@angular/platform-browser";
import { TranslateService } from "@ngx-translate/core";
import "rxjs/add/operator/debounceTime";
import "rxjs/add/operator/distinctUntilChanged";
import "rxjs/add/operator/map";
import { Subject } from "rxjs/Subject";
import { Subject } from "rxjs";
import { debounceTime, distinctUntilChanged } from "rxjs/operators";
import { AuthService } from "../auth/auth.service";
import { IIssueCategory, IRequestEngineResult, ISearchMovieResult } from "../interfaces";
@ -22,7 +20,7 @@ export class MovieSearchComponent implements OnInit {
public movieResults: ISearchMovieResult[];
public result: IRequestEngineResult;
public searchApplied = false;
@Input() public issueCategories: IIssueCategory[];
@Input() public issuesEnabled: boolean;
public issuesBarVisible = false;
@ -31,30 +29,31 @@ export class MovieSearchComponent implements OnInit {
public issueProviderId: string;
public issueCategorySelected: IIssueCategory;
public defaultPoster: string;
constructor(private searchService: SearchService, private requestService: RequestService,
private notificationService: NotificationService, private authService: AuthService,
private readonly translate: TranslateService, private sanitizer: DomSanitizer,
private readonly platformLocation: PlatformLocation) {
this.searchChanged
.debounceTime(600) // Wait Xms after the last event before emitting last event
.distinctUntilChanged() // only emit if value is different from previous value
.subscribe(x => {
this.searchText = x as string;
if (this.searchText === "") {
this.clearResults();
return;
}
this.searchService.searchMovie(this.searchText)
.subscribe(x => {
this.movieResults = x;
this.searchApplied = true;
// Now let's load some extra info including IMDB Id
// This way the search is fast at displaying results.
this.getExtraInfo();
});
});
constructor(
private searchService: SearchService, private requestService: RequestService,
private notificationService: NotificationService, private authService: AuthService,
private readonly translate: TranslateService, private sanitizer: DomSanitizer,
private readonly platformLocation: PlatformLocation) {
this.searchChanged.pipe(
debounceTime(600), // Wait Xms after the last event before emitting last event
distinctUntilChanged(), // only emit if value is different from previous value
).subscribe(x => {
this.searchText = x as string;
if (this.searchText === "") {
this.clearResults();
return;
}
this.searchService.searchMovie(this.searchText)
.subscribe(x => {
this.movieResults = x;
this.searchApplied = true;
// Now let's load some extra info including IMDB Id
// This way the search is fast at displaying results.
this.getExtraInfo();
});
});
this.defaultPoster = "../../../images/default_movie_poster.png";
const base = this.platformLocation.getBaseHrefFromDOM();
if (base) {
@ -105,7 +104,7 @@ export class MovieSearchComponent implements OnInit {
searchResult.approved = false;
searchResult.processed = false;
searchResult.requestProcessing = false;
}
});
} catch (e) {
@ -160,12 +159,12 @@ export class MovieSearchComponent implements OnInit {
public similarMovies(theMovieDbId: number) {
this.clearResults();
this.searchService.similarMovies(theMovieDbId)
.subscribe(x => {
this.movieResults = x;
this.getExtraInfo();
});
.subscribe(x => {
this.movieResults = x;
this.getExtraInfo();
});
}
public subscribe(r: ISearchMovieResult) {
r.subscribed = true;
this.requestService.subscribeToMovie(r.requestId)
@ -182,17 +181,17 @@ export class MovieSearchComponent implements OnInit {
});
}
private getExtraInfo() {
this.movieResults.forEach((val, index) => {
if (val.posterPath === null) {
val.posterPath = this.defaultPoster;
} else {
val.posterPath = "https://image.tmdb.org/t/p/w300/" + val.posterPath;
}
val.background = this.sanitizer.bypassSecurityTrustStyle
("url(" + "https://image.tmdb.org/t/p/w1280" + val.backdropPath + ")");
this.searchService.getMovieInformation(val.id)
private getExtraInfo() {
this.movieResults.forEach((val, index) => {
if (val.posterPath === null) {
val.posterPath = this.defaultPoster;
} else {
val.posterPath = "https://image.tmdb.org/t/p/w300/" + val.posterPath;
}
val.background = this.sanitizer.bypassSecurityTrustStyle
("url(" + "https://image.tmdb.org/t/p/w1280" + val.backdropPath + ")");
this.searchService.getMovieInformation(val.id)
.subscribe(m => {
this.updateItem(val, m);
});
@ -203,7 +202,7 @@ export class MovieSearchComponent implements OnInit {
const index = this.movieResults.indexOf(key, 0);
if (index > -1) {
const copy = { ...this.movieResults[index] };
this.movieResults[index] = updated;
this.movieResults[index] = updated;
this.movieResults[index].background = copy.background;
this.movieResults[index].posterPath = copy.posterPath;
}

@ -1,13 +1,10 @@
import { Component, OnInit } from "@angular/core";
import "rxjs/add/operator/debounceTime";
import "rxjs/add/operator/distinctUntilChanged";
import "rxjs/add/operator/map";
import { Subject } from "rxjs/Subject";
import { Component, OnInit } from "@angular/core";
import { Subject } from "rxjs";
import { debounceTime, distinctUntilChanged } from "rxjs/operators";
import { AuthService } from "../auth/auth.service";
import { NotificationService, RequestService, SearchService } from "../services";
import { IRequestEngineResult, ISearchMovieResult, ISearchMovieResultContainer } from "../interfaces";
import { NotificationService, RequestService, SearchService } from "../services";
@Component({
selector: "movie-search-grid",
@ -21,28 +18,29 @@ export class MovieSearchGridComponent implements OnInit {
public movieResultGrid: ISearchMovieResultContainer[] = [];
public result: IRequestEngineResult;
public searchApplied = false;
constructor(private searchService: SearchService, private requestService: RequestService,
private notificationService: NotificationService, private authService: AuthService) {
this.searchChanged
.debounceTime(600) // Wait Xms afterthe last event before emitting last event
.distinctUntilChanged() // only emit if value is different from previous value
.subscribe(x => {
this.searchText = x as string;
if (this.searchText === "") {
this.clearResults();
return;
}
this.searchService.searchMovie(this.searchText)
.subscribe(x => {
this.movieResults = x;
this.searchApplied = true;
// Now let's load some exta info including IMDBId
// This way the search is fast at displaying results.
this.getExtaInfo();
});
});
constructor(
private searchService: SearchService, private requestService: RequestService,
private notificationService: NotificationService, private authService: AuthService) {
this.searchChanged.pipe(
debounceTime(600), // Wait Xms afterthe last event before emitting last event
distinctUntilChanged(), // only emit if value is different from previous value
).subscribe(x => {
this.searchText = x as string;
if (this.searchText === "") {
this.clearResults();
return;
}
this.searchService.searchMovie(this.searchText)
.subscribe(x => {
this.movieResults = x;
this.searchApplied = true;
// Now let's load some exta info including IMDBId
// This way the search is fast at displaying results.
this.getExtaInfo();
});
});
}
public ngOnInit() {
@ -67,7 +65,7 @@ export class MovieSearchGridComponent implements OnInit {
}
try {
this.requestService.requestMovie({ theMovieDbId : searchResult.id})
this.requestService.requestMovie({ theMovieDbId: searchResult.id })
.subscribe(x => {
this.result = x;
@ -129,7 +127,7 @@ export class MovieSearchGridComponent implements OnInit {
});
}
private getExtaInfo() {
private getExtaInfo() {
this.movieResults.forEach((val) => {
this.searchService.getMovieInformation(val.id)
.subscribe(m => this.updateItem(val, m));
@ -147,18 +145,18 @@ export class MovieSearchGridComponent implements OnInit {
this.movieResults = [];
this.searchApplied = false;
}
private processGrid(movies: ISearchMovieResult[]) {
let container = <ISearchMovieResultContainer>{ movies: [] };
movies.forEach((movie, i) => {
i++;
if((i % 4) === 0) {
container.movies.push(movie);
if ((i % 4) === 0) {
container.movies.push(movie);
this.movieResultGrid.push(container);
container = <ISearchMovieResultContainer>{ movies: [] };
} else {
container.movies.push(movie);
container.movies.push(movie);
}
});
this.movieResultGrid.push(container);

@ -1,5 +1,4 @@
import { Component, Input, OnInit} from "@angular/core";
import "rxjs/add/operator/takeUntil";
import { NotificationService } from "../services";
import { RequestService } from "../services";

@ -5,7 +5,7 @@
<div class="input-group-addon right-radius">
<div class="btn-group">
<a href="#" class="btn btn-sm btn-primary-outline dropdown-toggle" data-toggle="dropdown" aria-expanded="false">
{{ 'Search.Suggestions' | translate }}
{{ 'Search.Suggestions' | translate }}
<i class="fa fa-chevron-down"></i>
</a>
<ul class="dropdown-menu">
@ -43,33 +43,36 @@
<div class='no-search-results-text'>{{ 'Search.NoResults' | translate }}</div>
</div>
<p-treeTable [value]="tvResults">
<p-column>
<ng-template let-col let-node="rowData" pTemplate="header">
{{ 'Search.TvShows.Results' | translate }}
</ng-template>
<ng-template let-col let-node="rowData" pTemplate="body">
<!--This is the section that holds the parent level search results set-->
<div *ngIf="!node.leaf">
<div class="row" >
<div class="myBg backdrop" [style.background-image]="node?.data?.background"></div>
<div class="tint" style="background-image: linear-gradient(to bottom, rgba(0,0,0,0.6) 0%,rgba(0,0,0,0.6) 100%);"></div>
<div class="col-sm-2 small-padding">
<img *ngIf="node?.data?.banner" class="img-responsive poster" width="150" [src]="node.data.banner" alt="poster">
<ng-template let-col let-node="rowData" pTemplate="header">
{{ 'Search.TvShows.Results' | translate }}
</ng-template>
<ng-template let-col let-node="rowData" pTemplate="body">
<!--This is the section that holds the parent level search results set-->
<div *ngIf="!node.leaf">
<div class="row">
</div>
<div class="col-sm-8 small-padding">
<div>
<div class="myBg backdrop" [style.background-image]="node?.data?.background"></div>
<div class="tint" style="background-image: linear-gradient(to bottom, rgba(0,0,0,0.6) 0%,rgba(0,0,0,0.6) 100%);"></div>
<div class="col-sm-2 small-padding">
<img *ngIf="node?.data?.banner" class="img-responsive poster" width="150" [src]="node.data.banner" alt="poster">
</div>
<div class="col-sm-8 small-padding">
<div>
<a *ngIf="node.data.imdbId" href="{{node.data.imdbId}}" target="_blank">
<h4>{{node.data.title}} ({{node.data.firstAired | date: 'yyyy'}})</h4>
<a *ngIf="node.data.imdbId" href="{{node.data.imdbId}}" target="_blank">
<h4>{{node.data.title}} ({{node.data.firstAired | date: 'yyyy'}})</h4>
</a>
<span class="tags">
<a *ngIf="node.data.homepage" id="homepageLabel" href="{{node.data.homepage}}" target="_blank">
<span class="label label-info">{{ 'Search.Movies.HomePage' | translate }}</span>
</a>
<a *ngIf="node.data.trailer" id="trailerLabel" href="{{node.data.trailer}}" target="_blank">
<span class="label label-info">{{ 'Search.Movies.Trailer' | translate }}</span>
</a>
<span class="tags">
<a *ngIf="node.data.homepage" id="homepageLabel" href="{{node.data.homepage}}" target="_blank"><span class="label label-info" >{{ 'Search.Movies.HomePage' | translate }}</span></a>
<a *ngIf="node.data.trailer" id="trailerLabel" href="{{node.data.trailer}}" target="_blank"><span class="label label-info">{{ 'Search.Movies.Trailer' | translate }}</span></a>
<span *ngIf="node.data.status" class="label label-primary" id="statusLabel" target="_blank">{{node.data.status}}</span>
@ -78,92 +81,89 @@
<span *ngIf="node.data.network" class="label label-info" id="networkLabel" target="_blank">{{node.data.network}}</span>
<span *ngIf="node.data.available" class="label label-success" id="availableLabel">{{ 'Common.Available' | translate }}</span>
<span *ngIf="node.data.partlyAvailable" class="label label-warning" id="partiallyAvailableLabel">{{ 'Common.PartlyAvailable' | translate }}</span>
<span *ngIf="node.data.available" class="label label-success" id="availableLabel">{{ 'Common.Available' | translate }}</span>
<span *ngIf="node.data.partlyAvailable" class="label label-warning" id="partiallyAvailableLabel">{{ 'Common.PartlyAvailable' | translate }}</span>
</span>
<br />
<br />
</div>
<p class="tv-overview">{{node.data.overview}}</p>
<br />
<br />
</div>
<p class="tv-overview">{{node.data.overview}}</p>
</div>
<div class="col-sm-2 small-padding">
<div *ngIf="!node.data.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 }}
<span class="caret"></span>
</button>
<ul class="dropdown-menu" aria-labelledby="dropdownMenu1">
<li>
<a href="#" (click)="allSeasons(node.data, $event)">{{ 'Search.TvShows.AllSeasons' | translate }}</a>
</li>
<li>
<a href="#" (click)="firstSeason(node.data, $event)">{{ 'Search.TvShows.FirstSeason' | translate }}</a>
</li>
<li>
<a href="#" (click)="latestSeason(node.data, $event)">{{ 'Search.TvShows.LatestSeason' | translate }}</a>
</li>
<li>
<a href="#" (click)="openClosestTab($event)">{{ 'Search.TvShows.Select' | translate }}</a>
</li>
</ul>
</div>
<div *ngIf="node.data.fullyAvailable">
<button style="text-align: right" class="btn btn-success-outline disabled" disabled>
<i class="fa fa-check"></i> {{ 'Common.Available' | translate }}
</button>
</div>
<br />
<div *ngIf="node.data.plexUrl && node.data.available">
<a style="text-align: right" class="btn btn-sm btn-success-outline" href="{{node.data.plexUrl}}"
target="_blank">
<i class="fa fa-eye"></i> {{ 'Search.ViewOnPlex' | translate }}
</a>
</div>
<div *ngIf="node.data.embyUrl && node.data.available">
<a style="text-align: right" id="embybtn" class="btn btn-sm btn-success-outline" href="{{node.data.embyUrl}}"
target="_blank">
<i class="fa fa-eye"></i> {{ 'Search.ViewOnEmby' | 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 }}
<span class="caret"></span>
</button>
<ul class="dropdown-menu" aria-labelledby="dropdownMenu1">
<li *ngFor="let cat of issueCategories">
<a [routerLink]="" (click)="reportIssue(cat, node.data)">{{cat.value}}</a>
</li>
</ul>
</div>
<div *ngIf="!node.data.available">
<br />
<br />
</div>
<div class="col-sm-2 small-padding">
<div *ngIf="!node.data.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 }}
<span class="caret"></span>
</button>
<ul class="dropdown-menu" aria-labelledby="dropdownMenu1">
<li>
<a href="#" (click)="allSeasons(node.data, $event)">{{ 'Search.TvShows.AllSeasons' | translate }}</a>
</li>
<li>
<a href="#" (click)="firstSeason(node.data, $event)">{{ 'Search.TvShows.FirstSeason' | translate }}</a>
</li>
<li>
<a href="#" (click)="latestSeason(node.data, $event)">{{ 'Search.TvShows.LatestSeason' | translate }}</a>
</li>
<li>
<a href="#" (click)="openClosestTab($event)">{{ 'Search.TvShows.Select' | translate }}</a>
</li>
</ul>
</div>
<div *ngIf="node.data.fullyAvailable">
<button style="text-align: right" class="btn btn-success-outline disabled" disabled>
<i class="fa fa-check"></i> {{ 'Common.Available' | translate }}
</button>
</div>
<br />
<div *ngIf="node.data.plexUrl && node.data.available">
<a style="text-align: right" class="btn btn-sm btn-success-outline" href="{{node.data.plexUrl}}" target="_blank">
<i class="fa fa-eye"></i> {{ 'Search.ViewOnPlex' | translate }}
</a>
</div>
<div *ngIf="node.data.embyUrl && node.data.available">
<a style="text-align: right" id="embybtn" class="btn btn-sm btn-success-outline" href="{{node.data.embyUrl}}" target="_blank">
<i class="fa fa-eye"></i> {{ 'Search.ViewOnEmby' | 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 }}
<span class="caret"></span>
</button>
<ul class="dropdown-menu" aria-labelledby="dropdownMenu1">
<li *ngFor="let cat of issueCategories">
<a [routerLink]="" (click)="reportIssue(cat, node.data)">{{cat.value}}</a>
</li>
</ul>
</div>
<div *ngIf="!node.data.available">
<br />
<br />
</div>
</div>
</div>
<!--This is the section that holds the child seasons if they want to specify specific episodes-->
<div *ngIf="node.leaf">
<seriesinformation [seriesId]="node.data.id"></seriesinformation>
</div>
<br/>
<br/>
</ng-template>
</p-column>
</div>
</div>
<!--This is the section that holds the child seasons if they want to specify specific episodes-->
<div *ngIf="node.leaf">
<seriesinformation [seriesId]="node.data.id"></seriesinformation>
</div>
<br/>
<br/>
</ng-template>
</p-treeTable>
</div>
</div>

@ -1,15 +1,14 @@
import { PlatformLocation } from "@angular/common";
import { PlatformLocation } from "@angular/common";
import { Component, Input, OnInit } from "@angular/core";
import { DomSanitizer } from "@angular/platform-browser";
import { Subject } from "rxjs/Subject";
import { TreeNode } from "primeng/primeng";
import { Subject } from "rxjs";
import { debounceTime, distinctUntilChanged } from "rxjs/operators";
import { AuthService } from "../auth/auth.service";
import { IIssueCategory, IRequestEngineResult, ISearchTvResult, ISeasonsViewModel, ITvRequestViewModel } from "../interfaces";
import { ImageService, NotificationService, RequestService, SearchService } from "../services";
import { TreeNode } from "primeng/primeng";
import { IRequestEngineResult } from "../interfaces";
import { IIssueCategory, ISearchTvResult, ISeasonsViewModel, ITvRequestViewModel } from "../interfaces";
@Component({
selector: "tv-search",
templateUrl: "./tvsearch.component.html",
@ -32,30 +31,31 @@ export class TvSearchComponent implements OnInit {
public issueProviderId: string;
public issueCategorySelected: IIssueCategory;
constructor(private searchService: SearchService, private requestService: RequestService,
private notificationService: NotificationService, private authService: AuthService,
private imageService: ImageService, private sanitizer: DomSanitizer,
private readonly platformLocation: PlatformLocation) {
constructor(
private searchService: SearchService, private requestService: RequestService,
private notificationService: NotificationService, private authService: AuthService,
private imageService: ImageService, private sanitizer: DomSanitizer,
private readonly platformLocation: PlatformLocation) {
this.searchChanged
.debounceTime(600) // Wait Xms after the last event before emitting last event
.distinctUntilChanged() // only emit if value is different from previous value
.subscribe(x => {
this.searchText = x as string;
if (this.searchText === "") {
this.clearResults();
return;
}
this.searchService.searchTvTreeNode(this.searchText)
.subscribe(x => {
this.tvResults = x;
this.searchApplied = true;
this.getExtraInfo();
});
});
this.searchChanged.pipe(
debounceTime(600), // Wait Xms after the last event before emitting last event
distinctUntilChanged(), // only emit if value is different from previous value
).subscribe(x => {
this.searchText = x as string;
if (this.searchText === "") {
this.clearResults();
return;
}
this.searchService.searchTvTreeNode(this.searchText)
.subscribe(x => {
this.tvResults = x;
this.searchApplied = true;
this.getExtraInfo();
});
});
this.defaultPoster = "../../../images/default_tv_poster.png";
const base = this.platformLocation.getBaseHrefFromDOM();
if(base) {
if (base) {
this.defaultPoster = "../../.." + base + "/images/default_tv_poster.png";
}
}
@ -91,7 +91,7 @@ export class TvSearchComponent implements OnInit {
this.result = {
message: "",
result: false,
errorMessage:"",
errorMessage: "",
};
this.popularShows();
}
@ -139,10 +139,10 @@ export class TvSearchComponent implements OnInit {
public getExtraInfo() {
this.tvResults.forEach((val, index) => {
this.imageService.getTvBanner(val.data.id).subscribe(x => {
if(x) {
if (x) {
val.data.background = this.sanitizer.
bypassSecurityTrustStyle
("url(" + x + ")");
bypassSecurityTrustStyle
("url(" + x + ")");
}
});
this.searchService.getShowInformationTreeNode(val.data.id)
@ -165,19 +165,19 @@ export class TvSearchComponent implements OnInit {
if (this.authService.hasRole("admin") || this.authService.hasRole("AutoApproveMovie")) {
searchResult.approved = true;
}
const viewModel = <ITvRequestViewModel>{ firstSeason: searchResult.firstSeason, latestSeason: searchResult.latestSeason, requestAll: searchResult.requestAll, tvDbId: searchResult.id};
const viewModel = <ITvRequestViewModel>{ firstSeason: searchResult.firstSeason, latestSeason: searchResult.latestSeason, requestAll: searchResult.requestAll, tvDbId: searchResult.id };
viewModel.seasons = [];
searchResult.seasonRequests.forEach((season) => {
const seasonsViewModel = <ISeasonsViewModel>{seasonNumber: season.seasonNumber, episodes: []};
const seasonsViewModel = <ISeasonsViewModel>{ seasonNumber: season.seasonNumber, episodes: [] };
season.episodes.forEach(ep => {
if(!searchResult.latestSeason || !searchResult.requestAll || !searchResult.firstSeason) {
if(ep.requested) {
seasonsViewModel.episodes.push({episodeNumber: ep.episodeNumber});
if (!searchResult.latestSeason || !searchResult.requestAll || !searchResult.firstSeason) {
if (ep.requested) {
seasonsViewModel.episodes.push({ episodeNumber: ep.episodeNumber });
}
}
});
viewModel.seasons.push(seasonsViewModel);
});

@ -1,7 +1,7 @@
import { PlatformLocation } from "@angular/common";
import { PlatformLocation } from "@angular/common";
import { HttpClient } from "@angular/common/http";
import { Injectable } from "@angular/core";
import { Observable } from "rxjs/Rx";
import { Observable } from "rxjs";
import { ServiceHelpers } from "../service.helpers";

@ -1,7 +1,7 @@
import { PlatformLocation } from "@angular/common";
import { PlatformLocation } from "@angular/common";
import { HttpClient } from "@angular/common/http";
import { Injectable } from "@angular/core";
import { Observable } from "rxjs/Rx";
import { Observable } from "rxjs";
import { ServiceHelpers } from "../service.helpers";

@ -1,8 +1,8 @@
import { PlatformLocation } from "@angular/common";
import { PlatformLocation } from "@angular/common";
import { HttpClient } from "@angular/common/http";
import { Injectable } from "@angular/core";
import { Observable } from "rxjs/Rx";
import { Observable } from "rxjs";
import { ServiceHelpers } from "../service.helpers";

@ -1,8 +1,8 @@
import { PlatformLocation } from "@angular/common";
import { PlatformLocation } from "@angular/common";
import { HttpClient } from "@angular/common/http";
import { Injectable } from "@angular/core";
import { Observable } from "rxjs/Rx";
import { Observable } from "rxjs";
import { ServiceHelpers } from "../service.helpers";

@ -1,7 +1,7 @@
import { PlatformLocation } from "@angular/common";
import { PlatformLocation } from "@angular/common";
import { HttpClient } from "@angular/common/http";
import { Injectable } from "@angular/core";
import { Observable } from "rxjs/Rx";
import { Observable } from "rxjs";
import { IRadarrProfile, IRadarrRootFolder } from "../../interfaces";
import { IRadarrSettings } from "../../interfaces";

@ -1,8 +1,8 @@
import { PlatformLocation } from "@angular/common";
import { PlatformLocation } from "@angular/common";
import { Injectable } from "@angular/core";
import { HttpClient } from "@angular/common/http";
import { Observable } from "rxjs/Rx";
import { Observable } from "rxjs";
import { ISonarrSettings } from "../../interfaces";
import { ISonarrProfile, ISonarrRootFolder } from "../../interfaces";

@ -1,8 +1,8 @@
import { PlatformLocation } from "@angular/common";
import { PlatformLocation } from "@angular/common";
import { Injectable } from "@angular/core";
import { HttpClient } from "@angular/common/http";
import { Observable } from "rxjs/Rx";
import { Observable } from "rxjs";
import { ServiceHelpers } from "../service.helpers";

@ -1,8 +1,8 @@
import { PlatformLocation } from "@angular/common";
import { PlatformLocation } from "@angular/common";
import { Injectable } from "@angular/core";
import { HttpClient } from "@angular/common/http";
import { Observable } from "rxjs/Rx";
import { Observable } from "rxjs";
import { ICheckbox, ICreateWizardUser, IIdentityResult, IResetPasswordToken, IUpdateLocalUser, IUser } from "../interfaces";
import { ServiceHelpers } from "./service.helpers";

@ -1,6 +1,6 @@
import { PlatformLocation } from "@angular/common";
import { PlatformLocation } from "@angular/common";
import { Injectable } from "@angular/core";
import { Observable } from "rxjs/Rx";
import { Observable } from "rxjs";
import { HttpClient } from "@angular/common/http";

@ -1,8 +1,8 @@
import { PlatformLocation } from "@angular/common";
import { PlatformLocation } from "@angular/common";
import { Injectable } from "@angular/core";
import { HttpClient } from "@angular/common/http";
import { Observable } from "rxjs/Rx";
import { Observable } from "rxjs";
import { IIssueCategory, IIssueComments,IIssueCount, IIssues, IIssuesChat, INewIssueComments, IssueStatus, IUpdateStatus } from "../interfaces";
import { ServiceHelpers } from "./service.helpers";

@ -1,8 +1,8 @@
import { PlatformLocation } from "@angular/common";
import { PlatformLocation } from "@angular/common";
import { Injectable } from "@angular/core";
import { HttpClient } from "@angular/common/http";
import { Observable } from "rxjs/Rx";
import { Observable } from "rxjs";
import { ServiceHelpers } from "./service.helpers";

@ -1,6 +1,6 @@
import { PlatformLocation } from "@angular/common";
import { PlatformLocation } from "@angular/common";
import { Injectable } from "@angular/core";
import { Observable } from "rxjs/Rx";
import { Observable } from "rxjs";
import { HttpClient } from "@angular/common/http";

@ -1,8 +1,8 @@
import { PlatformLocation } from "@angular/common";
import { PlatformLocation } from "@angular/common";
import { Injectable } from "@angular/core";
import { HttpClient } from "@angular/common/http";
import { Observable } from "rxjs/Rx";
import { Observable } from "rxjs";
import { IMobileUsersViewModel } from "./../interfaces";
import { ServiceHelpers } from "./service.helpers";

@ -1,8 +1,8 @@
import { PlatformLocation } from "@angular/common";
import { PlatformLocation } from "@angular/common";
import { Injectable } from "@angular/core";
import { HttpClient } from "@angular/common/http";
import { Observable } from "rxjs/Rx";
import { Observable } from "rxjs";
import { IMassEmailModel } from "./../interfaces";

@ -1,8 +1,8 @@
import { PlatformLocation } from "@angular/common";
import { PlatformLocation } from "@angular/common";
import { Injectable } from "@angular/core";
import { HttpClient } from "@angular/common/http";
import { Observable } from "rxjs/Rx";
import { Observable } from "rxjs";
import { IRecentlyAddedMovies, IRecentlyAddedTvShows } from "./../interfaces";
import { ServiceHelpers } from "./service.helpers";

@ -1,8 +1,8 @@
import { PlatformLocation } from "@angular/common";
import { PlatformLocation } from "@angular/common";
import { Injectable } from "@angular/core";
import { HttpClient } from "@angular/common/http";
import { Observable } from "rxjs/Rx";
import { Observable } from "rxjs";
import { TreeNode } from "primeng/primeng";
import { IRequestEngineResult } from "../interfaces";

@ -1,8 +1,8 @@
import { PlatformLocation } from "@angular/common";
import { PlatformLocation } from "@angular/common";
import { Injectable } from "@angular/core";
import { HttpClient } from "@angular/common/http";
import { Observable } from "rxjs/Rx";
import { Observable } from "rxjs";
import { TreeNode } from "primeng/primeng";
import { ISearchMovieResult } from "../interfaces";

@ -1,6 +1,5 @@
import { PlatformLocation } from "@angular/common";
import { HttpClient, HttpHeaders } from "@angular/common/http";
import "rxjs/add/observable/throw";
export class ServiceHelpers {

@ -1,7 +1,7 @@
import { PlatformLocation } from "@angular/common";
import { PlatformLocation } from "@angular/common";
import { HttpClient } from "@angular/common/http";
import { Injectable } from "@angular/core";
import { Observable } from "rxjs/Rx";
import { Observable } from "rxjs";
import {
IAbout,

@ -1,8 +1,8 @@
import { PlatformLocation } from "@angular/common";
import { PlatformLocation } from "@angular/common";
import { Injectable } from "@angular/core";
import { HttpClient } from "@angular/common/http";
import { Observable } from "rxjs/Rx";
import { Observable } from "rxjs";
import { ServiceHelpers } from "./service.helpers";

@ -1,10 +1,8 @@
import { Component, OnDestroy, OnInit } from "@angular/core";
import "rxjs/add/operator/takeUntil";
import { Subject } from "rxjs/Subject";
import { IPlexServerResponse, IPlexServerViewModel } from "../../interfaces";
import { IPlexLibrariesSettings, IPlexServer, IPlexSettings } from "../../interfaces";
import { Component, OnDestroy, OnInit } from "@angular/core";
import { Subject } from "rxjs";
import { takeUntil } from "rxjs/operators";
import { IPlexLibrariesSettings, IPlexServer, IPlexServerResponse, IPlexServerViewModel, IPlexSettings } from "../../interfaces";
import { JobService, NotificationService, PlexService, SettingsService, TesterService } from "../../services";
@Component({
@ -21,11 +19,12 @@ export class PlexComponent implements OnInit, OnDestroy {
private subscriptions = new Subject<void>();
constructor(private settingsService: SettingsService,
private notificationService: NotificationService,
private plexService: PlexService,
private testerService: TesterService,
private jobService: JobService) { }
constructor(
private settingsService: SettingsService,
private notificationService: NotificationService,
private plexService: PlexService,
private testerService: TesterService,
private jobService: JobService) { }
public ngOnInit() {
this.settingsService.getPlex().subscribe(x => {
@ -34,17 +33,17 @@ export class PlexComponent implements OnInit, OnDestroy {
}
public requestServers(server: IPlexServer) {
this.plexService.getServers(this.username, this.password)
.takeUntil(this.subscriptions)
.subscribe(x => {
if (x.success) {
this.loadedServers = x;
this.serversButton = true;
this.notificationService.success("Found the servers! Please select one!");
} else {
this.notificationService.warning("Error When Requesting Plex Servers", "Please make sure your username and password are correct");
}
});
this.plexService.getServers(this.username, this.password).pipe(
takeUntil(this.subscriptions),
).subscribe(x => {
if (x.success) {
this.loadedServers = x;
this.serversButton = true;
this.notificationService.success("Found the servers! Please select one!");
} else {
this.notificationService.warning("Error When Requesting Plex Servers", "Please make sure your username and password are correct");
}
});
}
public selectServer(selectedServer: IPlexServerResponse, server: IPlexServer) {
@ -91,19 +90,19 @@ export class PlexComponent implements OnInit, OnDestroy {
this.plexService.getLibraries(server).subscribe(x => {
server.plexSelectedLibraries = [];
if (x.successful) {
x.data.mediaContainer.directory.forEach((item) => {
const lib: IPlexLibrariesSettings = {
key: item.key,
title: item.title,
enabled: false,
};
server.plexSelectedLibraries.push(lib);
});
} else {
this.notificationService.error(x.message);
}
},
err => { this.notificationService.error(err); });
x.data.mediaContainer.directory.forEach((item) => {
const lib: IPlexLibrariesSettings = {
key: item.key,
title: item.title,
enabled: false,
};
server.plexSelectedLibraries.push(lib);
});
} else {
this.notificationService.error(x.message);
}
},
err => { this.notificationService.error(err); });
}
public save() {
@ -120,7 +119,7 @@ export class PlexComponent implements OnInit, OnDestroy {
public runCacher(): void {
this.jobService.runPlexCacher().subscribe(x => {
if(x) {
if (x) {
this.notificationService.success("Triggered the Plex Full Sync");
}
});
@ -128,7 +127,7 @@ export class PlexComponent implements OnInit, OnDestroy {
public runRecentlyAddedCacher(): void {
this.jobService.runPlexRecentlyAddedCacher().subscribe(x => {
if(x) {
if (x) {
this.notificationService.success("Triggered the Plex Recently Added Sync");
}
});

@ -1,14 +1,16 @@
import { CommonModule } from "@angular/common";
import { CommonModule } from "@angular/common";
import { NgModule } from "@angular/core";
import { FormsModule, ReactiveFormsModule } from "@angular/forms";
import { RouterModule, Routes } from "@angular/router";
import { NgbAccordionModule, NgbModule } from "@ng-bootstrap/ng-bootstrap";
import { ClipboardModule } from "ngx-clipboard/dist";
import { ClipboardModule } from "ngx-clipboard";
import { AuthGuard } from "../auth/auth.guard";
import { AuthService } from "../auth/auth.service";
import { CouchPotatoService, EmbyService, IssuesService, JobService, MobileService, NotificationMessageService, PlexService, RadarrService,
SonarrService, TesterService, ValidationService } from "../services";
import {
CouchPotatoService, EmbyService, IssuesService, JobService, MobileService, NotificationMessageService, PlexService, RadarrService,
SonarrService, TesterService, ValidationService,
} from "../services";
import { PipeModule } from "../pipes/pipe.module";
import { AboutComponent } from "./about/about.component";

@ -11,7 +11,7 @@ import { IEmbySettings } from "../../interfaces";
})
export class EmbyComponent implements OnInit {
private embySettings: IEmbySettings;
public embySettings: IEmbySettings;
constructor(private embyService: EmbyService,
private router: Router,

@ -1,2 +0,0 @@
import "rxjs/add/operator/catch";
import "rxjs/add/operator/map";

@ -1,5 +1,6 @@
import * as Pace from "pace-progress";
// Main
import * as Pace from "pace-progress";
Pace.start();
import "bootstrap/dist/js/bootstrap";
@ -11,8 +12,6 @@ import "./polyfills";
import "hammerjs";
import "./imports";
import { enableProdMode } from "@angular/core";
import { platformBrowserDynamic } from "@angular/platform-browser-dynamic";
import { AppModule } from "./app/app.module";
@ -29,7 +28,9 @@ if (module.hot) {
oldRootElem.parentNode.insertBefore(newRootElem, oldRootElem);
oldRootElem.parentNode.removeChild(oldRootElem);
}
modulePromise.then(appModule => appModule.destroy());
if (modulePromise) {
modulePromise.then(appModule => appModule.destroy());
}
});
} else {
enableProdMode();

@ -9,6 +9,7 @@ declare var module: any;
if (module.hot) {
Error.stackTraceLimit = Infinity;
// tslint:disable:no-var-requires
// tslint:disable-next-line
require("zone.js/dist/long-stack-trace-zone");
}

@ -1,5 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<Project ToolsVersion="15.0" Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>netcoreapp2.1</TargetFramework>
<RuntimeIdentifiers>win10-x64;win10-x86;osx-x64;ubuntu-x64;debian.8-x64;centos.7-x64;linux-x64;linux-arm;linux-arm64;</RuntimeIdentifiers>
@ -9,6 +8,7 @@
<FileVersion>$(SemVer)</FileVersion>
<Version>$(FullVer)</Version>
<PackageVersion></PackageVersion>
<TypeScriptToolsVersion>2.8</TypeScriptToolsVersion>
</PropertyGroup>
<PropertyGroup>
<ServerGarbageCollection>false</ServerGarbageCollection>
@ -23,17 +23,13 @@
<NoWarn>1701;1702;1705;1591;</NoWarn>
<DefineConstants>TRACE;RELEASE;NETCOREAPP2_0</DefineConstants>
</PropertyGroup>
<Target Name="NpmCommandsDebug" Condition="'$(Configuration)'=='Debug'" AfterTargets="Build">
<Exec Command="npm run-script vendor" />
</Target>
<ItemGroup>
<!-- Files not to show in IDE -->
<Compile Remove="Logs\**" />
<Compile Remove="Styles\**" />
<Compile Remove="wwwroot\dist\**" />
<!-- Files not to publish (note that the 'dist' subfolders are re-added below) -->
<Content Remove="ClientApp\**" />
<Content Remove="Logs\**" />
@ -46,7 +42,17 @@
<None Remove="Styles\**" />
<None Remove="wwwroot\dist\**" />
</ItemGroup>
<Target Name="NpmCommandsDebug" Condition="'$(Configuration)'=='Debug'" AfterTargets="Build">
<Exec Command="npm run vendor" />
</Target>
<!-- Disabled as run by CI once for many different runtime builds
<Target Name="NpmCommandsRelease" Condition="'$(Configuration)'=='Release'" AfterTargets="Build">
<Exec Command="npm run publish" />
</Target>
-->
<Target Name="NpmCommandsClean" AfterTargets="Clean">
<Exec Command="npm run clean" />
</Target>
<Target Name="RunWebpack" AfterTargets="ComputeFilesToPublish">
<ItemGroup>
<DistFiles Include="wwwroot\dist\**" />
@ -56,8 +62,6 @@
</ResolvedFileToPublish>
</ItemGroup>
</Target>
<ItemGroup>
<PackageReference Include="AutoMapper" Version="6.1.1" />
<PackageReference Include="CommandLineParser" Version="2.1.1-beta" />
@ -94,18 +98,4 @@
<ProjectReference Include="..\Ombi.TheMovieDbApi\Ombi.Api.TheMovieDb.csproj" />
<ProjectReference Include="..\Ombi.Updater\Ombi.Updater.csproj" />
</ItemGroup>
<ItemGroup>
<None Include="wwwroot\loading.css" />
<None Include="wwwroot\translations\*.json" />
</ItemGroup>
<ItemGroup>
<None Remove="ClientApp\app\animations\fadeinout.ts" />
</ItemGroup>
<ItemGroup>
<TypeScriptCompile Include="ClientApp\app\animations\fadeinout.ts" />
</ItemGroup>
</Project>

@ -156,7 +156,12 @@ namespace Ombi
app.UseWebpackDevMiddleware(new WebpackDevMiddlewareOptions
{
HotModuleReplacement = true,
ConfigFile = "webpack.dev.js"
ConfigFile = "webpack.config.ts",
//EnvParam = new
//{
// aot = true // can't use AOT with HMR currently https://github.com/angular/angular-cli/issues/6347
//}
});
}

@ -60,19 +60,19 @@
-->
@*<!-- Start SmartBanner configuration -->
<meta name="smartbanner:title" content="Smart Application">
<meta name="smartbanner:author" content="SmartBanner Contributors">
<meta name="smartbanner:price" content=" ">
<meta name="smartbanner:price-suffix-apple" content=" On the App Store">
<meta name="smartbanner:price-suffix-google" content=" In Google Play">
<meta name="smartbanner:icon-apple" content="http://a3.mzstatic.com/us/r30/Purple60/v4/c1/3b/b0/c13bb085-64c0-cc90-f97a-521b96963986/icon350x350.jpeg">
<meta name="smartbanner:icon-google" content="http://lh3.ggpht.com/f4oX61ljZ6x8aYDELZOgxlvdUEu73-wSQ4fy5bx6fCRISnZP8T353wdaM43RO_DbGg=w300">
<meta name="smartbanner:button" content="View">
<meta name="smartbanner:button-url-apple" content="https://itunes.apple.com/us/genre/ios/id36?mt=8">
<meta name="smartbanner:button-url-google" content="https://play.google.com/store">
<meta name="smartbanner:enabled-platforms" content="android,ios">e.com/store/apps/details?id=com.tidusjar.Ombi">
<meta name="smartbanner:enabled-platforms" content="android,ios">
<!-- End SmartBanner configuration -->*@
<meta name="smartbanner:title" content="Smart Application">
<meta name="smartbanner:author" content="SmartBanner Contributors">
<meta name="smartbanner:price" content=" ">
<meta name="smartbanner:price-suffix-apple" content=" On the App Store">
<meta name="smartbanner:price-suffix-google" content=" In Google Play">
<meta name="smartbanner:icon-apple" content="http://a3.mzstatic.com/us/r30/Purple60/v4/c1/3b/b0/c13bb085-64c0-cc90-f97a-521b96963986/icon350x350.jpeg">
<meta name="smartbanner:icon-google" content="http://lh3.ggpht.com/f4oX61ljZ6x8aYDELZOgxlvdUEu73-wSQ4fy5bx6fCRISnZP8T353wdaM43RO_DbGg=w300">
<meta name="smartbanner:button" content="View">
<meta name="smartbanner:button-url-apple" content="https://itunes.apple.com/us/genre/ios/id36?mt=8">
<meta name="smartbanner:button-url-google" content="https://play.google.com/store">
<meta name="smartbanner:enabled-platforms" content="android,ios">e.com/store/apps/details?id=com.tidusjar.Ombi">
<meta name="smartbanner:enabled-platforms" content="android,ios">
<!-- End SmartBanner configuration -->*@
<meta charset="utf-8" />
<meta http-equiv="x-ua-compatible" content="ie=edge">
<meta name="description" content="Ombi, media request tool">
@ -98,8 +98,10 @@
<link rel="stylesheet" href="~/loading.css" asp-append-version="true" />
<link rel="stylesheet" href="~/dist/vendor.css" asp-append-version="true" />
<script src="~/dist/vendor.js" asp-append-version="true" defer></script>
<script src="~/dist/main.js" asp-append-version="true" defer></script>
<environment include="Development">
<script src="~/dist/vendor.js" asp-append-version="true" defer></script>
</environment>
<script src="~/dist/app.js" asp-append-version="true" defer></script>
</head>
<body>
@{

@ -1,21 +1,25 @@
'use strict';
"use strict";
const gulp = require('gulp');
const run = require('gulp-run');
const runSequence = require('run-sequence');
const del = require('del');
const path = require('path');
const fs = require('fs');
const gulp = require("gulp");
const run = require("gulp-run");
const runSequence = require("run-sequence");
const del = require("del");
const path = require("path");
const fs = require("fs");
const outputDir = './wwwroot/dist';
const outputDir = "./wwwroot/dist";
global.aot = true;
function getEnvOptions() {
var options = [];
const options = [];
if (global.prod) {
options.push('--env.prod');
options.push("--env.prod");
}
if (global.analyse) {
options.push('--env.analyse');
options.push("--env.analyse");
}
if (global.aot) {
options.push("--env.aot");
}
if (options.length > 0) {
return " " + options.join(" ");
@ -24,12 +28,12 @@ function getEnvOptions() {
}
}
function webpack(vendor) {
return run(`webpack --config webpack.config${vendor ? '.vendor' : ''}.ts${getEnvOptions()}`).exec();
function webpack(type) {
// 'webpack' instead of direct path can cause https://github.com/angular/angular-cli/issues/6417
return run(`node node_modules\\webpack\\bin\\webpack.js --config webpack.config${type ? `.${type}` : ""}.ts${getEnvOptions()}`).exec();
}
gulp.task('vendor', () => {
gulp.task("vendor", () => {
let build = false;
const vendorPath = path.join(outputDir, "vendor.js");
const vendorExists = fs.existsSync(vendorPath);
@ -37,44 +41,47 @@ gulp.task('vendor', () => {
const vendorStat = fs.statSync(vendorPath);
const packageStat = fs.statSync("package.json");
const vendorConfigStat = fs.statSync("webpack.config.vendor.ts");
const commonConfigStat = fs.statSync("webpack.config.common.ts");
if (packageStat.mtime > vendorStat.mtime) {
build = true;
}
if (vendorConfigStat.mtime > vendorStat.mtime) {
build = true;
}
if (commonConfigStat.mtime > vendorStat.mtime) {
build = true;
}
} else {
build = true;
}
if (build) {
return webpack(true);
return webpack("vendor");
}
});
gulp.task('vendor_force', () => {
return webpack(true);
gulp.task("vendor_force", () => {
return webpack("vendor");
})
gulp.task('main', () => {
gulp.task("main", () => {
return webpack()
});
gulp.task('prod_var', () => {
gulp.task("prod_var", () => {
global.prod = true;
})
gulp.task('analyse_var', () => {
gulp.task("analyse_var", () => {
global.analyse = true;
})
gulp.task('clean', () => {
gulp.task("clean", () => {
del.sync(outputDir, { force: true });
});
gulp.task('lint', () => run("npm run lint").exec());
gulp.task('build', callback => runSequence('vendor', 'main', callback));
gulp.task('analyse', callback => runSequence('analyse_var', 'build'));
gulp.task('full', callback => runSequence('clean', 'build'));
gulp.task('publish', callback => runSequence('prod_var', 'build'));
gulp.task("lint", () => run("npm run lint").exec());
gulp.task("lint_fix", () => run("npm run lint -- --fix").exec());
gulp.task("build", callback => runSequence("vendor", "main", callback));
gulp.task("analyse", callback => runSequence("analyse_var", "clean", "build", callback));
gulp.task("full", callback => runSequence("clean", "build", callback));
gulp.task("publish", callback => runSequence("prod_var", "full", callback));

File diff suppressed because it is too large Load Diff

@ -1,94 +1,93 @@
{
"name": "ombi",
"version": "2.6.0",
"private": true,
"version": "1.0.0",
"scripts": {
"vendor": "gulp vendor",
"main": "gulp main",
"lint": "tslint -p .",
"publish": "gulp publish",
"lint": "tslint ClientApp/**/*.ts",
"restore": "dotnet restore && npm install"
"restore": "dotnet restore && yarn install",
"clean": "gulp clean"
},
"dependencies": {
"@angular/animations": "^5.2.5",
"@angular/cdk": "^5.2.1",
"@angular/common": "^5.2.5",
"@angular/compiler": "^5.2.5",
"@angular/core": "^5.2.5",
"@angular/forms": "^5.2.5",
"@angular/http": "^5.2.5",
"@angular/material": "^5.2.1",
"@angular/platform-browser": "^5.2.5",
"@angular/platform-browser-dynamic": "^5.2.5",
"@angular/platform-server": "^5.2.5",
"@angular/router": "^5.2.5",
"@auth0/angular-jwt": "1.0.0-beta.9",
"@ng-bootstrap/ng-bootstrap": "^1.0.0",
"@ngu/carousel": "^1.4.8",
"@ngx-translate/core": "^8.0.0",
"@ngx-translate/http-loader": "^2.0.1",
"@types/core-js": "^0.9.46",
"@types/extract-text-webpack-plugin": "^3.0.1",
"@types/intro.js": "^2.4.3",
"@types/node": "^8.9.4",
"@types/webpack": "^3.8.7",
"angular-router-loader": "^0.8.2",
"angular2-moment": "^1.8.0",
"@angular/animations": "^6.0.7",
"@angular/cdk": "^6.3.1",
"@angular/common": "^6.0.7",
"@angular/compiler": "^6.0.7",
"@angular/compiler-cli": "^6.0.7",
"@angular/core": "^6.0.7",
"@angular/forms": "^6.0.7",
"@angular/http": "^6.0.7",
"@angular/material": "^6.3.1",
"@angular/platform-browser": "^6.0.7",
"@angular/platform-browser-dynamic": "^6.0.7",
"@angular/platform-server": "^6.0.7",
"@angular/router": "^6.0.7",
"@auth0/angular-jwt": "^2.0.0",
"@ng-bootstrap/ng-bootstrap": "^2.2.0",
"@ngtools/webpack": "^6.1.0-beta.2",
"@ngu/carousel": "^1.4.9-beta-2",
"@ngx-translate/core": "^10.0.2",
"@ngx-translate/http-loader": "^3.0.1",
"@types/core-js": "^2.5.0",
"@types/mini-css-extract-plugin": "^0.2.0",
"@types/node": "^10.5.1",
"@types/webpack": "^4.4.4",
"@types/webpack-bundle-analyzer": "^2.9.2",
"@types/webpack-merge": "^4.1.3",
"angular-router-loader": "^0.8.5",
"angular2-template-loader": "^0.6.2",
"aspnet-webpack": "^2.0.3",
"awesome-typescript-loader": "^3.4.1",
"aspnet-webpack": "^3.0.0",
"awesome-typescript-loader": "^5.2.0",
"bootstrap": "3.3.7",
"bootswatch": "3.3.7",
"core-js": "^2.5.3",
"css": "^2.2.1",
"css-loader": "^0.28.9",
"copy-webpack-plugin": "^4.5.2",
"core-js": "^2.5.7",
"css": "^2.2.3",
"css-loader": "^0.28.11",
"del": "^3.0.0",
"event-source-polyfill": "^0.0.11",
"expose-loader": "^0.7.4",
"extract-text-webpack-plugin": "^3.0.2",
"file-loader": "^1.1.6",
"event-source-polyfill": "^0.0.12",
"expose-loader": "^0.7.5",
"file-loader": "^1.1.11",
"font-awesome": "^4.7.0",
"gulp": "^3.9.1",
"gulp-run": "^1.7.1",
"hammerjs": "^2.0.8",
"html-loader": "0.5.1",
"html-loader": "^0.5.5",
"jquery": "^3.3.1",
"mini-css-extract-plugin": "^0.4.1",
"moment": "^2.22.2",
"ng2-cookies": "^1.0.12",
"ngx-clipboard": "8.1.1",
"ngx-infinite-scroll": "^0.6.1",
"ngx-clipboard": "^11.1.1",
"ngx-infinite-scroll": "^6.0.1",
"ngx-moment": "^3.0.1",
"ngx-order-pipe": "^2.0.1",
"node-sass": "^4.7.2",
"npm": "^5.6.0",
"node-sass": "^4.9.0",
"pace-progress": "^1.0.2",
"primeng": "5.0.2",
"reflect-metadata": "0.1.10",
"primeng": "^6.0.0",
"raw-loader": "^0.5.1",
"reflect-metadata": "^0.1.12",
"run-sequence": "^2.2.1",
"rxjs": "5.5.2",
"sass-loader": "^6.0.6",
"style-loader": "^0.19.1",
"rxjs": "^6.2.1",
"sass-loader": "^7.0.3",
"style-loader": "^0.21.0",
"to-string-loader": "^1.1.5",
"ts-node": "^3.3.0",
"tslint": "^5.9.1",
"tslint-language-service": "^0.9.8",
"typescript": "^2.7.1",
"uglify-es": "^3.3.10",
"uglifyjs-webpack-plugin": "^1.1.8",
"url-loader": "^0.6.2",
"webpack": "^3.11.0",
"webpack-bundle-analyzer": "^2.10.0",
"webpack-hot-middleware": "^2.21.0",
"zone.js": "^0.8.20"
"ts-node": "^7.0.0",
"tslint": "^5.10.0",
"tslint-language-service": "^0.9.9",
"typescript": "2.7.2",
"uglify-es": "^3.3.9",
"uglifyjs-webpack-plugin": "^1.2.7",
"url-loader": "^1.0.1",
"webpack": "^4.14.0",
"webpack-bundle-analyzer": "^2.13.1",
"webpack-cli": "^3.0.8",
"webpack-dev-middleware": "^3.1.3",
"webpack-hot-middleware": "^2.22.2",
"webpack-merge": "^4.1.3",
"zone.js": "^0.8.26"
},
"devDependencies": {
"@types/chai": "4.0.4",
"@types/jasmine": "2.6.2",
"chai": "4.1.2",
"jasmine-core": "2.8.0",
"karma": "1.7.1",
"karma-chai": "0.1.0",
"karma-chrome-launcher": "2.2.0",
"karma-cli": "1.0.1",
"karma-jasmine": "1.1.0",
"karma-webpack": "2.0.5"
"resolutions": {
"@types/tapable": "1.0.0"
}
}

@ -2,7 +2,7 @@
"compilerOptions": {
"target": "es5",
"lib": [
"es6",
"es2017",
"dom"
],
"moduleResolution": "node",
@ -11,7 +11,7 @@
"noUnusedLocals": true,
"noImplicitThis": true,
"noImplicitReturns": true,
"noImplicitAny": false,
"noImplicitAny": true,
"suppressImplicitAnyIndexErrors": true,
"alwaysStrict": true,
"emitDecoratorMetadata": true,
@ -27,11 +27,15 @@
}
]
},
"exclude": [
"bin",
"node_modules"
"include": [
"ClientApp/**/*",
"typings/**/*",
"webpack.config.*"
],
"angularCompilerOptions": {
"preserveWhitespaces": false
}
}
"preserveWhitespaces": false,
"genDir": "./ClientApp/app/ngfactory",
"entryModule": "ClientApp/app/app.module#AppModule"
},
"compileOnSave": false
}

@ -0,0 +1,4 @@
// Globals
declare module "pace-progress";
declare var __webpack_public_path__: any;

@ -1,12 +0,0 @@
// Globals
declare var module: any;
declare var require: any;
declare var localStorage: any;
declare var introJs: any;
declare var __webpack_public_path__: any;
declare module "pace-progress";
declare module "webpack-bundle-analyzer";
declare module "uglifyjs-webpack-plugin";

@ -1 +1 @@
/// <reference path="globals/globals.d.ts" />
/// <reference path="globals.d.ts" />

@ -0,0 +1,83 @@
import { AngularCompilerPlugin } from "@ngtools/webpack";
import * as MiniCssExtractPlugin from "mini-css-extract-plugin";
import * as path from "path";
import { Configuration, ContextReplacementPlugin, ProvidePlugin } from "webpack";
import { BundleAnalyzerPlugin } from "webpack-bundle-analyzer";
export const outputDir = "./wwwroot/dist";
export function isProd(env: any) {
return env && env.prod as boolean;
}
export function isAOT(env: any) {
return env && env.aot as boolean;
}
export const WebpackCommonConfig = (env: any, type: string) => {
const prod = isProd(env);
const aot = isAOT(env);
const vendor = type === "vendor";
console.log(`${prod ? "Production" : "Dev"} ${type} build`);
console.log(`Output directory: ${outputDir}`);
console.log(`${aot ? "Using" : "Not using"} AOT compiler`);
const analyse = env && env.analyse as boolean;
if (analyse) { console.log("Analysing build"); }
const cssLoader = prod ? "css-loader?minimize" : "css-loader";
const bundleConfig: Configuration = {
mode: prod ? "production" : "development",
resolve: {
extensions: [".ts", ".js"],
alias: {
pace: "pace-progress",
},
},
output: {
path: path.resolve(outputDir),
filename: "[name].js",
chunkFilename: "[id].chunk.js",
publicPath: "/dist/",
},
module: {
rules: [
{ test: /\.ts$/, loader: aot ? "@ngtools/webpack" : ["awesome-typescript-loader?silent=true", "angular2-template-loader", "angular-router-loader"] },
{ test: /\.html$/, use: "html-loader?minimize=false" },
{ test: /\.css$/, use: [MiniCssExtractPlugin.loader, cssLoader] },
{ test: /\.scss$/, exclude: /ClientApp/, use: [MiniCssExtractPlugin.loader, cssLoader, "sass-loader"] },
{ test: /\.scss$/, include: /ClientApp(\\|\/)app/, use: ["to-string-loader", cssLoader, "sass-loader"] },
{ test: /\.scss$/, include: /ClientApp(\\|\/)styles/, use: ["style-loader", cssLoader, "sass-loader"] },
{ test: /\.(png|jpg|jpeg|gif|woff|woff2|eot|ttf|svg)(\?|$)/, use: "url-loader?limit=8192" },
{ test: /[\/\\]@angular[\/\\].+\.js$/, parser: { system: true } }, // ignore System.import warnings https://github.com/angular/angular/issues/21560
],
},
plugins: [
new MiniCssExtractPlugin({
filename: "[name].css",
}),
new ProvidePlugin({ $: "jquery", jQuery: "jquery", Hammer: "hammerjs/hammer" }), // Global identifiers
].concat(aot && !vendor ? [
new AngularCompilerPlugin({
mainPath: "./ClientApp/main.ts",
tsConfigPath: "./tsconfig.json",
skipCodeGeneration: false,
compilerOptions: {
noEmit: false,
},
}),
] : [
// AOT chunk splitting does not work while this is active but doesn't seem to be needed under AOT anyway https://github.com/angular/angular-cli/issues/4431
new ContextReplacementPlugin(/angular(\\|\/)core(\\|\/)/, path.join(__dirname, "./ClientApp")), // Workaround for https://github.com/angular/angular/issues/14898
]).concat(analyse ? [
new BundleAnalyzerPlugin({
analyzerMode: "static",
reportFilename: `${type}.html`,
openAnalyzer: false,
}),
] : []),
node: {
fs: "empty",
},
};
return bundleConfig;
};

@ -1,59 +1,26 @@
import { CheckerPlugin } from "awesome-typescript-loader";
import * as path from "path";
import * as UglifyJSPlugin from "uglifyjs-webpack-plugin";
import { BundleAnalyzerPlugin } from "webpack-bundle-analyzer";
import { Configuration, DllReferencePlugin } from "webpack";
import * as webpackMerge from "webpack-merge";
import * as webpack from "webpack";
import { isAOT, isProd, outputDir, WebpackCommonConfig } from "./webpack.config.common";
module.exports = (env: any) => {
// const prod = env && env.prod as boolean;
const prod = true;
console.log(prod ? "Production" : "Dev" + " main build");
const analyse = env && env.analyse as boolean;
if (analyse) { console.log("Analysing build"); }
const cssLoader = prod ? "css-loader?-url&minimize" : "css-loader?-url";
const outputDir = "./wwwroot/dist";
const bundleConfig: webpack.Configuration = {
entry: { main: "./ClientApp/main.ts" },
stats: { modules: false },
context: __dirname,
resolve: { extensions: [".ts", ".js"] },
devtool: prod ? "source-map" : "eval-source-map",
output: {
filename: "[name].js",
chunkFilename: "[id].[chunkhash].js",
publicPath: "/dist/",
path: path.join(__dirname, outputDir),
},
module: {
rules: [
{ test: /\.ts$/, include: /ClientApp/, use: ["awesome-typescript-loader?silent=true", "angular2-template-loader", "angular-router-loader"] },
{ test: /\.html$/, use: "html-loader?minimize=false" },
{ test: /\.css$/, use: ["to-string-loader", cssLoader] },
{ test: /\.scss$/, include: /ClientApp(\\|\/)app/, use: ["to-string-loader", cssLoader, "sass-loader"] },
{ test: /\.scss$/, include: /ClientApp(\\|\/)styles/, use: ["style-loader", cssLoader, "sass-loader"] },
{ test: /\.(png|jpg|jpeg|gif|svg)$/, use: "url-loader?limit=25000" },
],
const prod = isProd(env);
const aot = isAOT(env);
if (!prod && aot) { console.warn("Vendor dll bundle will not be used as AOT is enabled"); }
const bundleConfig: Configuration = webpackMerge(WebpackCommonConfig(env, "main"), {
entry: {
app: "./ClientApp/main.ts",
},
plugins: [
new CheckerPlugin(),
new webpack.DllReferencePlugin({
devtool: prod ? "source-map" : "eval-source-map",
plugins: prod || aot ? [] : [
// AOT chunk splitting does not work while this is active https://github.com/angular/angular-cli/issues/4565
new DllReferencePlugin({
context: __dirname,
manifest: require(path.join(__dirname, outputDir, "vendor-manifest.json")),
}),
].concat(prod ? [
// Plugins that apply in production builds only
new UglifyJSPlugin({ sourceMap: true }),
] : [
// Plugins that apply in development builds only
]).concat(analyse ? [
new BundleAnalyzerPlugin({
analyzerMode: "static",
reportFilename: "main.html",
openAnalyzer: false,
}),
] : []),
};
],
});
return bundleConfig;
};

@ -1,41 +1,25 @@
import * as ExtractTextPlugin from "extract-text-webpack-plugin";
import * as path from "path";
import * as UglifyJSPlugin from "uglifyjs-webpack-plugin";
import * as webpack from "webpack";
import { BundleAnalyzerPlugin } from "webpack-bundle-analyzer";
import * as webpackMerge from "webpack-merge";
import { isProd, outputDir, WebpackCommonConfig } from "./webpack.config.common";
module.exports = (env: any) => {
const extractCSS = new ExtractTextPlugin("vendor.css");
const prod = env && env.prod as boolean;
console.log(prod ? "Production" : "Dev" + " vendor build");
const analyse = env && env.analyse as boolean;
if (analyse) { console.log("Analysing build"); }
const outputDir = "./wwwroot/dist";
const bundleConfig = {
stats: { modules: false },
resolve: {
extensions: [".js"],
alias: {
pace: "pace-progress",
},
},
module: {
rules: [
{ test: /\.(png|woff|woff2|eot|ttf|svg|gif)(\?|$)/, use: "url-loader?limit=100000" },
{ test: /\.css(\?|$)/, use: extractCSS.extract({ use: prod ? "css-loader?minimize" : "css-loader" }) },
{ test: /\.scss(\?|$)/, use: extractCSS.extract({ use: [prod ? "css-loader?minimize" : "css-loader", "sass-loader"] }) },
],
const prod = isProd(env);
const bundleConfig = webpackMerge(WebpackCommonConfig(env, "vendor"), {
output: {
library: "[name]_[hash]",
},
entry: {
vendor: [
vendor: (<string[]>[ // add any vendor styles here e.g. bootstrap/dist/css/bootstrap.min.css
"pace-progress/themes/orange/pace-theme-flash.css",
"primeng/resources/primeng.min.css",
"@angular/material/prebuilt-themes/deeppurple-amber.css",
"font-awesome/scss/font-awesome.scss",
"bootswatch/superhero/bootstrap.min.css",
]).concat(prod ? [] : [ // used to speed up dev launch time
"@angular/animations",
"@angular/common",
"@angular/common/http",
"@angular/compiler",
"@angular/core",
"@angular/forms",
@ -67,41 +51,14 @@ module.exports = (env: any) => {
"@ngx-translate/core",
"@ngx-translate/http-loader",
"ngx-order-pipe",
//"smartbanner.js/dist/smartbanner.js",
//"smartbanner.js/dist/smartbanner.css",
],
},
output: {
publicPath: "/dist/",
filename: "[name].js",
library: "[name]_[hash]",
path: path.join(__dirname, outputDir),
},
node: {
fs: "empty",
]),
},
plugins: [
new webpack.ProvidePlugin({ $: "jquery", jQuery: "jquery", Hammer: "hammerjs/hammer" }), // Global identifiers
new webpack.ContextReplacementPlugin(/\@angular(\\|\/)core(\\|\/)esm5/, path.join(__dirname, "./client")), // Workaround for https://github.com/angular/angular/issues/20357
new webpack.ContextReplacementPlugin(/\@angular\b.*\b(bundles|linker)/, path.join(__dirname, "./ClientApp")), // Workaround for https://github.com/angular/angular/issues/11580
new webpack.ContextReplacementPlugin(/angular(\\|\/)core(\\|\/)@angular/, path.join(__dirname, "./ClientApp")), // Workaround for https://github.com/angular/angular/issues/14898
extractCSS,
plugins: prod ? [] : [
new webpack.DllPlugin({
path: path.join(__dirname, outputDir, "[name]-manifest.json"),
name: "[name]_[hash]",
}),
].concat(prod ? [
// Plugins that apply in production builds only
new UglifyJSPlugin(),
] : [
// Plugins that apply in development builds only
]).concat(analyse ? [
new BundleAnalyzerPlugin({
analyzerMode: "static",
reportFilename: "vendor.html",
openAnalyzer: false,
}),
] : []),
};
],
});
return bundleConfig;
};

@ -1,4 +0,0 @@
// https://github.com/aspnet/JavaScriptServices/issues/1046
require('ts-node/register')
module.exports = require("./webpack.config.ts");

File diff suppressed because it is too large Load Diff
Loading…
Cancel
Save