feat(agents): widget de status na topbar (entrar/pausar/retomar/sair)
Achado real reportado pelo usuário: "não achei como deixar o agente
online, tem algum perfil ou tipo de usuario especifico?" — não era
permissão nenhuma. POST /agents/me/login|pause|resume|logout sempre
funcionaram sem exigir permissão (só JwtAuthGuard, resolvem "meu
agente" pelo userId do próprio token). O problema: nenhuma tela chamava
esses endpoints — só existia o CRUD admin de Agentes (criar o vínculo
usuário+ramal), nunca um controle pro próprio usuário logado.
Adicionado GET /agents/me (404 = usuário sem Agent neste tenant, não um
erro — é assim que o widget decide se aparece) e GET /agents/me/pause-
reasons (motivos de pausa sem exigir agents.view, que listaria TODOS os
agentes do tenant — permissão que o role "agent" nunca teve e não devia
ganhar só pra isso).
AgentStatusWidget na topbar (visível em qualquer página do app do
tenant) só aparece pra quem tem Agent vinculado: Offline -> Entrar ->
Disponível -> Pausar (escolhe motivo) -> Em pausa -> Retomar/Sair.
Achado real construindo o widget: as Server Actions de login/logout/
pause/resume exportadas como arrow function que só repassavam
argumentos quebravam em runtime ("Server Actions must be async
functions") — o mesmo bug já documentado antes nesta sessão (wizard de
campanhas). Corrigido declarando como async function de verdade.
Testado ponta a ponta com Playwright, logado como um agente de teste
real (usuário novo, role "agent", Agent vinculado a um ramal real): o
fluxo completo (entrar/pausar/retomar/sair) funciona pela tela, sem
nenhuma chamada de API manual.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BFaBaBSQGhyXGEgtTYZGV8
This commit is contained in:
@@ -3,6 +3,7 @@ import {
|
||||
Body,
|
||||
Controller,
|
||||
ForbiddenException,
|
||||
Get,
|
||||
NotFoundException,
|
||||
Post,
|
||||
UseGuards,
|
||||
@@ -35,6 +36,41 @@ async function findMyAgent(tx: Prisma.TransactionClient, tenantId: string, userI
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@Controller("agents/me")
|
||||
export class AgentsMeController {
|
||||
/**
|
||||
* Achado real reportado pelo usuário: "não achei como deixar o agente
|
||||
* online" — os endpoints de login/pausa/logout sempre existiram, mas
|
||||
* não tinha nenhum jeito do frontend saber SE o usuário logado tem um
|
||||
* Agent vinculado (pra mostrar o controle) nem qual o estado atual.
|
||||
* 404 aqui = usuário sem Agent neste tenant, não um erro — é assim que
|
||||
* o widget da topbar decide se aparece ou não.
|
||||
*/
|
||||
@Get()
|
||||
async me(@CurrentUser() user: AccessTokenClaims) {
|
||||
const prisma = getPrismaClient();
|
||||
const tenantId = user.tenantId!;
|
||||
const agent = await withTenantContext(prisma, tenantId, (tx) => findMyAgent(tx, tenantId, user.sub));
|
||||
return {
|
||||
id: agent.id,
|
||||
name: agent.name,
|
||||
state: agent.state,
|
||||
enabled: agent.enabled,
|
||||
hasExtension: agent.extensionId != null,
|
||||
};
|
||||
}
|
||||
|
||||
/** Motivos de pausa pro próprio agente escolher — sem exigir
|
||||
* `agents.view` (que listaria TODOS os agentes do tenant, permissão
|
||||
* que o role "agent" nunca precisou ter até aqui). */
|
||||
@Get("pause-reasons")
|
||||
async pauseReasons(@CurrentUser() user: AccessTokenClaims) {
|
||||
const prisma = getPrismaClient();
|
||||
const tenantId = user.tenantId!;
|
||||
await withTenantContext(prisma, tenantId, (tx) => findMyAgent(tx, tenantId, user.sub));
|
||||
return withTenantContext(prisma, tenantId, (tx) =>
|
||||
tx.pauseReason.findMany({ where: { tenantId, enabled: true }, orderBy: { name: "asc" } }),
|
||||
);
|
||||
}
|
||||
|
||||
/** Fluxo de login (agente.md secao 47): valida usuário (JWT) e ramal,
|
||||
* cria sessão, configura contact/tiers no FreeSWITCH, fica AVAILABLE. */
|
||||
@Post("login")
|
||||
|
||||
Reference in New Issue
Block a user