+ } @else if (volume.chapters[0].titleName) {
+
+
+ {{volume.chapters[0].titleName}}
+
+
+ }
}
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 3a3087632..22405364f 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
@@ -82,7 +82,7 @@ export class DraggableOrderedListComponent {
get BufferAmount() {
- return Math.min(this.items.length / 20, 20);
+ return Math.floor(Math.min(this.items.length / 20, 20));
}
constructor() {
diff --git a/UI/Web/src/app/series-detail/_components/series-detail/series-detail.component.ts b/UI/Web/src/app/series-detail/_components/series-detail/series-detail.component.ts
index 890237be4..68d2ac4dd 100644
--- a/UI/Web/src/app/series-detail/_components/series-detail/series-detail.component.ts
+++ b/UI/Web/src/app/series-detail/_components/series-detail/series-detail.component.ts
@@ -115,6 +115,7 @@ import {CoverImageComponent} from "../../../_single-module/cover-image/cover-ima
import {DefaultModalOptions} from "../../../_models/default-modal-options";
import {LicenseService} from "../../../_services/license.service";
import {PageBookmark} from "../../../_models/readers/page-bookmark";
+import {VolumeRemovedEvent} from "../../../_models/events/volume-removed-event";
enum TabID {
@@ -353,11 +354,25 @@ export class SeriesDetailComponent implements OnInit, AfterContentChecked {
this.cdRef.markForCheck();
break;
case Action.Delete:
- await this.actionService.deleteMultipleChapters(seriesId, chapters, () => {
- // No need to update the page as the backend will spam volume/chapter deletions
- this.bulkSelectionService.deselectAll();
- this.cdRef.markForCheck();
- });
+ if (chapters.length > 0) {
+ await this.actionService.deleteMultipleChapters(seriesId, chapters, () => {
+ // No need to update the page as the backend will spam volume/chapter deletions
+ this.bulkSelectionService.deselectAll();
+ this.cdRef.markForCheck();
+ });
+
+ // It's not possible to select both chapters and volumes
+ break;
+ }
+
+ if (selectedVolumeIds.length > 0) {
+ await this.actionService.deleteMultipleVolumes(selectedVolumeIds, () => {
+ // No need to update the page as the backend will spam volume deletions
+ this.bulkSelectionService.deselectAll();
+ this.cdRef.markForCheck();
+ });
+ }
+
break;
}
}
@@ -486,6 +501,11 @@ export class SeriesDetailComponent implements OnInit, AfterContentChecked {
const removedEvent = event.payload as ChapterRemovedEvent;
if (removedEvent.seriesId !== this.seriesId) return;
this.loadPageSource.next(false);
+ } else if (event.event === EVENTS.VolumeRemoved) {
+ const volumeRemoveEvent = event.payload as VolumeRemovedEvent;
+ if (volumeRemoveEvent.seriesId === this.seriesId) {
+ this.loadPageSource.next(false);
+ }
}
});
@@ -660,7 +680,7 @@ export class SeriesDetailComponent implements OnInit, AfterContentChecked {
case (Action.Delete):
await this.actionService.deleteChapter(chapter.id, (success) => {
if (!success) return;
-
+
this.chapters = this.chapters.filter(c => c.id != chapter.id);
this.cdRef.markForCheck();
});
diff --git a/UI/Web/src/assets/langs/en.json b/UI/Web/src/assets/langs/en.json
index 2b9d6644a..4d22e44bb 100644
--- a/UI/Web/src/assets/langs/en.json
+++ b/UI/Web/src/assets/langs/en.json
@@ -2640,6 +2640,7 @@
"alert-long-running": "This is a long running process. Please give it the time to complete before invoking again.",
"confirm-delete-multiple-series": "Are you sure you want to delete {{count}} series? It will not modify files on disk.",
"confirm-delete-multiple-chapters": "Are you sure you want to delete {{count}} chapter/volumes? It will not modify files on disk.",
+ "confirm-delete-multiple-volumes": "Are you sure you want to delete {{count}} volumes? It will not modify files on disk.",
"confirm-delete-series": "Are you sure you want to delete this series? It will not modify files on disk.",
"confirm-delete-chapter": "Are you sure you want to delete this chapter? It will not modify files on disk.",
"confirm-delete-volume": "Are you sure you want to delete this volume? It will not modify files on disk.",
diff --git a/UI/Web/src/assets/langs/fi.json b/UI/Web/src/assets/langs/fi.json
index edcd8166f..9a316f77a 100644
--- a/UI/Web/src/assets/langs/fi.json
+++ b/UI/Web/src/assets/langs/fi.json
@@ -10,7 +10,7 @@
"devices-tab": "{{tabs.devices-tab}}",
"smart-filters-tab": "{{tabs.smart-filters-tab}}",
"success-toast": "Käyttäjäasetukset päivitetty",
- "global-settings-title": "Laajamittaiset asetukset",
+ "global-settings-title": "Yleisesti pätevät asetukset",
"page-layout-mode-label": "Sivun asettelutila",
"page-layout-mode-tooltip": "Näytä kohteet kortteina tai luettelonäkymänä Sarjojen yksityiskohdat -sivulla.",
"locale-label": "Kieliasetus",
diff --git a/UI/Web/src/assets/langs/zh_Hans.json b/UI/Web/src/assets/langs/zh_Hans.json
index d3a8496e0..a81869f69 100644
--- a/UI/Web/src/assets/langs/zh_Hans.json
+++ b/UI/Web/src/assets/langs/zh_Hans.json
@@ -2219,12 +2219,12 @@
"delete-device": "您确定要删除该设备吗?",
"confirm-regen-covers": "刷新封面将强制重新生成所有封面图片。这是一项繁重的运算。您确定执行,而不想使用扫描操作代替吗?",
"alert-long-running": "这是一个长时间运行的任务。请等待其完成后再次进行操作。",
- "confirm-delete-multiple-series": "您确定要删除{{count}}个系列吗?这不会修改磁盘上的文件。",
+ "confirm-delete-multiple-series": "您确定要删除这 {{count}} 个系列吗?这不会修改磁盘上的文件。",
"confirm-delete-series": "您确定要删除此系列吗?这不会修改磁盘上的文件。",
"confirm-delete-chapter": "您确定要删除此章节吗?它不会修改磁盘上的文件。",
"confirm-delete-volume": "您确定要删除此卷吗?它不会修改磁盘上的文件。",
"alert-bad-theme": "主题中存在无效或不安全的CSS。请联系管理员进行修正。将默认为暗色主题。",
- "confirm-library-delete": "您确定要删除{{name}}资料库吗?此操作无法撤销。",
+ "confirm-library-delete": "您确定要删除 {{name}} 资料库吗?此操作无法撤销。",
"confirm-library-type-change": "更改资料库类型将触发具有不同解析规则的新扫描,并可能导致重新创建系列,因此您可能会丢失进度和书签。您应该在执行此操作之前进行备份。您确定要继续吗?",
"confirm-download-size": "{{entityType}}的大小为{{size}}。确定要继续吗?",
"confirm-download-size-ios": "iOS 在下载大于 200MB 的文件时出现问题,此下载可能无法完成。",
diff --git a/openapi.json b/openapi.json
index db02f4511..e71ecfd55 100644
--- a/openapi.json
+++ b/openapi.json
@@ -1,8 +1,8 @@
{
"openapi": "3.0.4",
"info": {
- "title": "Kavita (v0.8.6.0)",
- "description": "Kavita provides a set of APIs that are authenticated by JWT. JWT token can be copied from local storage. Assume all fields of a payload are required. Built against v0.8.6.0",
+ "title": "Kavita (v0.8.6.1)",
+ "description": "Kavita provides a set of APIs that are authenticated by JWT. JWT token can be copied from local storage. Assume all fields of a payload are required. Built against v0.8.6.1",
"license": {
"name": "GPL-3.0",
"url": "https://github.com/Kareadita/Kavita/blob/develop/LICENSE"
@@ -14508,6 +14508,66 @@
}
}
},
+ "/api/Volume/multiple": {
+ "post": {
+ "tags": [
+ "Volume"
+ ],
+ "requestBody": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "array",
+ "items": {
+ "type": "integer",
+ "format": "int32"
+ }
+ }
+ },
+ "text/json": {
+ "schema": {
+ "type": "array",
+ "items": {
+ "type": "integer",
+ "format": "int32"
+ }
+ }
+ },
+ "application/*+json": {
+ "schema": {
+ "type": "array",
+ "items": {
+ "type": "integer",
+ "format": "int32"
+ }
+ }
+ }
+ }
+ },
+ "responses": {
+ "200": {
+ "description": "OK",
+ "content": {
+ "text/plain": {
+ "schema": {
+ "type": "boolean"
+ }
+ },
+ "application/json": {
+ "schema": {
+ "type": "boolean"
+ }
+ },
+ "text/json": {
+ "schema": {
+ "type": "boolean"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
"/api/want-to-read": {
"post": {
"tags": [