From d8f9acd1f83a221aceacbebcc37fd73d76a3dc52 Mon Sep 17 00:00:00 2001 From: Lizandro Guarnizo <77708265+lizandrogd@users.noreply.github.com> Date: Thu, 13 Aug 2026 12:02:54 -0500 Subject: [PATCH] =?UTF-8?q?feat(studio):=20redise=C3=B1o=20con=20design=20?= =?UTF-8?q?tokens,=20pantalla=20de=20consumo=20y=20rename=20a=20Studio?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit El SPA pasa a llamarse uMind Studio y vive en /studio (el nombre "Orquestador" no le decía nada al cliente final, que ahora es quien lo usa). Diseño: - Los colores viven una sola vez como variables CSS + clases semánticas (.card, .input, .btn-*, .badge-*). Antes cada elemento repetía el par claro/oscuro a mano en cientos de lugares y cambiar un tono era buscar y reemplazar. - darkMode pasa de 'media' a 'class' con toggle propio persistido: el usuario elige, no el sistema operativo. Se aplica antes de montar la app para que no parpadee. - Componentes compartidos (UiModal, UiBadge, UiEmptyState) donde antes había markup duplicado inline. Nueva pantalla de consumo (/tenants/:id/uso): filtros por fecha con atajos, total del período, pendiente de facturar, barra contra el tope del plan, desglose por tipo y gráfico por día. El gráfico son divs con altura porcentual — no vale traer una librería de charts para esto. Rename: - /studio y /portal/studio; /orchestrator redirige 301 conservando la ruta interna, así los enlaces guardados siguen funcionando. Los assets del bundle quedan exentos (el `base` de Vite sigue en /orchestrator/): redirigirlos rompería el SPA. - El submódulo sembrado migra el mismo registro buscando por las tres URLs históricas (/app/umind → /orchestrator → /studio) en vez de dejar entradas duplicadas en el menú. Co-Authored-By: Claude Sonnet 5 --- migrations/migrate.go | 15 +- orchestrator/src/App.vue | 16 +- orchestrator/src/components/Sidebar.vue | 56 ++-- orchestrator/src/components/ui/UiBadge.vue | 16 ++ .../src/components/ui/UiEmptyState.vue | 12 + orchestrator/src/components/ui/UiModal.vue | 20 ++ orchestrator/src/lib/contexto.js | 2 +- orchestrator/src/lib/tema.js | 23 ++ orchestrator/src/main.js | 1 + orchestrator/src/router.js | 2 + orchestrator/src/style.css | 85 +++++++ orchestrator/src/views/AgenteDetail.vue | 240 +++++++++--------- orchestrator/src/views/TenantAgentes.vue | 55 ++-- orchestrator/src/views/Uso.vue | 198 +++++++++++++++ orchestrator/tailwind.config.js | 29 ++- public/orchestrator/assets/index-C6K_wyko.css | 1 - public/orchestrator/assets/index-CkF90HJJ.css | 1 + public/orchestrator/assets/index-DP70_OF3.js | 26 ++ public/orchestrator/assets/index-DPluLgCZ.js | 26 -- public/orchestrator/index.html | 4 +- rest/controllers/umind_oauth_controller.go | 8 +- rest/routes/auth.go | 2 +- rest/routes/landing.go | 1 - rest/routes/studio_redirect.go | 18 ++ rest/routes/studio_redirect_test.go | 29 +++ rest/routes/user.go | 23 +- 26 files changed, 685 insertions(+), 224 deletions(-) create mode 100644 orchestrator/src/components/ui/UiBadge.vue create mode 100644 orchestrator/src/components/ui/UiEmptyState.vue create mode 100644 orchestrator/src/components/ui/UiModal.vue create mode 100644 orchestrator/src/lib/tema.js create mode 100644 orchestrator/src/views/Uso.vue delete mode 100644 public/orchestrator/assets/index-C6K_wyko.css create mode 100644 public/orchestrator/assets/index-CkF90HJJ.css create mode 100644 public/orchestrator/assets/index-DP70_OF3.js delete mode 100644 public/orchestrator/assets/index-DPluLgCZ.js create mode 100644 rest/routes/studio_redirect.go create mode 100644 rest/routes/studio_redirect_test.go diff --git a/migrations/migrate.go b/migrations/migrate.go index daf717a..9708a8d 100755 --- a/migrations/migrate.go +++ b/migrations/migrate.go @@ -1297,16 +1297,15 @@ func SeedUmind() { return } // El panel viejo (Alpine, /app/umind) sigue existiendo y respondiendo, pero - // el menú ahora apunta al orquestador (SPA Vue). Si ya existía el submódulo - // apuntando a la URL vieja, se migra en el mismo registro en vez de crear - // uno duplicado. - url := "/orchestrator" - urlVieja := "/app/umind" + // el menú apunta al SPA. La URL pasó por /app/umind → /orchestrator → + // /studio: se busca por cualquiera de las tres y se migra el mismo + // registro, en vez de dejar submódulos duplicados en el menú. + url := "/studio" var sub models.Submodules - if err := db.Where("url = ? OR url = ?", url, urlVieja).First(&sub).Error; err != nil { + if err := db.Where("url IN ?", []string{url, "/orchestrator", "/app/umind"}).First(&sub).Error; err != nil { sub = models.Submodules{ - Title: "uMind", - Description: "Chat con IA embebible por sitio, con base de conocimiento propia (RAG)", + Title: "uMind Studio", + Description: "Creación y gestión de agentes de IA: conocimiento, canales, herramientas y consumo", Url: url, ModuleId: modulo.ID, ModifiedAt: time.Now(), diff --git a/orchestrator/src/App.vue b/orchestrator/src/App.vue index b776b1d..47ec168 100644 --- a/orchestrator/src/App.vue +++ b/orchestrator/src/App.vue @@ -1,12 +1,22 @@