From d286d531ad0597b17511d1c67be761e999ed11fd Mon Sep 17 00:00:00 2001 From: Joe Milazzo Date: Thu, 19 Oct 2023 20:00:33 -0500 Subject: [PATCH] Release Polish 2 (#2332) --- API.Tests/Helpers/OrderableHelperTests.cs | 112 ++++++++++++++++++ API/Helpers/OrderableHelper.cs | 2 +- API/Services/StreamService.cs | 3 +- .../metadata-filter-row.component.ts | 17 ++- .../draggable-ordered-list.component.ts | 13 +- .../reading-list-detail.component.ts | 7 +- .../customize-dashboard-modal.component.scss | 1 - openapi.json | 2 +- 8 files changed, 134 insertions(+), 23 deletions(-) create mode 100644 API.Tests/Helpers/OrderableHelperTests.cs diff --git a/API.Tests/Helpers/OrderableHelperTests.cs b/API.Tests/Helpers/OrderableHelperTests.cs new file mode 100644 index 000000000..a6d741be1 --- /dev/null +++ b/API.Tests/Helpers/OrderableHelperTests.cs @@ -0,0 +1,112 @@ +using System.Collections.Generic; +using System.Linq; +using API.Entities; +using API.Helpers; +using Xunit; + +namespace API.Tests.Helpers; + +public class OrderableHelperTests +{ + [Fact] + public void ReorderItems_ItemExists_SuccessfullyReorders() + { + // Arrange + var items = new List + { + new AppUserSideNavStream { Id = 1, Order = 0, Name = "A" }, + new AppUserSideNavStream { Id = 2, Order = 1, Name = "A" }, + new AppUserSideNavStream { Id = 3, Order = 2, Name = "A" }, + }; + + // Act + OrderableHelper.ReorderItems(items, 2, 0); + + // Assert + Assert.Equal(2, items[0].Id); // Item 2 should be at position 0 + Assert.Equal(1, items[1].Id); // Item 1 should be at position 1 + Assert.Equal(3, items[2].Id); // Item 3 should remain at position 2 + } + + [Fact] + public void ReorderItems_ItemNotFound_NoChange() + { + // Arrange + var items = new List + { + new AppUserSideNavStream { Id = 1, Order = 0, Name = "A" }, + new AppUserSideNavStream { Id = 2, Order = 1, Name = "A" }, + }; + + // Act + OrderableHelper.ReorderItems(items, 3, 0); // Item with Id 3 doesn't exist + + // Assert + Assert.Equal(1, items[0].Id); // Item 1 should remain at position 0 + Assert.Equal(2, items[1].Id); // Item 2 should remain at position 1 + } + + [Fact] + public void ReorderItems_InvalidPosition_NoChange() + { + // Arrange + var items = new List + { + new AppUserSideNavStream { Id = 1, Order = 0, Name = "A" }, + new AppUserSideNavStream { Id = 2, Order = 1, Name = "A" }, + }; + + // Act + OrderableHelper.ReorderItems(items, 2, 3); // Position 3 is out of range + + // Assert + Assert.Equal(1, items[0].Id); // Item 1 should remain at position 0 + Assert.Equal(2, items[1].Id); // Item 2 should remain at position 1 + } + + [Fact] + public void ReorderItems_EmptyList_NoChange() + { + // Arrange + var items = new List(); + + // Act + OrderableHelper.ReorderItems(items, 2, 1); // List is empty + + // Assert + Assert.Empty(items); // The list should remain empty + } + + [Fact] + public void ReorderItems_DoubleMove() + { + // Arrange + var items = new List + { + new AppUserSideNavStream { Id = 1, Order = 0, Name = "0" }, + new AppUserSideNavStream { Id = 2, Order = 1, Name = "1" }, + new AppUserSideNavStream { Id = 3, Order = 2, Name = "2" }, + new AppUserSideNavStream { Id = 4, Order = 3, Name = "3" }, + new AppUserSideNavStream { Id = 5, Order = 4, Name = "4" }, + new AppUserSideNavStream { Id = 6, Order = 5, Name = "5" }, + }; + + // Move 4 -> 1 + OrderableHelper.ReorderItems(items, 5, 1); + + // Assert + Assert.Equal(1, items[0].Id); + Assert.Equal(0, items[0].Order); + Assert.Equal(5, items[1].Id); + Assert.Equal(1, items[1].Order); + Assert.Equal(2, items[2].Id); + Assert.Equal(2, items[2].Order); + + // Ensure the items are in the correct order + Assert.Equal("041235", string.Join("", items.Select(s => s.Name))); + + OrderableHelper.ReorderItems(items, items[4].Id, 1); // 3 -> 1 + + Assert.Equal("034125", string.Join("", items.Select(s => s.Name))); + } +} diff --git a/API/Helpers/OrderableHelper.cs b/API/Helpers/OrderableHelper.cs index f45a7abc0..06a53f575 100644 --- a/API/Helpers/OrderableHelper.cs +++ b/API/Helpers/OrderableHelper.cs @@ -23,7 +23,7 @@ public static class OrderableHelper public static void ReorderItems(List items, int itemId, int toPosition) { var item = items.Find(r => r.Id == itemId); - if (item != null) + if (item != null && toPosition < items.Count) { items.Remove(item); items.Insert(toPosition, item); diff --git a/API/Services/StreamService.cs b/API/Services/StreamService.cs index 1609ffa89..faab07f80 100644 --- a/API/Services/StreamService.cs +++ b/API/Services/StreamService.cs @@ -247,6 +247,7 @@ public class StreamService : IStreamService var stream = await _unitOfWork.UserRepository.GetSideNavStream(dto.Id); if (stream == null) throw new KavitaException(await _localizationService.Translate(userId, "sidenav-stream-doesnt-exist")); + stream.Visible = dto.Visible; _unitOfWork.UserRepository.Update(stream); @@ -266,8 +267,8 @@ public class StreamService : IStreamService var list = user!.SideNavStreams.ToList(); OrderableHelper.ReorderItems(list, stream.Id, dto.ToPosition); user.SideNavStreams = list; - _unitOfWork.UserRepository.Update(user); + _unitOfWork.UserRepository.Update(user); await _unitOfWork.CommitAsync(); if (!stream.Visible) return; await _eventHub.SendMessageToAsync(MessageFactory.SideNavUpdate, MessageFactory.SideNavUpdateEvent(userId), diff --git a/UI/Web/src/app/metadata-filter/_components/metadata-filter-row/metadata-filter-row.component.ts b/UI/Web/src/app/metadata-filter/_components/metadata-filter-row/metadata-filter-row.component.ts index 5261f9349..d16fb1aca 100644 --- a/UI/Web/src/app/metadata-filter/_components/metadata-filter-row/metadata-filter-row.component.ts +++ b/UI/Web/src/app/metadata-filter/_components/metadata-filter-row/metadata-filter-row.component.ts @@ -7,7 +7,7 @@ import { inject, Input, OnInit, - Output, ViewChild, + Output, } from '@angular/core'; import {FormControl, FormGroup, ReactiveFormsModule} from '@angular/forms'; import {FilterStatement} from '../../../_models/metadata/v2/filter-statement'; @@ -29,7 +29,6 @@ import { NgbDate, NgbDateParserFormatter, NgbDatepicker, - NgbDateStruct, NgbInputDatepicker, NgbTooltip } from "@ng-bootstrap/ng-bootstrap"; @@ -79,20 +78,26 @@ const NumberFieldsThatIncludeDateComparisons = [ FilterField.ReleaseYear ]; -const StringComparisons = [FilterComparison.Equal, +const StringComparisons = [ + FilterComparison.Equal, FilterComparison.NotEqual, FilterComparison.BeginsWith, FilterComparison.EndsWith, FilterComparison.Matches]; -const DateComparisons = [FilterComparison.IsBefore, FilterComparison.IsAfter, FilterComparison.Equal, +const DateComparisons = [ + FilterComparison.IsBefore, + FilterComparison.IsAfter, + FilterComparison.Equal, FilterComparison.NotEqual,]; -const NumberComparisons = [FilterComparison.Equal, +const NumberComparisons = [ + FilterComparison.Equal, FilterComparison.NotEqual, FilterComparison.LessThan, FilterComparison.LessThanEqual, FilterComparison.GreaterThan, FilterComparison.GreaterThanEqual]; -const DropdownComparisons = [FilterComparison.Equal, +const DropdownComparisons = [ + FilterComparison.Equal, FilterComparison.NotEqual, FilterComparison.Contains, FilterComparison.NotContains, diff --git a/UI/Web/src/app/reading-list/_components/draggable-ordered-list/draggable-ordered-list.component.ts b/UI/Web/src/app/reading-list/_components/draggable-ordered-list/draggable-ordered-list.component.ts index 10b1b9d94..83b9e72d9 100644 --- a/UI/Web/src/app/reading-list/_components/draggable-ordered-list/draggable-ordered-list.component.ts +++ b/UI/Web/src/app/reading-list/_components/draggable-ordered-list/draggable-ordered-list.component.ts @@ -81,9 +81,6 @@ export class DraggableOrderedListComponent { return Math.min(this.items.length / 20, 20); } - log(a: any, b: any) {console.log('item: ', a, 'index', b)} - - constructor(private readonly cdRef: ChangeDetectorRef) { this.bulkSelectionService.selections$.pipe( takeUntilDestroyed(this.destroyRef) @@ -108,12 +105,12 @@ export class DraggableOrderedListComponent { // get the new value of the input const inputElem = document.querySelector('#reorder-' + previousIndex); const newIndex = parseInt(inputElem.value, 10); - if (previousIndex === newIndex) return; - moveItemInArray(this.items, previousIndex, newIndex); + if (item.order === newIndex) return; + moveItemInArray(this.items, item.order, newIndex); this.orderUpdated.emit({ - fromPosition: previousIndex, + fromPosition: item.order, toPosition: newIndex, - item: this.items[newIndex], + item: item, fromAccessibilityMode: true }); this.cdRef.markForCheck(); @@ -121,7 +118,7 @@ export class DraggableOrderedListComponent { removeItem(item: any, position: number) { this.itemRemove.emit({ - position, + position: item!.order, item }); this.cdRef.markForCheck(); diff --git a/UI/Web/src/app/reading-list/_components/reading-list-detail/reading-list-detail.component.ts b/UI/Web/src/app/reading-list/_components/reading-list-detail/reading-list-detail.component.ts index d63674a8b..1997bd102 100644 --- a/UI/Web/src/app/reading-list/_components/reading-list-detail/reading-list-detail.component.ts +++ b/UI/Web/src/app/reading-list/_components/reading-list-detail/reading-list-detail.component.ts @@ -67,17 +67,13 @@ export class ReadingListDetailComponent implements OnInit { characters$!: Observable; private translocoService = inject(TranslocoService); - - get MangaFormat(): typeof MangaFormat { - return MangaFormat; - } + protected readonly MangaFormat = MangaFormat; constructor(private route: ActivatedRoute, private router: Router, private readingListService: ReadingListService, private actionService: ActionService, private actionFactoryService: ActionFactoryService, public utilityService: UtilityService, public imageService: ImageService, private accountService: AccountService, private toastr: ToastrService, private confirmService: ConfirmService, private libraryService: LibraryService, private readerService: ReaderService, private readonly cdRef: ChangeDetectorRef, private filterUtilityService: FilterUtilitiesService, private titleService: Title) { - this.titleService.setTitle('Kavita - ' + translate('side-nav.reading-lists')); } ngOnInit(): void { @@ -87,6 +83,7 @@ export class ReadingListDetailComponent implements OnInit { this.router.navigateByUrl('/libraries'); return; } + this.titleService.setTitle('Kavita - ' + translate('side-nav.reading-lists')); this.listId = parseInt(listId, 10); this.characters$ = this.readingListService.getCharacters(this.listId); diff --git a/UI/Web/src/app/sidenav/_components/customize-dashboard-modal/customize-dashboard-modal.component.scss b/UI/Web/src/app/sidenav/_components/customize-dashboard-modal/customize-dashboard-modal.component.scss index 158863aa7..384ca5114 100644 --- a/UI/Web/src/app/sidenav/_components/customize-dashboard-modal/customize-dashboard-modal.component.scss +++ b/UI/Web/src/app/sidenav/_components/customize-dashboard-modal/customize-dashboard-modal.component.scss @@ -1,6 +1,5 @@ .modal-body { overflow: hidden; - padding: 1rem 0 1rem 1rem; .tab-content { max-height: calc(var(--vh) * 100 - 235px); diff --git a/openapi.json b/openapi.json index cbeffc9d1..d0d191837 100644 --- a/openapi.json +++ b/openapi.json @@ -7,7 +7,7 @@ "name": "GPL-3.0", "url": "https://github.com/Kareadita/Kavita/blob/develop/LICENSE" }, - "version": "0.7.8.13" + "version": "0.7.8.14" }, "servers": [ {