mirror of
https://github.com/Kareadita/Kavita.git
synced 2025-07-09 03:04:19 -04:00
Angular Upgrade (#1059)
* Upgraded to Angular 12 * Bump ng-bootstrap for upgrade * Angular 13 upgrade, ng-bootstrap bump * Angular 13 upgrade (broken) * Angular 13 upgrade. CSS is broken completely * Angular 13 upgrade is complete.
This commit is contained in:
parent
d7450497a6
commit
97b1249a0e
2
.gitignore
vendored
2
.gitignore
vendored
@ -526,3 +526,5 @@ API/config/post-metadata/
|
||||
API.Tests/TestResults/
|
||||
UI/Web/.vscode/settings.json
|
||||
/API.Tests/Services/Test Data/ArchiveService/CoverImages/output/*
|
||||
/UI/Web/.angular/
|
||||
|
||||
|
@ -28,7 +28,6 @@
|
||||
"main": "src/main.ts",
|
||||
"polyfills": "src/polyfills.ts",
|
||||
"tsConfig": "tsconfig.app.json",
|
||||
"aot": true,
|
||||
"assets": [
|
||||
"src/assets",
|
||||
"src/site.webmanifest"
|
||||
@ -46,7 +45,12 @@
|
||||
"node_modules/lazysizes/lazysizes.min.js",
|
||||
"node_modules/lazysizes/plugins/rias/ls.rias.min.js",
|
||||
"node_modules/lazysizes/plugins/attrchange/ls.attrchange.min.js"
|
||||
]
|
||||
],
|
||||
"vendorChunk": true,
|
||||
"extractLicenses": false,
|
||||
"buildOptimizer": false,
|
||||
"optimization": true,
|
||||
"namedChunks": true
|
||||
},
|
||||
"configurations": {
|
||||
"production": {
|
||||
@ -60,7 +64,6 @@
|
||||
"outputHashing": "all",
|
||||
"namedChunks": false,
|
||||
"extractLicenses": true,
|
||||
"vendorChunk": true,
|
||||
"buildOptimizer": true,
|
||||
"budgets": [
|
||||
{
|
||||
@ -75,7 +78,8 @@
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"defaultConfiguration": ""
|
||||
},
|
||||
"serve": {
|
||||
"builder": "@angular-devkit/build-angular:dev-server",
|
||||
|
13698
UI/Web/package-lock.json
generated
13698
UI/Web/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -5,7 +5,7 @@
|
||||
"ng": "ng",
|
||||
"start": "ng serve",
|
||||
"build": "ng build",
|
||||
"prod": "ng build --prod",
|
||||
"prod": "ng build --configuration production",
|
||||
"explore": "ng build --stats-json && webpack-bundle-analyzer dist/stats.json",
|
||||
"test": "jest",
|
||||
"test:watch": "jest --watch",
|
||||
@ -16,50 +16,50 @@
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@angular-slider/ngx-slider": "^2.0.3",
|
||||
"@angular/animations": "~11.0.0",
|
||||
"@angular/cdk": "^12.2.3",
|
||||
"@angular/common": "~11.0.0",
|
||||
"@angular/compiler": "~11.0.0",
|
||||
"@angular/core": "~11.0.0",
|
||||
"@angular/forms": "~11.0.0",
|
||||
"@angular/localize": "~11.0.0",
|
||||
"@angular/platform-browser": "~11.0.0",
|
||||
"@angular/platform-browser-dynamic": "~11.0.0",
|
||||
"@angular/router": "~11.0.0",
|
||||
"@fortawesome/fontawesome-free": "^5.15.1",
|
||||
"@microsoft/signalr": "^5.0.8",
|
||||
"@ng-bootstrap/ng-bootstrap": "^9.1.0",
|
||||
"@ngx-lite/nav-drawer": "^0.4.6",
|
||||
"@ngx-lite/util": "0.0.0",
|
||||
"@types/file-saver": "^2.0.1",
|
||||
"bootstrap": "^4.5.0",
|
||||
"@angular/animations": "~13.2.2",
|
||||
"@angular/cdk": "^13.2.2",
|
||||
"@angular/common": "~13.2.2",
|
||||
"@angular/compiler": "~13.2.2",
|
||||
"@angular/core": "~13.2.2",
|
||||
"@angular/forms": "~13.2.2",
|
||||
"@angular/localize": "~13.2.2",
|
||||
"@angular/platform-browser": "~13.2.2",
|
||||
"@angular/platform-browser-dynamic": "~13.2.2",
|
||||
"@angular/router": "~13.2.2",
|
||||
"@fortawesome/fontawesome-free": "^6.0.0",
|
||||
"@microsoft/signalr": "^6.0.2",
|
||||
"@ng-bootstrap/ng-bootstrap": "^11.0.0",
|
||||
"@ngx-lite/nav-drawer": "^0.4.7",
|
||||
"@ngx-lite/util": "0.0.1",
|
||||
"@types/file-saver": "^2.0.5",
|
||||
"bootstrap": "^4.6.1",
|
||||
"bowser": "^2.11.0",
|
||||
"file-saver": "^2.0.5",
|
||||
"lazysizes": "^5.3.2",
|
||||
"ng-circle-progress": "^1.6.0",
|
||||
"ng-lazyload-image": "^9.1.0",
|
||||
"ngx-file-drop": "^11.1.0",
|
||||
"ngx-toastr": "^13.2.1",
|
||||
"rxjs": "~6.6.0",
|
||||
"swiper": "^6.5.8",
|
||||
"tslib": "^2.0.0",
|
||||
"webpack-bundle-analyzer": "^4.4.2",
|
||||
"zone.js": "~0.10.2"
|
||||
"ng-lazyload-image": "^9.1.2",
|
||||
"ngx-file-drop": "^13.0.0",
|
||||
"ngx-toastr": "^14.2.1",
|
||||
"rxjs": "~7.5.4",
|
||||
"swiper": "^8.0.3",
|
||||
"tslib": "^2.3.1",
|
||||
"webpack-bundle-analyzer": "^4.5.0",
|
||||
"zone.js": "~0.11.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@angular-devkit/build-angular": "~0.1100.0",
|
||||
"@angular/cli": "^11.2.11",
|
||||
"@angular/compiler-cli": "~11.0.0",
|
||||
"@types/jest": "^26.0.20",
|
||||
"@types/node": "^12.11.1",
|
||||
"codelyzer": "^6.0.0",
|
||||
"jest": "^26.6.3",
|
||||
"jest-preset-angular": "^8.3.2",
|
||||
"karma-coverage": "~2.0.3",
|
||||
"@angular-devkit/build-angular": "~13.2.3",
|
||||
"@angular/cli": "^13.2.3",
|
||||
"@angular/compiler-cli": "~13.2.2",
|
||||
"@types/jest": "^27.4.0",
|
||||
"@types/node": "^17.0.17",
|
||||
"codelyzer": "^6.0.2",
|
||||
"jest": "^27.5.1",
|
||||
"jest-preset-angular": "^11.1.0",
|
||||
"karma-coverage": "~2.2.0",
|
||||
"protractor": "~7.0.0",
|
||||
"ts-node": "~8.3.0",
|
||||
"ts-node": "~10.5.0",
|
||||
"tslint": "^6.1.3",
|
||||
"typescript": "~4.0.2"
|
||||
"typescript": "~4.5.5"
|
||||
},
|
||||
"jest": {
|
||||
"preset": "jest-preset-angular",
|
||||
|
@ -3,7 +3,6 @@ import { CanActivate } from '@angular/router';
|
||||
import { ToastrService } from 'ngx-toastr';
|
||||
import { Observable } from 'rxjs';
|
||||
import { map, take } from 'rxjs/operators';
|
||||
import { User } from '../_models/user';
|
||||
import { AccountService } from '../_services/account.service';
|
||||
|
||||
@Injectable({
|
||||
@ -15,8 +14,8 @@ export class AdminGuard implements CanActivate {
|
||||
canActivate(): Observable<boolean> {
|
||||
// this automaticallys subs due to being router guard
|
||||
return this.accountService.currentUser$.pipe(take(1),
|
||||
map((user: User) => {
|
||||
if (this.accountService.hasAdminRole(user)) {
|
||||
map((user) => {
|
||||
if (user && this.accountService.hasAdminRole(user)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -3,7 +3,6 @@ import { CanActivate, Router } from '@angular/router';
|
||||
import { ToastrService } from 'ngx-toastr';
|
||||
import { Observable } from 'rxjs';
|
||||
import { map, take } from 'rxjs/operators';
|
||||
import { User } from '../_models/user';
|
||||
import { AccountService } from '../_services/account.service';
|
||||
|
||||
@Injectable({
|
||||
@ -15,7 +14,7 @@ export class AuthGuard implements CanActivate {
|
||||
|
||||
canActivate(): Observable<boolean> {
|
||||
return this.accountService.currentUser$.pipe(take(1),
|
||||
map((user: User) => {
|
||||
map((user) => {
|
||||
if (user) {
|
||||
return true;
|
||||
}
|
||||
|
@ -7,7 +7,6 @@ import {
|
||||
} from '@angular/common/http';
|
||||
import { Observable } from 'rxjs';
|
||||
import { AccountService } from '../_services/account.service';
|
||||
import { User } from '../_models/user';
|
||||
import { take } from 'rxjs/operators';
|
||||
|
||||
@Injectable()
|
||||
@ -16,16 +15,13 @@ export class JwtInterceptor implements HttpInterceptor {
|
||||
constructor(private accountService: AccountService) {}
|
||||
|
||||
intercept(request: HttpRequest<unknown>, next: HttpHandler): Observable<HttpEvent<unknown>> {
|
||||
let currentUser: User;
|
||||
|
||||
// Take 1 means we don't have to unsubscribe because we take 1 then complete
|
||||
this.accountService.currentUser$.pipe(take(1)).subscribe(user => {
|
||||
currentUser = user;
|
||||
|
||||
if (currentUser) {
|
||||
if (user) {
|
||||
request = request.clone({
|
||||
setHeaders: {
|
||||
Authorization: `Bearer ${currentUser.token}`
|
||||
Authorization: `Bearer ${user.token}`
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -19,7 +19,10 @@ export class AccountService implements OnDestroy {
|
||||
currentUser: User | undefined;
|
||||
|
||||
// Stores values, when someone subscribes gives (1) of last values seen.
|
||||
private currentUserSource = new ReplaySubject<User>(1);
|
||||
private currentUserSource = new ReplaySubject<User | undefined>(1);
|
||||
/**
|
||||
*
|
||||
*/
|
||||
currentUser$ = this.currentUserSource.asObservable();
|
||||
|
||||
/**
|
||||
|
@ -35,8 +35,10 @@ export class ManageUsersComponent implements OnInit, OnDestroy {
|
||||
private confirmService: ConfirmService,
|
||||
public messageHub: MessageHubService,
|
||||
private serverService: ServerService) {
|
||||
this.accountService.currentUser$.pipe(take(1)).subscribe((user: User) => {
|
||||
this.accountService.currentUser$.pipe(take(1)).subscribe((user) => {
|
||||
if (user) {
|
||||
this.loggedInUsername = user.username;
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
@ -2,14 +2,14 @@
|
||||
<div>
|
||||
<h2 style="display: inline-block;"><a href="javascript:void(0)" (click)="sectionClicked($event)" class="section-title">{{title}}</a></h2>
|
||||
<div class="float-right">
|
||||
<button class="btn btn-icon" [disabled]="swiper?.isBeginning" (click)="prevPage()"><i class="fa fa-angle-left" aria-hidden="true"></i><span class="sr-only">Previous Items</span></button>
|
||||
<button class="btn btn-icon" [disabled]="swiper?.isEnd" (click)="nextPage()"><i class="fa fa-angle-right" aria-hidden="true"></i><span class="sr-only">Next Items</span></button>
|
||||
<button class="btn btn-icon" [disabled]="isBeginning" (click)="prevPage()"><i class="fa fa-angle-left" aria-hidden="true"></i><span class="sr-only">Previous Items</span></button>
|
||||
<button class="btn btn-icon" [disabled]="isEnd" (click)="nextPage()"><i class="fa fa-angle-right" aria-hidden="true"></i><span class="sr-only">Next Items</span></button>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<swiper
|
||||
#swiper
|
||||
[slidesPerView]="'auto'"
|
||||
(swiper)="onSwiper($event)"
|
||||
[freeMode]="true">
|
||||
<ng-template *ngFor="let item of items; index as i;" swiperSlide>
|
||||
<ng-container [ngTemplateOutlet]="carouselItemTemplate" [ngTemplateOutletContext]="{ $implicit: item, idx: i }"></ng-container>
|
||||
|
@ -1,5 +1,7 @@
|
||||
import { Component, ContentChild, EventEmitter, Input, OnInit, Output, TemplateRef } from '@angular/core';
|
||||
import Swiper from 'swiper';
|
||||
import { Component, ContentChild, EventEmitter, Input, OnInit, Output, TemplateRef, ViewChild } from '@angular/core';
|
||||
import { SwiperComponent } from 'swiper/angular';
|
||||
//import Swiper from 'swiper';
|
||||
//import { SwiperEvents, Swiper } from 'swiper/types';
|
||||
|
||||
@Component({
|
||||
selector: 'app-carousel-reel',
|
||||
@ -13,10 +15,20 @@ export class CarouselReelComponent implements OnInit {
|
||||
@Input() title = '';
|
||||
@Output() sectionClick = new EventEmitter<string>();
|
||||
|
||||
@ViewChild('swiper', { static: false }) swiper?: SwiperComponent;
|
||||
|
||||
swiper!: Swiper;
|
||||
|
||||
//swiper!: Swiper;
|
||||
trackByIdentity: (index: number, item: any) => string;
|
||||
|
||||
get isEnd() {
|
||||
return this.swiper?.swiperRef.isEnd;
|
||||
}
|
||||
|
||||
get isBeginning() {
|
||||
return this.swiper?.swiperRef.isBeginning;
|
||||
}
|
||||
|
||||
constructor() {
|
||||
this.trackByIdentity = (index: number, item: any) => `${this.title}_${item.id}_${item?.name}_${item?.pagesRead}_${index}`;
|
||||
}
|
||||
@ -25,13 +37,13 @@ export class CarouselReelComponent implements OnInit {
|
||||
|
||||
nextPage() {
|
||||
if (this.swiper) {
|
||||
this.swiper.setProgress(this.swiper.progress + 0.25, 600);
|
||||
this.swiper.swiperRef.setProgress(this.swiper.swiperRef.progress + 0.25, 600);
|
||||
}
|
||||
}
|
||||
|
||||
prevPage() {
|
||||
if (this.swiper) {
|
||||
this.swiper.setProgress(this.swiper.progress - 0.25, 600);
|
||||
this.swiper.swiperRef.setProgress(this.swiper.swiperRef.progress - 0.25, 600);
|
||||
}
|
||||
}
|
||||
|
||||
@ -39,7 +51,14 @@ export class CarouselReelComponent implements OnInit {
|
||||
this.sectionClick.emit(this.title);
|
||||
}
|
||||
|
||||
onSwiper(swiper: any) {
|
||||
this.swiper = swiper;
|
||||
}
|
||||
// onSwiper(eventParams: Parameters<SwiperEvents['init']>) {
|
||||
// console.log('swiper: ', eventParams);
|
||||
// [this.swiper] = eventParams;
|
||||
// }
|
||||
|
||||
// onSwiper(params: Swiper) {
|
||||
// // const [swiper] = params;
|
||||
// // console.log(swiper);
|
||||
// // return params;
|
||||
// }
|
||||
}
|
||||
|
@ -73,11 +73,13 @@ export class LibraryComponent implements OnInit, OnDestroy {
|
||||
this.isLoading = true;
|
||||
this.accountService.currentUser$.pipe(take(1)).subscribe(user => {
|
||||
this.user = user;
|
||||
if (this.user) {
|
||||
this.isAdmin = this.accountService.hasAdminRole(this.user);
|
||||
this.libraryService.getLibrariesForMember().pipe(take(1)).subscribe(libraries => {
|
||||
this.libraries = libraries;
|
||||
this.isLoading = false;
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
this.reloadSeries();
|
||||
|
@ -1,7 +1,9 @@
|
||||
|
||||
@use '../../../../theme/colors';
|
||||
.clickable {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.clickable:hover, .clickable:focus {
|
||||
background-color: lightgreen;
|
||||
background-color: colors.$primary-color;
|
||||
}
|
@ -83,7 +83,7 @@ export class UserPreferencesComponent implements OnInit, OnDestroy {
|
||||
|
||||
ngOnInit(): void {
|
||||
this.titleService.setTitle('Kavita - User Preferences');
|
||||
this.accountService.currentUser$.pipe(take(1)).subscribe((user: User) => {
|
||||
this.accountService.currentUser$.pipe(take(1)).subscribe((user) => {
|
||||
if (user) {
|
||||
this.user = user;
|
||||
this.isAdmin = this.accountService.hasAdminRole(user);
|
||||
|
@ -15,4 +15,4 @@ export const environment = {
|
||||
* This import should be commented out in production mode because it will have a negative impact
|
||||
* on performance if an error is thrown.
|
||||
*/
|
||||
// import 'zone.js/dist/zone-error'; // Included with Angular CLI.
|
||||
// import 'zone.js/plugins/zone-error'; // Included with Angular CLI.
|
||||
|
@ -59,7 +59,7 @@ import '@angular/localize/init';
|
||||
/***************************************************************************************************
|
||||
* Zone JS is required by default for Angular itself.
|
||||
*/
|
||||
import 'zone.js/dist/zone'; // Included with Angular CLI.
|
||||
import 'zone.js'; // Included with Angular CLI.
|
||||
|
||||
|
||||
/***************************************************************************************************
|
||||
|
@ -1,14 +1,20 @@
|
||||
@use '../node_modules/swiper/swiper.scss' as swiper;
|
||||
@use '~bootstrap/scss/mixins/_breakpoints.scss' as breakpoints;
|
||||
|
||||
// Import colors for overrides of bootstrap theme
|
||||
@import './theme/colors';
|
||||
@import './theme/toastr';
|
||||
|
||||
// Bootstrap must be after _colors since we define the colors there
|
||||
@import '~bootstrap/scss/bootstrap';
|
||||
@import '~bootstrap/scss/mixins/_breakpoints.scss';
|
||||
|
||||
@import '~swiper/swiper.scss';
|
||||
|
||||
@import './assets/themes/dark.scss';
|
||||
|
||||
@import './theme/dark.scss';
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// Global Styles
|
||||
button:disabled, .form-control:disabled, .form-control[readonly], .disabled, :disabled {
|
||||
@ -72,14 +78,16 @@ app-root {
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// Utiliities
|
||||
@include media-breakpoint-down(xs, (xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px)) {
|
||||
@include breakpoints.media-breakpoint-down(xs, (xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px)) {
|
||||
.phone-hidden {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
@include media-breakpoint-up(sm, (xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px)) {
|
||||
@include breakpoints.media-breakpoint-up(sm, (xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px)) {
|
||||
.not-phone-hidden {
|
||||
display: none;
|
||||
}
|
||||
|
@ -18,6 +18,26 @@ $dark-item-accent-bg: #292d32;
|
||||
|
||||
$white-item-accent-bg: rgba(247, 247, 247, 1);
|
||||
|
||||
// Default variables for light mode
|
||||
:root {
|
||||
--primary-color: #4ac694;
|
||||
--error-color: #ff4136;
|
||||
--bs-body-bg: #fff;
|
||||
}
|
||||
|
||||
// Dark mode theme
|
||||
:root .bg-dark {
|
||||
--primary-color: #4ac694;
|
||||
--error-color: #ff4136;
|
||||
--bs-body-bg: red; // This is bootstrap v5 only
|
||||
}
|
||||
|
||||
// E-ink theme
|
||||
:root .bg-eink {
|
||||
--primary-color: black;
|
||||
--bs-body-bg: white;
|
||||
}
|
||||
|
||||
|
||||
//=========================
|
||||
// Ratings
|
||||
|
@ -1,6 +1,10 @@
|
||||
// All dark style overrides should live here
|
||||
|
||||
@use "../../theme/colors";
|
||||
@use "./colors";
|
||||
|
||||
// :root {
|
||||
// --bs-body-color: #212529;
|
||||
// }
|
||||
|
||||
.bg-dark {
|
||||
color: $dark-text-color;
|
||||
@ -155,7 +159,7 @@
|
||||
|
||||
&::before {
|
||||
content: "";
|
||||
background-image: url('../../assets/images/login-bg.jpg');
|
||||
background-image: url('../assets/images/login-bg.jpg');
|
||||
background-size: cover;
|
||||
position: absolute;
|
||||
top: 0;
|
Loading…
x
Reference in New Issue
Block a user