Files
agent-ui/frontend/src/components/Canvas.vue
josedario87 acde6b37d6 feat: Add dynamic MCP tool registration per page
- webmcp.ts: Add tool tracking, unregisterTool(), clearAllTools()
- tools/canvasTools.ts: render_html, render_vue_component
- tools/componentTools.ts: save/load/list/delete_vue_component
- tools/themeTools.ts: get_design_tokens, get_active_theme, set_theme_variable, save_theme
- tools/globalTools.ts: get_current_page, navigate_to, list_available_tools
- toolRegistry.ts: Orchestrates tool registration per page
- App.vue: Initializes WebMCP once, watches route for tool changes
- Canvas.vue: Removed tool registration (now handled by registry)

Tools are now registered when entering a page and unregistered when leaving.
Refresh initializes tools correctly for the current page.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-13 05:42:17 -06:00

101 lines
2.5 KiB
Vue

<script setup lang="ts">
import { onMounted, onUnmounted } from 'vue'
import { renderInlineComponent, type VueComponentDefinition } from '../services/dynamicComponents'
import { useCanvasStore } from '../stores/canvas'
const canvasStore = useCanvasStore()
function handleLoadComponent(e: Event) {
const detail = (e as CustomEvent).detail
if (!detail) return
const container = document.getElementById('canvas-content')
if (!container) return
const placeholder = container.querySelector('.canvas-placeholder')
if (placeholder) placeholder.remove()
const definition: VueComponentDefinition = {
id: detail.id,
name: detail.name,
template: detail.template,
setup: detail.setup,
style: detail.style,
props: detail.props,
imports: detail.imports || ['ref', 'reactive', 'computed']
}
const result = renderInlineComponent(definition, container, {}, false)
;(window as any).__vueComponentUnmount = result.unmount
window.dispatchEvent(new CustomEvent('vue-component-rendered', { detail }))
canvasStore.addToHistory({ tool: 'load_vue_component', args: detail, timestamp: Date.now() })
}
onMounted(() => {
window.addEventListener('load-vue-component', handleLoadComponent)
})
onUnmounted(() => {
window.removeEventListener('load-vue-component', handleLoadComponent)
})
</script>
<template>
<div class="canvas-container">
<div id="canvas-content" class="canvas-content">
<div class="canvas-placeholder">
<svg xmlns="http://www.w3.org/2000/svg" width="64" height="64" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5">
<rect x="3" y="3" width="18" height="18" rx="2"/>
<path d="M3 9h18"/>
<path d="M9 21V9"/>
</svg>
<p>Canvas listo</p>
<span>Haz clic en el cuadrado azul (abajo derecha) para conectar con Claude Code</span>
</div>
</div>
</div>
</template>
<style scoped>
.canvas-container {
flex: 1;
display: flex;
flex-direction: column;
background: var(--bg-primary);
overflow: auto;
}
.canvas-content {
flex: 1;
padding: 1.5rem;
min-height: 100%;
}
.canvas-placeholder {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 100%;
min-height: 400px;
color: var(--text-muted);
text-align: center;
}
.canvas-placeholder svg {
margin-bottom: 1rem;
opacity: 0.5;
}
.canvas-placeholder p {
font-size: 1.25rem;
margin: 0 0 0.5rem 0;
}
.canvas-placeholder span {
font-size: 0.875rem;
opacity: 0.7;
}
</style>