feat(api,web): modélisation série + volume et parcours de série
- Table series + colonnes seriesId/volumeNumber/volumeLabel sur les livres, extraction souple des numéros (T03, 003, etc.) via extract-series-volume - Contrôleur et page de série, badge volume sur les cartes de livre, styles associés (fond/clarté série, ajustements globaux) - Statuts de scan/enrichissement et provenance des métadonnées en base Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@ -3,6 +3,25 @@ import type { ContinueItem } from "./types";
|
||||
|
||||
const now = new Date().toISOString();
|
||||
|
||||
type BookPipelineStatus = "idle" | "running" | "succeeded" | "failed";
|
||||
type BookMetadataStatus = "enriched" | "partial" | "none";
|
||||
type MockBookDto = Omit<BookDto, "metadataStatus" | "metadataProvenance" | "scanStatus" | "enrichmentStatus"> & {
|
||||
metadataStatus?: BookMetadataStatus;
|
||||
metadataProvenance?: Record<string, string>;
|
||||
scanStatus?: BookPipelineStatus;
|
||||
enrichmentStatus?: BookPipelineStatus;
|
||||
};
|
||||
|
||||
function mockBook(book: MockBookDto): BookDto {
|
||||
return {
|
||||
metadataStatus: "partial",
|
||||
metadataProvenance: { local: "fixture" },
|
||||
scanStatus: "idle",
|
||||
enrichmentStatus: "idle",
|
||||
...book
|
||||
} as BookDto;
|
||||
}
|
||||
|
||||
export const mockUser: UserDto = {
|
||||
id: 1,
|
||||
email: "admin@readabook.local",
|
||||
@ -17,7 +36,7 @@ export const mockLibraries: LibraryDto[] = [
|
||||
];
|
||||
|
||||
export const mockBooks: BookDto[] = [
|
||||
{
|
||||
mockBook({
|
||||
id: 1,
|
||||
libraryId: 1,
|
||||
title: "L'Herbier des machines",
|
||||
@ -35,8 +54,8 @@ export const mockBooks: BookDto[] = [
|
||||
fileMtime: now,
|
||||
createdAt: now,
|
||||
updatedAt: now
|
||||
},
|
||||
{
|
||||
}),
|
||||
mockBook({
|
||||
id: 2,
|
||||
libraryId: 2,
|
||||
title: "Cartographie des songes",
|
||||
@ -54,8 +73,8 @@ export const mockBooks: BookDto[] = [
|
||||
fileMtime: now,
|
||||
createdAt: now,
|
||||
updatedAt: now
|
||||
},
|
||||
{
|
||||
}),
|
||||
mockBook({
|
||||
id: 3,
|
||||
libraryId: 2,
|
||||
title: "Les vitrines de verre",
|
||||
@ -73,8 +92,8 @@ export const mockBooks: BookDto[] = [
|
||||
fileMtime: now,
|
||||
createdAt: now,
|
||||
updatedAt: now
|
||||
},
|
||||
{
|
||||
}),
|
||||
mockBook({
|
||||
id: 4,
|
||||
libraryId: 2,
|
||||
title: "Cabinet noir",
|
||||
@ -92,7 +111,7 @@ export const mockBooks: BookDto[] = [
|
||||
fileMtime: now,
|
||||
createdAt: now,
|
||||
updatedAt: now
|
||||
}
|
||||
})
|
||||
];
|
||||
|
||||
export const mockProgress: ProgressDto[] = [
|
||||
|
||||
@ -36,3 +36,17 @@ export type ReaderPreferencesDto = {
|
||||
mode: ReaderMode;
|
||||
fit?: ReaderFit;
|
||||
};
|
||||
|
||||
export function hasActiveCoverWork(jobs: JobDto[]) {
|
||||
return jobs.some((job) => {
|
||||
if (job.status !== "queued" && job.status !== "running") return false;
|
||||
const type = job.type.toLowerCase();
|
||||
return type.includes("scan") || type.includes("enrich") || type.includes("metadata") || type.includes("cover");
|
||||
});
|
||||
}
|
||||
|
||||
export function isBookCoverUpdating(book: BookDto, fallbackActive = false) {
|
||||
const statuses = book as BookDto & { scanStatus?: string; enrichmentStatus?: string };
|
||||
if (statuses.scanStatus === "running" || statuses.enrichmentStatus === "running") return true;
|
||||
return statuses.scanStatus === undefined && statuses.enrichmentStatus === undefined && fallbackActive;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user