feat(studio): muestra el cupo de agentes del plan en pantalla
Se podían crear 2 agentes con un plan de 1 sin que nada lo explicara. El
límite del backend sí funciona, pero solo aplica si el tenant tiene un
plan asignado — y hasta 115f167 los campos Cliente y Plan no aparecían en
el formulario del tenant, así que en la práctica quedaban todos sin plan
y sin límite.
El problema de fondo era que ese estado no se veía por ningún lado: un
tenant sin plan se comportaba igual que un límite roto.
- La lista de agentes devuelve también el plan y cuántos hay usados.
- La pantalla muestra "Básico · 1 de 1", "Pro · ilimitado" o "sin plan ·
sin límite", y en este último caso explica que hay que asignarle uno.
- El botón + Nuevo agente se deshabilita al llegar al tope, en vez de
dejar que el límite aparezca recién como un error al guardar.
El backend sigue siendo la autoridad: esto es feedback, no la validación.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
5c931c9400
commit
45f773fb62
@@ -17,6 +17,24 @@ const showForm = ref(false)
|
||||
const editing = ref(null)
|
||||
const form = ref(vacio())
|
||||
|
||||
const plan = ref(null)
|
||||
|
||||
// max_agentes 0 = ilimitado. Sin plan asignado tampoco hay límite: es
|
||||
// deliberado (los tenants que existían antes de los planes no se rompen),
|
||||
// pero hay que decirlo, o parece que el límite está fallando.
|
||||
const cupo = computed(() => {
|
||||
if (!plan.value) return { sinPlan: true }
|
||||
const max = plan.value.max_agentes || 0
|
||||
return {
|
||||
sinPlan: false,
|
||||
nombre: plan.value.nombre,
|
||||
ilimitado: max <= 0,
|
||||
max,
|
||||
usados: agentes.value.length,
|
||||
lleno: max > 0 && agentes.value.length >= max,
|
||||
}
|
||||
})
|
||||
|
||||
function vacio() {
|
||||
return { nombre: '', ai_config_id: null, tono: '', mensaje_bienvenida: '', color: '#8eb02f', activo: true }
|
||||
}
|
||||
@@ -31,6 +49,7 @@ async function cargar() {
|
||||
])
|
||||
tenant.value = (t.items || []).find((x) => String(x.ID) === props.id) || null
|
||||
agentes.value = a.items || []
|
||||
plan.value = a.plan || null
|
||||
aiConfigs.value = ai.items || []
|
||||
} catch (e) {
|
||||
error.value = e.message
|
||||
@@ -96,9 +115,22 @@ onMounted(cargar)
|
||||
<p v-if="error" class="text-sm text-red-600 dark:text-red-400 mb-4">{{ error }}</p>
|
||||
|
||||
<div class="flex items-center justify-between mb-4">
|
||||
<h2 class="text-sm font-medium text-tenue">Agentes</h2>
|
||||
<button class="btn-primary" @click="nuevoAgente">+ Nuevo agente</button>
|
||||
<div class="flex items-center gap-2">
|
||||
<h2 class="text-sm font-medium text-tenue">Agentes</h2>
|
||||
<span v-if="cupo.sinPlan" class="badge-alerta">sin plan · sin límite</span>
|
||||
<span v-else-if="cupo.ilimitado" class="badge-neutro">{{ cupo.nombre }} · ilimitado</span>
|
||||
<span v-else :class="cupo.lleno ? 'badge-alerta' : 'badge-neutro'">
|
||||
{{ cupo.nombre }} · {{ cupo.usados }} de {{ cupo.max }}
|
||||
</span>
|
||||
</div>
|
||||
<button class="btn-primary" :disabled="cupo.lleno" @click="nuevoAgente">+ Nuevo agente</button>
|
||||
</div>
|
||||
<p v-if="cupo.sinPlan && !contexto.esPortal" class="text-xs text-tenue -mt-2 mb-4">
|
||||
Este tenant no tiene plan asignado, así que no se le aplica ningún límite de agentes. Asignale uno desde el lápiz del tenant en la barra izquierda.
|
||||
</p>
|
||||
<p v-else-if="cupo.lleno" class="text-xs text-tenue -mt-2 mb-4">
|
||||
Alcanzaste el máximo de agentes de tu plan.
|
||||
</p>
|
||||
|
||||
<div class="card divide-y divide-borde overflow-hidden">
|
||||
<UiEmptyState
|
||||
|
||||
Reference in New Issue
Block a user