Release Shakeout 4 (#1600)

* Fixed a bug where bulk selection on series detail wouldn't allow you to select the whole card, only the checkbox.

* Refactored the implementation of MarkChaptersAsRead to streamline it.

* Fixed a bug where volume cards weren't properly updating their read state based on events from backend.

* Added [ScannerService] to more loggers

* Fixed invite user flow

* Fixed broken edit user flow

* Fixed calling device service on unauthenticated screens causing redirection

* Fixed reset password via email not working when success message was sent back

* Fixed broken white theme on book reader

* Small tweaks to white theme

* More fixes

* Adjusted AutomaticRetries

* When an auth change occures, reset the devices in service so devices don't leak between profiles

* Fixed a bug where sendTo for series wasn't properly taking into account specials (on series detail page)

* Drop down how long series detail caches for to prevent signalr updates from refreshing the UI

* Close submenus when hovering over other items, not just other submenus

* Fixed a bug where scanning for themes would always report theme didn't exist

* Added Hangfire.db back in

* Fixed a bad build
This commit is contained in:
Joe Milazzo 2022-10-21 17:21:43 -07:00 committed by GitHub
parent 8afa7d4868
commit 3659bf8a7c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 19 additions and 11 deletions

View File

@ -383,7 +383,7 @@ public class SeriesController : BaseApiController
/// <param name="seriesId"></param> /// <param name="seriesId"></param>
/// <returns></returns> /// <returns></returns>
/// <remarks>Do not rely on this API externally. May change without hesitation. </remarks> /// <remarks>Do not rely on this API externally. May change without hesitation. </remarks>
[ResponseCache(CacheProfileName = "Hour", VaryByQueryKeys = new [] {"seriesId"})] [ResponseCache(CacheProfileName = "5Minute", VaryByQueryKeys = new [] {"seriesId"})]
[HttpGet("series-detail")] [HttpGet("series-detail")]
public async Task<ActionResult<SeriesDetailDto>> GetSeriesDetailBreakdown(int seriesId) public async Task<ActionResult<SeriesDetailDto>> GetSeriesDetailBreakdown(int seriesId)
{ {

View File

@ -7,13 +7,11 @@ using API.Services.Tasks.Metadata;
using API.Services.Tasks.Scanner; using API.Services.Tasks.Scanner;
using API.SignalR; using API.SignalR;
using API.SignalR.Presence; using API.SignalR.Presence;
using Kavita.Common;
using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Hosting;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
namespace API.Extensions; namespace API.Extensions;

View File

@ -9,7 +9,6 @@ using API.Data;
using API.Data.Repositories; using API.Data.Repositories;
using API.Entities; using API.Entities;
using API.Entities.Enums; using API.Entities.Enums;
using API.Extensions;
using API.Helpers; using API.Helpers;
using API.Parser; using API.Parser;
using API.Services.Tasks.Metadata; using API.Services.Tasks.Metadata;

View File

@ -17,6 +17,7 @@ using API.Services.Tasks;
using API.SignalR; using API.SignalR;
using Hangfire; using Hangfire;
using Hangfire.MemoryStorage; using Hangfire.MemoryStorage;
using Hangfire.Storage.SQLite;
using Kavita.Common; using Kavita.Common;
using Kavita.Common.EnvironmentInfo; using Kavita.Common.EnvironmentInfo;
using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Builder;
@ -176,7 +177,7 @@ public class Startup
services.AddHangfire(configuration => configuration services.AddHangfire(configuration => configuration
.UseSimpleAssemblyNameTypeSerializer() .UseSimpleAssemblyNameTypeSerializer()
.UseRecommendedSerializerSettings() .UseRecommendedSerializerSettings()
.UseMemoryStorage()); // UseSQLiteStorage - SQLite has some issues around resuming jobs when aborted .UseSQLiteStorage("config/Hangfire.db")); // UseSQLiteStorage - SQLite has some issues around resuming jobs when aborted
// Add the processing server as IHostedService // Add the processing server as IHostedService
services.AddHangfireServer(options => services.AddHangfireServer(options =>

View File

@ -1,6 +1,6 @@
import { HttpClient } from '@angular/common/http'; import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { ReplaySubject, shareReplay, take, tap } from 'rxjs'; import { ReplaySubject, shareReplay, tap } from 'rxjs';
import { environment } from 'src/environments/environment'; import { environment } from 'src/environments/environment';
import { Device } from '../_models/device/device'; import { Device } from '../_models/device/device';
import { DevicePlatform } from '../_models/device/device-platform'; import { DevicePlatform } from '../_models/device/device-platform';
@ -19,8 +19,11 @@ export class DeviceService {
constructor(private httpClient: HttpClient, private accountService: AccountService) { constructor(private httpClient: HttpClient, private accountService: AccountService) {
// Ensure we are authenticated before we make an authenticated api call. // Ensure we are authenticated before we make an authenticated api call.
this.accountService.currentUser$.pipe(take(1)).subscribe(user => { this.accountService.currentUser$.subscribe(user => {
if (!user) return; if (!user) {
this.devicesSource.next([]);
return;
}
this.httpClient.get<Device[]>(this.baseUrl + 'device', {}).subscribe(data => { this.httpClient.get<Device[]>(this.baseUrl + 'device', {}).subscribe(data => {
this.devicesSource.next(data); this.devicesSource.next(data);

View File

@ -78,7 +78,7 @@ export class ThemeService implements OnDestroy {
this.themeCache = themes; this.themeCache = themes;
this.themesSource.next(themes); this.themesSource.next(themes);
this.currentTheme$.pipe(take(1)).subscribe(theme => { this.currentTheme$.pipe(take(1)).subscribe(theme => {
if (!themes.includes(theme)) { if (themes.filter(t => t.id === theme.id).length === 0) {
this.setTheme(this.defaultTheme); this.setTheme(this.defaultTheme);
this.toastr.info('The active theme no longer exists. Please refresh the page.'); this.toastr.info('The active theme no longer exists. Please refresh the page.');
} }

View File

@ -18,7 +18,7 @@
</ng-container> </ng-container>
<ng-template #justItem> <ng-template #justItem>
<button ngbDropdownItem *ngIf="willRenderAction(action)" (click)="performAction($event, action)">{{action.title}}</button> <button ngbDropdownItem *ngIf="willRenderAction(action)" (click)="performAction($event, action)" (mouseover)="closeAllSubmenus()">{{action.title}}</button>
</ng-template> </ng-template>
</ng-container> </ng-container>
<ng-template #submenuDropdown> <ng-template #submenuDropdown>

View File

@ -77,6 +77,13 @@ export class CardActionablesComponent implements OnInit {
subMenu.open(); subMenu.open();
} }
closeAllSubmenus() {
Object.keys(this.submenu).forEach(key => {
this.submenu[key].close();
delete this.submenu[key];
});
}
performDynamicClick(event: any, action: ActionItem<any>, dynamicItem: any) { performDynamicClick(event: any, action: ActionItem<any>, dynamicItem: any) {
action._extra = dynamicItem; action._extra = dynamicItem;
this.performAction(event, action); this.performAction(event, action);

View File

@ -368,7 +368,7 @@ export class SeriesDetailComponent implements OnInit, OnDestroy, AfterContentChe
break; break;
case Action.SendTo: case Action.SendTo:
{ {
const chapterIds = this.volumes.map(v => v.chapters.map(c => c.id)).flat() const chapterIds = [...this.volumes.map(v => v.chapters.map(c => c.id)).flat(), ...this.specials.map(c => c.id)]
const device = (action._extra!.data as Device); const device = (action._extra!.data as Device);
this.actionService.sendToDevice(chapterIds, device); this.actionService.sendToDevice(chapterIds, device);
break; break;