feat: add external metadata sync system with multiple providers
Add a complete metadata synchronization system allowing users to search and sync series/book metadata from external providers (Google Books, Open Library, ComicVine, AniList, Bédéthèque). Each library can use a different provider. Matching requires manual approval with detailed sync reports showing what was updated or skipped (locked fields protection). Key changes: - DB migrations: external_metadata_links, external_book_metadata tables, library metadata_provider column, locked_fields, total_volumes, book metadata fields (summary, isbn, publish_date) - Rust API: MetadataProvider trait + 5 provider implementations, 7 metadata endpoints (search, match, approve, reject, links, missing, delete), sync report system, provider language preference support - Backoffice: MetadataSearchModal, ProviderIcon, SafeHtml components, settings UI for provider/language config, enriched book detail page, edit forms with locked fields support, API proxy routes - OpenAPI/Swagger documentation for all new endpoints and schemas Closes #3 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
29
apps/backoffice/app/components/SafeHtml.tsx
Normal file
29
apps/backoffice/app/components/SafeHtml.tsx
Normal file
@@ -0,0 +1,29 @@
|
||||
import sanitizeHtml from "sanitize-html";
|
||||
import React from "react";
|
||||
|
||||
interface SafeHtmlProps {
|
||||
html: string;
|
||||
className?: string;
|
||||
as?: "div" | "p" | "span";
|
||||
}
|
||||
|
||||
const sanitizeOptions: sanitizeHtml.IOptions = {
|
||||
allowedTags: [
|
||||
"b", "i", "em", "strong", "a", "p", "br", "ul", "ol", "li",
|
||||
"h1", "h2", "h3", "h4", "h5", "h6", "blockquote", "span",
|
||||
],
|
||||
allowedAttributes: {
|
||||
a: ["href", "target", "rel"],
|
||||
span: ["class"],
|
||||
},
|
||||
transformTags: {
|
||||
a: sanitizeHtml.simpleTransform("a", { target: "_blank", rel: "noopener noreferrer" }),
|
||||
},
|
||||
};
|
||||
|
||||
export function SafeHtml({ html, className, as: tag = "div" }: SafeHtmlProps) {
|
||||
return React.createElement(tag, {
|
||||
className,
|
||||
dangerouslySetInnerHTML: { __html: sanitizeHtml(html, sanitizeOptions) },
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user