mirror of
https://github.com/Kareadita/Kavita.git
synced 2025-07-09 03:04:19 -04:00
Shakeout Bugs (#623)
* Fixed an issue where ScanSeries would not fetch all the entities and thus files would get duplicated on the Chapter * Remove building extra language binaries on build. * Fixed an issue where first scan would cause an issue with websocket due to trying to send NaN over the wire. * Fixed an issue where on new scans scan in progress indicators wouldn't turn off due to the way we were consuming events off the pipe. * Ensure login page doesn't flash on first load * Don't process touch events at all unless selection is enabled.
This commit is contained in:
parent
fccdfa3bfe
commit
d750ce77a0
@ -16,6 +16,10 @@
|
|||||||
<DocumentationFile>bin\Debug\API.xml</DocumentationFile>
|
<DocumentationFile>bin\Debug\API.xml</DocumentationFile>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<SatelliteResourceLanguages>en</SatelliteResourceLanguages>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
<!-- Set the Product and Version info for our own projects -->
|
<!-- Set the Product and Version info for our own projects -->
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<Product>Kavita</Product>
|
<Product>Kavita</Product>
|
||||||
|
@ -42,7 +42,7 @@ namespace API.Extensions
|
|||||||
|
|
||||||
services.AddSqLite(config, env);
|
services.AddSqLite(config, env);
|
||||||
services.AddLogging(config);
|
services.AddLogging(config);
|
||||||
services.AddSignalR();
|
services.AddSignalR(opt => opt.EnableDetailedErrors = true);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void AddSqLite(this IServiceCollection services, IConfiguration config,
|
private static void AddSqLite(this IServiceCollection services, IConfiguration config,
|
||||||
|
@ -52,7 +52,7 @@ namespace API.Services.Tasks
|
|||||||
{
|
{
|
||||||
var sw = new Stopwatch();
|
var sw = new Stopwatch();
|
||||||
var files = await _unitOfWork.SeriesRepository.GetFilesForSeries(seriesId);
|
var files = await _unitOfWork.SeriesRepository.GetFilesForSeries(seriesId);
|
||||||
var series = await _unitOfWork.SeriesRepository.GetSeriesByIdAsync(seriesId);
|
var series = await _unitOfWork.SeriesRepository.GetFullSeriesForSeriesIdAsync(seriesId);
|
||||||
var chapterIds = await _unitOfWork.SeriesRepository.GetChapterIdsForSeriesAsync(new[] {seriesId});
|
var chapterIds = await _unitOfWork.SeriesRepository.GetChapterIdsForSeriesAsync(new[] {seriesId});
|
||||||
var library = await _unitOfWork.LibraryRepository.GetLibraryForIdAsync(libraryId, LibraryIncludes.Folders);
|
var library = await _unitOfWork.LibraryRepository.GetLibraryForIdAsync(libraryId, LibraryIncludes.Folders);
|
||||||
var folderPaths = library.Folders.Select(f => f.Path).ToList();
|
var folderPaths = library.Folders.Select(f => f.Path).ToList();
|
||||||
@ -186,7 +186,7 @@ namespace API.Services.Tasks
|
|||||||
|
|
||||||
_logger.LogInformation("[ScannerService] Beginning file scan on {LibraryName}", library.Name);
|
_logger.LogInformation("[ScannerService] Beginning file scan on {LibraryName}", library.Name);
|
||||||
await _messageHub.Clients.All.SendAsync(SignalREvents.ScanLibraryProgress,
|
await _messageHub.Clients.All.SendAsync(SignalREvents.ScanLibraryProgress,
|
||||||
MessageFactory.ScanLibraryProgressEvent(libraryId, 0, string.Empty));
|
MessageFactory.ScanLibraryProgressEvent(libraryId, 0));
|
||||||
|
|
||||||
var scanner = new ParseScannedFiles(_bookService, _logger);
|
var scanner = new ParseScannedFiles(_bookService, _logger);
|
||||||
var series = scanner.ScanLibrariesForSeries(library.Type, library.Folders.Select(fp => fp.Path), out var totalFiles, out var scanElapsedTime);
|
var series = scanner.ScanLibrariesForSeries(library.Type, library.Folders.Select(fp => fp.Path), out var totalFiles, out var scanElapsedTime);
|
||||||
@ -217,7 +217,7 @@ namespace API.Services.Tasks
|
|||||||
|
|
||||||
BackgroundJob.Enqueue(() => _metadataService.RefreshMetadata(libraryId, false));
|
BackgroundJob.Enqueue(() => _metadataService.RefreshMetadata(libraryId, false));
|
||||||
await _messageHub.Clients.All.SendAsync(SignalREvents.ScanLibraryProgress,
|
await _messageHub.Clients.All.SendAsync(SignalREvents.ScanLibraryProgress,
|
||||||
MessageFactory.ScanLibraryProgressEvent(libraryId, 100, string.Empty));
|
MessageFactory.ScanLibraryProgressEvent(libraryId, 100));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -253,6 +253,7 @@ namespace API.Services.Tasks
|
|||||||
_logger.LogDebug("[ScannerService] Updating existing series");
|
_logger.LogDebug("[ScannerService] Updating existing series");
|
||||||
for (var chunk = 0; chunk <= chunkInfo.TotalChunks; chunk++)
|
for (var chunk = 0; chunk <= chunkInfo.TotalChunks; chunk++)
|
||||||
{
|
{
|
||||||
|
if (chunkInfo.TotalChunks == 0) continue;
|
||||||
totalTime += stopwatch.ElapsedMilliseconds;
|
totalTime += stopwatch.ElapsedMilliseconds;
|
||||||
stopwatch.Restart();
|
stopwatch.Restart();
|
||||||
_logger.LogDebug($"[ScannerService] Processing chunk {chunk} / {chunkInfo.TotalChunks} with size {chunkInfo.ChunkSize} Series ({chunk * chunkInfo.ChunkSize} - {(chunk + 1) * chunkInfo.ChunkSize}");
|
_logger.LogDebug($"[ScannerService] Processing chunk {chunk} / {chunkInfo.TotalChunks} with size {chunkInfo.ChunkSize} Series ({chunk * chunkInfo.ChunkSize} - {(chunk + 1) * chunkInfo.ChunkSize}");
|
||||||
@ -298,8 +299,9 @@ namespace API.Services.Tasks
|
|||||||
await _messageHub.Clients.All.SendAsync(SignalREvents.SeriesRemoved, MessageFactory.SeriesRemovedEvent(missing.Id, missing.Name, library.Id));
|
await _messageHub.Clients.All.SendAsync(SignalREvents.SeriesRemoved, MessageFactory.SeriesRemovedEvent(missing.Id, missing.Name, library.Id));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var progress = Math.Max(0, Math.Min(100, ((chunk + 1F) * chunkInfo.ChunkSize) / chunkInfo.TotalSize));
|
||||||
await _messageHub.Clients.All.SendAsync(SignalREvents.ScanLibraryProgress,
|
await _messageHub.Clients.All.SendAsync(SignalREvents.ScanLibraryProgress,
|
||||||
MessageFactory.ScanLibraryProgressEvent(library.Id, ((chunk + 1F) * chunkInfo.ChunkSize) / chunkInfo.TotalSize, string.Empty));
|
MessageFactory.ScanLibraryProgressEvent(library.Id, progress));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -336,6 +338,7 @@ namespace API.Services.Tasks
|
|||||||
newSeries.Add(existingSeries);
|
newSeries.Add(existingSeries);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var i = 0;
|
||||||
foreach(var series in newSeries)
|
foreach(var series in newSeries)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@ -353,6 +356,9 @@ namespace API.Services.Tasks
|
|||||||
|
|
||||||
// Inform UI of new series added
|
// Inform UI of new series added
|
||||||
await _messageHub.Clients.All.SendAsync(SignalREvents.SeriesAdded, MessageFactory.SeriesAddedEvent(series.Id, series.Name, library.Id));
|
await _messageHub.Clients.All.SendAsync(SignalREvents.SeriesAdded, MessageFactory.SeriesAddedEvent(series.Id, series.Name, library.Id));
|
||||||
|
var progress = Math.Max(0F, Math.Min(100F, i * 1F / newSeries.Count));
|
||||||
|
await _messageHub.Clients.All.SendAsync(SignalREvents.ScanLibraryProgress,
|
||||||
|
MessageFactory.ScanLibraryProgressEvent(library.Id, progress));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -360,6 +366,8 @@ namespace API.Services.Tasks
|
|||||||
_logger.LogCritical(
|
_logger.LogCritical(
|
||||||
"[ScannerService] There was a critical error that resulted in a failed scan. Please check logs and rescan");
|
"[ScannerService] There was a critical error that resulted in a failed scan. Please check logs and rescan");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
i++;
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
@ -59,7 +59,7 @@ namespace API.SignalR
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public static SignalRMessage ScanLibraryProgressEvent(int libraryId, float progress, string seriesName)
|
public static SignalRMessage ScanLibraryProgressEvent(int libraryId, float progress)
|
||||||
{
|
{
|
||||||
return new SignalRMessage()
|
return new SignalRMessage()
|
||||||
{
|
{
|
||||||
@ -68,7 +68,6 @@ namespace API.SignalR
|
|||||||
{
|
{
|
||||||
LibraryId = libraryId,
|
LibraryId = libraryId,
|
||||||
Progress = progress,
|
Progress = progress,
|
||||||
SeriesName = seriesName
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -36,9 +36,12 @@ export class ManageLibraryComponent implements OnInit, OnDestroy {
|
|||||||
this.getLibraries();
|
this.getLibraries();
|
||||||
|
|
||||||
// when a progress event comes in, show it on the UI next to library
|
// when a progress event comes in, show it on the UI next to library
|
||||||
this.hubService.messages$.pipe(takeWhile(event => event.event === EVENTS.ScanLibraryProgress)).subscribe((event) => {
|
this.hubService.messages$.pipe(takeUntil(this.onDestroy)).subscribe((event) => {
|
||||||
|
if (event.event != EVENTS.ScanLibraryProgress) return;
|
||||||
|
|
||||||
const scanEvent = event.payload as ScanLibraryProgressEvent;
|
const scanEvent = event.payload as ScanLibraryProgressEvent;
|
||||||
this.scanInProgress[scanEvent.libraryId] = scanEvent.progress !== 100;
|
this.scanInProgress[scanEvent.libraryId] = scanEvent.progress !== 100;
|
||||||
|
|
||||||
if (this.scanInProgress[scanEvent.libraryId] === false && scanEvent.progress === 100) {
|
if (this.scanInProgress[scanEvent.libraryId] === false && scanEvent.progress === 100) {
|
||||||
this.libraryService.getLibraries().pipe(take(1)).subscribe(libraries => {
|
this.libraryService.getLibraries().pipe(take(1)).subscribe(libraries => {
|
||||||
const newLibrary = libraries.find(lib => lib.id === scanEvent.libraryId);
|
const newLibrary = libraries.find(lib => lib.id === scanEvent.libraryId);
|
||||||
|
@ -123,6 +123,7 @@ export class CardItemComponent implements OnInit, OnDestroy {
|
|||||||
prevOffset: number = 0;
|
prevOffset: number = 0;
|
||||||
@HostListener('touchstart', ['$event'])
|
@HostListener('touchstart', ['$event'])
|
||||||
onTouchStart(event: TouchEvent) {
|
onTouchStart(event: TouchEvent) {
|
||||||
|
if (!this.allowSelection) return;
|
||||||
const verticalOffset = (window.pageYOffset
|
const verticalOffset = (window.pageYOffset
|
||||||
|| document.documentElement.scrollTop
|
|| document.documentElement.scrollTop
|
||||||
|| document.body.scrollTop || 0);
|
|| document.body.scrollTop || 0);
|
||||||
@ -133,6 +134,7 @@ export class CardItemComponent implements OnInit, OnDestroy {
|
|||||||
|
|
||||||
@HostListener('touchend', ['$event'])
|
@HostListener('touchend', ['$event'])
|
||||||
onTouchEnd(event: TouchEvent) {
|
onTouchEnd(event: TouchEvent) {
|
||||||
|
if (!this.allowSelection) return;
|
||||||
const delta = event.timeStamp - this.prevTouchTime;
|
const delta = event.timeStamp - this.prevTouchTime;
|
||||||
const verticalOffset = (window.pageYOffset
|
const verticalOffset = (window.pageYOffset
|
||||||
|| document.documentElement.scrollTop
|
|| document.documentElement.scrollTop
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
import { Component, EventEmitter, Input, OnChanges, OnInit, Output } from '@angular/core';
|
import { Component, EventEmitter, Input, OnChanges, OnDestroy, OnInit, Output } from '@angular/core';
|
||||||
import { Router } from '@angular/router';
|
import { Router } from '@angular/router';
|
||||||
import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
|
import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
|
||||||
import { ToastrService } from 'ngx-toastr';
|
import { ToastrService } from 'ngx-toastr';
|
||||||
import { take, takeWhile } from 'rxjs/operators';
|
import { take, takeUntil, takeWhile } from 'rxjs/operators';
|
||||||
import { Series } from 'src/app/_models/series';
|
import { Series } from 'src/app/_models/series';
|
||||||
import { AccountService } from 'src/app/_services/account.service';
|
import { AccountService } from 'src/app/_services/account.service';
|
||||||
import { ImageService } from 'src/app/_services/image.service';
|
import { ImageService } from 'src/app/_services/image.service';
|
||||||
@ -13,13 +13,14 @@ import { ActionService } from 'src/app/_services/action.service';
|
|||||||
import { EditSeriesModalComponent } from '../_modals/edit-series-modal/edit-series-modal.component';
|
import { EditSeriesModalComponent } from '../_modals/edit-series-modal/edit-series-modal.component';
|
||||||
import { RefreshMetadataEvent } from 'src/app/_models/events/refresh-metadata-event';
|
import { RefreshMetadataEvent } from 'src/app/_models/events/refresh-metadata-event';
|
||||||
import { MessageHubService } from 'src/app/_services/message-hub.service';
|
import { MessageHubService } from 'src/app/_services/message-hub.service';
|
||||||
|
import { Subject } from 'rxjs';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-series-card',
|
selector: 'app-series-card',
|
||||||
templateUrl: './series-card.component.html',
|
templateUrl: './series-card.component.html',
|
||||||
styleUrls: ['./series-card.component.scss']
|
styleUrls: ['./series-card.component.scss']
|
||||||
})
|
})
|
||||||
export class SeriesCardComponent implements OnInit, OnChanges {
|
export class SeriesCardComponent implements OnInit, OnChanges, OnDestroy {
|
||||||
@Input() data!: Series;
|
@Input() data!: Series;
|
||||||
@Input() libraryId = 0;
|
@Input() libraryId = 0;
|
||||||
@Input() suppressLibraryLink = false;
|
@Input() suppressLibraryLink = false;
|
||||||
@ -43,6 +44,7 @@ export class SeriesCardComponent implements OnInit, OnChanges {
|
|||||||
isAdmin = false;
|
isAdmin = false;
|
||||||
actions: ActionItem<Series>[] = [];
|
actions: ActionItem<Series>[] = [];
|
||||||
imageUrl: string = '';
|
imageUrl: string = '';
|
||||||
|
onDestroy: Subject<void> = new Subject<void>();
|
||||||
|
|
||||||
constructor(private accountService: AccountService, private router: Router,
|
constructor(private accountService: AccountService, private router: Router,
|
||||||
private seriesService: SeriesService, private toastr: ToastrService,
|
private seriesService: SeriesService, private toastr: ToastrService,
|
||||||
@ -61,12 +63,10 @@ export class SeriesCardComponent implements OnInit, OnChanges {
|
|||||||
if (this.data) {
|
if (this.data) {
|
||||||
this.imageUrl = this.imageService.randomize(this.imageService.getSeriesCoverImage(this.data.id));
|
this.imageUrl = this.imageService.randomize(this.imageService.getSeriesCoverImage(this.data.id));
|
||||||
|
|
||||||
this.hubService.refreshMetadata.pipe(takeWhile(event => event.libraryId === this.libraryId)).subscribe((event: RefreshMetadataEvent) => {
|
this.hubService.refreshMetadata.pipe(takeWhile(event => event.libraryId === this.libraryId), takeUntil(this.onDestroy)).subscribe((event: RefreshMetadataEvent) => {
|
||||||
if (this.data.id === event.seriesId) {
|
if (this.data.id === event.seriesId) {
|
||||||
this.imageUrl = this.imageService.randomize(this.imageService.getSeriesCoverImage(this.data.id));
|
this.imageUrl = this.imageService.randomize(this.imageService.getSeriesCoverImage(this.data.id));
|
||||||
console.log('Refresh event came through, updating cover image');
|
}
|
||||||
}
|
|
||||||
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -78,6 +78,11 @@ export class SeriesCardComponent implements OnInit, OnChanges {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ngOnDestroy() {
|
||||||
|
this.onDestroy.next();
|
||||||
|
this.onDestroy.complete();
|
||||||
|
}
|
||||||
|
|
||||||
handleSeriesActionCallback(action: Action, series: Series) {
|
handleSeriesActionCallback(action: Action, series: Series) {
|
||||||
switch (action) {
|
switch (action) {
|
||||||
case(Action.MarkAsRead):
|
case(Action.MarkAsRead):
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
import { Component, HostListener, OnInit } from '@angular/core';
|
import { Component, HostListener, OnDestroy, OnInit } from '@angular/core';
|
||||||
import { Title } from '@angular/platform-browser';
|
import { Title } from '@angular/platform-browser';
|
||||||
import { ActivatedRoute, Router } from '@angular/router';
|
import { ActivatedRoute, Router } from '@angular/router';
|
||||||
import { debounceTime, take, takeWhile } from 'rxjs/operators';
|
import { Subject } from 'rxjs';
|
||||||
|
import { debounceTime, take, takeUntil, takeWhile } from 'rxjs/operators';
|
||||||
import { BulkSelectionService } from '../cards/bulk-selection.service';
|
import { BulkSelectionService } from '../cards/bulk-selection.service';
|
||||||
import { UpdateFilterEvent } from '../cards/card-detail-layout/card-detail-layout.component';
|
import { UpdateFilterEvent } from '../cards/card-detail-layout/card-detail-layout.component';
|
||||||
import { KEY_CODES } from '../shared/_services/utility.service';
|
import { KEY_CODES } from '../shared/_services/utility.service';
|
||||||
@ -21,7 +22,7 @@ import { SeriesService } from '../_services/series.service';
|
|||||||
templateUrl: './library-detail.component.html',
|
templateUrl: './library-detail.component.html',
|
||||||
styleUrls: ['./library-detail.component.scss']
|
styleUrls: ['./library-detail.component.scss']
|
||||||
})
|
})
|
||||||
export class LibraryDetailComponent implements OnInit {
|
export class LibraryDetailComponent implements OnInit, OnDestroy {
|
||||||
|
|
||||||
libraryId!: number;
|
libraryId!: number;
|
||||||
libraryName = '';
|
libraryName = '';
|
||||||
@ -33,6 +34,7 @@ export class LibraryDetailComponent implements OnInit {
|
|||||||
filter: SeriesFilter = {
|
filter: SeriesFilter = {
|
||||||
mangaFormat: null
|
mangaFormat: null
|
||||||
};
|
};
|
||||||
|
onDestroy: Subject<void> = new Subject<void>();
|
||||||
|
|
||||||
bulkActionCallback = (action: Action, data: any) => {
|
bulkActionCallback = (action: Action, data: any) => {
|
||||||
const selectedSeriesIndexies = this.bulkSelectionService.getSelectedCardsForSource('series');
|
const selectedSeriesIndexies = this.bulkSelectionService.getSelectedCardsForSource('series');
|
||||||
@ -80,11 +82,16 @@ export class LibraryDetailComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
this.hubService.seriesAdded.pipe(takeWhile(event => event.libraryId === this.libraryId), debounceTime(6000)).subscribe((event: SeriesAddedEvent) => {
|
this.hubService.seriesAdded.pipe(takeWhile(event => event.libraryId === this.libraryId), debounceTime(6000), takeUntil(this.onDestroy)).subscribe((event: SeriesAddedEvent) => {
|
||||||
this.loadPage();
|
this.loadPage();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ngOnDestroy() {
|
||||||
|
this.onDestroy.next();
|
||||||
|
this.onDestroy.complete();
|
||||||
|
}
|
||||||
|
|
||||||
@HostListener('document:keydown.shift', ['$event'])
|
@HostListener('document:keydown.shift', ['$event'])
|
||||||
handleKeypress(event: KeyboardEvent) {
|
handleKeypress(event: KeyboardEvent) {
|
||||||
if (event.key === KEY_CODES.SHIFT) {
|
if (event.key === KEY_CODES.SHIFT) {
|
||||||
|
@ -1,44 +1,46 @@
|
|||||||
<div class="mx-auto login">
|
<div class="mx-auto login">
|
||||||
|
|
||||||
<div class="display: inline-block" *ngIf="firstTimeFlow">
|
<ng-container *ngIf="isLoaded">
|
||||||
<h3 class="card-title text-center">Create an Admin Account</h3>
|
<div class="display: inline-block" *ngIf="firstTimeFlow">
|
||||||
<div class="card p-3">
|
<h3 class="card-title text-center">Create an Admin Account</h3>
|
||||||
<p>Please create an admin account for yourself to start your reading journey.</p>
|
<div class="card p-3">
|
||||||
<app-register-member (created)="onAdminCreated($event)" [firstTimeFlow]="firstTimeFlow"></app-register-member>
|
<p>Please create an admin account for yourself to start your reading journey.</p>
|
||||||
|
<app-register-member (created)="onAdminCreated($event)" [firstTimeFlow]="firstTimeFlow"></app-register-member>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
|
<form [formGroup]="loginForm" (ngSubmit)="login()" novalidate class="needs-validation" *ngIf="!firstTimeFlow">
|
||||||
<form [formGroup]="loginForm" (ngSubmit)="login()" novalidate class="needs-validation" *ngIf="!firstTimeFlow">
|
<div class="row row-cols-4 row-cols-md-4 row-cols-sm-2 row-cols-xs-2">
|
||||||
<div class="row row-cols-4 row-cols-md-4 row-cols-sm-2 row-cols-xs-2">
|
<ng-container *ngFor="let member of memberNames">
|
||||||
<ng-container *ngFor="let member of memberNames">
|
<div class="col align-self-center card p-3 m-3" style="width: 12rem;">
|
||||||
<div class="col align-self-center card p-3 m-3" style="width: 12rem;">
|
<span tabindex="0" (click)="select(member)" a11y-click="13,32">
|
||||||
<span tabindex="0" (click)="select(member)" a11y-click="13,32">
|
<div class="logo-container">
|
||||||
<div class="logo-container">
|
<h3 class="card-title text-center">{{member | titlecase}}</h3>
|
||||||
<h3 class="card-title text-center">{{member | titlecase}}</h3>
|
</div>
|
||||||
</div>
|
</span>
|
||||||
</span>
|
|
||||||
|
<div class="card-text" #collapse="ngbCollapse" [(ngbCollapse)]="isCollapsed[member]" (keyup.enter)="$event.stopPropagation()">
|
||||||
<div class="card-text" #collapse="ngbCollapse" [(ngbCollapse)]="isCollapsed[member]" (keyup.enter)="$event.stopPropagation()">
|
<div class="form-group" [ngStyle]="authDisabled ? {display: 'none'} : {}">
|
||||||
<div class="form-group" [ngStyle]="authDisabled ? {display: 'none'} : {}">
|
<label for="username--{{member}}">Username</label>
|
||||||
<label for="username--{{member}}">Username</label>
|
<input class="form-control" formControlName="username" id="username--{{member}}" type="text" [readonly]="authDisabled">
|
||||||
<input class="form-control" formControlName="username" id="username--{{member}}" type="text" [readonly]="authDisabled">
|
</div>
|
||||||
</div>
|
|
||||||
|
<div class="form-group">
|
||||||
<div class="form-group">
|
<label for="password--{{member}}">Password</label>
|
||||||
<label for="password--{{member}}">Password</label>
|
<input class="form-control" formControlName="password" id="password--{{member}}" type="password" autofocus>
|
||||||
<input class="form-control" formControlName="password" id="password--{{member}}" type="password" autofocus>
|
<div *ngIf="authDisabled" class="invalid-feedback">
|
||||||
<div *ngIf="authDisabled" class="invalid-feedback">
|
Authentication is disabled. Only type password if this is an admin account.
|
||||||
Authentication is disabled. Only type password if this is an admin account.
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="float-right">
|
||||||
|
<button class="btn btn-primary alt" type="submit--{{member}}">Login</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="float-right">
|
|
||||||
<button class="btn btn-primary alt" type="submit--{{member}}">Login</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
</ng-container>
|
||||||
</div>
|
</div>
|
||||||
</ng-container>
|
</form>
|
||||||
</div>
|
</ng-container>
|
||||||
</form>
|
|
||||||
|
|
||||||
</div>
|
</div>
|
@ -29,6 +29,10 @@ export class UserLoginComponent implements OnInit {
|
|||||||
* If there are no admins on the server, this will enable the registration to kick in.
|
* If there are no admins on the server, this will enable the registration to kick in.
|
||||||
*/
|
*/
|
||||||
firstTimeFlow: boolean = true;
|
firstTimeFlow: boolean = true;
|
||||||
|
/**
|
||||||
|
* Used for first time the page loads to ensure no flashing
|
||||||
|
*/
|
||||||
|
isLoaded: boolean = false;
|
||||||
|
|
||||||
constructor(private accountService: AccountService, private router: Router, private memberService: MemberService,
|
constructor(private accountService: AccountService, private router: Router, private memberService: MemberService,
|
||||||
private toastr: ToastrService, private navService: NavService, private settingsService: SettingsService) { }
|
private toastr: ToastrService, private navService: NavService, private settingsService: SettingsService) { }
|
||||||
@ -53,11 +57,13 @@ export class UserLoginComponent implements OnInit {
|
|||||||
const isOnlyOne = this.memberNames.length === 1;
|
const isOnlyOne = this.memberNames.length === 1;
|
||||||
this.memberNames.forEach(name => this.isCollapsed[name] = !isOnlyOne);
|
this.memberNames.forEach(name => this.isCollapsed[name] = !isOnlyOne);
|
||||||
this.firstTimeFlow = members.length === 0;
|
this.firstTimeFlow = members.length === 0;
|
||||||
|
this.isLoaded = true;
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
this.memberService.adminExists().pipe(take(1)).subscribe(adminExists => {
|
this.memberService.adminExists().pipe(take(1)).subscribe(adminExists => {
|
||||||
this.firstTimeFlow = !adminExists;
|
this.firstTimeFlow = !adminExists;
|
||||||
this.setupAuthenticatedLoginFlow();
|
this.setupAuthenticatedLoginFlow();
|
||||||
|
this.isLoaded = true;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
Loading…
x
Reference in New Issue
Block a user