From 63e650ed664451d1b368b31358fb623c58c1aac4 Mon Sep 17 00:00:00 2001 From: Gemini Date: Mon, 13 Jul 2026 15:56:37 -0300 Subject: [PATCH] KB-PLUGIN-043: padroes de UX de card kanban (anatomia nativa, own_ticket, is_private, TTR, prioridade, gotchas CSS/JS) Aprendizados do mindscrum 0.7.0-0.9.0. Co-Authored-By: Claude Fable 5 --- index.json | 23 +++++ ...UGIN-043-glpi11-kanban-card-ux-patterns.md | 98 +++++++++++++++++++ 2 files changed, 121 insertions(+) create mode 100644 records/plugin-dev/KB-PLUGIN-043-glpi11-kanban-card-ux-patterns.md diff --git a/index.json b/index.json index 1c317b5..afa1010 100755 --- a/index.json +++ b/index.json @@ -826,6 +826,29 @@ "severity": "high", "path": "records/plugin-dev/KB-PLUGIN-042-glpi11-effective-duration-overwrite-native-effort-rollup.md", "summary": "id: KB-PLUGIN-042" + }, + { + "id": "KB-PLUGIN-043", + "title": "\"GLPI 11 — Padrões de UX de card kanban em plugin: anatomia do card nativo, own_ticket, is_private, TTR, cores de prioridade e gotchas de CSS\"", + "domain": "plugin-dev", + "tags": [ + "glpi11", + "plugin", + "kanban", + "card", + "ux", + "own-ticket", + "itilfollowup", + "time-to-resolve", + "priority", + "css", + "gotcha", + "mindscrum" + ], + "status": "active", + "severity": "medium", + "path": "records/plugin-dev/KB-PLUGIN-043-glpi11-kanban-card-ux-patterns.md", + "summary": "id: KB-PLUGIN-043" } ] } diff --git a/records/plugin-dev/KB-PLUGIN-043-glpi11-kanban-card-ux-patterns.md b/records/plugin-dev/KB-PLUGIN-043-glpi11-kanban-card-ux-patterns.md new file mode 100644 index 0000000..318c45a --- /dev/null +++ b/records/plugin-dev/KB-PLUGIN-043-glpi11-kanban-card-ux-patterns.md @@ -0,0 +1,98 @@ +--- +id: KB-PLUGIN-043 +title: "GLPI 11 — Padrões de UX de card kanban em plugin: anatomia do card nativo, own_ticket, is_private, TTR, cores de prioridade e gotchas de CSS" +domain: plugin-dev +tags: + - glpi11 + - plugin + - kanban + - card + - ux + - own-ticket + - itilfollowup + - time-to-resolve + - priority + - css + - gotcha + - mindscrum +status: active +severity: medium +created_at: 2026-07-13 +updated_at: 2026-07-13 +applies_to: + - GLPI 11.0.8 dev + - plugin mindscrum 0.7.0–0.9.0 +related_records: + - KB-PLUGIN-040 + - KB-PLUGIN-041 + - KB-PLUGIN-042 +--- + +# GLPI 11 — Padrões de UX de card kanban em plugin (aprendizados mindscrum 0.7–0.9) + +## Anatomia do card do Kanban NATIVO (receita para replicar) + +Fonte: `Project::getKanbanColumns()` + Vue `Kanban-Card` (compilado em +`public/build/vue/vue-sfc/`). O card nativo carrega: +- `title`; **descrição** via `RichText::getTextFromHtml($content)` (em `_metadata`); +- **link do pai** ("Subtask of X") → `getFormURLWithID` do pai; +- contador "x / y tasks complete" a partir de `_steps` (`percent_done === 100`); +- **barra de progresso** `Html::progress(100, $percent)` (Tabler `.progress`); +- `_team` (badges de membros), `due_date` = `Html::convDateTime(plan_end_date)`; +- `_form_link`; hooks de plugin `PRE/POST_KANBAN_CONTENT` e `KANBAN_ITEM_METADATA`. + +Replicar server-side com queries EM LOTE (1 p/ equipes, 1 p/ contagens +`COUNT/SUM(GROUPBY)`, 1 p/ pais via join, 1 p/ nomes de usuários) — sem N+1. + +## Técnicos elegíveis para atribuição (dropdown nativo) + +`User::getSqlSearchResult(false, 'own_ticket', $entities_id, 0, [], '', 0, $limit)` +→ retorna o **iterator** pronto. `'own_ticket'` é o right que o próprio core usa +para o ator "atribuído" de Ticket (exclui contas só-requisitantes). Para equipe de +projeto, right `'all'` na entidade do projeto. + +## Followup privado (nota "só técnico") + +`ITILFollowup` nativo: campo `is_private`; right `followup` com +`ITILFollowup::SEEPRIVATE`. Visibilidade: privada aparece só para o AUTOR ou quem +tem SEEPRIVATE — replicar esse filtro ao listar followups por fora da API padrão. + +## time_to_resolve (prazo/SLA manual) + +- `Ticket` NÃO tem data prevista de início nativa. Datas do chamado: `date` + (abertura), `time_to_resolve`, `time_to_own` (+ `internal_*`). Início planejado + vive nas tasks (`TicketTask.begin/end`, `ProjectTask.plan_*`). +- `time_to_resolve` aceita valor manual no `add()`/`update()` — herdar + `plan_end_date` da task de projeto ao criar chamado dá visão de estouro "de graça". +- ⚠️ **Gotcha:** o core DESCARTA SILENCIOSAMENTE `time_to_resolve` anterior à data + de abertura (`update()` retorna true e o campo fica null). Em testes, usar + abertura retroativa (`date` no input do add) para simular estouro. +- Barrinha de "SLA": `% = (now - date) / (time_to_resolve - date)`, capado em 100. + +## Cores/ícones de prioridade + +Cores nativas configuráveis em `$CFG_GLPI['priority_1'..'priority_6']` +(tons de vermelho claro — são cores de FUNDO). Para UI discreta, preferir ícone +Tabler + tooltip (`getPriorityName`): chevrons (baixas), `ti-equal` (média), +`ti-exclamation-circle`/`ti-alert-triangle`/`ti-alert-octagon` (altas). + +## Gotchas de CSS/JS em modal custom + +- **Keyframe que anima `transform` SUBSTITUI o transform do elemento** durante a + animação: se a centralização usa `translate(-50%,-50%)`, o elemento "nasce" + deslocado e pula ao final. Solução: centralizar com flex no wrapper + (`position:fixed; inset:0; display:flex`) e deixar o keyframe só com scale. +- Flatpickr com `altInput`: estilizar via `altInputClass` (o input visível é NOVO; + regras no input original não pegam) — senão o layout quebra. +- `.catch()` de `fetch(...).then(render)` captura exceções do RENDER também — um + erro de JS no template do modal aparece como se fosse falha de rede/endpoint. + (Sintoma clássico: "modal funciona pra um itemtype e não pra outro".) +- Popover/sub-modal empilhado sobre modal custom: z-index acima (1070+) e Esc + tratado em pilha (fecha o de cima primeiro). + +## Espelhamento de descrição (padrão mindscrum) + +Spawn task→chamado importa título + `content` (texto via RichText) + prazo. A +seção "Descrição" do modal aponta para a FONTE: projeto → `Project.content`; +chamado → `ProjectTask.content` da task de origem (fallback: do chamado). Editar +grava na fonte via `update()` — allowlist de itemtype/campo no endpoint.