diff --git a/CHANGELOG.md b/CHANGELOG.md
index 5c0d089..8b3ed06 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,11 @@
# Changelog - project.linkedcorp.net
+## [4.0.3] - 2026-10-23
+### Fixed
+- Las consultas a la IA ("Nuevo con IA" y "Plan con IA") muestran un indicador de proceso con
+ spinner, mensaje y segundos transcurridos (componente compartido `BusyPanel`); antes parecía
+ que el botón no hacía nada mientras la IA respondía.
+
## [4.0.2] - 2026-10-23
### Changed
- Detección de proyectos duplicados en "Nuevo con IA" ahora la decide la IA, dentro de la misma
diff --git a/VERSION b/VERSION
index 4d54dad..c4e41f9 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-4.0.2
+4.0.3
diff --git a/backend/package.json b/backend/package.json
index f67cbe7..3d45691 100644
--- a/backend/package.json
+++ b/backend/package.json
@@ -1,6 +1,6 @@
{
"name": "project-linkedcorp-backend",
- "version": "4.0.2",
+ "version": "4.0.3",
"private": true,
"type": "module",
"main": "src/server.js",
diff --git a/frontend/package.json b/frontend/package.json
index e07a69b..c1bf081 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -1,7 +1,7 @@
{
"name": "project-linkedcorp-frontend",
"private": true,
- "version": "4.0.2",
+ "version": "4.0.3",
"type": "module",
"scripts": {
"dev": "vite",
diff --git a/frontend/src/components/BusyPanel.jsx b/frontend/src/components/BusyPanel.jsx
new file mode 100644
index 0000000..0d1b271
--- /dev/null
+++ b/frontend/src/components/BusyPanel.jsx
@@ -0,0 +1,20 @@
+import { useEffect, useState } from 'react';
+
+// Indicador de proceso largo (ej. consultas a la IA): spinner, mensaje y segundos transcurridos,
+// para que el usuario sepa que el sistema esta trabajando y no colgado.
+export function BusyPanel({ message, hint }) {
+ const [seconds, setSeconds] = useState(0);
+ useEffect(() => {
+ const id = setInterval(() => setSeconds((s) => s + 1), 1000);
+ return () => clearInterval(id);
+ }, []);
+ return (
+
+
+
+
{message} ({seconds}s)
+ {hint &&
{hint}
}
+
+
+ );
+}
diff --git a/frontend/src/i18n/messages.js b/frontend/src/i18n/messages.js
index bad0c39..ac81196 100644
--- a/frontend/src/i18n/messages.js
+++ b/frontend/src/i18n/messages.js
@@ -26,6 +26,9 @@ export const messages = {
ai_plan_generating: 'Generando...',
ai_plan_review: 'Desmarca lo que no quieras. Las actividades se crean encadenadas desde hoy, con prioridad media; luego puedes editarlas.',
ai_plan_days: 'días',
+ ai_busy_generating: 'La IA está preparando la propuesta...',
+ ai_busy_hint: 'Suele tardar entre 5 y 30 segundos. No cierres esta ventana.',
+ ai_busy_creating: 'Creando actividades y tareas...',
ai_plan_day: 'día',
ai_plan_apply: 'Crear seleccionadas',
ai_plan_creating: 'Creando...',
@@ -588,6 +591,9 @@ export const messages = {
ai_plan_generating: 'Generating...',
ai_plan_review: 'Uncheck what you do not want. Activities are created back to back from today with medium priority; you can edit them later.',
ai_plan_days: 'days',
+ ai_busy_generating: 'AI is preparing the proposal...',
+ ai_busy_hint: 'It usually takes 5 to 30 seconds. Do not close this window.',
+ ai_busy_creating: 'Creating activities and tasks...',
ai_plan_day: 'day',
ai_plan_apply: 'Create selected',
ai_plan_creating: 'Creating...',
diff --git a/frontend/src/pages/Proyectos/AiPlanDialog.jsx b/frontend/src/pages/Proyectos/AiPlanDialog.jsx
index 995c3fb..1959ee4 100644
--- a/frontend/src/pages/Proyectos/AiPlanDialog.jsx
+++ b/frontend/src/pages/Proyectos/AiPlanDialog.jsx
@@ -4,6 +4,7 @@ import { DetailPopup } from '../../components/DetailPopup.jsx';
import { Button } from '../../components/Button.jsx';
import { Field } from '../../components/Field.jsx';
import { InfoBar } from '../../components/InfoBar.jsx';
+import { BusyPanel } from '../../components/BusyPanel.jsx';
import { useUi } from '../../context/ui-context.jsx';
import { generateProjectPlan, applyProjectPlan } from '../../services/ai.js';
@@ -54,6 +55,7 @@ export function AiPlanDialog({ open, projectId, onClose, onCreated }) {
return (
{} : close} width={720} height={620}>
{error && {error}}
+ {busy && }
{!plan ? (
<>
{t('ai_plan_hint')}
diff --git a/frontend/src/pages/Proyectos/NewProjectAiDialog.jsx b/frontend/src/pages/Proyectos/NewProjectAiDialog.jsx
index faac9ee..246bb12 100644
--- a/frontend/src/pages/Proyectos/NewProjectAiDialog.jsx
+++ b/frontend/src/pages/Proyectos/NewProjectAiDialog.jsx
@@ -5,6 +5,7 @@ import { Button } from '../../components/Button.jsx';
import { Field, FieldRow } from '../../components/Field.jsx';
import { ComboBox } from '../../components/ComboBox.jsx';
import { InfoBar } from '../../components/InfoBar.jsx';
+import { BusyPanel } from '../../components/BusyPanel.jsx';
import { useUi } from '../../context/ui-context.jsx';
import { useAuth } from '../../context/auth-context.jsx';
import { proposeNewProject, createNewProject } from '../../services/ai.js';
@@ -71,6 +72,7 @@ export function NewProjectAiDialog({ open, deptOptions, minLength = 20, onClose,
return (
{error && {error}}
+ {busy && }
{!proposal ? (
<>
diff --git a/frontend/src/styles/app.css b/frontend/src/styles/app.css
index e3fa47f..c003f7f 100644
--- a/frontend/src/styles/app.css
+++ b/frontend/src/styles/app.css
@@ -575,3 +575,9 @@ table.list-table { width: 100%; border-collapse: collapse; font-size: .8rem; }
.text-muted { color: rgb(var(--muted)); }
.mt-0 { margin-top: 0; }
.empty-state { text-align: center; padding: 40px 16px; color: rgb(var(--muted)); }
+
+/* BusyPanel: proceso largo en curso (consultas a la IA) */
+.busy-panel { display: flex; align-items: center; gap: 14px; padding: 16px; margin: 12px 0; border-radius: 8px; background: rgb(var(--accent) / .08); border: 1px solid rgb(var(--accent) / .3); }
+.busy-spinner { width: 28px; height: 28px; flex: none; border-radius: 50%; border: 3px solid rgb(var(--accent) / .25); border-top-color: rgb(var(--accent)); animation: update-spin .9s linear infinite; }
+.busy-message { font-weight: 600; }
+.busy-hint { font-size: .78rem; margin-top: 2px; }