From ee727278411839868b83503901ba71c0b37687f0 Mon Sep 17 00:00:00 2001 From: Joe Milazzo Date: Sun, 12 Nov 2023 08:29:46 -0600 Subject: [PATCH] Polish Round 4 (#2429) --- .editorconfig | 3 + API.Tests/Parser/DefaultParserTests.cs | 8 +- API.Tests/Services/SeriesServiceTests.cs | 2 +- API/API.csproj | 19 +- API/Controllers/SeriesController.cs | 3 +- API/DTOs/SeriesMetadataDto.cs | 20 +- API/Services/AccountService.cs | 8 +- API/Services/SeriesService.cs | 21 +- .../Tasks/Scanner/Parser/DefaultParser.cs | 39 +- API/Services/Tasks/Scanner/Parser/Parser.cs | 20 +- API/Services/Tasks/Scanner/ProcessSeries.cs | 3 + UI/Web/package-lock.json | 170 +++-- UI/Web/package.json | 24 +- .../app/_models/metadata/series-metadata.ts | 22 +- .../src/app/_pipes/utc-to-local-time.pipe.ts | 2 +- .../directory-picker.component.html | 2 +- .../directory-picker.component.ts | 10 +- .../admin/dashboard/dashboard.component.html | 3 - .../admin/dashboard/dashboard.component.ts | 6 +- .../all-series/all-series.component.ts | 5 +- UI/Web/src/app/app-routing.module.ts | 4 +- .../book-reader/book-reader.component.ts | 4 +- .../edit-series-modal.component.html | 40 +- .../next-expected-card.component.ts | 3 +- .../reading-list-detail.component.ts | 4 +- .../reading-lists/reading-lists.component.ts | 7 +- .../import-cbl-modal.component.ts | 2 +- .../library-settings-modal.component.html | 2 +- .../change-email/change-email.component.scss | 4 +- .../user-preferences.component.html | 688 +++++++++--------- .../user-preferences.component.ts | 7 +- UI/Web/src/assets/langs/en.json | 4 + openapi.json | 20 +- 33 files changed, 623 insertions(+), 556 deletions(-) diff --git a/.editorconfig b/.editorconfig index faf506c4e1..c24677846f 100644 --- a/.editorconfig +++ b/.editorconfig @@ -19,3 +19,6 @@ trim_trailing_whitespace = false [*.yml] indent_size = 2 + +[*.csproj] +indent_size = 2 diff --git a/API.Tests/Parser/DefaultParserTests.cs b/API.Tests/Parser/DefaultParserTests.cs index a658080de4..14e75f353f 100644 --- a/API.Tests/Parser/DefaultParserTests.cs +++ b/API.Tests/Parser/DefaultParserTests.cs @@ -62,7 +62,7 @@ public void ParseFromFallbackFolders_ShouldParseSeriesVolumeAndChapter(string in [Theory] [InlineData("/manga/Btooom!/Vol.1/Chapter 1/1.cbz", "Btooom!")] [InlineData("/manga/Btooom!/Vol.1 Chapter 2/1.cbz", "Btooom!")] - [InlineData("/manga/Monster #8 (Digital)/Ch. 001-016 [MangaPlus] [Digital] [amit34521]/Monster #8 Ch. 001 [MangaPlus] [Digital] [amit34521]/13.jpg", "Monster")] + [InlineData("/manga/Monster #8 (Digital)/Ch. 001-016 [MangaPlus] [Digital] [amit34521]/Monster #8 Ch. 001 [MangaPlus] [Digital] [amit34521]/13.jpg", "manga")] [InlineData("/manga/Monster (Digital)/Ch. 001-016 [MangaPlus] [Digital] [amit34521]/Monster Ch. 001 [MangaPlus] [Digital] [amit34521]/13.jpg", "Monster")] [InlineData("/manga/Foo 50/Specials/Foo 50 SP01.cbz", "Foo 50")] [InlineData("/manga/Foo 50 (kiraa)/Specials/Foo 50 SP01.cbz", "Foo 50")] @@ -293,7 +293,7 @@ public void Parse_ParseInfo_Manga_ImageOnly() var expectedInfo2 = new ParserInfo { Series = "Monster #8", Volumes = "0", Edition = "", - Chapters = "1", Filename = "13.jpg", Format = MangaFormat.Image, + Chapters = "8", Filename = "13.jpg", Format = MangaFormat.Image, FullFilePath = filepath, IsSpecial = false }; var actual2 = _defaultParser.Parse(filepath, @"E:\Manga\Monster #8"); @@ -314,7 +314,7 @@ public void Parse_ParseInfo_Manga_ImageOnly() Assert.Equal(expectedInfo2.FullFilePath, actual2.FullFilePath); _testOutputHelper.WriteLine("FullFilePath ✓"); - filepath = @"E:\Manga\Extra layer for no reason\Just Images the second\Vol19\ch186\Vol. 19 p106.gif"; + filepath = @"E:\Manga\Extra layer for no reason\Just Images the second\Vol19\ch. 186\Vol. 19 p106.gif"; expectedInfo2 = new ParserInfo { Series = "Just Images the second", Volumes = "19", Edition = "", @@ -340,7 +340,7 @@ public void Parse_ParseInfo_Manga_ImageOnly() Assert.Equal(expectedInfo2.FullFilePath, actual2.FullFilePath); _testOutputHelper.WriteLine("FullFilePath ✓"); - filepath = @"E:\Manga\Extra layer for no reason\Just Images the second\Blank Folder\Vol19\ch186\Vol. 19 p106.gif"; + filepath = @"E:\Manga\Extra layer for no reason\Just Images the second\Blank Folder\Vol19\ch. 186\Vol. 19 p106.gif"; expectedInfo2 = new ParserInfo { Series = "Just Images the second", Volumes = "19", Edition = "", diff --git a/API.Tests/Services/SeriesServiceTests.cs b/API.Tests/Services/SeriesServiceTests.cs index 352b7ca9da..ed5a729ad2 100644 --- a/API.Tests/Services/SeriesServiceTests.cs +++ b/API.Tests/Services/SeriesServiceTests.cs @@ -657,7 +657,7 @@ public async Task UpdateSeriesMetadata_ShouldAddNewPerson_ExistingPeople() { SeriesId = 1, Publishers = new List() {new () {Id = 0, Name = "Existing Person", Role = PersonRole.Publisher}}, - PublishersLocked = true + PublisherLocked = true }, CollectionTags = new List() }); diff --git a/API/API.csproj b/API/API.csproj index 8fec465175..8e80b029d2 100644 --- a/API/API.csproj +++ b/API/API.csproj @@ -53,6 +53,10 @@ + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + @@ -60,28 +64,15 @@ - - - - + - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - - - - - - - diff --git a/API/Controllers/SeriesController.cs b/API/Controllers/SeriesController.cs index 36b4ff3d28..df74a54f79 100644 --- a/API/Controllers/SeriesController.cs +++ b/API/Controllers/SeriesController.cs @@ -437,8 +437,7 @@ public ActionResult AnalyzeSeries(RefreshSeriesDto refreshSeriesDto) [HttpGet("metadata")] public async Task> GetSeriesMetadata(int seriesId) { - var metadata = await _unitOfWork.SeriesRepository.GetSeriesMetadata(seriesId); - return Ok(metadata); + return Ok(await _unitOfWork.SeriesRepository.GetSeriesMetadata(seriesId)); } /// diff --git a/API/DTOs/SeriesMetadataDto.cs b/API/DTOs/SeriesMetadataDto.cs index 8230134be7..e2a4c7aa25 100644 --- a/API/DTOs/SeriesMetadataDto.cs +++ b/API/DTOs/SeriesMetadataDto.cs @@ -75,16 +75,16 @@ public class SeriesMetadataDto public bool PublicationStatusLocked { get; set; } public bool GenresLocked { get; set; } public bool TagsLocked { get; set; } - public bool WritersLocked { get; set; } - public bool CharactersLocked { get; set; } - public bool ColoristsLocked { get; set; } - public bool EditorsLocked { get; set; } - public bool InkersLocked { get; set; } - public bool LetterersLocked { get; set; } - public bool PencillersLocked { get; set; } - public bool PublishersLocked { get; set; } - public bool TranslatorsLocked { get; set; } - public bool CoverArtistsLocked { get; set; } + public bool WriterLocked { get; set; } + public bool CharacterLocked { get; set; } + public bool ColoristLocked { get; set; } + public bool EditorLocked { get; set; } + public bool InkerLocked { get; set; } + public bool LettererLocked { get; set; } + public bool PencillerLocked { get; set; } + public bool PublisherLocked { get; set; } + public bool TranslatorLocked { get; set; } + public bool CoverArtistLocked { get; set; } public bool ReleaseYearLocked { get; set; } diff --git a/API/Services/AccountService.cs b/API/Services/AccountService.cs index 995604f176..4b03646e84 100644 --- a/API/Services/AccountService.cs +++ b/API/Services/AccountService.cs @@ -73,12 +73,14 @@ public async Task GenerateEmailLink(HttpRequest request, string token, s basePart = serverSettings.HostName; if (!serverSettings.BaseUrl.Equals(Configuration.DefaultBaseUrl)) { - basePart += serverSettings.BaseUrl.Substring(0, serverSettings.BaseUrl.Length - 1); + var removeCount = serverSettings.BaseUrl.EndsWith("/") ? 2 : 1; + basePart += serverSettings.BaseUrl.Substring(0, serverSettings.BaseUrl.Length - removeCount); } } - if (withHost) return $"{basePart}/registration/{routePart}?token={HttpUtility.UrlEncode(token)}&email={HttpUtility.UrlEncode(email)}".Replace("//", "/"); - return $"registration/{routePart}?token={HttpUtility.UrlEncode(token)}&email={HttpUtility.UrlEncode(email)}".Replace("//", "/"); + if (withHost) return $"{basePart}/registration/{routePart}?token={HttpUtility.UrlEncode(token)}&email={HttpUtility.UrlEncode(email)}"; + return $"registration/{routePart}?token={HttpUtility.UrlEncode(token)}&email={HttpUtility.UrlEncode(email)}" + .Replace("//", "/"); } public async Task> ChangeUserPassword(AppUser user, string newPassword) diff --git a/API/Services/SeriesService.cs b/API/Services/SeriesService.cs index f944ed3306..af763d5c92 100644 --- a/API/Services/SeriesService.cs +++ b/API/Services/SeriesService.cs @@ -107,6 +107,7 @@ public async Task UpdateSeriesMetadata(UpdateSeriesMetadataDto updateSerie var series = await _unitOfWork.SeriesRepository.GetSeriesByIdAsync(seriesId); if (series == null) return false; var allCollectionTags = (await _unitOfWork.CollectionTagRepository.GetAllTagsAsync()).ToList(); + // TODO: This is Diesel's performance problem with Komf. For some systems, this is too heavy of a call if komf is spamming updates. var allGenres = (await _unitOfWork.GenreRepository.GetAllGenresAsync()).ToList(); var allPeople = (await _unitOfWork.PersonRepository.GetAllPeople()).ToList(); var allTags = (await _unitOfWork.TagRepository.GetAllTagsAsync()).ToList(); @@ -219,16 +220,16 @@ void HandleAddPerson(Person person) series.Metadata.LanguageLocked = updateSeriesMetadataDto.SeriesMetadata.LanguageLocked; series.Metadata.GenresLocked = updateSeriesMetadataDto.SeriesMetadata.GenresLocked; series.Metadata.TagsLocked = updateSeriesMetadataDto.SeriesMetadata.TagsLocked; - series.Metadata.CharacterLocked = updateSeriesMetadataDto.SeriesMetadata.CharactersLocked; - series.Metadata.ColoristLocked = updateSeriesMetadataDto.SeriesMetadata.ColoristsLocked; - series.Metadata.EditorLocked = updateSeriesMetadataDto.SeriesMetadata.EditorsLocked; - series.Metadata.InkerLocked = updateSeriesMetadataDto.SeriesMetadata.InkersLocked; - series.Metadata.LettererLocked = updateSeriesMetadataDto.SeriesMetadata.LetterersLocked; - series.Metadata.PencillerLocked = updateSeriesMetadataDto.SeriesMetadata.PencillersLocked; - series.Metadata.PublisherLocked = updateSeriesMetadataDto.SeriesMetadata.PublishersLocked; - series.Metadata.TranslatorLocked = updateSeriesMetadataDto.SeriesMetadata.TranslatorsLocked; - series.Metadata.CoverArtistLocked = updateSeriesMetadataDto.SeriesMetadata.CoverArtistsLocked; - series.Metadata.WriterLocked = updateSeriesMetadataDto.SeriesMetadata.WritersLocked; + series.Metadata.CharacterLocked = updateSeriesMetadataDto.SeriesMetadata.CharacterLocked; + series.Metadata.ColoristLocked = updateSeriesMetadataDto.SeriesMetadata.ColoristLocked; + series.Metadata.EditorLocked = updateSeriesMetadataDto.SeriesMetadata.EditorLocked; + series.Metadata.InkerLocked = updateSeriesMetadataDto.SeriesMetadata.InkerLocked; + series.Metadata.LettererLocked = updateSeriesMetadataDto.SeriesMetadata.LettererLocked; + series.Metadata.PencillerLocked = updateSeriesMetadataDto.SeriesMetadata.PencillerLocked; + series.Metadata.PublisherLocked = updateSeriesMetadataDto.SeriesMetadata.PublisherLocked; + series.Metadata.TranslatorLocked = updateSeriesMetadataDto.SeriesMetadata.TranslatorLocked; + series.Metadata.CoverArtistLocked = updateSeriesMetadataDto.SeriesMetadata.CoverArtistLocked; + series.Metadata.WriterLocked = updateSeriesMetadataDto.SeriesMetadata.WriterLocked; series.Metadata.SummaryLocked = updateSeriesMetadataDto.SeriesMetadata.SummaryLocked; series.Metadata.ReleaseYearLocked = updateSeriesMetadataDto.SeriesMetadata.ReleaseYearLocked; diff --git a/API/Services/Tasks/Scanner/Parser/DefaultParser.cs b/API/Services/Tasks/Scanner/Parser/DefaultParser.cs index dd6328272b..d54404c22b 100644 --- a/API/Services/Tasks/Scanner/Parser/DefaultParser.cs +++ b/API/Services/Tasks/Scanner/Parser/DefaultParser.cs @@ -119,19 +119,46 @@ private ParserInfo ParseImage(string filePath, string rootPath, ParserInfo ret) { ret.Volumes = Parser.DefaultVolume; ret.Chapters = Parser.DefaultChapter; - // Next we need to see if the image has a folder between rootPath and filePath. - // if so, take that folder as a volume 0 chapter 0 special and group everything under there (if we can't parse a volume/chapter) + var directoryName = _directoryService.FileSystem.DirectoryInfo.New(rootPath).Name; + ret.Series = directoryName; + ParseFromFallbackFolders(filePath, rootPath, LibraryType.Image, ref ret); - if ((string.IsNullOrEmpty(ret.Chapters) || ret.Chapters == Parser.DefaultChapter) && - (string.IsNullOrEmpty(ret.Volumes) || ret.Volumes == Parser.DefaultVolume)) + + + if (IsEmptyOrDefault(ret.Volumes, ret.Chapters)) { ret.IsSpecial = true; } + else + { + var parsedVolume = Parser.ParseVolume(ret.Filename); + var parsedChapter = Parser.ParseChapter(ret.Filename); + if (IsEmptyOrDefault(ret.Volumes, string.Empty) && !parsedVolume.Equals(Parser.DefaultVolume)) + { + ret.Volumes = parsedVolume; + } + if (IsEmptyOrDefault(string.Empty, ret.Chapters) && !parsedChapter.Equals(Parser.DefaultChapter)) + { + ret.Chapters = parsedChapter; + } + } + + + // Override the series name, as fallback folders needs it to try and parse folder name + if (string.IsNullOrEmpty(ret.Series) || ret.Series.Equals(directoryName)) + { + ret.Series = Parser.CleanTitle(directoryName, replaceSpecials: false); + } - ret.Series = _directoryService.FileSystem.DirectoryInfo.New(rootPath).Name; return ret; } + private static bool IsEmptyOrDefault(string volumes, string chapters) + { + return (string.IsNullOrEmpty(chapters) || chapters == Parser.DefaultChapter) && + (string.IsNullOrEmpty(volumes) || volumes == Parser.DefaultVolume); + } + /// /// Fills out by trying to parse volume, chapters, and series from folders /// @@ -193,7 +220,7 @@ public void ParseFromFallbackFolders(string filePath, string rootPath, LibraryTy break; } - if (!string.IsNullOrEmpty(series) && (string.IsNullOrEmpty(ret.Series) || !folder.Contains(ret.Series))) + if (!string.IsNullOrEmpty(series) && (string.IsNullOrEmpty(ret.Series) && !folder.Contains(ret.Series))) { ret.Series = series; break; diff --git a/API/Services/Tasks/Scanner/Parser/Parser.cs b/API/Services/Tasks/Scanner/Parser/Parser.cs index d4c7b9bf20..8a27076aaa 100644 --- a/API/Services/Tasks/Scanner/Parser/Parser.cs +++ b/API/Services/Tasks/Scanner/Parser/Parser.cs @@ -843,23 +843,27 @@ private static string RemoveComicSpecialTags(string title) /// /// - public static string CleanTitle(string title, bool isComic = false) + public static string CleanTitle(string title, bool isComic = false, bool replaceSpecials = true) { title = ReplaceUnderscores(title); title = RemoveEditionTagHolders(title); - if (isComic) + if (replaceSpecials) { - title = RemoveComicSpecialTags(title); - title = RemoveEuropeanTags(title); - } - else - { - title = RemoveMangaSpecialTags(title); + if (isComic) + { + title = RemoveComicSpecialTags(title); + title = RemoveEuropeanTags(title); + } + else + { + title = RemoveMangaSpecialTags(title); + } } + title = title.Trim(SpacesAndSeparators); title = EmptySpaceRegex.Replace(title, " "); diff --git a/API/Services/Tasks/Scanner/ProcessSeries.cs b/API/Services/Tasks/Scanner/ProcessSeries.cs index 3a13e8d25d..f14cbc2359 100644 --- a/API/Services/Tasks/Scanner/ProcessSeries.cs +++ b/API/Services/Tasks/Scanner/ProcessSeries.cs @@ -293,6 +293,9 @@ public void UpdateSeriesMetadata(Series series, Library library) if ((maxChapter == 0 || maxChapter > series.Metadata.TotalCount) && maxVolume <= series.Metadata.TotalCount) + { + series.Metadata.MaxCount = maxVolume; + } else if (maxVolume == series.Metadata.TotalCount) { series.Metadata.MaxCount = maxVolume; } diff --git a/UI/Web/package-lock.json b/UI/Web/package-lock.json index 44ca7b8d76..681d99a2b3 100644 --- a/UI/Web/package-lock.json +++ b/UI/Web/package-lock.json @@ -8,16 +8,16 @@ "name": "kavita-webui", "version": "0.4.2", "dependencies": { - "@angular/animations": "^17.0.1", + "@angular/animations": "^17.0.2", "@angular/cdk": "^17.0.0", - "@angular/common": "^17.0.1", - "@angular/compiler": "^17.0.1", - "@angular/core": "^17.0.1", - "@angular/forms": "^17.0.1", - "@angular/localize": "^17.0.1", - "@angular/platform-browser": "^17.0.1", - "@angular/platform-browser-dynamic": "^17.0.1", - "@angular/router": "^17.0.1", + "@angular/common": "^17.0.2", + "@angular/compiler": "^17.0.2", + "@angular/core": "^17.0.2", + "@angular/forms": "^17.0.2", + "@angular/localize": "^17.0.2", + "@angular/platform-browser": "^17.0.2", + "@angular/platform-browser-dynamic": "^17.0.2", + "@angular/router": "^17.0.2", "@fortawesome/fontawesome-free": "^6.4.2", "@iharbeck/ngx-virtual-scroller": "^16.0.0", "@iplab/ngx-file-upload": "^16.0.2", @@ -29,7 +29,7 @@ "@ngneat/transloco-persist-translations": "^5.0.0", "@ngneat/transloco-preload-langs": "^5.0.0", "@popperjs/core": "^2.11.7", - "@swimlane/ngx-charts": "^20.1.2", + "@swimlane/ngx-charts": "^20.5.0", "@tweenjs/tween.js": "^21.0.0", "bootstrap": "^5.3.2", "charts.css": "^1.1.0", @@ -52,13 +52,13 @@ }, "devDependencies": { "@angular-devkit/build-angular": "^17.0.0", - "@angular-eslint/builder": "^17.0.0", + "@angular-eslint/builder": "^17.0.1", "@angular-eslint/eslint-plugin": "^17.0.0", "@angular-eslint/eslint-plugin-template": "^17.0.0", "@angular-eslint/schematics": "^17.0.1", "@angular-eslint/template-parser": "^17.0.1", "@angular/cli": "^17.0.0", - "@angular/compiler-cli": "^17.0.1", + "@angular/compiler-cli": "^17.0.2", "@types/d3": "^7.4.3", "@types/file-saver": "^2.0.7", "@types/luxon": "^3.3.4", @@ -744,9 +744,9 @@ } }, "node_modules/@angular-eslint/builder": { - "version": "17.0.0", - "resolved": "https://registry.npmjs.org/@angular-eslint/builder/-/builder-17.0.0.tgz", - "integrity": "sha512-cquqJH0R/IIh2PElcGXdo9FTcrkwO78H2MXk9ChGFBjQrYjihFLhFm12VuQsih7X6bJjA0cmr2PL1KbtgjMk1Q==", + "version": "17.0.1", + "resolved": "https://registry.npmjs.org/@angular-eslint/builder/-/builder-17.0.1.tgz", + "integrity": "sha512-bNXi5tdqIFdNDHxphDRUUbzA+7v6emOX2B/PFLG2pe+K6/JpHS0auwY/nq7hCroH7pMS5HZ+Q4i90q0GN/DWPg==", "dev": true, "dependencies": { "@nx/devkit": "17.0.3", @@ -842,9 +842,9 @@ } }, "node_modules/@angular/animations": { - "version": "17.0.1", - "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-17.0.1.tgz", - "integrity": "sha512-Uee6E8zyU6XjDfKFozybcf+JZy0nUFQ1bUEmRwFP5HvYJSSJ5YiUDokNiVxyn9znwZ7zKHlM6Bq9ZY9cCmeKKQ==", + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-17.0.2.tgz", + "integrity": "sha512-32RHWhTgFLMonI3kRdstACay/nvetfxXjdwcTtABjcvBoND7nD9GMhkISQdgS+hcR/IhgXxaPidq8f2UAY5DBw==", "dependencies": { "tslib": "^2.3.0" }, @@ -852,7 +852,7 @@ "node": "^18.13.0 || >=20.9.0" }, "peerDependencies": { - "@angular/core": "17.0.1" + "@angular/core": "17.0.2" } }, "node_modules/@angular/cdk": { @@ -939,9 +939,9 @@ "dev": true }, "node_modules/@angular/common": { - "version": "17.0.1", - "resolved": "https://registry.npmjs.org/@angular/common/-/common-17.0.1.tgz", - "integrity": "sha512-AvvhZc+PhX5lVEW/Vorxe3Zf1rIEJJvfduRuRv+nsjijo3ZGjdgYjTYEx4ighZgH60RLIAuwyBE24gPkT2Pm7g==", + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/@angular/common/-/common-17.0.2.tgz", + "integrity": "sha512-hCW0njHgrcwTWNoKZDwf02DnhYLVWNXM2FMw66MKpfxTp7McSyaXjGBU9/hchW3dZJ0xTwyxoyoqJFoHYvg0yg==", "dependencies": { "tslib": "^2.3.0" }, @@ -949,14 +949,14 @@ "node": "^18.13.0 || >=20.9.0" }, "peerDependencies": { - "@angular/core": "17.0.1", + "@angular/core": "17.0.2", "rxjs": "^6.5.3 || ^7.4.0" } }, "node_modules/@angular/compiler": { - "version": "17.0.1", - "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-17.0.1.tgz", - "integrity": "sha512-qlKqCvjoxPHJ1e8+UMaBl/n9zzrmGXI5eWMVhULSvQnQvPWkwNlUh5XFeoSFcTEQxORjaO2/08Z31DmTJAqlPA==", + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-17.0.2.tgz", + "integrity": "sha512-ewUFbKhMEhAmw2dGfk0ImhTlyrO2y4pJSKIZdFrkR1d0HiJX8bCHUdTiiR/2jeP7w2eamjXj15Rptb+iZZes2Q==", "dependencies": { "tslib": "^2.3.0" }, @@ -964,7 +964,7 @@ "node": "^18.13.0 || >=20.9.0" }, "peerDependencies": { - "@angular/core": "17.0.1" + "@angular/core": "17.0.2" }, "peerDependenciesMeta": { "@angular/core": { @@ -973,9 +973,9 @@ } }, "node_modules/@angular/compiler-cli": { - "version": "17.0.1", - "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-17.0.1.tgz", - "integrity": "sha512-Rnvh2V2CYhG7NR5VI4cESGKk9jyqLat0HoqXa06v3TtbjkiZyjjwh0SyZ8NYOBMkQeWiQTHGcgxGvjKD3L3qqA==", + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-17.0.2.tgz", + "integrity": "sha512-IUYL3Yz5RbR0Z0/x7it4GK3sMb2qVihxu0tlgfUW53P1Vi6nU/Zda0bCJTu6Z64qEtS8zwCwF1Ekomuq6UaiKg==", "dev": true, "dependencies": { "@babel/core": "7.23.2", @@ -996,14 +996,14 @@ "node": "^18.13.0 || >=20.9.0" }, "peerDependencies": { - "@angular/compiler": "17.0.1", + "@angular/compiler": "17.0.2", "typescript": ">=5.2 <5.3" } }, "node_modules/@angular/core": { - "version": "17.0.1", - "resolved": "https://registry.npmjs.org/@angular/core/-/core-17.0.1.tgz", - "integrity": "sha512-yVwU+oz0G8g6Q5ORyOCpgqMPdSiCdfW+uQhjI37WROnXHja3jY843AqrYTKE6mMx1r6q9h1wbDy+x2E61OWP7A==", + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/@angular/core/-/core-17.0.2.tgz", + "integrity": "sha512-MjDxWeyn3Txi0qo/V/I+B/gndh0uptQ0XWgBRwOx6Wcr5zRGeZIFlXBxPpyXnGTlJkeyErsTN7FfFCZ4C3kCPA==", "dependencies": { "tslib": "^2.3.0" }, @@ -1016,9 +1016,9 @@ } }, "node_modules/@angular/forms": { - "version": "17.0.1", - "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-17.0.1.tgz", - "integrity": "sha512-FpmUf2kgzwZXVbFB4VrwbnrO0m88QLUBsDsbLfQVQQwb7KxwSaftUu/aIrjst1gFCdl9k0Vqtrq2gwLZKzdSGQ==", + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-17.0.2.tgz", + "integrity": "sha512-w1QKifaVG4daxUktcBNZqBtOH1vn8t0YiwDR3woEdUYt0XYKMipfDzQfyIK+6fIVPOJUd42pRns1nbWJQHOInA==", "dependencies": { "tslib": "^2.3.0" }, @@ -1026,16 +1026,16 @@ "node": "^18.13.0 || >=20.9.0" }, "peerDependencies": { - "@angular/common": "17.0.1", - "@angular/core": "17.0.1", - "@angular/platform-browser": "17.0.1", + "@angular/common": "17.0.2", + "@angular/core": "17.0.2", + "@angular/platform-browser": "17.0.2", "rxjs": "^6.5.3 || ^7.4.0" } }, "node_modules/@angular/localize": { - "version": "17.0.1", - "resolved": "https://registry.npmjs.org/@angular/localize/-/localize-17.0.1.tgz", - "integrity": "sha512-pNLLnEbXjoW1agKwA4cBcM/HnqGuwQMpIhx9H46Y/oC2JkAvTCMVyXLbZUESeXmhysC9x2JDmF+Awhu7JzVVCA==", + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/@angular/localize/-/localize-17.0.2.tgz", + "integrity": "sha512-ct8xEy8Xk+PRfjrHLu7uywSQDzozmzlz6ptUCuYkRHrS4rJabXn3c0Sz4w+mh9B58qrK6KM+JSmXEZngEMXMTw==", "dependencies": { "@babel/core": "7.23.2", "fast-glob": "3.3.1", @@ -1050,14 +1050,14 @@ "node": "^18.13.0 || >=20.9.0" }, "peerDependencies": { - "@angular/compiler": "17.0.1", - "@angular/compiler-cli": "17.0.1" + "@angular/compiler": "17.0.2", + "@angular/compiler-cli": "17.0.2" } }, "node_modules/@angular/platform-browser": { - "version": "17.0.1", - "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-17.0.1.tgz", - "integrity": "sha512-JpvU0YDEM5KYdHtxC0Kdzk/hdwvZPq5vju5lTmIjTVa2OOabApOrQ6cq1MpKlrvjv1rw8MClHIM0l5Y0g9KH5g==", + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-17.0.2.tgz", + "integrity": "sha512-eTnPILEA/eAMkVUR/+g6fWhhMTmnmOzcZSGX/bBgQcvOhayZrDDxA6/Qf+jIB4RwC0wd3KA9zT5BCMmNojoUsg==", "dependencies": { "tslib": "^2.3.0" }, @@ -1065,9 +1065,9 @@ "node": "^18.13.0 || >=20.9.0" }, "peerDependencies": { - "@angular/animations": "17.0.1", - "@angular/common": "17.0.1", - "@angular/core": "17.0.1" + "@angular/animations": "17.0.2", + "@angular/common": "17.0.2", + "@angular/core": "17.0.2" }, "peerDependenciesMeta": { "@angular/animations": { @@ -1076,9 +1076,9 @@ } }, "node_modules/@angular/platform-browser-dynamic": { - "version": "17.0.1", - "resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-17.0.1.tgz", - "integrity": "sha512-xEcbB/ukXc65LaX4JBQYEM7D5Z8LcUIZniSJFneY7deZt3wNiKgmPZrPoXUyDV26QULh7N0IADEzvbcMF60AFQ==", + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-17.0.2.tgz", + "integrity": "sha512-clcHqHcfD00/TlTixDbJ3q4EQxpm0t2ZFG76rRFmGrmE5tKYUPfaofIa3hQCxy3q269MAYuF16wALhUtrEWyUA==", "dependencies": { "tslib": "^2.3.0" }, @@ -1086,16 +1086,16 @@ "node": "^18.13.0 || >=20.9.0" }, "peerDependencies": { - "@angular/common": "17.0.1", - "@angular/compiler": "17.0.1", - "@angular/core": "17.0.1", - "@angular/platform-browser": "17.0.1" + "@angular/common": "17.0.2", + "@angular/compiler": "17.0.2", + "@angular/core": "17.0.2", + "@angular/platform-browser": "17.0.2" } }, "node_modules/@angular/router": { - "version": "17.0.1", - "resolved": "https://registry.npmjs.org/@angular/router/-/router-17.0.1.tgz", - "integrity": "sha512-73PCDDsRAjemODMRndZhwEN6Tb9rVVbDfMWgLQ4HgfgKnjek8P9BoYf8rOf3qV5fXf3c1Sm9MmKtaPv+l5lU9Q==", + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/@angular/router/-/router-17.0.2.tgz", + "integrity": "sha512-A1Ulv4qBAtJyK5g1yBlK1qZHe+KaaL5vMPAaPWUxICH8lHEodDkJlbYAUI2e4VL2BN7zBmdOep6tlBKPmHY3mw==", "dependencies": { "tslib": "^2.3.0" }, @@ -1103,9 +1103,9 @@ "node": "^18.13.0 || >=20.9.0" }, "peerDependencies": { - "@angular/common": "17.0.1", - "@angular/core": "17.0.1", - "@angular/platform-browser": "17.0.1", + "@angular/common": "17.0.2", + "@angular/core": "17.0.2", + "@angular/platform-browser": "17.0.2", "rxjs": "^6.5.3 || ^7.4.0" } }, @@ -4251,9 +4251,9 @@ "dev": true }, "node_modules/@swimlane/ngx-charts": { - "version": "20.4.1", - "resolved": "https://registry.npmjs.org/@swimlane/ngx-charts/-/ngx-charts-20.4.1.tgz", - "integrity": "sha512-DyTQe0fcqLDoLEZca45gkdjxP8iLH7kh4pCkr+TCFIkmgEdfQ5DpavNBOOVO0qd5J5uV/tbtSnkYWSx8JkbFpg==", + "version": "20.5.0", + "resolved": "https://registry.npmjs.org/@swimlane/ngx-charts/-/ngx-charts-20.5.0.tgz", + "integrity": "sha512-PNBIHdu/R3ceD7jnw1uCBVOj4k3T6IxfdW6xsDsglGkZyoWMEEq4tLoEurjLEKzmDtRv9c35kVNOXy0lkOuXeA==", "dependencies": { "d3-array": "^3.1.1", "d3-brush": "^3.0.0", @@ -4262,6 +4262,7 @@ "d3-format": "^3.1.0", "d3-hierarchy": "^3.1.0", "d3-interpolate": "^3.0.1", + "d3-sankey": "^0.12.3", "d3-scale": "^4.0.2", "d3-selection": "^3.0.0", "d3-shape": "^3.2.0", @@ -7166,6 +7167,41 @@ "node": ">=12" } }, + "node_modules/d3-sankey": { + "version": "0.12.3", + "resolved": "https://registry.npmjs.org/d3-sankey/-/d3-sankey-0.12.3.tgz", + "integrity": "sha512-nQhsBRmM19Ax5xEIPLMY9ZmJ/cDvd1BG3UVvt5h3WRxKg5zGRbvnteTyWAbzeSvlh3tW7ZEmq4VwR5mB3tutmQ==", + "dependencies": { + "d3-array": "1 - 2", + "d3-shape": "^1.2.0" + } + }, + "node_modules/d3-sankey/node_modules/d3-array": { + "version": "2.12.1", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-2.12.1.tgz", + "integrity": "sha512-B0ErZK/66mHtEsR1TkPEEkwdy+WDesimkM5gpZr5Dsg54BiTA5RXtYW5qTLIAcekaS9xfZrzBLF/OAkB3Qn1YQ==", + "dependencies": { + "internmap": "^1.0.0" + } + }, + "node_modules/d3-sankey/node_modules/d3-path": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-1.0.9.tgz", + "integrity": "sha512-VLaYcn81dtHVTjEHd8B+pbe9yHWpXKZUC87PzoFmsFrJqgFwDe/qxfp5MlfsfM1V5E/iVt0MmEbWQ7FVIXh/bg==" + }, + "node_modules/d3-sankey/node_modules/d3-shape": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-1.3.7.tgz", + "integrity": "sha512-EUkvKjqPFUAZyOlhY5gzCxCeI0Aep04LwIRpsZ/mLFelJiUfnK56jo5JMDSE7yyP2kLSb6LtF+S5chMk7uqPqw==", + "dependencies": { + "d3-path": "1" + } + }, + "node_modules/d3-sankey/node_modules/internmap": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/internmap/-/internmap-1.0.1.tgz", + "integrity": "sha512-lDB5YccMydFBtasVtxnZ3MRBHuaoE8GKsppq+EchKL2U4nK/DmEpPHNH8MZe5HkMtpSiTSOZwfN0tzYjO/lJEw==" + }, "node_modules/d3-scale": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz", diff --git a/UI/Web/package.json b/UI/Web/package.json index a8459dd1ad..73d8598e83 100644 --- a/UI/Web/package.json +++ b/UI/Web/package.json @@ -13,16 +13,16 @@ }, "private": true, "dependencies": { - "@angular/animations": "^17.0.1", + "@angular/animations": "^17.0.2", "@angular/cdk": "^17.0.0", - "@angular/common": "^17.0.1", - "@angular/compiler": "^17.0.1", - "@angular/core": "^17.0.1", - "@angular/forms": "^17.0.1", - "@angular/localize": "^17.0.1", - "@angular/platform-browser": "^17.0.1", - "@angular/platform-browser-dynamic": "^17.0.1", - "@angular/router": "^17.0.1", + "@angular/common": "^17.0.2", + "@angular/compiler": "^17.0.2", + "@angular/core": "^17.0.2", + "@angular/forms": "^17.0.2", + "@angular/localize": "^17.0.2", + "@angular/platform-browser": "^17.0.2", + "@angular/platform-browser-dynamic": "^17.0.2", + "@angular/router": "^17.0.2", "@fortawesome/fontawesome-free": "^6.4.2", "@iharbeck/ngx-virtual-scroller": "^16.0.0", "@iplab/ngx-file-upload": "^16.0.2", @@ -34,7 +34,7 @@ "@ngneat/transloco-persist-translations": "^5.0.0", "@ngneat/transloco-preload-langs": "^5.0.0", "@popperjs/core": "^2.11.7", - "@swimlane/ngx-charts": "^20.1.2", + "@swimlane/ngx-charts": "^20.5.0", "@tweenjs/tween.js": "^21.0.0", "bootstrap": "^5.3.2", "charts.css": "^1.1.0", @@ -57,13 +57,13 @@ }, "devDependencies": { "@angular-devkit/build-angular": "^17.0.0", - "@angular-eslint/builder": "^17.0.0", + "@angular-eslint/builder": "^17.0.1", "@angular-eslint/eslint-plugin": "^17.0.0", "@angular-eslint/eslint-plugin-template": "^17.0.0", "@angular-eslint/schematics": "^17.0.1", "@angular-eslint/template-parser": "^17.0.1", "@angular/cli": "^17.0.0", - "@angular/compiler-cli": "^17.0.1", + "@angular/compiler-cli": "^17.0.2", "@types/d3": "^7.4.3", "@types/file-saver": "^2.0.7", "@types/luxon": "^3.3.4", diff --git a/UI/Web/src/app/_models/metadata/series-metadata.ts b/UI/Web/src/app/_models/metadata/series-metadata.ts index f32bf28380..27e0e1917b 100644 --- a/UI/Web/src/app/_models/metadata/series-metadata.ts +++ b/UI/Web/src/app/_models/metadata/series-metadata.ts @@ -34,18 +34,18 @@ export interface SeriesMetadata { summaryLocked: boolean; genresLocked: boolean; tagsLocked: boolean; - writersLocked: boolean; - coverArtistsLocked: boolean; - publishersLocked: boolean; - charactersLocked: boolean; - pencillersLocked: boolean; - inkersLocked: boolean; - coloristsLocked: boolean; - letterersLocked: boolean; - editorsLocked: boolean; - translatorsLocked: boolean; + writerLocked: boolean; + coverArtistLocked: boolean; + publisherLocked: boolean; + characterLocked: boolean; + pencillerLocked: boolean; + inkerLocked: boolean; + coloristLocked: boolean; + lettererLocked: boolean; + editorLocked: boolean; + translatorLocked: boolean; ageRatingLocked: boolean; releaseYearLocked: boolean; languageLocked: boolean; publicationStatusLocked: boolean; -} \ No newline at end of file +} diff --git a/UI/Web/src/app/_pipes/utc-to-local-time.pipe.ts b/UI/Web/src/app/_pipes/utc-to-local-time.pipe.ts index 784bf19a8d..a9be8e300b 100644 --- a/UI/Web/src/app/_pipes/utc-to-local-time.pipe.ts +++ b/UI/Web/src/app/_pipes/utc-to-local-time.pipe.ts @@ -23,7 +23,7 @@ export class UtcToLocalTimePipe implements PipeTransform { case 'short': return dateTime.toLocaleString(DateTime.DATETIME_SHORT); case 'shortDate': - return dateTime.toLocaleString(DateTime.DATE_MED); + return dateTime.toLocaleString(DateTime.DATE_SHORT); case 'shortTime': return dateTime.toLocaleString(DateTime.TIME_SIMPLE); case 'full': diff --git a/UI/Web/src/app/admin/_modals/directory-picker/directory-picker.component.html b/UI/Web/src/app/admin/_modals/directory-picker/directory-picker.component.html index 6cf59f9011..d4ec401e31 100644 --- a/UI/Web/src/app/admin/_modals/directory-picker/directory-picker.component.html +++ b/UI/Web/src/app/admin/_modals/directory-picker/directory-picker.component.html @@ -8,7 +8,7 @@
- diff --git a/UI/Web/src/app/admin/_modals/directory-picker/directory-picker.component.ts b/UI/Web/src/app/admin/_modals/directory-picker/directory-picker.component.ts index 6d3d28d21e..1584248db2 100644 --- a/UI/Web/src/app/admin/_modals/directory-picker/directory-picker.component.ts +++ b/UI/Web/src/app/admin/_modals/directory-picker/directory-picker.component.ts @@ -17,10 +17,10 @@ export interface DirectoryPickerResult { @Component({ - selector: 'app-directory-picker', - templateUrl: './directory-picker.component.html', - styleUrls: ['./directory-picker.component.scss'], - standalone: true, + selector: 'app-directory-picker', + templateUrl: './directory-picker.component.html', + styleUrls: ['./directory-picker.component.scss'], + standalone: true, imports: [ReactiveFormsModule, NgbTypeahead, FormsModule, NgbHighlight, NgIf, NgFor, NgClass, TranslocoDirective] }) export class DirectoryPickerComponent implements OnInit { @@ -37,7 +37,7 @@ export class DirectoryPickerComponent implements OnInit { path: string = ''; - @ViewChild('instance', {static: true}) instance!: NgbTypeahead; + @ViewChild('instance', {static: false}) instance!: NgbTypeahead; focus$ = new Subject(); click$ = new Subject(); searching: boolean = false; diff --git a/UI/Web/src/app/admin/dashboard/dashboard.component.html b/UI/Web/src/app/admin/dashboard/dashboard.component.html index 7523a76a42..0d52c86b06 100644 --- a/UI/Web/src/app/admin/dashboard/dashboard.component.html +++ b/UI/Web/src/app/admin/dashboard/dashboard.component.html @@ -24,9 +24,6 @@

- - - diff --git a/UI/Web/src/app/admin/dashboard/dashboard.component.ts b/UI/Web/src/app/admin/dashboard/dashboard.component.ts index 350d3d184a..7ffca3d090 100644 --- a/UI/Web/src/app/admin/dashboard/dashboard.component.ts +++ b/UI/Web/src/app/admin/dashboard/dashboard.component.ts @@ -38,7 +38,10 @@ enum TabID { templateUrl: './dashboard.component.html', styleUrls: ['./dashboard.component.scss'], standalone: true, - imports: [SideNavCompanionBarComponent, NgbNav, NgFor, NgbNavItem, NgbNavItemRole, NgbNavLink, RouterLink, NgbNavContent, NgIf, ManageSettingsComponent, ManageEmailSettingsComponent, ManageMediaSettingsComponent, ManageUsersComponent, ManageLibraryComponent, ManageLogsComponent, ManageSystemComponent, ServerStatsComponent, ManageTasksSettingsComponent, LicenseComponent, NgbNavOutlet, SentenceCasePipe, TranslocoDirective], + imports: [SideNavCompanionBarComponent, NgbNav, NgFor, NgbNavItem, NgbNavItemRole, NgbNavLink, RouterLink, + NgbNavContent, NgIf, ManageSettingsComponent, ManageEmailSettingsComponent, ManageMediaSettingsComponent, + ManageUsersComponent, ManageLibraryComponent, ManageSystemComponent, ServerStatsComponent, + ManageTasksSettingsComponent, LicenseComponent, NgbNavOutlet, SentenceCasePipe, TranslocoDirective], changeDetection: ChangeDetectionStrategy.OnPush }) export class DashboardComponent implements OnInit { @@ -47,7 +50,6 @@ export class DashboardComponent implements OnInit { {title: 'general-tab', fragment: TabID.General}, {title: 'users-tab', fragment: TabID.Users}, {title: 'libraries-tab', fragment: TabID.Libraries}, - //{title: 'logs-tab', fragment: TabID.Logs}, {title: 'media-tab', fragment: TabID.Media}, {title: 'email-tab', fragment: TabID.Email}, {title: 'tasks-tab', fragment: TabID.Tasks}, diff --git a/UI/Web/src/app/all-series/_components/all-series/all-series.component.ts b/UI/Web/src/app/all-series/_components/all-series/all-series.component.ts index 5b7fea7793..be68010f91 100644 --- a/UI/Web/src/app/all-series/_components/all-series/all-series.component.ts +++ b/UI/Web/src/app/all-series/_components/all-series/all-series.component.ts @@ -44,7 +44,7 @@ import {SeriesFilterV2} from "../../../_models/metadata/v2/series-filter-v2"; }) export class AllSeriesComponent implements OnInit { - title!: string; + title: string = translate('side-nav.all-series'); series: Series[] = []; loadingSeries = false; pagination: Pagination = new Pagination(); @@ -115,10 +115,8 @@ export class AllSeriesComponent implements OnInit { this.filterUtilityService.filterPresetsFromUrl(this.route.snapshot).subscribe(filter => { this.filter = filter; - this.title = this.route.snapshot.queryParamMap.get('title') || this.filter.name || this.title; this.titleService.setTitle('Kavita - ' + this.title); - this.filterActiveCheck = this.filterUtilityService.createSeriesV2Filter(); this.filterActiveCheck!.statements.push(this.filterUtilityService.createSeriesV2DefaultStatement()); this.filterSettings.presetsV2 = this.filter; @@ -128,7 +126,6 @@ export class AllSeriesComponent implements OnInit { } ngOnInit(): void { - this.title = translate('all-series.title'); this.hubService.messages$.pipe(debounceTime(6000), takeUntilDestroyed(this.destroyRef)).subscribe((event: Message) => { if (event.event !== EVENTS.SeriesAdded) return; this.loadPage(); diff --git a/UI/Web/src/app/app-routing.module.ts b/UI/Web/src/app/app-routing.module.ts index ea85a1c742..debbc3d123 100644 --- a/UI/Web/src/app/app-routing.module.ts +++ b/UI/Web/src/app/app-routing.module.ts @@ -81,6 +81,7 @@ const routes: Routes = [ }, ] }, + {path: '', pathMatch: 'full', redirectTo: 'home'}, ] }, { @@ -91,9 +92,10 @@ const routes: Routes = [ path: 'login', loadChildren: () => import('./_routes/registration.router.module').then(m => m.routes) // TODO: Refactor so we just use /registration/login going forward }, - {path: '**', pathMatch: 'full', redirectTo: 'home'}, {path: 'libraries', pathMatch: 'full', redirectTo: 'home'}, {path: '**', pathMatch: 'prefix', redirectTo: 'home'}, + {path: '**', pathMatch: 'full', redirectTo: 'home'}, + {path: '', pathMatch: 'full', redirectTo: 'home'}, ]; @NgModule({ diff --git a/UI/Web/src/app/book-reader/_components/book-reader/book-reader.component.ts b/UI/Web/src/app/book-reader/_components/book-reader/book-reader.component.ts index a4f80e4a69..bcf50bb26c 100644 --- a/UI/Web/src/app/book-reader/_components/book-reader/book-reader.component.ts +++ b/UI/Web/src/app/book-reader/_components/book-reader/book-reader.component.ts @@ -1617,9 +1617,7 @@ export class BookReaderComponent implements OnInit, AfterViewInit, OnDestroy { // Responsible for handling pagination only handleContainerClick(event: MouseEvent) { - console.log('target: ', event.target); - if (this.actionBarVisible || ['action-bar'].some(className => (event.target as Element).classList.contains(className))) { - //console.log('exiting early') + if (this.drawerOpen || ['action-bar'].some(className => (event.target as Element).classList.contains(className))) { return; } diff --git a/UI/Web/src/app/cards/_modals/edit-series-modal/edit-series-modal.component.html b/UI/Web/src/app/cards/_modals/edit-series-modal/edit-series-modal.component.html index 1b11959465..576fe69485 100644 --- a/UI/Web/src/app/cards/_modals/edit-series-modal/edit-series-modal.component.html +++ b/UI/Web/src/app/cards/_modals/edit-series-modal/edit-series-modal.component.html @@ -187,8 +187,8 @@