"use client"; import { useEffect, useState } from "react"; import Link from "next/link"; import { AdminCard } from "@/components/admin/AdminCard"; import { Badge } from "@/components/ui/badge"; import { Button } from "@/components/ui/button"; import InfoTooltip from "@/components/ui/info-tooltip"; import { Input } from "@/components/ui/input"; import { useTranslation } from "@/lib/i18n/client"; import { formatBytes } from "@/lib/utils"; import { useMutation, useQuery } from "@tanstack/react-query"; import { formatDistanceToNow } from "date-fns"; import { AlertCircle, CheckCircle2, ChevronDown, ChevronRight, Clock, Database, ExternalLink, FileText, FileType, Image as ImageIcon, Link as LinkIcon, Loader2, RefreshCw, Search, Sparkles, Tag, User, XCircle, } from "lucide-react"; import { parseAsString, useQueryState } from "nuqs"; import { toast } from "sonner"; import { useTRPC } from "@karakeep/shared-react/trpc"; import { BookmarkTypes } from "@karakeep/shared/types/bookmarks"; export default function BookmarkDebugger() { const api = useTRPC(); const { t } = useTranslation(); const [inputValue, setInputValue] = useState(""); const [bookmarkId, setBookmarkId] = useQueryState( "bookmarkId", parseAsString.withDefault(""), ); const [showHtmlPreview, setShowHtmlPreview] = useState(false); // Sync input value with URL on mount/change useEffect(() => { if (bookmarkId) { setInputValue(bookmarkId); } }, [bookmarkId]); const { data: debugInfo, isLoading, error, } = useQuery( api.admin.getBookmarkDebugInfo.queryOptions( { bookmarkId: bookmarkId }, { enabled: !!bookmarkId && bookmarkId.length > 0 }, ), ); const handleLookup = () => { if (inputValue.trim()) { setBookmarkId(inputValue.trim()); } }; const recrawlMutation = useMutation( api.admin.adminRecrawlBookmark.mutationOptions({ onSuccess: () => { toast.success(t("admin.admin_tools.action_success"), { description: t("admin.admin_tools.recrawl_queued"), }); }, onError: (error) => { toast.error(t("admin.admin_tools.action_failed"), { description: error.message, }); }, }), ); const reindexMutation = useMutation( api.admin.adminReindexBookmark.mutationOptions({ onSuccess: () => { toast.success(t("admin.admin_tools.action_success"), { description: t("admin.admin_tools.reindex_queued"), }); }, onError: (error) => { toast.error(t("admin.admin_tools.action_failed"), { description: error.message, }); }, }), ); const retagMutation = useMutation( api.admin.adminRetagBookmark.mutationOptions({ onSuccess: () => { toast.success(t("admin.admin_tools.action_success"), { description: t("admin.admin_tools.retag_queued"), }); }, onError: (error) => { toast.error(t("admin.admin_tools.action_failed"), { description: error.message, }); }, }), ); const resummarizeMutation = useMutation( api.admin.adminResummarizeBookmark.mutationOptions({ onSuccess: () => { toast.success(t("admin.admin_tools.action_success"), { description: t("admin.admin_tools.resummarize_queued"), }); }, onError: (error) => { toast.error(t("admin.admin_tools.action_failed"), { description: error.message, }); }, }), ); const handleRecrawl = () => { if (bookmarkId) { recrawlMutation.mutate({ bookmarkId }); } }; const handleReindex = () => { if (bookmarkId) { reindexMutation.mutate({ bookmarkId }); } }; const handleRetag = () => { if (bookmarkId) { retagMutation.mutate({ bookmarkId }); } }; const handleResummarize = () => { if (bookmarkId) { resummarizeMutation.mutate({ bookmarkId }); } }; const getStatusBadge = (status: "pending" | "failure" | "success" | null) => { if (!status) return null; const config = { success: { variant: "default" as const, icon: CheckCircle2, }, failure: { variant: "destructive" as const, icon: XCircle, }, pending: { variant: "secondary" as const, icon: AlertCircle, }, }; const { variant, icon: Icon } = config[status]; return ( {status} ); }; return (
{/* Input Section */}

{t("admin.admin_tools.bookmark_debugger")}

Some data will be redacted for privacy.
setInputValue(e.target.value)} onKeyDown={(e) => { if (e.key === "Enter") { handleLookup(); } }} className="pl-9" />
{/* Loading State */} {isLoading && (
)} {/* Error State */} {!isLoading && error && (

{t("admin.admin_tools.fetch_error")}

{error.message}

)} {/* Debug Info Display */} {!isLoading && !error && debugInfo && (
{/* Basic Info & Status */}
{/* Basic Info */}

{t("admin.admin_tools.basic_info")}

{t("common.id")} {debugInfo.id}
{t("common.type")} {debugInfo.type}
{t("common.source")} {debugInfo.source || "N/A"}
{t("admin.admin_tools.owner_user_id")} {debugInfo.userId}
{t("common.created_at")} {formatDistanceToNow(new Date(debugInfo.createdAt), { addSuffix: true, })}
{debugInfo.modifiedAt && (
{t("common.updated_at")} {formatDistanceToNow(new Date(debugInfo.modifiedAt), { addSuffix: true, })}
)}
{/* Status */}

{t("admin.admin_tools.status")}

{t("admin.admin_tools.tagging_status")} {getStatusBadge(debugInfo.taggingStatus)}
{t("admin.admin_tools.summarization_status")} {getStatusBadge(debugInfo.summarizationStatus)}
{debugInfo.linkInfo && ( <>
{t("admin.admin_tools.crawl_status")} {getStatusBadge(debugInfo.linkInfo.crawlStatus)}
{t("admin.admin_tools.crawl_status_code")} = 200 && debugInfo.linkInfo.crawlStatusCode < 300) ? "default" : "destructive" } > {debugInfo.linkInfo.crawlStatusCode}
{debugInfo.linkInfo.crawledAt && (
{t("admin.admin_tools.crawled_at")} {formatDistanceToNow( new Date(debugInfo.linkInfo.crawledAt), { addSuffix: true, }, )}
)} )}
{/* Content */} {(debugInfo.title || debugInfo.summary || debugInfo.linkInfo || debugInfo.textInfo?.sourceUrl || debugInfo.assetInfo) && (

{t("admin.admin_tools.content")}

{debugInfo.title && (
{t("common.title")}
{debugInfo.title}
)} {debugInfo.summary && (
{t("admin.admin_tools.summary")}
{debugInfo.summary}
)} {debugInfo.linkInfo && (
{t("admin.admin_tools.url")}
{debugInfo.linkInfo.url}
)} {debugInfo.textInfo?.sourceUrl && (
{t("admin.admin_tools.source_url")}
{debugInfo.textInfo.sourceUrl}
)} {debugInfo.assetInfo && (
{t("admin.admin_tools.asset_type")}
{debugInfo.assetInfo.assetType} {debugInfo.assetInfo.fileName && (
{debugInfo.assetInfo.fileName}
)}
)}
)} {/* HTML Preview */} {debugInfo.linkInfo && debugInfo.linkInfo.htmlContentPreview && (
{showHtmlPreview && (
                    {debugInfo.linkInfo.htmlContentPreview}
                  
)}
)} {/* Tags */} {debugInfo.tags.length > 0 && (

{t("common.tags")}{" "} ({debugInfo.tags.length})

{debugInfo.tags.map((tag) => ( {tag.attachedBy === "ai" && ( )} {tag.name} ))}
)} {/* Assets */} {debugInfo.assets.length > 0 && (

{t("common.attachments")}{" "} ({debugInfo.assets.length})

{debugInfo.assets.map((asset) => (
{asset.assetType}
{formatBytes(asset.size)}
{asset.url && ( {t("admin.admin_tools.view")} )}
))}
)} {/* Actions */}

{t("common.actions")}

)}
); }