UNPKG

@restnfeel/agentc-starter-kit

Version:

한국어 기업용 CMS 모듈 - Task Master AI와 함께 빠르게 웹사이트를 구현할 수 있는 재사용 가능한 컴포넌트 시스템

145 lines (142 loc) 9.89 kB
import { jsxs, jsx } from 'react/jsx-runtime'; import { useState, useEffect, useCallback } from 'react'; import { Card, CardHeader, CardContent } from '../../../../components/ui/Card.js'; import { CardTitle } from '../../../../components/ui/CardTitle.js'; import { Input } from '../../../../components/ui/Input.js'; import { Button } from '../../../../components/ui/Button.js'; import { RAGEngine } from '../../../../rag/engine.js'; function RSSManager({ ragEngine, onFeedAdded, onFeedRemoved, onFeedRefreshed, }) { const [feeds, setFeeds] = useState([]); const [newFeedUrl, setNewFeedUrl] = useState(""); const [customFeedName, setCustomFeedName] = useState(""); const [maxItems, setMaxItems] = useState("20"); const [isLoading, setIsLoading] = useState(false); const [refreshingFeeds, setRefreshingFeeds] = useState(new Set()); const [error, setError] = useState(null); const [success, setSuccess] = useState(null); // Load existing feeds on component mount useEffect(() => { loadExistingFeeds(); }, [ragEngine]); const loadExistingFeeds = useCallback(() => { try { const feedNames = ragEngine.getRSSFeedNames(); const feedInfos = feedNames.map((name) => { const info = ragEngine.getRSSFeedInfo(name); return { name, type: info.type || "generic", url: info.rssUrl, blogId: info.blogId, }; }); setFeeds(feedInfos); } catch (err) { console.error("Failed to load existing feeds:", err); } }, [ragEngine]); const clearMessages = () => { setError(null); setSuccess(null); }; const detectFeedType = (url) => { const blogId = RAGEngine.extractNaverBlogId(url); if (blogId) { return { type: "naver", blogId }; } return { type: "generic" }; }; const addFeed = async () => { if (!newFeedUrl.trim()) { setError("RSS URL을 입력해주세요."); return; } setIsLoading(true); clearMessages(); try { const { type, blogId } = detectFeedType(newFeedUrl); const feedName = customFeedName.trim() || (type === "naver" ? `네이버블로그_${blogId}` : `RSS피드_${Date.now()}`); const config = { maxItems: parseInt(maxItems) || 20, includeContent: true, }; let result; if (type === "naver" && blogId) { result = await ragEngine.addNaverBlogRSS(blogId, feedName, config); } else { result = await ragEngine.addRSSFeed(newFeedUrl, feedName, config); } const newFeedInfo = { name: result.feedName, type, url: type === "naver" ? `https://rss.blog.naver.com/${blogId}` : newFeedUrl, blogId: type === "naver" ? blogId : undefined, itemCount: result.itemCount, lastUpdated: new Date(), }; setFeeds((prev) => [...prev, newFeedInfo]); setNewFeedUrl(""); setCustomFeedName(""); setSuccess(`RSS 피드가 성공적으로 추가되었습니다! ${result.itemCount}개의 문서를 학습했습니다.`); onFeedAdded === null || onFeedAdded === void 0 ? void 0 : onFeedAdded(newFeedInfo); } catch (err) { setError(`RSS 피드 추가 실패: ${err instanceof Error ? err.message : "알 수 없는 오류"}`); } finally { setIsLoading(false); } }; const removeFeed = async (feedName) => { try { const success = ragEngine.removeRSSFeed(feedName); if (success) { setFeeds((prev) => prev.filter((feed) => feed.name !== feedName)); setSuccess(`RSS 피드 "${feedName}"가 제거되었습니다.`); onFeedRemoved === null || onFeedRemoved === void 0 ? void 0 : onFeedRemoved(feedName); } else { setError(`RSS 피드 "${feedName}" 제거에 실패했습니다.`); } } catch (err) { setError(`RSS 피드 제거 실패: ${err instanceof Error ? err.message : "알 수 없는 오류"}`); } }; const refreshFeed = async (feedName) => { setRefreshingFeeds((prev) => new Set([...prev, feedName])); clearMessages(); try { const result = await ragEngine.refreshRSSFeed(feedName); setFeeds((prev) => prev.map((feed) => feed.name === feedName ? { ...feed, itemCount: result.itemCount, lastUpdated: new Date() } : feed)); setSuccess(`RSS 피드 "${feedName}"가 새로고침되었습니다! ${result.itemCount}개의 문서를 처리했습니다.`); onFeedRefreshed === null || onFeedRefreshed === void 0 ? void 0 : onFeedRefreshed(feedName, result.itemCount); } catch (err) { setError(`RSS 피드 새로고침 실패: ${err instanceof Error ? err.message : "알 수 없는 오류"}`); } finally { setRefreshingFeeds((prev) => { const next = new Set(prev); next.delete(feedName); return next; }); } }; return (jsxs("div", { className: "space-y-6", children: [jsxs(Card, { children: [jsx(CardHeader, { children: jsx(CardTitle, { children: "RSS \uD53C\uB4DC \uCD94\uAC00" }) }), jsxs(CardContent, { className: "space-y-4", children: [jsxs("div", { children: [jsx("label", { htmlFor: "rss-url", className: "block text-sm font-medium mb-1", children: "RSS URL \uB610\uB294 \uB124\uC774\uBC84 \uBE14\uB85C\uADF8 ID" }), jsx(Input, { type: "text", placeholder: "https://rss.blog.naver.com/blogid \uB610\uB294 blogid", value: newFeedUrl, onChange: (e) => setNewFeedUrl(e.target.value), className: "w-full" }), jsx("p", { className: "text-xs text-gray-500 mt-1", children: "\uB124\uC774\uBC84 \uBE14\uB85C\uADF8: https://rss.blog.naver.com/\uBE14\uB85C\uADF8ID \uB610\uB294 \uBE14\uB85C\uADF8ID\uB9CC \uC785\uB825" })] }), jsxs("div", { children: [jsx("label", { htmlFor: "feed-name", className: "block text-sm font-medium mb-1", children: "\uD53C\uB4DC \uC774\uB984 (\uC120\uD0DD\uC0AC\uD56D)" }), jsx(Input, { type: "text", placeholder: "\uCEE4\uC2A4\uD140 \uD53C\uB4DC \uC774\uB984", value: customFeedName, onChange: (e) => setCustomFeedName(e.target.value), className: "w-full" })] }), jsxs("div", { children: [jsx("label", { htmlFor: "max-items", className: "block text-sm font-medium mb-1", children: "\uCD5C\uB300 \uBB38\uC11C \uC218" }), jsx("input", { type: "number", min: "1", max: "100", value: maxItems, onChange: (e) => setMaxItems(e.target.value), className: "w-full h-10 px-3 rounded-md border border-gray-300 focus:outline-none focus:ring-2 focus:ring-blue-500" })] }), jsx(Button, { onClick: addFeed, disabled: isLoading, className: "w-full", children: isLoading ? "추가 중..." : "RSS 피드 추가" })] })] }), jsxs(Card, { children: [jsx(CardHeader, { children: jsxs(CardTitle, { children: ["\uB4F1\uB85D\uB41C RSS \uD53C\uB4DC (", feeds.length, "\uAC1C)"] }) }), jsx(CardContent, { children: feeds.length === 0 ? (jsx("p", { className: "text-gray-500 text-center py-4", children: "\uB4F1\uB85D\uB41C RSS \uD53C\uB4DC\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4." })) : (jsx("div", { className: "space-y-3", children: feeds.map((feed) => (jsxs("div", { className: "flex items-center justify-between p-3 border rounded-lg", children: [jsxs("div", { className: "flex-1", children: [jsxs("div", { className: "flex items-center gap-2 mb-1", children: [jsx("h4", { className: "font-medium", children: feed.name }), jsx("span", { className: `px-2 py-1 text-xs rounded ${feed.type === "naver" ? "bg-blue-100 text-blue-800" : "bg-gray-100 text-gray-800"}`, children: feed.type === "naver" ? "네이버" : "RSS" })] }), jsxs("div", { className: "text-sm text-gray-600 space-y-1", children: [feed.url && (jsx("div", { children: jsx("a", { href: feed.url, target: "_blank", rel: "noopener noreferrer", className: "hover:underline", children: feed.blogId ? `네이버 블로그: ${feed.blogId}` : feed.url }) })), feed.itemCount !== undefined && (jsxs("p", { children: ["\uBB38\uC11C \uC218: ", feed.itemCount, "\uAC1C"] })), feed.lastUpdated && (jsxs("p", { children: ["\uB9C8\uC9C0\uB9C9 \uC5C5\uB370\uC774\uD2B8: ", feed.lastUpdated.toLocaleString()] }))] })] }), jsxs("div", { className: "flex items-center gap-2", children: [jsx(Button, { variant: "outline", size: "sm", onClick: () => refreshFeed(feed.name), disabled: refreshingFeeds.has(feed.name), children: refreshingFeeds.has(feed.name) ? "새로고침 중..." : "새로고침" }), jsx(Button, { variant: "outline", size: "sm", onClick: () => removeFeed(feed.name), children: "\uC81C\uAC70" })] })] }, feed.name))) })) })] }), error && (jsx("div", { className: "p-4 bg-red-50 border border-red-200 rounded-lg", children: jsx("p", { className: "text-red-800", children: error }) })), success && (jsx("div", { className: "p-4 bg-green-50 border border-green-200 rounded-lg", children: jsx("p", { className: "text-green-800", children: success }) }))] })); } export { RSSManager }; //# sourceMappingURL=rss-manager.js.map