Files
stripstream-librarian/apps/backoffice/app/components/SafeHtml.tsx
Froidefond Julien c9ccf5cd90 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>
2026-03-18 14:59:24 +01:00

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) },
});
}