feat: Add UI/UX improvements to catalog.html including search, config json copy, and guide modal
Some checks failed
Deploy to OCIWP / deploy (push) Failing after 34s
Some checks failed
Deploy to OCIWP / deploy (push) Failing after 34s
This commit is contained in:
@@ -79,12 +79,24 @@
|
||||
|
||||
<main class="max-w-6xl mx-auto px-6 py-10">
|
||||
<div class="flex flex-col md:flex-row justify-between items-start md:items-end mb-8">
|
||||
<div class="max-w-2xl">
|
||||
<h1 class="text-3xl font-bold tracking-tight mb-2" style="color:#f4f4f5;">Registry Catalog</h1>
|
||||
<p class="text-sm" style="color:#a1a1aa;">Currently integrated AI function tools across all modules. View parameters, descriptions, and integration types.</p>
|
||||
<div class="max-w-2xl w-full">
|
||||
<div class="flex items-center space-x-3 mb-2">
|
||||
<h1 class="text-3xl font-bold tracking-tight" style="color:#f4f4f5;">Registry Catalog</h1>
|
||||
<button onclick="openGuideModal()" class="w-6 h-6 rounded-full flex items-center justify-center text-sm font-bold bg-zinc-800 text-zinc-400 hover:bg-zinc-700 hover:text-white transition-colors" title="Connection Guide">?</button>
|
||||
</div>
|
||||
<p class="text-sm mb-6" style="color:#a1a1aa;">Currently integrated AI function tools across all modules. View parameters, descriptions, and integration types.</p>
|
||||
|
||||
<div class="relative max-w-md w-full">
|
||||
<input type="text" id="searchInput" placeholder="Search tools by name, description, or category..." class="w-full bg-zinc-900 border border-zinc-700 rounded-lg px-4 py-2.5 text-sm text-zinc-200 placeholder-zinc-500 focus:outline-none focus:border-blue-500 transition-colors">
|
||||
<svg class="w-4 h-4 absolute right-3 top-3 text-zinc-500" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"></path></svg>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-4 md:mt-0">
|
||||
<button id="copyMdBtn" class="btn-primary flex items-center">
|
||||
<div class="mt-4 md:mt-0 flex space-x-3 w-full md:w-auto">
|
||||
<button id="copyJsonBtn" class="btn-primary flex items-center justify-center flex-1 md:flex-none" style="background: linear-gradient(135deg, #10b981, #059669); box-shadow: 0 0 20px rgba(16, 185, 129, 0.2);">
|
||||
<svg class="w-4 h-4 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z"></path></svg>
|
||||
<span id="copyJsonText">Copy Client Config</span>
|
||||
</button>
|
||||
<button id="copyMdBtn" class="btn-primary flex items-center justify-center flex-1 md:flex-none">
|
||||
<svg class="w-4 h-4 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 5H6a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2v-1M8 5a2 2 0 002 2h2a2 2 0 002-2M8 5a2 2 0 012-2h2a2 2 0 012 2m0 0h2a2 2 0 012 2v3m2 4H10m0 0l3-3m-3 3l3 3"></path></svg>
|
||||
<span id="copyBtnText">Copy Markdown Docs</span>
|
||||
</button>
|
||||
@@ -99,13 +111,52 @@
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<!-- Guide Modal -->
|
||||
<div id="guideModal" class="fixed inset-0 z-[100] hidden flex items-center justify-center">
|
||||
<div class="absolute inset-0 bg-black/60 backdrop-blur-sm" onclick="closeGuideModal()"></div>
|
||||
<div class="relative bg-zinc-900 border border-zinc-700 rounded-xl shadow-2xl w-full max-w-2xl mx-4 overflow-hidden">
|
||||
<div class="p-5 border-b border-zinc-800 flex justify-between items-center bg-zinc-900/50">
|
||||
<h3 class="text-lg font-semibold text-zinc-100 flex items-center">
|
||||
<svg class="w-5 h-5 mr-2 text-blue-400" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path></svg>
|
||||
AI Agent Connection Guide
|
||||
</h3>
|
||||
<button onclick="closeGuideModal()" class="text-zinc-400 hover:text-white transition-colors">
|
||||
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"></path></svg>
|
||||
</button>
|
||||
</div>
|
||||
<div class="p-6 space-y-6 max-h-[70vh] overflow-y-auto text-sm text-zinc-300">
|
||||
<div>
|
||||
<h4 class="font-semibold text-blue-400 mb-3 flex items-center"><span class="w-5 h-5 rounded bg-blue-500/20 flex items-center justify-center mr-2 text-xs">1</span> Cursor IDE 연동</h4>
|
||||
<p class="mb-2">1. Cursor 설정 창 열기 (<kbd class="px-1.5 py-0.5 bg-zinc-800 border border-zinc-700 rounded text-xs text-zinc-300">Cmd/Ctrl + ,</kbd>)</p>
|
||||
<p class="mb-2">2. 사이드바에서 <strong>Features</strong> > <strong>MCP</strong> 메뉴로 이동</p>
|
||||
<p>3. <strong>+ Add New MCP Server</strong>를 클릭하고, 툴 카테고리의 [Copy SSE URL] 버튼으로 복사한 주소를 `SSE` 타입으로 붙여넣기 하세요.</p>
|
||||
</div>
|
||||
<div class="border-t border-zinc-800 pt-6">
|
||||
<h4 class="font-semibold text-orange-400 mb-3 flex items-center"><span class="w-5 h-5 rounded bg-orange-500/20 flex items-center justify-center mr-2 text-xs">2</span> Claude Desktop 연동</h4>
|
||||
<p class="mb-2">1. 아래 설정 파일을 텍스트 에디터로 엽니다:</p>
|
||||
<div class="bg-black/40 p-3 rounded-lg border border-zinc-800/80 font-mono text-xs mb-3 text-zinc-400">
|
||||
<div class="mb-1"><strong>Mac:</strong> ~/Library/Application Support/Claude/claude_desktop_config.json</div>
|
||||
<div><strong>Win:</strong> %APPDATA%\Claude\claude_desktop_config.json</div>
|
||||
</div>
|
||||
<p>2. 화면 우측 상단의 <strong>[Copy Client Config]</strong> 버튼을 누른 후, 복사된 JSON 코드를 이 파일 안에 그대로 붙여넣습니다.</p>
|
||||
</div>
|
||||
<div class="border-t border-zinc-800 pt-6">
|
||||
<h4 class="font-semibold text-emerald-400 mb-3 flex items-center"><span class="w-5 h-5 rounded bg-emerald-500/20 flex items-center justify-center mr-2 text-xs">3</span> 커스텀 Python/Node Agent 연동</h4>
|
||||
<p class="mb-2">1. MCP 공식 SDK를 설치합니다. <code class="text-xs bg-zinc-800 px-1.5 py-0.5 rounded text-zinc-300 border border-zinc-700">npm i @modelcontextprotocol/sdk</code></p>
|
||||
<p>2. SSE Client Transport를 사용하여 복사한 카테고리별 URL로 연결합니다.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
let allTools = []; // 글로벌 변수로 툴 데이터 보관
|
||||
async function fetchTools() {
|
||||
try {
|
||||
const response = await fetch('/mcp/api/v1/tools/list');
|
||||
const data = await response.json();
|
||||
const tools = data.result?.tools || [];
|
||||
renderCatalog(tools);
|
||||
allTools = data.result?.tools || [];
|
||||
renderCatalog(allTools);
|
||||
} catch (err) {
|
||||
document.getElementById('catalogContainer').innerHTML = `
|
||||
<div style="padding:16px; border:1px solid #7f1d1d; background:rgba(127,29,29,0.15); color:#fca5a5; font-size:14px; border-radius:8px;">
|
||||
@@ -134,7 +185,12 @@
|
||||
header.style.cssText = 'margin-bottom:16px; padding-bottom:8px; border-bottom:1px solid #27272a; display:flex; align-items:baseline; justify-content:space-between;';
|
||||
header.innerHTML = `
|
||||
<h2 style="font-size:20px; font-weight:600; color:#f4f4f5; text-transform:capitalize;">${group}</h2>
|
||||
<span class="geist-mono" style="font-size:12px; color:#71717a;">${grouped[group].length} items</span>
|
||||
<div style="display:flex; align-items:center; gap:8px;">
|
||||
<span class="geist-mono" style="font-size:12px; color:#71717a;">${grouped[group].length} items</span>
|
||||
<button onclick="copySseUrl('${group.toLowerCase()}', this)" class="hover:text-blue-400 text-zinc-500 transition-colors p-1.5 rounded hover:bg-zinc-800/50" title="Copy SSE URL">
|
||||
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z"></path></svg>
|
||||
</button>
|
||||
</div>
|
||||
`;
|
||||
section.appendChild(header);
|
||||
const grid = document.createElement('div');
|
||||
@@ -227,6 +283,60 @@
|
||||
}
|
||||
});
|
||||
|
||||
document.getElementById('searchInput').addEventListener('input', (e) => {
|
||||
const query = e.target.value.toLowerCase();
|
||||
const filtered = allTools.filter(t =>
|
||||
(t.name && t.name.toLowerCase().includes(query)) ||
|
||||
(t.displayName && t.displayName.toLowerCase().includes(query)) ||
|
||||
(t.description && t.description.toLowerCase().includes(query)) ||
|
||||
(t.categoryKey && t.categoryKey.toLowerCase().includes(query))
|
||||
);
|
||||
renderCatalog(filtered);
|
||||
});
|
||||
|
||||
function copySseUrl(category, btnElement) {
|
||||
const url = `${window.location.origin}/mcp/sse/${category}`;
|
||||
navigator.clipboard.writeText(url).then(() => {
|
||||
const originalSvg = btnElement.innerHTML;
|
||||
btnElement.innerHTML = `<svg class="w-4 h-4 text-emerald-400" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"></path></svg>`;
|
||||
setTimeout(() => { btnElement.innerHTML = originalSvg; }, 2000);
|
||||
}).catch(() => alert('Failed to copy.'));
|
||||
}
|
||||
|
||||
function openGuideModal() {
|
||||
document.getElementById('guideModal').classList.remove('hidden');
|
||||
}
|
||||
|
||||
function closeGuideModal() {
|
||||
document.getElementById('guideModal').classList.add('hidden');
|
||||
}
|
||||
|
||||
document.getElementById('copyJsonBtn').addEventListener('click', () => {
|
||||
const groups = [...new Set(allTools.map(t => t.categoryKey || 'Others'))];
|
||||
const config = { mcpServers: {} };
|
||||
groups.forEach(g => {
|
||||
const safeKey = g.toLowerCase().replace(/[^a-z0-9]/g, '-');
|
||||
config.mcpServers[`axhub-${safeKey}`] = {
|
||||
"command": "node",
|
||||
"args": [],
|
||||
"env": {},
|
||||
"type": "sse",
|
||||
"url": `${window.location.origin}/mcp/sse/${g.toLowerCase()}`
|
||||
};
|
||||
// Note: Claude desktop expects command/args for stdio, but for SSE it usually accepts just url/type or requires specialized settings.
|
||||
// Adjusted to basic config.
|
||||
delete config.mcpServers[`axhub-${safeKey}`].command;
|
||||
delete config.mcpServers[`axhub-${safeKey}`].args;
|
||||
delete config.mcpServers[`axhub-${safeKey}`].env;
|
||||
});
|
||||
const textSpan = document.getElementById('copyJsonText');
|
||||
const originalText = textSpan.textContent;
|
||||
navigator.clipboard.writeText(JSON.stringify(config, null, 2)).then(() => {
|
||||
textSpan.textContent = 'Copied JSON!';
|
||||
setTimeout(() => { textSpan.textContent = originalText; }, 2000);
|
||||
}).catch(() => alert('Failed to copy JSON.'));
|
||||
});
|
||||
|
||||
document.addEventListener('DOMContentLoaded', fetchTools);
|
||||
</script>
|
||||
</body>
|
||||
|
||||
Reference in New Issue
Block a user