@restnfeel/agentc-starter-kit
Version:
한국어 기업용 CMS 모듈 - Task Master AI와 함께 빠르게 웹사이트를 구현할 수 있는 재사용 가능한 컴포넌트 시스템
144 lines (141 loc) • 9.84 kB
JavaScript
import { jsxs, jsx } from 'react/jsx-runtime';
import { useState, useEffect, useCallback } from 'react';
import { Card, CardHeader, CardTitle, CardContent } from '../../../../components/ui/Card.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