diff --git a/API/Controllers/AccountController.cs b/API/Controllers/AccountController.cs index abe81d1b2..8e549d5e1 100644 --- a/API/Controllers/AccountController.cs +++ b/API/Controllers/AccountController.cs @@ -579,17 +579,26 @@ namespace API.Controllers [HttpPost("confirm-password-reset")] public async Task> ConfirmForgotPassword(ConfirmPasswordResetDto dto) { - var user = await _unitOfWork.UserRepository.GetUserByEmailAsync(dto.Email); - if (user == null) + try { - return BadRequest("Invalid Details"); + var user = await _unitOfWork.UserRepository.GetUserByEmailAsync(dto.Email); + if (user == null) + { + return BadRequest("Invalid Details"); + } + + var result = await _userManager.VerifyUserTokenAsync(user, TokenOptions.DefaultProvider, + "ResetPassword", dto.Token); + if (!result) return BadRequest("Unable to reset password, your email token is not correct."); + + var errors = await _accountService.ChangeUserPassword(user, dto.Password); + return errors.Any() ? BadRequest(errors) : Ok("Password updated"); + } + catch (Exception ex) + { + _logger.LogError(ex, "There was an unexpected error when confirming new password"); + return BadRequest("There was an unexpected error when confirming new password"); } - - var result = await _userManager.VerifyUserTokenAsync(user, TokenOptions.DefaultProvider, "ResetPassword", dto.Token); - if (!result) return BadRequest("Unable to reset password, your email token is not correct."); - - var errors = await _accountService.ChangeUserPassword(user, dto.Password); - return errors.Any() ? BadRequest(errors) : Ok("Password updated"); } diff --git a/API/Data/MigrateBookmarks.cs b/API/Data/MigrateBookmarks.cs deleted file mode 100644 index a659afd17..000000000 --- a/API/Data/MigrateBookmarks.cs +++ /dev/null @@ -1,105 +0,0 @@ -using System; -using System.Linq; -using System.Threading.Tasks; -using API.Comparators; -using API.Entities.Enums; -using API.Services; -using Microsoft.Extensions.Logging; - -namespace API.Data; - -/// -/// Responsible to migrate existing bookmarks to files. Introduced in v0.4.9.27 -/// -public static class MigrateBookmarks -{ - /// - /// This will migrate existing bookmarks to bookmark folder based. - /// If the bookmarks folder already exists, this will not run. - /// - /// Bookmark directory is configurable. This will always use the default bookmark directory. - /// - /// - /// - /// - /// - public static async Task Migrate(IDirectoryService directoryService, IUnitOfWork unitOfWork, - ILogger logger, ICacheService cacheService) - { - var bookmarkDirectory = (await unitOfWork.SettingsRepository.GetSettingAsync(ServerSettingKey.BookmarkDirectory)) - .Value; - if (string.IsNullOrEmpty(bookmarkDirectory)) - { - bookmarkDirectory = directoryService.BookmarkDirectory; - } - - if (directoryService.Exists(bookmarkDirectory)) return; - - logger.LogInformation("Bookmark migration is needed....This may take some time"); - - var allBookmarks = (await unitOfWork.UserRepository.GetAllBookmarksAsync()).ToList(); - - var uniqueChapterIds = allBookmarks.Select(b => b.ChapterId).Distinct().ToList(); - var uniqueUserIds = allBookmarks.Select(b => b.AppUserId).Distinct().ToList(); - foreach (var userId in uniqueUserIds) - { - foreach (var chapterId in uniqueChapterIds) - { - var chapterBookmarks = allBookmarks.Where(b => b.ChapterId == chapterId).ToList(); - var chapterPages = chapterBookmarks - .Select(b => b.Page).ToList(); - var seriesId = chapterBookmarks - .Select(b => b.SeriesId).First(); - var mangaFiles = await unitOfWork.ChapterRepository.GetFilesForChapterAsync(chapterId); - var chapterExtractPath = directoryService.FileSystem.Path.Join(directoryService.TempDirectory, $"bookmark_c{chapterId}_u{userId}_s{seriesId}"); - - var numericComparer = new NumericComparer(); - if (!mangaFiles.Any()) continue; - - switch (mangaFiles.First().Format) - { - case MangaFormat.Image: - directoryService.ExistOrCreate(chapterExtractPath); - directoryService.CopyFilesToDirectory(mangaFiles.Select(f => f.FilePath), chapterExtractPath); - break; - case MangaFormat.Archive: - case MangaFormat.Pdf: - cacheService.ExtractChapterFiles(chapterExtractPath, mangaFiles.ToList()); - break; - case MangaFormat.Epub: - continue; - default: - continue; - } - - var files = directoryService.GetFilesWithExtension(chapterExtractPath, Services.Tasks.Scanner.Parser.Parser.ImageFileExtensions); - // Filter out images that aren't in bookmarks - Array.Sort(files, numericComparer); - foreach (var chapterPage in chapterPages) - { - var file = files.ElementAt(chapterPage); - var bookmark = allBookmarks.FirstOrDefault(b => - b.ChapterId == chapterId && b.SeriesId == seriesId && b.AppUserId == userId && - b.Page == chapterPage); - if (bookmark == null) continue; - - var filename = directoryService.FileSystem.Path.GetFileName(file); - var newLocation = directoryService.FileSystem.Path.Join( - ReaderService.FormatBookmarkFolderPath(String.Empty, userId, seriesId, chapterId), - filename); - bookmark.FileName = newLocation; - directoryService.CopyFileToDirectory(file, - ReaderService.FormatBookmarkFolderPath(bookmarkDirectory, userId, seriesId, chapterId)); - unitOfWork.UserRepository.Update(bookmark); - } - } - // Clear temp after each user to avoid too much space being eaten - directoryService.ClearDirectory(directoryService.TempDirectory); - } - - await unitOfWork.CommitAsync(); - // Run CleanupService as we cache a ton of files - directoryService.ClearDirectory(directoryService.TempDirectory); - - } -} diff --git a/API/Services/Tasks/ScannerService.cs b/API/Services/Tasks/ScannerService.cs index 1dbf8057f..710647764 100644 --- a/API/Services/Tasks/ScannerService.cs +++ b/API/Services/Tasks/ScannerService.cs @@ -406,30 +406,6 @@ public class ScannerService : IScannerService var libraryFolderPaths = library.Folders.Select(fp => fp.Path).ToList(); if (!await CheckMounts(library.Name, libraryFolderPaths)) return; - // If all library Folder paths haven't been modified since last scan, abort - // Unless the user did something on the library (delete series) and thus we can bypass this check - var wasLibraryUpdatedSinceLastScan = (library.LastModified.Truncate(TimeSpan.TicksPerMinute) > - library.LastScanned.Truncate(TimeSpan.TicksPerMinute)) - && library.LastScanned != DateTime.MinValue; - if (!forceUpdate && !wasLibraryUpdatedSinceLastScan) - { - var haveFoldersChangedSinceLastScan = library.Folders - .All(f => _directoryService.GetLastWriteTime(f.Path).Truncate(TimeSpan.TicksPerMinute) > f.LastScanned.Truncate(TimeSpan.TicksPerMinute)); - - // If nothing changed && library folder's have all been scanned at least once - if (!haveFoldersChangedSinceLastScan && library.Folders.All(f => f.LastScanned > DateTime.MinValue)) - { - _logger.LogInformation("[ScannerService] {LibraryName} scan has no work to do. All folders have not been changed since last scan", library.Name); - await _eventHub.SendMessageAsync(MessageFactory.Info, - MessageFactory.InfoEvent($"{library.Name} scan has no work to do", - $"All folders have not been changed since last scan ({library.Folders.Max(f => f.LastScanned).ToString(CultureInfo.CurrentCulture)}). Scan will be aborted.")); - - BackgroundJob.Enqueue(() => _metadataService.GenerateCoversForLibrary(library.Id, false)); - BackgroundJob.Enqueue(() => _wordCountAnalyzerService.ScanLibrary(library.Id, false)); - return; - } - } - // Validations are done, now we can start actual scan _logger.LogInformation("[ScannerService] Beginning file scan on {LibraryName}", library.Name); diff --git a/API/SignalR/Presence/PresenceTracker.cs b/API/SignalR/Presence/PresenceTracker.cs index 45118aa8d..40cec42d0 100644 --- a/API/SignalR/Presence/PresenceTracker.cs +++ b/API/SignalR/Presence/PresenceTracker.cs @@ -38,6 +38,7 @@ namespace API.SignalR.Presence public async Task UserConnected(string username, string connectionId) { var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync(username); + if (user == null) return; var isAdmin = await _unitOfWork.UserRepository.IsUserAdminAsync(user); lock (OnlineUsers) { diff --git a/API/Startup.cs b/API/Startup.cs index 8eab1221b..14af6f0b6 100644 --- a/API/Startup.cs +++ b/API/Startup.cs @@ -185,8 +185,6 @@ namespace API var themeService = serviceProvider.GetRequiredService(); var dataContext = serviceProvider.GetRequiredService(); - await MigrateBookmarks.Migrate(directoryService, unitOfWork, - logger, cacheService); // Only run this if we are upgrading await MigrateChangePasswordRoles.Migrate(unitOfWork, userManager); diff --git a/UI/Web/src/app/_services/account.service.ts b/UI/Web/src/app/_services/account.service.ts index 04809a4dc..3675e818e 100644 --- a/UI/Web/src/app/_services/account.service.ts +++ b/UI/Web/src/app/_services/account.service.ts @@ -165,7 +165,7 @@ export class AccountService implements OnDestroy { } confirmResetPasswordEmail(model: {email: string, token: string, password: string}) { - return this.httpClient.post(this.baseUrl + 'account/confirm-password-reset', model); + return this.httpClient.post(this.baseUrl + 'account/confirm-password-reset', model, {responseType: 'json' as 'text'}); } resetPassword(username: string, password: string, oldPassword: string) { diff --git a/UI/Web/src/app/admin/_modals/library-editor-modal/library-editor-modal.component.ts b/UI/Web/src/app/admin/_modals/library-editor-modal/library-editor-modal.component.ts index 9b71f4e2a..710d0e4d7 100644 --- a/UI/Web/src/app/admin/_modals/library-editor-modal/library-editor-modal.component.ts +++ b/UI/Web/src/app/admin/_modals/library-editor-modal/library-editor-modal.component.ts @@ -1,5 +1,5 @@ import { Component, Input, OnInit } from '@angular/core'; -import { UntypedFormControl, UntypedFormGroup, Validators } from '@angular/forms'; +import { FormControl, FormGroup, Validators } from '@angular/forms'; import { NgbActiveModal, NgbModal } from '@ng-bootstrap/ng-bootstrap'; import { ToastrService } from 'ngx-toastr'; import { ConfirmService } from 'src/app/shared/confirm.service'; @@ -17,9 +17,9 @@ export class LibraryEditorModalComponent implements OnInit { @Input() library: Library | undefined = undefined; - libraryForm: UntypedFormGroup = new UntypedFormGroup({ - name: new UntypedFormControl('', [Validators.required]), - type: new UntypedFormControl(0, [Validators.required]) + libraryForm: FormGroup = new FormGroup({ + name: new FormControl('', [Validators.required]), + type: new FormControl(0, [Validators.required]) }); selectedFolders: string[] = []; diff --git a/UI/Web/src/app/admin/edit-user/edit-user.component.ts b/UI/Web/src/app/admin/edit-user/edit-user.component.ts index e002d7661..29b61caa5 100644 --- a/UI/Web/src/app/admin/edit-user/edit-user.component.ts +++ b/UI/Web/src/app/admin/edit-user/edit-user.component.ts @@ -1,5 +1,5 @@ import { Component, Input, OnInit } from '@angular/core'; -import { UntypedFormGroup, UntypedFormControl, Validators } from '@angular/forms'; +import { FormGroup, FormControl, Validators } from '@angular/forms'; import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'; import { Library } from 'src/app/_models/library'; import { Member } from 'src/app/_models/member'; @@ -19,7 +19,7 @@ export class EditUserComponent implements OnInit { selectedLibraries: Array = []; isSaving: boolean = false; - userForm: UntypedFormGroup = new UntypedFormGroup({}); + userForm: FormGroup = new FormGroup({}); public get email() { return this.userForm.get('email'); } public get username() { return this.userForm.get('username'); } @@ -28,8 +28,8 @@ export class EditUserComponent implements OnInit { constructor(public modal: NgbActiveModal, private accountService: AccountService) { } ngOnInit(): void { - this.userForm.addControl('email', new UntypedFormControl(this.member.email, [Validators.required, Validators.email])); - this.userForm.addControl('username', new UntypedFormControl(this.member.username, [Validators.required])); + this.userForm.addControl('email', new FormControl(this.member.email, [Validators.required, Validators.email])); + this.userForm.addControl('username', new FormControl(this.member.username, [Validators.required])); this.userForm.get('email')?.disable(); } diff --git a/UI/Web/src/app/admin/invite-user/invite-user.component.ts b/UI/Web/src/app/admin/invite-user/invite-user.component.ts index 781a880ab..13f18b7eb 100644 --- a/UI/Web/src/app/admin/invite-user/invite-user.component.ts +++ b/UI/Web/src/app/admin/invite-user/invite-user.component.ts @@ -1,5 +1,5 @@ import { Component, OnInit } from '@angular/core'; -import { UntypedFormControl, UntypedFormGroup, Validators } from '@angular/forms'; +import { FormControl, FormGroup, Validators } from '@angular/forms'; import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'; import { ToastrService } from 'ngx-toastr'; import { ConfirmService } from 'src/app/shared/confirm.service'; @@ -19,7 +19,7 @@ export class InviteUserComponent implements OnInit { * Maintains if the backend is sending an email */ isSending: boolean = false; - inviteForm: UntypedFormGroup = new UntypedFormGroup({}); + inviteForm: FormGroup = new FormGroup({}); selectedRoles: Array = []; selectedLibraries: Array = []; emailLink: string = ''; @@ -32,7 +32,7 @@ export class InviteUserComponent implements OnInit { private confirmService: ConfirmService, private toastr: ToastrService) { } ngOnInit(): void { - this.inviteForm.addControl('email', new UntypedFormControl('', [Validators.required])); + this.inviteForm.addControl('email', new FormControl('', [Validators.required])); } close() { diff --git a/UI/Web/src/app/admin/manage-email-settings/manage-email-settings.component.ts b/UI/Web/src/app/admin/manage-email-settings/manage-email-settings.component.ts index 93a6ea911..480ac55b3 100644 --- a/UI/Web/src/app/admin/manage-email-settings/manage-email-settings.component.ts +++ b/UI/Web/src/app/admin/manage-email-settings/manage-email-settings.component.ts @@ -1,5 +1,5 @@ import { Component, OnInit } from '@angular/core'; -import { UntypedFormControl, UntypedFormGroup, Validators } from '@angular/forms'; +import { FormControl, FormGroup, Validators } from '@angular/forms'; import { ToastrService } from 'ngx-toastr'; import { take } from 'rxjs'; import { SettingsService, EmailTestResult } from '../settings.service'; @@ -13,14 +13,14 @@ import { ServerSettings } from '../_models/server-settings'; export class ManageEmailSettingsComponent implements OnInit { serverSettings!: ServerSettings; - settingsForm: UntypedFormGroup = new UntypedFormGroup({}); + settingsForm: FormGroup = new FormGroup({}); constructor(private settingsService: SettingsService, private toastr: ToastrService) { } ngOnInit(): void { this.settingsService.getServerSettings().pipe(take(1)).subscribe((settings: ServerSettings) => { this.serverSettings = settings; - this.settingsForm.addControl('emailServiceUrl', new UntypedFormControl(this.serverSettings.emailServiceUrl, [Validators.required])); + this.settingsForm.addControl('emailServiceUrl', new FormControl(this.serverSettings.emailServiceUrl, [Validators.required])); }); } diff --git a/UI/Web/src/app/admin/manage-media-settings/manage-media-settings.component.ts b/UI/Web/src/app/admin/manage-media-settings/manage-media-settings.component.ts index 9f619dfe7..f3b19e012 100644 --- a/UI/Web/src/app/admin/manage-media-settings/manage-media-settings.component.ts +++ b/UI/Web/src/app/admin/manage-media-settings/manage-media-settings.component.ts @@ -1,5 +1,5 @@ import { Component, OnInit } from '@angular/core'; -import { UntypedFormGroup, UntypedFormControl, Validators } from '@angular/forms'; +import { FormGroup, FormControl, Validators } from '@angular/forms'; import { ToastrService } from 'ngx-toastr'; import { take } from 'rxjs'; import { SettingsService } from '../settings.service'; @@ -13,14 +13,14 @@ import { ServerSettings } from '../_models/server-settings'; export class ManageMediaSettingsComponent implements OnInit { serverSettings!: ServerSettings; - settingsForm: UntypedFormGroup = new UntypedFormGroup({}); + settingsForm: FormGroup = new FormGroup({}); constructor(private settingsService: SettingsService, private toastr: ToastrService) { } ngOnInit(): void { this.settingsService.getServerSettings().pipe(take(1)).subscribe((settings: ServerSettings) => { this.serverSettings = settings; - this.settingsForm.addControl('convertBookmarkToWebP', new UntypedFormControl(this.serverSettings.convertBookmarkToWebP, [Validators.required])); + this.settingsForm.addControl('convertBookmarkToWebP', new FormControl(this.serverSettings.convertBookmarkToWebP, [Validators.required])); }); } diff --git a/UI/Web/src/app/admin/manage-system/manage-system.component.ts b/UI/Web/src/app/admin/manage-system/manage-system.component.ts index 77891e859..4fb54a977 100644 --- a/UI/Web/src/app/admin/manage-system/manage-system.component.ts +++ b/UI/Web/src/app/admin/manage-system/manage-system.component.ts @@ -1,5 +1,5 @@ import { Component, OnInit } from '@angular/core'; -import { UntypedFormControl, UntypedFormGroup, Validators } from '@angular/forms'; +import { FormControl, FormGroup, Validators } from '@angular/forms'; import { ToastrService } from 'ngx-toastr'; import { take } from 'rxjs/operators'; import { ServerService } from 'src/app/_services/server.service'; @@ -14,7 +14,7 @@ import { ServerSettings } from '../_models/server-settings'; }) export class ManageSystemComponent implements OnInit { - settingsForm: UntypedFormGroup = new UntypedFormGroup({}); + settingsForm: FormGroup = new FormGroup({}); serverSettings!: ServerSettings; serverInfo!: ServerInfo; @@ -30,12 +30,12 @@ export class ManageSystemComponent implements OnInit { this.settingsService.getServerSettings().pipe(take(1)).subscribe((settings: ServerSettings) => { this.serverSettings = settings; - this.settingsForm.addControl('cacheDirectory', new UntypedFormControl(this.serverSettings.cacheDirectory, [Validators.required])); - this.settingsForm.addControl('taskScan', new UntypedFormControl(this.serverSettings.taskScan, [Validators.required])); - this.settingsForm.addControl('taskBackup', new UntypedFormControl(this.serverSettings.taskBackup, [Validators.required])); - this.settingsForm.addControl('port', new UntypedFormControl(this.serverSettings.port, [Validators.required])); - this.settingsForm.addControl('loggingLevel', new UntypedFormControl(this.serverSettings.loggingLevel, [Validators.required])); - this.settingsForm.addControl('allowStatCollection', new UntypedFormControl(this.serverSettings.allowStatCollection, [Validators.required])); + this.settingsForm.addControl('cacheDirectory', new FormControl(this.serverSettings.cacheDirectory, [Validators.required])); + this.settingsForm.addControl('taskScan', new FormControl(this.serverSettings.taskScan, [Validators.required])); + this.settingsForm.addControl('taskBackup', new FormControl(this.serverSettings.taskBackup, [Validators.required])); + this.settingsForm.addControl('port', new FormControl(this.serverSettings.port, [Validators.required])); + this.settingsForm.addControl('loggingLevel', new FormControl(this.serverSettings.loggingLevel, [Validators.required])); + this.settingsForm.addControl('allowStatCollection', new FormControl(this.serverSettings.allowStatCollection, [Validators.required])); }); } diff --git a/UI/Web/src/app/admin/manage-tasks-settings/manage-tasks-settings.component.ts b/UI/Web/src/app/admin/manage-tasks-settings/manage-tasks-settings.component.ts index a78d0daaf..f0ca52d75 100644 --- a/UI/Web/src/app/admin/manage-tasks-settings/manage-tasks-settings.component.ts +++ b/UI/Web/src/app/admin/manage-tasks-settings/manage-tasks-settings.component.ts @@ -1,5 +1,5 @@ import { Component, OnInit } from '@angular/core'; -import { UntypedFormGroup, UntypedFormControl, Validators } from '@angular/forms'; +import { FormGroup, FormControl, Validators } from '@angular/forms'; import { ToastrService } from 'ngx-toastr'; import { ConfirmService } from 'src/app/shared/confirm.service'; import { SettingsService } from '../settings.service'; @@ -28,7 +28,7 @@ interface AdhocTask { export class ManageTasksSettingsComponent implements OnInit { serverSettings!: ServerSettings; - settingsForm: UntypedFormGroup = new UntypedFormGroup({}); + settingsForm: FormGroup = new FormGroup({}); taskFrequencies: Array = []; logLevels: Array = []; @@ -89,8 +89,8 @@ export class ManageTasksSettingsComponent implements OnInit { this.taskFrequencies = result.frequencies; this.logLevels = result.levels; this.serverSettings = result.settings; - this.settingsForm.addControl('taskScan', new UntypedFormControl(this.serverSettings.taskScan, [Validators.required])); - this.settingsForm.addControl('taskBackup', new UntypedFormControl(this.serverSettings.taskBackup, [Validators.required])); + this.settingsForm.addControl('taskScan', new FormControl(this.serverSettings.taskScan, [Validators.required])); + this.settingsForm.addControl('taskBackup', new FormControl(this.serverSettings.taskBackup, [Validators.required])); }); this.reoccuringTasks$ = this.serverService.getReoccuringJobs().pipe(shareReplay()); diff --git a/UI/Web/src/app/book-reader/reader-settings/reader-settings.component.ts b/UI/Web/src/app/book-reader/reader-settings/reader-settings.component.ts index be94a245e..40a00ce43 100644 --- a/UI/Web/src/app/book-reader/reader-settings/reader-settings.component.ts +++ b/UI/Web/src/app/book-reader/reader-settings/reader-settings.component.ts @@ -1,6 +1,6 @@ import { DOCUMENT } from '@angular/common'; import { ChangeDetectionStrategy, ChangeDetectorRef, Component, EventEmitter, Inject, Input, OnDestroy, OnInit, Output } from '@angular/core'; -import { UntypedFormControl, UntypedFormGroup } from '@angular/forms'; +import { FormControl, FormGroup } from '@angular/forms'; import { Subject, take, takeUntil } from 'rxjs'; import { BookPageLayoutMode } from 'src/app/_models/book-page-layout-mode'; import { BookTheme } from 'src/app/_models/preferences/book-theme'; @@ -110,7 +110,7 @@ export class ReaderSettingsComponent implements OnInit, OnDestroy { isFullscreen: boolean = false; - settingsForm: UntypedFormGroup = new UntypedFormGroup({}); + settingsForm: FormGroup = new FormGroup({}); /** * System provided themes @@ -163,7 +163,7 @@ export class ReaderSettingsComponent implements OnInit, OnDestroy { this.readingDirectionModel = this.user.preferences.bookReaderReadingDirection; - this.settingsForm.addControl('bookReaderFontFamily', new UntypedFormControl(this.user.preferences.bookReaderFontFamily, [])); + this.settingsForm.addControl('bookReaderFontFamily', new FormControl(this.user.preferences.bookReaderFontFamily, [])); this.settingsForm.get('bookReaderFontFamily')!.valueChanges.pipe(takeUntil(this.onDestroy)).subscribe(fontName => { const familyName = this.fontFamilies.filter(f => f.title === fontName)[0].family; if (familyName === 'default') { @@ -175,36 +175,36 @@ export class ReaderSettingsComponent implements OnInit, OnDestroy { this.styleUpdate.emit(this.pageStyles); }); - this.settingsForm.addControl('bookReaderFontSize', new UntypedFormControl(this.user.preferences.bookReaderFontSize, [])); + this.settingsForm.addControl('bookReaderFontSize', new FormControl(this.user.preferences.bookReaderFontSize, [])); this.settingsForm.get('bookReaderFontSize')?.valueChanges.pipe(takeUntil(this.onDestroy)).subscribe(value => { this.pageStyles['font-size'] = value + '%'; this.styleUpdate.emit(this.pageStyles); }); - this.settingsForm.addControl('bookReaderTapToPaginate', new UntypedFormControl(this.user.preferences.bookReaderTapToPaginate, [])); + this.settingsForm.addControl('bookReaderTapToPaginate', new FormControl(this.user.preferences.bookReaderTapToPaginate, [])); this.settingsForm.get('bookReaderTapToPaginate')?.valueChanges.pipe(takeUntil(this.onDestroy)).subscribe(value => { this.clickToPaginateChanged.emit(value); }); - this.settingsForm.addControl('bookReaderLineSpacing', new UntypedFormControl(this.user.preferences.bookReaderLineSpacing, [])); + this.settingsForm.addControl('bookReaderLineSpacing', new FormControl(this.user.preferences.bookReaderLineSpacing, [])); this.settingsForm.get('bookReaderLineSpacing')?.valueChanges.pipe(takeUntil(this.onDestroy)).subscribe(value => { this.pageStyles['line-height'] = value + '%'; this.styleUpdate.emit(this.pageStyles); }); - this.settingsForm.addControl('bookReaderMargin', new UntypedFormControl(this.user.preferences.bookReaderMargin, [])); + this.settingsForm.addControl('bookReaderMargin', new FormControl(this.user.preferences.bookReaderMargin, [])); this.settingsForm.get('bookReaderMargin')?.valueChanges.pipe(takeUntil(this.onDestroy)).subscribe(value => { this.pageStyles['margin-left'] = value + '%'; this.pageStyles['margin-right'] = value + '%'; this.styleUpdate.emit(this.pageStyles); }); - this.settingsForm.addControl('layoutMode', new UntypedFormControl(this.user.preferences.bookReaderLayoutMode || BookPageLayoutMode.Default, [])); + this.settingsForm.addControl('layoutMode', new FormControl(this.user.preferences.bookReaderLayoutMode || BookPageLayoutMode.Default, [])); this.settingsForm.get('layoutMode')?.valueChanges.pipe(takeUntil(this.onDestroy)).subscribe((layoutMode: BookPageLayoutMode) => { this.layoutModeUpdate.emit(layoutMode); }); - this.settingsForm.addControl('bookReaderImmersiveMode', new UntypedFormControl(this.user.preferences.bookReaderImmersiveMode, [])); + this.settingsForm.addControl('bookReaderImmersiveMode', new FormControl(this.user.preferences.bookReaderImmersiveMode, [])); this.settingsForm.get('bookReaderImmersiveMode')?.valueChanges.pipe(takeUntil(this.onDestroy)).subscribe((immersiveMode: boolean) => { if (immersiveMode) { this.settingsForm.get('bookReaderTapToPaginate')?.setValue(true); diff --git a/UI/Web/src/app/cards/_modals/bulk-add-to-collection/bulk-add-to-collection.component.ts b/UI/Web/src/app/cards/_modals/bulk-add-to-collection/bulk-add-to-collection.component.ts index a55b01eee..e04e36ad6 100644 --- a/UI/Web/src/app/cards/_modals/bulk-add-to-collection/bulk-add-to-collection.component.ts +++ b/UI/Web/src/app/cards/_modals/bulk-add-to-collection/bulk-add-to-collection.component.ts @@ -1,5 +1,5 @@ import { ChangeDetectionStrategy, ChangeDetectorRef, Component, ElementRef, Input, OnInit, ViewChild, ViewEncapsulation } from '@angular/core'; -import { UntypedFormGroup, UntypedFormControl } from '@angular/forms'; +import { FormGroup, FormControl } from '@angular/forms'; import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'; import { ToastrService } from 'ngx-toastr'; import { CollectionTag } from 'src/app/_models/collection-tag'; @@ -26,7 +26,7 @@ export class BulkAddToCollectionComponent implements OnInit { */ lists: Array = []; loading: boolean = false; - listForm: UntypedFormGroup = new UntypedFormGroup({}); + listForm: FormGroup = new FormGroup({}); collectionTitleTrackby = (index: number, item: CollectionTag) => `${item.title}`; @@ -38,8 +38,8 @@ export class BulkAddToCollectionComponent implements OnInit { ngOnInit(): void { - this.listForm.addControl('title', new UntypedFormControl(this.title, [])); - this.listForm.addControl('filterQuery', new UntypedFormControl('', [])); + this.listForm.addControl('title', new FormControl(this.title, [])); + this.listForm.addControl('filterQuery', new FormControl('', [])); this.loading = true; this.cdRef.markForCheck(); diff --git a/UI/Web/src/app/cards/_modals/edit-collection-tags/edit-collection-tags.component.ts b/UI/Web/src/app/cards/_modals/edit-collection-tags/edit-collection-tags.component.ts index 6f0783ef9..6797d90fb 100644 --- a/UI/Web/src/app/cards/_modals/edit-collection-tags/edit-collection-tags.component.ts +++ b/UI/Web/src/app/cards/_modals/edit-collection-tags/edit-collection-tags.component.ts @@ -1,5 +1,5 @@ import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnInit } from '@angular/core'; -import { UntypedFormControl, UntypedFormGroup } from '@angular/forms'; +import { FormControl, FormGroup } from '@angular/forms'; import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'; import { ToastrService } from 'ngx-toastr'; import { forkJoin } from 'rxjs'; @@ -37,7 +37,7 @@ export class EditCollectionTagsComponent implements OnInit { pagination!: Pagination; selectAll: boolean = true; libraryNames!: any; - collectionTagForm!: UntypedFormGroup; + collectionTagForm!: FormGroup; tabs = [{title: 'General', id: TabID.General}, {title: 'Cover Image', id: TabID.CoverImage}]; active = TabID.General; imageUrls: Array = []; @@ -65,10 +65,10 @@ export class EditCollectionTagsComponent implements OnInit { if (this.pagination == undefined) { this.pagination = {totalPages: 1, totalItems: 200, itemsPerPage: 200, currentPage: 0}; } - this.collectionTagForm = new UntypedFormGroup({ - summary: new UntypedFormControl(this.tag.summary, []), - coverImageLocked: new UntypedFormControl(this.tag.coverImageLocked, []), - coverImageIndex: new UntypedFormControl(0, []), + this.collectionTagForm = new FormGroup({ + summary: new FormControl(this.tag.summary, []), + coverImageLocked: new FormControl(this.tag.coverImageLocked, []), + coverImageIndex: new FormControl(0, []), }); this.imageUrls.push(this.imageService.randomize(this.imageService.getCollectionCoverImage(this.tag.id))); diff --git a/UI/Web/src/app/collections/collection-detail/collection-detail.component.html b/UI/Web/src/app/collections/collection-detail/collection-detail.component.html index 811e37527..cc8998a04 100644 --- a/UI/Web/src/app/collections/collection-detail/collection-detail.component.html +++ b/UI/Web/src/app/collections/collection-detail/collection-detail.component.html @@ -37,5 +37,17 @@ (selection)="bulkSelectionService.handleCardSelection('series', position, series.length, $event)" [selected]="bulkSelectionService.isCardSelected('series', position)" [allowSelection]="true" > + +
+ + There are no items. Try adding a series. + +
+ +
+ + No items match your current filter. + +
\ No newline at end of file diff --git a/UI/Web/src/app/metadata-filter/metadata-filter.component.ts b/UI/Web/src/app/metadata-filter/metadata-filter.component.ts index a61a48ca6..0ebeade4e 100644 --- a/UI/Web/src/app/metadata-filter/metadata-filter.component.ts +++ b/UI/Web/src/app/metadata-filter/metadata-filter.component.ts @@ -1,5 +1,5 @@ import { ChangeDetectionStrategy, ChangeDetectorRef, Component, ContentChild, EventEmitter, Input, OnDestroy, OnInit, Output } from '@angular/core'; -import { UntypedFormControl, UntypedFormGroup } from '@angular/forms'; +import { FormControl, FormGroup } from '@angular/forms'; import { NgbCollapse } from '@ng-bootstrap/ng-bootstrap'; import { distinctUntilChanged, forkJoin, map, Observable, of, ReplaySubject, Subject, takeUntil } from 'rxjs'; import { UtilityService } from '../shared/_services/utility.service'; @@ -66,9 +66,9 @@ export class MetadataFilterComponent implements OnInit, OnDestroy { libraries: Array> = []; - readProgressGroup!: UntypedFormGroup; - sortGroup!: UntypedFormGroup; - seriesNameGroup!: UntypedFormGroup; + readProgressGroup!: FormGroup; + sortGroup!: FormGroup; + seriesNameGroup!: FormGroup; isAscendingSort: boolean = true; updateApplied: number = 0; @@ -106,18 +106,18 @@ export class MetadataFilterComponent implements OnInit, OnDestroy { } this.filter = this.seriesService.createSeriesFilter(); - this.readProgressGroup = new UntypedFormGroup({ - read: new UntypedFormControl({value: this.filter.readStatus.read, disabled: this.filterSettings.readProgressDisabled}, []), - notRead: new UntypedFormControl({value: this.filter.readStatus.notRead, disabled: this.filterSettings.readProgressDisabled}, []), - inProgress: new UntypedFormControl({value: this.filter.readStatus.inProgress, disabled: this.filterSettings.readProgressDisabled}, []), + this.readProgressGroup = new FormGroup({ + read: new FormControl({value: this.filter.readStatus.read, disabled: this.filterSettings.readProgressDisabled}, []), + notRead: new FormControl({value: this.filter.readStatus.notRead, disabled: this.filterSettings.readProgressDisabled}, []), + inProgress: new FormControl({value: this.filter.readStatus.inProgress, disabled: this.filterSettings.readProgressDisabled}, []), }); - this.sortGroup = new UntypedFormGroup({ - sortField: new UntypedFormControl({value: this.filter.sortOptions?.sortField || SortField.SortName, disabled: this.filterSettings.sortDisabled}, []), + this.sortGroup = new FormGroup({ + sortField: new FormControl({value: this.filter.sortOptions?.sortField || SortField.SortName, disabled: this.filterSettings.sortDisabled}, []), }); - this.seriesNameGroup = new UntypedFormGroup({ - seriesNameQuery: new UntypedFormControl({value: this.filter.seriesNameQuery || '', disabled: this.filterSettings.searchNameDisabled}, []) + this.seriesNameGroup = new FormGroup({ + seriesNameQuery: new FormControl({value: this.filter.seriesNameQuery || '', disabled: this.filterSettings.searchNameDisabled}, []) }); this.readProgressGroup.valueChanges.pipe(takeUntil(this.onDestroy)).subscribe(changes => { diff --git a/UI/Web/src/app/nav/grouped-typeahead/grouped-typeahead.component.ts b/UI/Web/src/app/nav/grouped-typeahead/grouped-typeahead.component.ts index f2a1fd01b..687e54c3d 100644 --- a/UI/Web/src/app/nav/grouped-typeahead/grouped-typeahead.component.ts +++ b/UI/Web/src/app/nav/grouped-typeahead/grouped-typeahead.component.ts @@ -1,5 +1,5 @@ import { ChangeDetectionStrategy, ChangeDetectorRef, Component, ContentChild, ElementRef, EventEmitter, HostListener, Input, OnDestroy, OnInit, Output, TemplateRef, ViewChild } from '@angular/core'; -import { UntypedFormControl, UntypedFormGroup } from '@angular/forms'; +import { FormControl, FormGroup } from '@angular/forms'; import { Subject } from 'rxjs'; import { debounceTime, takeUntil } from 'rxjs/operators'; import { KEY_CODES } from '../../shared/_services/utility.service'; @@ -66,7 +66,7 @@ export class GroupedTypeaheadComponent implements OnInit, OnDestroy { hasFocus: boolean = false; isLoading: boolean = false; - typeaheadForm: UntypedFormGroup = new UntypedFormGroup({}); + typeaheadForm: FormGroup = new FormGroup({}); prevSearchTerm: string = ''; @@ -106,7 +106,7 @@ export class GroupedTypeaheadComponent implements OnInit, OnDestroy { } ngOnInit(): void { - this.typeaheadForm.addControl('typeahead', new UntypedFormControl(this.initialValue, [])); + this.typeaheadForm.addControl('typeahead', new FormControl(this.initialValue, [])); this.cdRef.markForCheck(); this.typeaheadForm.valueChanges.pipe(debounceTime(this.debounceTime), takeUntil(this.onDestroy)).subscribe(change => { diff --git a/UI/Web/src/app/reading-list/_modals/add-to-list-modal/add-to-list-modal.component.ts b/UI/Web/src/app/reading-list/_modals/add-to-list-modal/add-to-list-modal.component.ts index b90a5732d..3d88fcd1b 100644 --- a/UI/Web/src/app/reading-list/_modals/add-to-list-modal/add-to-list-modal.component.ts +++ b/UI/Web/src/app/reading-list/_modals/add-to-list-modal/add-to-list-modal.component.ts @@ -1,5 +1,5 @@ import { AfterViewInit, Component, ElementRef, Input, OnInit, ViewChild } from '@angular/core'; -import { UntypedFormControl, UntypedFormGroup } from '@angular/forms'; +import { FormControl, FormGroup } from '@angular/forms'; import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'; import { ToastrService } from 'ngx-toastr'; import { ReadingList } from 'src/app/_models/reading-list'; @@ -56,7 +56,7 @@ export class AddToListModalComponent implements OnInit, AfterViewInit { */ lists: Array = []; loading: boolean = false; - listForm: UntypedFormGroup = new UntypedFormGroup({}); + listForm: FormGroup = new FormGroup({}); @ViewChild('title') inputElem!: ElementRef; @@ -65,8 +65,8 @@ export class AddToListModalComponent implements OnInit, AfterViewInit { ngOnInit(): void { - this.listForm.addControl('title', new UntypedFormControl(this.title, [])); - this.listForm.addControl('filterQuery', new UntypedFormControl('', [])); + this.listForm.addControl('title', new FormControl(this.title, [])); + this.listForm.addControl('filterQuery', new FormControl('', [])); this.loading = true; this.readingListService.getReadingLists(false).subscribe(lists => { diff --git a/UI/Web/src/app/reading-list/_modals/edit-reading-list-modal/edit-reading-list-modal.component.ts b/UI/Web/src/app/reading-list/_modals/edit-reading-list-modal/edit-reading-list-modal.component.ts index 89f634e62..13d6960a4 100644 --- a/UI/Web/src/app/reading-list/_modals/edit-reading-list-modal/edit-reading-list-modal.component.ts +++ b/UI/Web/src/app/reading-list/_modals/edit-reading-list-modal/edit-reading-list-modal.component.ts @@ -1,5 +1,5 @@ import { Component, Input, OnInit } from '@angular/core'; -import { UntypedFormGroup, UntypedFormControl, Validators } from '@angular/forms'; +import { FormGroup, FormControl, Validators } from '@angular/forms'; import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'; import { ToastrService } from 'ngx-toastr'; import { forkJoin } from 'rxjs'; @@ -18,7 +18,7 @@ import { UploadService } from 'src/app/_services/upload.service'; export class EditReadingListModalComponent implements OnInit { @Input() readingList!: ReadingList; - reviewGroup!: UntypedFormGroup; + reviewGroup!: FormGroup; coverImageIndex: number = 0; /** @@ -41,9 +41,9 @@ export class EditReadingListModalComponent implements OnInit { private imageService: ImageService) { } ngOnInit(): void { - this.reviewGroup = new UntypedFormGroup({ - title: new UntypedFormControl(this.readingList.title, [Validators.required]), - summary: new UntypedFormControl(this.readingList.summary, []) + this.reviewGroup = new FormGroup({ + title: new FormControl(this.readingList.title, [Validators.required]), + summary: new FormControl(this.readingList.summary, []) }); this.imageUrls.push(this.imageService.randomize(this.imageService.getReadingListCoverImage(this.readingList.id))); diff --git a/UI/Web/src/app/registration/add-email-to-account-migration-modal/add-email-to-account-migration-modal.component.ts b/UI/Web/src/app/registration/add-email-to-account-migration-modal/add-email-to-account-migration-modal.component.ts index 784832e7c..ca0292424 100644 --- a/UI/Web/src/app/registration/add-email-to-account-migration-modal/add-email-to-account-migration-modal.component.ts +++ b/UI/Web/src/app/registration/add-email-to-account-migration-modal/add-email-to-account-migration-modal.component.ts @@ -1,5 +1,5 @@ import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnInit } from '@angular/core'; -import { UntypedFormControl, UntypedFormGroup, Validators } from '@angular/forms'; +import { FormControl, FormGroup, Validators } from '@angular/forms'; import { SafeUrl } from '@angular/platform-browser'; import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'; import { ToastrService } from 'ngx-toastr'; @@ -17,7 +17,7 @@ export class AddEmailToAccountMigrationModalComponent implements OnInit { @Input() password!: string; isSaving: boolean = false; - registerForm: UntypedFormGroup = new UntypedFormGroup({}); + registerForm: FormGroup = new FormGroup({}); emailLink: string = ''; emailLinkUrl: SafeUrl | undefined; error: string = ''; @@ -27,9 +27,9 @@ export class AddEmailToAccountMigrationModalComponent implements OnInit { } ngOnInit(): void { - this.registerForm.addControl('username', new UntypedFormControl(this.username, [Validators.required])); - this.registerForm.addControl('email', new UntypedFormControl('', [Validators.required, Validators.email])); - this.registerForm.addControl('password', new UntypedFormControl(this.password, [Validators.required])); + this.registerForm.addControl('username', new FormControl(this.username, [Validators.required])); + this.registerForm.addControl('email', new FormControl('', [Validators.required, Validators.email])); + this.registerForm.addControl('password', new FormControl(this.password, [Validators.required])); this.cdRef.markForCheck(); } diff --git a/UI/Web/src/app/registration/confirm-email/confirm-email.component.ts b/UI/Web/src/app/registration/confirm-email/confirm-email.component.ts index dd39bd145..d75c677fc 100644 --- a/UI/Web/src/app/registration/confirm-email/confirm-email.component.ts +++ b/UI/Web/src/app/registration/confirm-email/confirm-email.component.ts @@ -1,5 +1,5 @@ import { ChangeDetectionStrategy, ChangeDetectorRef, Component } from '@angular/core'; -import { UntypedFormControl, UntypedFormGroup, Validators } from '@angular/forms'; +import { FormControl, FormGroup, Validators } from '@angular/forms'; import { ActivatedRoute, Router } from '@angular/router'; import { ToastrService } from 'ngx-toastr'; import { ThemeService } from 'src/app/_services/theme.service'; @@ -18,10 +18,10 @@ export class ConfirmEmailComponent { */ token: string = ''; - registerForm: UntypedFormGroup = new UntypedFormGroup({ - email: new UntypedFormControl('', [Validators.required, Validators.email]), - username: new UntypedFormControl('', [Validators.required]), - password: new UntypedFormControl('', [Validators.required, Validators.maxLength(32), Validators.minLength(6)]), + registerForm: FormGroup = new FormGroup({ + email: new FormControl('', [Validators.required, Validators.email]), + username: new FormControl('', [Validators.required]), + password: new FormControl('', [Validators.required, Validators.maxLength(32), Validators.minLength(6)]), }); /** diff --git a/UI/Web/src/app/registration/confirm-reset-password/confirm-reset-password.component.html b/UI/Web/src/app/registration/confirm-reset-password/confirm-reset-password.component.html index 5b5422bdf..917c83e60 100644 --- a/UI/Web/src/app/registration/confirm-reset-password/confirm-reset-password.component.html +++ b/UI/Web/src/app/registration/confirm-reset-password/confirm-reset-password.component.html @@ -1,7 +1,7 @@

Password Reset

-

Enter the email of your account. We will send you an email

+

Enter the new password

  diff --git a/UI/Web/src/app/registration/confirm-reset-password/confirm-reset-password.component.scss b/UI/Web/src/app/registration/confirm-reset-password/confirm-reset-password.component.scss index e69de29bb..4d637eb32 100644 --- a/UI/Web/src/app/registration/confirm-reset-password/confirm-reset-password.component.scss +++ b/UI/Web/src/app/registration/confirm-reset-password/confirm-reset-password.component.scss @@ -0,0 +1,4 @@ +input { + background-color: #fff !important; + color: black !important; +} \ No newline at end of file diff --git a/UI/Web/src/app/registration/confirm-reset-password/confirm-reset-password.component.ts b/UI/Web/src/app/registration/confirm-reset-password/confirm-reset-password.component.ts index 61a86dd88..f297ba092 100644 --- a/UI/Web/src/app/registration/confirm-reset-password/confirm-reset-password.component.ts +++ b/UI/Web/src/app/registration/confirm-reset-password/confirm-reset-password.component.ts @@ -1,8 +1,9 @@ import { ChangeDetectionStrategy, ChangeDetectorRef, Component } from '@angular/core'; -import { UntypedFormGroup, UntypedFormControl, Validators } from '@angular/forms'; +import { FormGroup, FormControl, Validators } from '@angular/forms'; import { ActivatedRoute, Router } from '@angular/router'; import { ToastrService } from 'ngx-toastr'; import { AccountService } from 'src/app/_services/account.service'; +import { NavService } from 'src/app/_services/nav.service'; @Component({ selector: 'app-confirm-reset-password', @@ -13,14 +14,18 @@ import { AccountService } from 'src/app/_services/account.service'; export class ConfirmResetPasswordComponent { token: string = ''; - registerForm: UntypedFormGroup = new UntypedFormGroup({ - email: new UntypedFormControl('', [Validators.required, Validators.email]), - password: new UntypedFormControl('', [Validators.required, Validators.maxLength(32), Validators.minLength(6)]), + registerForm: FormGroup = new FormGroup({ + email: new FormControl('', [Validators.required, Validators.email]), + password: new FormControl('', [Validators.required, Validators.maxLength(32), Validators.minLength(6)]), }); constructor(private route: ActivatedRoute, private router: Router, private accountService: AccountService, private toastr: ToastrService, - private readonly cdRef: ChangeDetectorRef) { + private readonly cdRef: ChangeDetectorRef, private navService: NavService) { + + this.navService.showNavBar(); + this.navService.hideSideNav(); + const token = this.route.snapshot.queryParamMap.get('token'); const email = this.route.snapshot.queryParamMap.get('email'); diff --git a/UI/Web/src/app/registration/register/register.component.ts b/UI/Web/src/app/registration/register/register.component.ts index 222ee2a81..e472c3efc 100644 --- a/UI/Web/src/app/registration/register/register.component.ts +++ b/UI/Web/src/app/registration/register/register.component.ts @@ -1,5 +1,5 @@ import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core'; -import { UntypedFormGroup, UntypedFormControl, Validators } from '@angular/forms'; +import { FormGroup, FormControl, Validators } from '@angular/forms'; import { Router } from '@angular/router'; import { ToastrService } from 'ngx-toastr'; import { take } from 'rxjs/operators'; @@ -17,10 +17,10 @@ import { MemberService } from 'src/app/_services/member.service'; }) export class RegisterComponent implements OnInit { - registerForm: UntypedFormGroup = new UntypedFormGroup({ - email: new UntypedFormControl('', [Validators.required, Validators.email]), - username: new UntypedFormControl('', [Validators.required]), - password: new UntypedFormControl('', [Validators.required, Validators.maxLength(32), Validators.minLength(6)]), + registerForm: FormGroup = new FormGroup({ + email: new FormControl('', [Validators.required, Validators.email]), + username: new FormControl('', [Validators.required]), + password: new FormControl('', [Validators.required, Validators.maxLength(32), Validators.minLength(6)]), }); constructor(private router: Router, private accountService: AccountService, diff --git a/UI/Web/src/app/registration/user-login/user-login.component.ts b/UI/Web/src/app/registration/user-login/user-login.component.ts index 8b6ba2ac4..1a5c0184c 100644 --- a/UI/Web/src/app/registration/user-login/user-login.component.ts +++ b/UI/Web/src/app/registration/user-login/user-login.component.ts @@ -1,5 +1,5 @@ import { ChangeDetectionStrategy, ChangeDetectorRef, Component, OnInit } from '@angular/core'; -import { UntypedFormGroup, UntypedFormControl, Validators } from '@angular/forms'; +import { FormGroup, FormControl, Validators } from '@angular/forms'; import { Router } from '@angular/router'; import { NgbModal } from '@ng-bootstrap/ng-bootstrap'; import { ToastrService } from 'ngx-toastr'; @@ -20,9 +20,9 @@ import { NavService } from '../../_services/nav.service'; export class UserLoginComponent implements OnInit { //model: any = {username: '', password: ''}; - loginForm: UntypedFormGroup = new UntypedFormGroup({ - username: new UntypedFormControl('', [Validators.required]), - password: new UntypedFormControl('', [Validators.required]) + loginForm: FormGroup = new FormGroup({ + username: new FormControl('', [Validators.required]), + password: new FormControl('', [Validators.required]) }); /** diff --git a/UI/Web/src/app/series-detail/review-series-modal/review-series-modal.component.ts b/UI/Web/src/app/series-detail/review-series-modal/review-series-modal.component.ts index f98eba109..eba3daed9 100644 --- a/UI/Web/src/app/series-detail/review-series-modal/review-series-modal.component.ts +++ b/UI/Web/src/app/series-detail/review-series-modal/review-series-modal.component.ts @@ -1,5 +1,5 @@ import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnInit } from '@angular/core'; -import { UntypedFormControl, UntypedFormGroup } from '@angular/forms'; +import { FormControl, FormGroup } from '@angular/forms'; import { NgbModal, NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'; import { Series } from 'src/app/_models/series'; import { SeriesService } from 'src/app/_services/series.service'; @@ -13,14 +13,14 @@ import { SeriesService } from 'src/app/_services/series.service'; export class ReviewSeriesModalComponent implements OnInit { @Input() series!: Series; - reviewGroup!: UntypedFormGroup; + reviewGroup!: FormGroup; constructor(public modal: NgbActiveModal, private seriesService: SeriesService, private readonly cdRef: ChangeDetectorRef) {} ngOnInit(): void { - this.reviewGroup = new UntypedFormGroup({ - review: new UntypedFormControl(this.series.userReview, []), - rating: new UntypedFormControl(this.series.userRating, []) + this.reviewGroup = new FormGroup({ + review: new FormControl(this.series.userReview, []), + rating: new FormControl(this.series.userRating, []) }); this.cdRef.markForCheck(); } diff --git a/UI/Web/src/app/series-detail/series-detail.component.ts b/UI/Web/src/app/series-detail/series-detail.component.ts index d0997103c..16f59d084 100644 --- a/UI/Web/src/app/series-detail/series-detail.component.ts +++ b/UI/Web/src/app/series-detail/series-detail.component.ts @@ -35,7 +35,7 @@ import { NavService } from '../_services/nav.service'; import { RelatedSeries } from '../_models/series-detail/related-series'; import { RelationKind } from '../_models/series-detail/relation-kind'; import { CardDetailDrawerComponent } from '../cards/card-detail-drawer/card-detail-drawer.component'; -import { FormGroup, UntypedFormControl, UntypedFormGroup } from '@angular/forms'; +import { FormGroup, FormControl } from '@angular/forms'; import { PageLayoutMode } from '../_models/page-layout-mode'; import { DOCUMENT } from '@angular/common'; import { User } from '../_models/user'; @@ -151,8 +151,8 @@ export class SeriesDetailComponent implements OnInit, OnDestroy, AfterContentChe renderMode: PageLayoutMode = PageLayoutMode.Cards; pageExtrasGroup = new FormGroup({ - 'sortingOption': new UntypedFormControl(this.sortingOptions[0].value, []), - 'renderMode': new UntypedFormControl(this.renderMode, []), + 'sortingOption': new FormControl(this.sortingOptions[0].value, []), + 'renderMode': new FormControl(this.renderMode, []), }); isAscendingSort: boolean = false; // TODO: Get this from User preferences @@ -299,7 +299,8 @@ export class SeriesDetailComponent implements OnInit, OnDestroy, AfterContentChe this.changeDetectionRef.markForCheck(); this.loadSeries(this.seriesId); - this.pageExtrasGroup.get('renderMode')?.valueChanges.pipe(takeUntil(this.onDestroy)).subscribe((val: PageLayoutMode) => { + this.pageExtrasGroup.get('renderMode')?.valueChanges.pipe(takeUntil(this.onDestroy)).subscribe((val: PageLayoutMode | null) => { + if (val == null) return; this.renderMode = val; this.changeDetectionRef.markForCheck(); }); diff --git a/UI/Web/src/app/typeahead/typeahead-settings.ts b/UI/Web/src/app/typeahead/typeahead-settings.ts index e13a67d4e..c0cbe648f 100644 --- a/UI/Web/src/app/typeahead/typeahead-settings.ts +++ b/UI/Web/src/app/typeahead/typeahead-settings.ts @@ -1,5 +1,5 @@ import { Observable } from 'rxjs'; -import { UntypedFormControl } from '@angular/forms'; +import { FormControl } from '@angular/forms'; export type SelectionCompareFn = (a: T, b: T) => boolean; @@ -48,7 +48,7 @@ export class TypeaheadSettings { /** * Optional form Control to tie model to. */ - formControl?: UntypedFormControl; + formControl?: FormControl; /** * If true, typeahead will remove already selected items from fetchFn results. Only appies when multiple=true */ diff --git a/UI/Web/src/app/typeahead/typeahead.component.ts b/UI/Web/src/app/typeahead/typeahead.component.ts index ecae70e21..232e6153f 100644 --- a/UI/Web/src/app/typeahead/typeahead.component.ts +++ b/UI/Web/src/app/typeahead/typeahead.component.ts @@ -1,7 +1,7 @@ import { trigger, state, style, transition, animate } from '@angular/animations'; import { DOCUMENT } from '@angular/common'; import { ChangeDetectionStrategy, ChangeDetectorRef, Component, ContentChild, ElementRef, EventEmitter, HostListener, Inject, Input, OnDestroy, OnInit, Output, Renderer2, RendererStyleFlags2, TemplateRef, ViewChild } from '@angular/core'; -import { UntypedFormControl, UntypedFormGroup } from '@angular/forms'; +import { FormControl, FormGroup } from '@angular/forms'; import { Observable, of, ReplaySubject, Subject } from 'rxjs'; import { auditTime, distinctUntilChanged, filter, map, shareReplay, switchMap, take, takeUntil, tap } from 'rxjs/operators'; import { KEY_CODES } from '../shared/_services/utility.service'; @@ -189,8 +189,8 @@ export class TypeaheadComponent implements OnInit, OnDestroy { showAddItem: boolean = false; filteredOptions!: Observable; isLoadingOptions: boolean = false; - typeaheadControl!: UntypedFormControl; - typeaheadForm!: UntypedFormGroup; + typeaheadControl!: FormControl; + typeaheadForm!: FormGroup; private readonly onDestroy = new Subject(); @@ -230,9 +230,9 @@ export class TypeaheadComponent implements OnInit, OnDestroy { if (this.settings.hasOwnProperty('formControl') && this.settings.formControl) { this.typeaheadControl = this.settings.formControl; } else { - this.typeaheadControl = new UntypedFormControl(''); + this.typeaheadControl = new FormControl(''); } - this.typeaheadForm = new UntypedFormGroup({ + this.typeaheadForm = new FormGroup({ 'typeahead': this.typeaheadControl });