- Add project_canvas and canvas_components tables for persistent canvas storage - Add ProjectCanvas store with full CRUD operations - Add ProjectCanvasPage for rendering saved canvas with components - Add ProjectsPage for managing canvas list (create, clone, delete) - Add HomePage that loads default canvas or falls back to dynamic canvas - Add toolbar support for displaying canvas as pages with custom icons - Add component usage validation to prevent deletion of components in use - Add MCP tools for canvas management (list, create, update, delete, clone) - Update router with /canvas/:id and /projects routes - Update Toolbar to show dynamic canvas pages from database
247 lines
7.0 KiB
TypeScript
247 lines
7.0 KiB
TypeScript
import { registerTool, unregisterTools } from '../webmcp'
|
|
import { useProjectCanvasStore } from '../../stores/projectCanvas'
|
|
|
|
export const PROJECT_CANVAS_TOOLS = [
|
|
'list_canvases',
|
|
'create_canvas',
|
|
'get_canvas',
|
|
'update_canvas',
|
|
'delete_canvas',
|
|
'clone_canvas',
|
|
'add_component_to_canvas',
|
|
'remove_component_from_canvas',
|
|
'get_canvas_components'
|
|
]
|
|
|
|
export function registerProjectCanvasTools() {
|
|
const store = useProjectCanvasStore()
|
|
|
|
// list_canvases
|
|
registerTool(
|
|
'list_canvases',
|
|
'Lista todos los canvas disponibles (proyectos, sistema)',
|
|
{
|
|
type: 'object',
|
|
properties: {
|
|
type: {
|
|
type: 'string',
|
|
enum: ['all', 'project', 'system'],
|
|
description: 'Filtrar por tipo de canvas'
|
|
}
|
|
}
|
|
},
|
|
async (args: { type?: string }) => {
|
|
await store.fetchCanvases()
|
|
let canvases = store.canvases
|
|
|
|
if (args.type === 'project') {
|
|
canvases = store.projectCanvases
|
|
} else if (args.type === 'system') {
|
|
canvases = store.systemCanvases
|
|
}
|
|
|
|
return JSON.stringify(canvases.map(c => ({
|
|
id: c.id,
|
|
name: c.name,
|
|
type: c.type,
|
|
description: c.description,
|
|
is_system: c.is_system
|
|
})), null, 2)
|
|
}
|
|
)
|
|
|
|
// create_canvas
|
|
registerTool(
|
|
'create_canvas',
|
|
'Crea un nuevo project canvas',
|
|
{
|
|
type: 'object',
|
|
properties: {
|
|
name: { type: 'string', description: 'Nombre del canvas' },
|
|
description: { type: 'string', description: 'Descripcion del canvas' },
|
|
theme_id: { type: 'string', description: 'ID del tema a usar (opcional)' },
|
|
config: {
|
|
type: 'object',
|
|
description: 'Configuracion del canvas (layout, settings, permissions)'
|
|
}
|
|
},
|
|
required: ['name']
|
|
},
|
|
async (args: { name: string; description?: string; theme_id?: string; config?: object }) => {
|
|
const id = await store.createCanvas({
|
|
name: args.name,
|
|
description: args.description,
|
|
theme_id: args.theme_id,
|
|
config: args.config as any,
|
|
type: 'project'
|
|
})
|
|
|
|
if (id) {
|
|
return `Canvas "${args.name}" creado con ID: ${id}`
|
|
}
|
|
return `Error al crear canvas: ${store.error}`
|
|
}
|
|
)
|
|
|
|
// get_canvas
|
|
registerTool(
|
|
'get_canvas',
|
|
'Obtiene los detalles de un canvas por ID',
|
|
{
|
|
type: 'object',
|
|
properties: {
|
|
id: { type: 'string', description: 'ID del canvas' }
|
|
},
|
|
required: ['id']
|
|
},
|
|
async (args: { id: string }) => {
|
|
const canvas = await store.fetchCanvasById(args.id)
|
|
if (!canvas) {
|
|
return `Canvas con ID "${args.id}" no encontrado`
|
|
}
|
|
return JSON.stringify(canvas, null, 2)
|
|
}
|
|
)
|
|
|
|
// update_canvas
|
|
registerTool(
|
|
'update_canvas',
|
|
'Actualiza un canvas existente',
|
|
{
|
|
type: 'object',
|
|
properties: {
|
|
id: { type: 'string', description: 'ID del canvas a actualizar' },
|
|
name: { type: 'string', description: 'Nuevo nombre' },
|
|
description: { type: 'string', description: 'Nueva descripcion' },
|
|
theme_id: { type: 'string', description: 'Nuevo tema' },
|
|
config: { type: 'object', description: 'Nueva configuracion' }
|
|
},
|
|
required: ['id']
|
|
},
|
|
async (args: { id: string; name?: string; description?: string; theme_id?: string; config?: object }) => {
|
|
const { id, ...data } = args
|
|
const success = await store.updateCanvas(id, data as any)
|
|
|
|
if (success) {
|
|
return `Canvas "${id}" actualizado`
|
|
}
|
|
return `Error al actualizar canvas: ${store.error}`
|
|
}
|
|
)
|
|
|
|
// delete_canvas
|
|
registerTool(
|
|
'delete_canvas',
|
|
'Elimina un canvas (no se pueden eliminar canvas del sistema)',
|
|
{
|
|
type: 'object',
|
|
properties: {
|
|
id: { type: 'string', description: 'ID del canvas a eliminar' }
|
|
},
|
|
required: ['id']
|
|
},
|
|
async (args: { id: string }) => {
|
|
const success = await store.deleteCanvas(args.id)
|
|
|
|
if (success) {
|
|
return `Canvas "${args.id}" eliminado`
|
|
}
|
|
return `Error al eliminar canvas: ${store.error}`
|
|
}
|
|
)
|
|
|
|
// clone_canvas
|
|
registerTool(
|
|
'clone_canvas',
|
|
'Clona un canvas existente (incluyendo sus componentes)',
|
|
{
|
|
type: 'object',
|
|
properties: {
|
|
id: { type: 'string', description: 'ID del canvas a clonar' },
|
|
name: { type: 'string', description: 'Nombre para el nuevo canvas (opcional)' }
|
|
},
|
|
required: ['id']
|
|
},
|
|
async (args: { id: string; name?: string }) => {
|
|
const newId = await store.cloneCanvas(args.id, args.name)
|
|
|
|
if (newId) {
|
|
return `Canvas clonado con nuevo ID: ${newId}`
|
|
}
|
|
return `Error al clonar canvas: ${store.error}`
|
|
}
|
|
)
|
|
|
|
// add_component_to_canvas
|
|
registerTool(
|
|
'add_component_to_canvas',
|
|
'Agrega un componente guardado a un canvas',
|
|
{
|
|
type: 'object',
|
|
properties: {
|
|
canvas_id: { type: 'string', description: 'ID del canvas' },
|
|
component_id: { type: 'string', description: 'ID del componente a agregar' },
|
|
props: { type: 'object', description: 'Props para el componente en este canvas' },
|
|
position: { type: 'number', description: 'Posicion del componente (orden de renderizado)' }
|
|
},
|
|
required: ['canvas_id', 'component_id']
|
|
},
|
|
async (args: { canvas_id: string; component_id: string; props?: object; position?: number }) => {
|
|
const success = await store.addComponentToCanvas(
|
|
args.canvas_id,
|
|
args.component_id,
|
|
args.props as Record<string, any>,
|
|
args.position
|
|
)
|
|
|
|
if (success) {
|
|
return `Componente "${args.component_id}" agregado al canvas "${args.canvas_id}"`
|
|
}
|
|
return 'Error al agregar componente al canvas'
|
|
}
|
|
)
|
|
|
|
// remove_component_from_canvas
|
|
registerTool(
|
|
'remove_component_from_canvas',
|
|
'Remueve un componente de un canvas',
|
|
{
|
|
type: 'object',
|
|
properties: {
|
|
canvas_id: { type: 'string', description: 'ID del canvas' },
|
|
component_id: { type: 'string', description: 'ID del componente a remover' }
|
|
},
|
|
required: ['canvas_id', 'component_id']
|
|
},
|
|
async (args: { canvas_id: string; component_id: string }) => {
|
|
const success = await store.removeComponentFromCanvas(args.canvas_id, args.component_id)
|
|
|
|
if (success) {
|
|
return `Componente "${args.component_id}" removido del canvas "${args.canvas_id}"`
|
|
}
|
|
return 'Error al remover componente del canvas'
|
|
}
|
|
)
|
|
|
|
// get_canvas_components
|
|
registerTool(
|
|
'get_canvas_components',
|
|
'Obtiene los componentes de un canvas con sus definiciones',
|
|
{
|
|
type: 'object',
|
|
properties: {
|
|
canvas_id: { type: 'string', description: 'ID del canvas' }
|
|
},
|
|
required: ['canvas_id']
|
|
},
|
|
async (args: { canvas_id: string }) => {
|
|
await store.fetchCanvasComponents(args.canvas_id)
|
|
return JSON.stringify(store.activeCanvasComponents, null, 2)
|
|
}
|
|
)
|
|
}
|
|
|
|
export function unregisterProjectCanvasTools() {
|
|
unregisterTools(PROJECT_CANVAS_TOOLS)
|
|
}
|