diff --git a/docs/CHANGELOG-AGENTS.md b/docs/CHANGELOG-AGENTS.md index 2a20040d..fdd22a32 100644 --- a/docs/CHANGELOG-AGENTS.md +++ b/docs/CHANGELOG-AGENTS.md @@ -4,6 +4,8 @@ Conteúdo movido do `AGENTS.md` em 2026-07-30 (fatiamento do paradigma de agente --- +**C145 — editor de permissão do assessor em modal central (desktop) + bottom drawer (mobile) no lugar do popover (2026-08-23):** na lista de assessores (`/campanha/assessores`), o badge "Permissão" abria o editor Visão × Edição num popover ancorado que estourava o viewport (tabela `min-w-[56rem]` com scroll horizontal). Troca do invólucro contida em `AdvisorPermissionBadge.tsx` (ponto único dos dois usos — linha de dados com `advisorId`+`formAction` e linha de rascunho com `onDraftChange` local): o badge agora abre um **Dialog central** no desktop e um **bottom drawer** no celular, selecionados por `useNarrowMeasured(640)` vivendo no próprio badge (não na tabela). O `AdvisorPermissionEditor` entra com props idênticas às de hoje — mesmos combos Visão/Edição (`advisor-permission-visibility`/`advisor-permission-editing`), nota, footer Cancelar/Salvar e regras de coerência intactos; `onSaved`/`onCancel` fecham o overlay e o badge reflete o novo perfil; a linha de rascunho segue via `onDraftChange` local, sem escrita nova no servidor. A11y: `DialogTitle`/`DrawerTitle` sr-only "Permissão da conta" cumprem o Radix sem duplicar o heading visível do editor; guards de altura (`max-h-[calc(100dvh-2rem)]`+scroll no dialog, capa do drawer) garantem o "nunca estoura" do aceite. Editor embutido no detalhe `assessores/[id]/page.tsx` intocado; import de `Popover` removido. Débito adiado com gatilho: o padrão "Dialog/Drawer keyed em `isNarrow`" se repete em >3 overlays — extrair primitivo `ResponsiveSheet` só quando uma 3ª superfície precisar do mesmo wrapper. Verificação: lint/typecheck/unit + int 830 verdes; `gate:push` na entrega; PR em main com auto-merge. + **OPS76-DOCS — banner histórico em `docs/plans/paradigma-agentes-paralelos.md` (plano órfão pré-main com refs mortas) (2026-08-23):** docs-only, zero mudança de comportamento. Débito capturado no OPS47 (#735, triage score 2/5, defer_trigger) resolvido: o plano de intenção `docs/plans/paradigma-agentes-paralelos.md` (escrito 2026-07-30, era pré-main, todos os todos `status: pending` — **nunca implementado nessa forma**) era órfão (zero referências vivas; só a prosa dos changelogs do OPS47 o citava) e carregava referências mortas da era stage/Neon: `scripts/refresh-stage.mjs` (deletado 2026-08-01), Neon/stage (`STAGE_DATABASE_URL`, branch git `stage`, `ci-stage.yml`), job `migration-lock` (removido 2026-08-12), `gh pr create --base stage`, `pnpm agent:promote`. **Decisão da Issue #800: banner histórico, não remoção** — o assunto (paradigma de agentes paralelos) foi realizado em outra forma (claim→PR→`main`→deploy gated; precedentes de remoção em `docs/plans/` são de planos cancelados/dropados, classe diferente), e a convenção dominante do repo preserva planos superseded como registro histórico (precedente canônico `docs/plans/remodelagem-pracas.md:3`). **Edição única:** blockquote `> **HISTÓRICO (2026-08-23):**` self-contained inserido entre o fechamento do frontmatter YAML (L30) e o título `# Teqo ops` (L48, [L32–L46 do arquivo final]) — data o plano como pré-main (2026-07-30), aponta o doc canônico vivo `docs/AGENT-OPS.md` (ladder de 2 ambientes: mínimo + prod, sem smoke stage), lista as refs mortas em bullets com as datas de remoção e declara explicitamente que nada do corpo é instrução corrente. **Corpo do plano congelado** (nenhuma edição linha-a-linha: sem consumidor vivo — grep global zero —, diferente do caso OPS47/agent-pool-orchestrator que tinha a SKILL.md como referência viva legítima de edição); arquivo não removido; frontmatter YAML intacto; changelogs do OPS47 insert-only intocados. Sem migration/access/Consent/UI/schema. Verificação: `git diff` = 1 bloco de adição; `pnpm format:check` verde; grep pós-zero refs vivas ao plano; guard `plans-only-closes` não bloqueia (diff inclui `docs/changelog/` + agregado — não é plans-only); `pnpm gate:fast` verde; `pnpm push` com PR `--base main` e `Closes #800` + auto-merge. **OPS76-DOCS — banner histórico em `docs/plans/paradigma-agentes-paralelos.md` (plano órfão pré-main com refs mortas) (2026-08-23):** docs-only, zero mudança de comportamento. Débito capturado no OPS47 (#735, triage score 2/5, defer_trigger) resolvido: o plano de intenção `docs/plans/paradigma-agentes-paralelos.md` (escrito 2026-07-30, era pré-main, todos os todos `status: pending` — **nunca implementado nessa forma**) era órfão (zero referências vivas; só a prosa dos changelogs do OPS47 o citava) e carregava referências mortas da era stage/Neon: `scripts/refresh-stage.mjs` (deletado 2026-08-01), Neon/stage (`STAGE_DATABASE_URL`, branch git `stage`, `ci-stage.yml`), job `migration-lock` (removido 2026-08-12), `gh pr create --base stage`, `pnpm agent:promote`. **Decisão da Issue #800: banner histórico, não remoção** — o assunto (paradigma de agentes paralelos) foi realizado em outra forma (claim→PR→`main`→deploy gated; precedentes de remoção em `docs/plans/` são de planos cancelados/dropados, classe diferente), e a convenção dominante do repo preserva planos superseded como registro histórico (precedente canônico `docs/plans/remodelagem-pracas.md:3`). **Edição única de ~9 linhas:** blockquote `> **HISTÓRICO (2026-08-23):**` self-contained inserido entre o fechamento do frontmatter YAML (L30) e o título `# Teqo ops` (L32) — data o plano como pré-main (2026-07-30), aponta o doc canônico vivo `docs/AGENT-OPS.md` (ladder de 2 ambientes: mínimo + prod, sem smoke stage), lista as refs mortas com as datas de remoção e declara explicitamente que nada do corpo é instrução corrente. **Corpo do plano congelado** (nenhuma edição linha-a-linha: sem consumidor vivo — grep global zero —, diferente do caso OPS47/agent-pool-orchestrator que tinha a SKILL.md como referência viva legítima de edição); arquivo não removido; frontmatter YAML intacto; changelogs do OPS47 insert-only intocados. Sem migration/access/Consent/UI/schema. Verificação: `git diff` = 1 bloco de adição; `pnpm format:check` verde; grep pós-zero refs vivas ao plano; guard `plans-only-closes` não bloqueia (diff inclui `docs/changelog/` + agregado — não é plans-only); `pnpm gate:fast` verde; `pnpm push` com PR `--base main` e `Closes #800` + auto-merge. diff --git a/docs/changelog/2026-08-23-c145.md b/docs/changelog/2026-08-23-c145.md new file mode 100644 index 00000000..811f76b6 --- /dev/null +++ b/docs/changelog/2026-08-23-c145.md @@ -0,0 +1 @@ +**C145 — editor de permissão do assessor em modal central (desktop) + bottom drawer (mobile) no lugar do popover (2026-08-23):** na lista de assessores (`/campanha/assessores`), o badge "Permissão" abria o editor Visão × Edição num popover ancorado que estourava o viewport (tabela `min-w-[56rem]` com scroll horizontal). Troca do invólucro contida em `AdvisorPermissionBadge.tsx` (ponto único dos dois usos — linha de dados com `advisorId`+`formAction` e linha de rascunho com `onDraftChange` local): o badge agora abre um **Dialog central** no desktop e um **bottom drawer** no celular, selecionados por `useNarrowMeasured(640)` vivendo no próprio badge (não na tabela). O `AdvisorPermissionEditor` entra com props idênticas às de hoje — mesmos combos Visão/Edição (`advisor-permission-visibility`/`advisor-permission-editing`), nota, footer Cancelar/Salvar e regras de coerência intactos; `onSaved`/`onCancel` fecham o overlay e o badge reflete o novo perfil; a linha de rascunho segue via `onDraftChange` local, sem escrita nova no servidor. A11y: `DialogTitle`/`DrawerTitle` sr-only "Permissão da conta" cumprem o Radix sem duplicar o heading visível do editor; guards de altura (`max-h-[calc(100dvh-2rem)]`+scroll no dialog, capa do drawer) garantem o "nunca estoura" do aceite. Editor embutido no detalhe `assessores/[id]/page.tsx` intocado; import de `Popover` removido. Débito adiado com gatilho: o padrão "Dialog/Drawer keyed em `isNarrow`" se repete em >3 overlays — extrair primitivo `ResponsiveSheet` só quando uma 3ª superfície precisar do mesmo wrapper. Verificação: lint/typecheck/unit + int 830 verdes; `gate:push` na entrega; PR em main com auto-merge. diff --git a/docs/plans/permissao-assessores-modal-central-impl.md b/docs/plans/permissao-assessores-modal-central-impl.md new file mode 100644 index 00000000..85a8e460 --- /dev/null +++ b/docs/plans/permissao-assessores-modal-central-impl.md @@ -0,0 +1,75 @@ +# Impl: Assessores — editor de permissão em modal central (desktop) + bottom drawer (mobile) no lugar do popover + +Status: rascunho +Atualizado em: 2026-08-23 +Issue: #813 +Intenção: docs/plans/permissao-assessores-modal-central.md +Appetite restante: herdado (~0,5–1 dia eng) + +## Leitura da intenção + +- **Outcome**: na `/campanha/assessores`, tocar no badge "Permissão" abre o editor Visão × Edição num overlay **centralizado que nunca estoura o viewport** — Dialog central no desktop, bottom drawer no celular. Só o invólucro muda; o editor, os combos, a nota e as regras de coerência do C141 ficam intactos. Salvar fecha o overlay e o badge reflete o novo perfil; a linha de assessor de rascunho segue usando `onDraftChange` local. +- **O que NÃO negociar**: editor intocado (inclusive footer Cancelar condicional + Salvar e ids `advisor-permission-visibility`/`advisor-permission-editing`); `aria-label="Permissão de ${advisorName}"` do badge preservado; editor embutido no detalhe do assessor (`[id]/page.tsx`) não participa; nenhuma escrita nova no banco (acesso/transações N/A); sinal de breakpoint **vive no badge/overlay, não na tabela**. +- **O que reavaliar**: nada de produtividade aberto — bottom drawer, "salvar fecha" e footer mantido foram assumidos na intenção. Reavaliar só decisões técnicas caras (a11y do Dialog, onde mora o `isNarrow`, guarda de altura) — detalhadas abaixo. + +## Abordagem recomendada + +```mermaid +flowchart TD + A[AdvisorPermissionBadge: botão + estado open local] --> B{useNarrowMeasured 640} + B -- isNarrow true --> C[Drawer bottom swipeDirection=down] + B -- isNarrow false --> D[Dialog central] + C --> E[AdvisorPermissionEditor
props hoje-idênticas + onSaved/onCancel => setOpen false] + D --> E + E --> F[Salvar => onSaved => overlay fecha
badge reflete; onDraftChange mantido] +``` + +**Opções consideradas:** A (manter Popover) | B (`isNarrow` passado por prop a partir da `AdvisorsTable`) | C (troca do invólucro **dentro** do `AdvisorPermissionBadge`, `isNarrow` via hook no próprio badge) — **recomendada C**. + +**Rejeitadas (só decisões caras):** + +- **A — manter Popover.** É o status quo que estoura o viewport; a tabela `min-w-[56rem]` com scroll horizontal é exatamente o sintoma que o outcome manda matar. Rejeitada pela intenção. +- **B — `isNarrow` em cada call site / prop do host.** Forçaria `AdvisorsTable` a conhecer o breakpoint e a passar o sinal nos dois usos (dados ~473 e rascunho ~351) — é o rabbit hole "estado responsivo na tabela" que a intenção manda cortar; o sinal pertence ao invólucro. Rejeitada. +- _(Não considerada: componente two-in-one responsivo novo — não pedido; a troca fica no arquivo do badge.)_ + +### Componentes / mudanças + +- **`AdvisorPermissionBadge.tsx`** (`src/components/campaign/advisor/`): o único arquivo alterado. Troca o wrapper `Popover` por `isNarrow ? : `; adiciona `useNarrowMeasured(640)` no badge; mantém o ` - - - setOpen(false)} - onCancel={() => setOpen(false)} - /> - - + <> + + + {isNarrow ? ( + + + + {OVERLAY_TITLE} + +
{editor}
+
+
+ ) : ( + + + + {OVERLAY_TITLE} + + {editor} + + + )} + ) }