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>
30 lines
783 B
TypeScript
30 lines
783 B
TypeScript
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) },
|
|
});
|
|
}
|