New Research: Supply Chain Attack on Axios Pulls Malicious Dependency from npm.Details →
Socket
Book a DemoSign in
Socket

@praxisui/table

Package Overview
Dependencies
Maintainers
1
Versions
65
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@praxisui/table

Advanced data table for Angular (Praxis UI) with editing, filtering, sorting, virtualization, and settings panel integration.

latest
Source
npmnpm
Version
1.0.0-beta.28
Version published
Maintainers
1
Created
Source

@praxisui/table

🔰 Exemplos / Quickstart

Para ver esta biblioteca em funcionamento em uma aplicação completa, utilize o projeto de exemplo (Quickstart):

  • Repositório: https://github.com/codexrodrigues/praxis-ui-quickstart
  • O Quickstart demonstra a integração das bibliotecas @praxisui/* em um app Angular, incluindo instalação, configuração e uso em telas reais.

Componente de tabela empresarial avançado com arquitetura unificada

🌟 Visão Geral

A biblioteca @praxisui/table fornece um componente de tabela robusto e altamente configurável para aplicações Angular empresariais. Com a nova arquitetura unificada, oferece uma experiência de desenvolvimento simplificada mantendo todos os recursos avançados.

✨ Características Principais

🏗️ Arquitetura Unificada

  • Interface única: TableConfig consolidada
  • Type Safety: Tipagem forte em toda a API
  • Performance otimizada: Eliminação de overhead de adaptação
  • API simplificada: Menos confusão, mais produtividade

📊 Recursos Avançados

  • Paginação inteligente: Client-side e server-side
  • Ordenação múltipla: Suporte a multi-sort
  • Filtros dinâmicos: Global e por coluna
  • Seleção de linhas: Single, multiple e bulk actions
  • Redimensionamento: Colunas redimensionáveis
  • Virtualização: Para grandes volumes de dados
  • Exportação: CSV, Excel, PDF
  • Acessibilidade: WCAG 2.1 AA compliant
  • Verificação de Schema: ETag/If-None-Match com notificações (somente em customização)

🎨 Editores Visuais

  • Behavior Editor: Configuração de comportamentos
  • Columns Editor: Gestão avançada de colunas
  • Toolbar Editor: Personalização de ações
  • Messages Editor: Textos e localização

Nota (Regras)

  • A antiga aba visual genérica foi removida deste pacote. Um editor especializado para regras da Tabela está em desenvolvimento e já pode ser usado no painel de configuração.

🧩 Editor de Regras (column-first)

O novo editor é "column-first" e usa uma tipagem compartilhada com o Editor de Colunas. Principais pontos:

  • Escopo: aplique regras na linha inteira (rowConditionalStyles) ou em uma coluna específica (columns[].conditionalStyles).
  • Operadores por tipo: o conjunto de operadores é filtrado por tipo (string/number/date/boolean/enum).
  • Editores de valor dinâmicos: inputs numéricos, listas (CSV/múltipla seleção), datepickers.
  • Grupos lógicos: construa condições com AND/OR/NOT e reordene via arrastar-e-soltar (CDK DragDrop).
  • Preview: execute “Testar” para ver quantas linhas seriam afetadas pelas regras ativas.
  • Import/Export: exporta JSON sem o campo enabled; importa com validação de DSL e sanitização de estilos (allowlist).

Exemplos de DSL:

contains(status, 'Ativo')
not (status in ['A', 'I'])
(price >= 10 and price <= 20)
(createdAt >= '2024-10-01' and createdAt <= '2024-10-31')
(name == null or name == '')
active == true

Notas sobre enum/CSV:

  • Para campos enumerados, as opções são inferidas de valueMapping da coluna ou de fields?.options.
  • Para in/not in em números/strings, use CSV (ex.: 10, 20, 30 ou Alice, Bob).

Extensões de DSL (JSON/Tempo)

Você pode registrar funções adicionais no DslParser do app host para expressões com JSON e data/tempo.

Exemplo rápido (registro direto):

import { DslParser } from '@praxisui/specification';
import { registerJsonDslFunctions, registerDateDslFunctions } from '@praxisui/table';

const parser = new DslParser<any>();
registerJsonDslFunctions(parser);
registerDateDslFunctions(parser);

Exemplos de DSL:

  • jsonGet(payload, '$.user.name') == 'Alice'
  • hasJsonKey(payload, '$.meta.etag')
  • jsonPathMatches(payload, '$.roles[0]', '^admin$')

Guia completo: projects/praxis-table/docs/DSL-Extensions-Guide.md

🎨 Efeitos (Conteúdo C)

O bloco de Efeitos permite aplicar estilo e visuais quando a condição é verdadeira:

  • Toolbar de texto com ícones (negrito, itálico, sublinhado) e presets rápidos (tachado, maiúsculas/minúsculas/capitalizar, tamanho +/- e reset).
  • Presets de feedback com ícones (sucesso, aviso, erro, info) — mantêm o rótulo via tooltip e aria-label.
  • “Posição do valor” como grupo de alternância (antes / entre-1 / entre-2 / depois / oculto).
  • “Ordem dos visuais” com seletor compacto (3 mais comuns) e menu para opções extras.
  • Layout do compose: espaçamento, alinhamento, quebra de linha e reticências.

Dicas

  • Use “Resetar texto” para reverter efeitos de texto sem perder cor de fundo/borda.
  • Para acessibilidade, os grupos possuem role="toolbar", tooltips e navegação por teclado consistente.

Como reverter efeitos

  • “Reset Text” remove apenas propriedades de tipografia e transformação de texto.
  • “Limpar efeitos” apaga classe e estilo livres do bloco rápido.

Observação: capturas de tela “antes/depois” podem ser adicionadas no PR conforme necessário.

Relacionais (lookup)

Campos relacionais (FK/objetos) podem ser editados no Rules Editor com busca assíncrona (typeahead) e seleção single/multiple.

Boas práticas

  • Informe resourcePath (ou endpoint) no FieldDefinition para habilitar o lookup via GenericCrudService do host.
  • Defina valueField (chave estável, tipicamente id) e displayField (label amigável, como name).
  • Para múltipla seleção, use multiple: true no FieldDefinition quando aplicável.
  • No runtime, registre as funções JSON no parser (ver guia) para que as expressões de ID/JSON funcionem: jsonGet/hasJsonKey/jsonPathMatches.
  • APIs com busca: suporte a um parâmetro livre de texto (por ex. search) facilita a experiência do autocomplete.

Exemplo de FieldDefinition (lookup)

import type { FieldDefinition } from '@praxisui/core';

const fields: FieldDefinition[] = [
  {
    name: 'customer',
    type: 'object',
    // Habilita o lookup via GenericCrudService
    resourcePath: 'customers',
    // Mapeia o id/label que virão do backend
    valueField: 'id',
    displayField: 'name',
    // Se quiser multiseleção em todo o app
    // multiple: true,
  },
];

Operadores e DSL gerada (relacional)

  • id ==jsonGet(customer, '$.id') == 10
  • id injsonGet(customer, '$.id') in [10, 20]
  • has propertyhasJsonKey(customer, '$.meta.etag')
  • Condições por caminho (join simples): use key == (JSON Path + valor)

UI (no editor)

  • id == (single): autocomplete + chip “label [id]” com ação “Limpar”.
  • id in (multi): autocomplete + chips removíveis por item.
  • has property: input do caminho (ex.: $.meta.etag).

Formato esperado do payload (relacional)

Para que o editor/preview e o runtime avaliem corretamente as regras relacionais, o valor do campo deve ser um objeto (ou compatível com JSON) contendo ao menos o identificador e, opcionalmente, propriedades exibidas:

// Exemplo de linha (row) com campo relacional "customer"
const row = {
  id: 123,
  customer: {
    id: 10,          // ← usado em id == / id in via jsonGet(customer, '$.id')
    name: 'ACME',    // ← usado para exibir label no autocomplete/chip
    meta: { etag: 'v1' },
  },
};

// Regras DSL comuns
// id ==
//   jsonGet(customer, '$.id') == 10
// id in
//   jsonGet(customer, '$.id') in [10, 20]
// has property
//   hasJsonKey(customer, '$.meta.etag')
// caminho/valor (join simples)
//   jsonGet(customer, '$.name') == 'ACME'

Notas

  • O editor usa displayField (ex.: name) para compor o rótulo, e valueField (ex.: id) para gerar a DSL.
  • Se o backend devolver o relacionamento já "normalizado" (ex.: customerId e customerName na mesma linha), você ainda pode expressar condições com operadores padrão (==, in) no campo numérico/literal — a abordagem relacional é útil quando o payload contém o objeto.

Onde é consumido (preview e runtime)

  • Preview/validação no Editor de Regras (usa DslParser interno):
    • Validação da expressão (parse): projects/praxis-table/src/lib/rules-editor/table-rules-editor.component.ts:536
    • Preview “Testar” (parse + evaluate): projects/praxis-table/src/lib/rules-editor/table-rules-editor.component.ts:909
  • Runtime na Tabela (aplica rowConditionalStyles/conditionalStyles):
    • Parser interno do componente: projects/praxis-table/src/lib/praxis-table.ts:282

Observação

  • Ao registrar funções via DslParserFactory (ex.: registerJsonDslFunctions/registerDateDslFunctions), use a mesma estratégia para o parser que avalia regras no runtime (Tabela) e para qualquer serviço que precise avaliar DSL. O Editor usa um parser interno para validação/preview; as funções de data já são suportadas por padrão, e as de JSON podem exigir extensão no runtime (ver guia).

Exemplo de Provider (recomendado)

import { Injectable } from '@angular/core';
import { DslParser } from '@praxisui/specification';
import { registerJsonDslFunctions, registerDateDslFunctions } from '@praxisui/table';

@Injectable({ providedIn: 'root' })
export class DslParserFactory {
  private parser: DslParser<any>;

  constructor() {
    this.parser = new DslParser<any>();
    registerJsonDslFunctions(this.parser);
    registerDateDslFunctions(this.parser);
  }

  get(): DslParser<any> {
    return this.parser;
  }
}

// Em um componente/serviço que avalia regras:
// constructor(factory: DslParserFactory) {
//   const parser = factory.get();
//   const spec = parser.parse("jsonGet(payload, '$.user.name') == 'Alice'");
//   const ok = spec.isSatisfiedBy({ payload: { user: { name: 'Alice' } } });
// }

⚙️ Painel de Configurações

Para abrir o painel de configurações, habilite o modo de edição na tabela:

<praxis-table [editModeEnabled]="true"></praxis-table>

Um botão de engrenagem será exibido no canto superior direito. Ao clicar nele, o SettingsPanel é aberto permitindo ajustar:

  • Comportamento: paginação, ordenação, filtros e recursos avançados.
  • Colunas: visibilidade, ordem, largura e estilo.
  • Toolbar: ações e botões da barra de ferramentas.
  • Mensagens: textos e rótulos exibidos na interface.

As alterações podem ser aplicadas temporariamente com Aplicar ou salvas de forma persistente com Salvar & Fechar.

🚀 Instalação

npm install @praxisui/core @praxisui/table

Peers necessários (instale no app host):

  • @angular/core ^20.0.0, @angular/common ^20.0.0
  • @praxisui/core ^0.0.1
  • @praxisui/dynamic-fields ^0.0.1 (quando usar editores/inputs dinâmicos)
  • @praxisui/dynamic-form ^0.0.1 (quando integrar com formulários dinâmicos)
  • @praxisui/settings-panel ^0.0.1 (para painel de configuração embutido)

📝 Uso Básico

Conectando ao Backend com resourcePath

A forma mais poderosa de usar a <praxis-table> é conectá-la diretamente a um endpoint de API compatível com o ecossistema Praxis. Isso é feito através do input resourcePath.

Quando resourcePath é fornecido, a tabela se torna "inteligente":

  • Busca automática de dados: A tabela gerencia a paginação, ordenação e filtros, fazendo as requisições necessárias ao backend.
  • Geração dinâmica de colunas: A tabela busca os metadados (schema) do backend para gerar as colunas automaticamente, respeitando as configurações definidas no praxis-metadata-core (via anotação @UISchema).
<!-- Exemplo no template do seu componente -->
<praxis-table resourcePath="human-resources/departamentos" [editModeEnabled]="true"> </praxis-table>

Neste exemplo:

  • resourcePath="human-resources/departamentos" instrui a tabela a se comunicar com o endpoint /api/human-resources/departamentos.
  • A tabela fará requisições como POST /api/human-resources/departamentos/filter para obter os dados e GET /api/human-resources/departamentos/schemas para obter a configuração das colunas.
  • [editModeEnabled]="true" permite a edição visual da configuração da tabela em tempo real.

Empty State + Quick Connect (sem resourcePath)

Se a tabela for renderizada sem resourcePath, um cartão de "Empty State" é exibido convidando a conectar o componente a um recurso. Basta clicar em "Conectar a recurso" para abrir um painel rápido com um único campo:

resourcePath: ex.: human-resources/departamentos

Ao aplicar/salvar, a <praxis-table> é automaticamente configurada para buscar o schema e os dados do backend. Esse fluxo evita telas em branco e simplifica o onboarding do componente em páginas novas.

Fluxo de Comunicação do resourcePath

O diagrama abaixo ilustra como a propriedade resourcePath conecta o componente frontend ao controller do backend. O fluxo de inicialização ocorre em três etapas principais: Configurar, Carregar Schema e Buscar Dados.

sequenceDiagram
    participant FE_Component as Componente Angular<br>(departamentos.html)
    participant Praxis_Table as @praxisui/table<br>(praxis-table.ts)
    participant Crud_Service as @praxisui/core<br>(generic-crud.service.ts)
    participant BE_Controller as Backend Controller<br>(DepartamentoController.java)
    participant Abstract_Controller as AbstractCrudController

    FE_Component->>Praxis_Table: Usa o componente com <br> <praxis-table resourcePath="human-resources/departamentos">

    activate Praxis_Table
    Praxis_Table->>Praxis_Table: ngOnChanges() detecta o @Input() resourcePath
    Praxis_Table->>Crud_Service: 1. Chama crudService.configure("human-resources/departamentos")

    activate Crud_Service
    Crud_Service->>Crud_Service: Armazena o resourcePath
    deactivate Crud_Service

    Praxis_Table->>Praxis_Table: 2. Chama this.loadSchema()
    Praxis_Table->>Crud_Service: Chama crudService.getSchema()

    activate Crud_Service
    Crud_Service->>Crud_Service: getEndpointUrl('schema') constrói a URL: <br> "/api/human-resources/departamentos/schemas"
    Crud_Service->>BE_Controller: Requisição HTTP GET para .../schemas
    deactivate Crud_Service

    activate BE_Controller
    Note over BE_Controller: @RequestMapping("/human-resources/departamentos")
    BE_Controller->>Abstract_Controller: Herda o método que lida com @GetMapping("/schemas")

    activate Abstract_Controller
    Abstract_Controller->>Abstract_Controller: Gera e retorna o Schema da UI
    Abstract_Controller-->>BE_Controller: Retorna o Schema
    deactivate Abstract_Controller

    BE_Controller-->>Crud_Service: Resposta HTTP com o JSON do Schema
    deactivate BE_Controller

    activate Crud_Service
    Crud_Service-->>Praxis_Table: Retorna um Observable com as<br>definições de colunas (FieldDefinition[])
    deactivate Crud_Service

    Praxis_Table->>Praxis_Table: Constrói as colunas da tabela<br>a partir do schema recebido

    Praxis_Table->>Praxis_Table: 3. Chama this.fetchData()
    Praxis_Table->>Crud_Service: Chama crudService.filter(...) para buscar dados

    activate Crud_Service
    Crud_Service->>Crud_Service: getEndpointUrl('filter') constrói a URL: <br> "/api/human-resources/departamentos/filter"
    Crud_Service->>BE_Controller: Requisição HTTP POST para .../filter
    deactivate Crud_Service

    activate BE_Controller
    BE_Controller->>Abstract_Controller: Herda o método que lida com @PostMapping("/filter")

    activate Abstract_Controller
    Abstract_Controller->>Abstract_Controller: Processa a requisição e busca os dados
    Abstract_Controller-->>BE_Controller: Retorna os dados
    deactivate Abstract_Controller

    BE_Controller-->>Crud_Service: Resposta HTTP com os dados (Page<DepartamentoDTO>)
    deactivate BE_Controller

    activate Crud_Service
    Crud_Service-->>Praxis_Table: Retorna um Observable com os dados
    deactivate Crud_Service

    Praxis_Table->>Praxis_Table: Atualiza o dataSource da tabela com os dados recebidos
    deactivate Praxis_Table

ℹ️ Dicas de UX (Tabela)

  • Multi‑sort: habilite em Comportamento → Ordenação. No uso, mantenha Ctrl/Cmd pressionado ao clicar em múltiplas colunas.
  • Duplo clique na linha: configure em Comportamento → Interação (habilitar e escolha a ação: editar/visualizar/personalizada).
  • Virtualização: habilite em Comportamento → Virtualização para listas grandes (requer altura de linha previsível).
  • Densidade e linhas de grade: ajuste em Comportamento → Aparência rápida (compacta/confortável/espaçosa; bordas horizontais/verticais).

Rolagem Horizontal (owner do scroll)

Por padrão, a <praxis-table> agora assume a responsabilidade pela rolagem horizontal quando o conteúdo excede a largura do container. Isso evita cortes de conteúdo e comportamentos inconsistentes entre projetos.

Input: horizontalScroll

@Input() horizontalScroll: 'auto' | 'wrap' | 'none' = 'auto';
  • auto (padrão): a tabela cria um viewport com overflow-x: auto e permite que a tabela interna cresça com width: max-content. Quando a soma das colunas > container, aparece a barra de rolagem horizontal neste viewport.
  • wrap: permite quebra de linha nas células (libera white-space: normal), reduzindo a largura necessária; ideal quando você prefere minimizar a rolagem horizontal.
  • none: desabilita o comportamento interno; o host (página) deve fornecer o container com overflow-x: auto e as regras de largura necessárias.

Exemplo:

<!-- Comportamento padrão (auto) -->
<praxis-table resourcePath="employees"></praxis-table>

<!-- Reduz rolagem: permite quebra de linha nas células -->
<praxis-table resourcePath="employees" horizontalScroll="wrap"></praxis-table>

<!-- Host controla o scroll horizontal -->
<div class="table-shell" style="overflow-x:auto">
  <praxis-table resourcePath="employees" horizontalScroll="none"></praxis-table>
  <!-- host pode usar width: max-content na tabela interna conforme seu design system -->
</div>

Editor de Configuração (Settings Panel)

Na aba “Visão Geral & Comportamento”, há um seletor “Scroll Horizontal” com as opções Auto, Wrap e Host (none). As alterações podem ser aplicadas (Aplicar) ou salvas (Salvar & Fechar). O valor é persistido junto com outras preferências da tabela.

Notas

  • O caminho virtual (CDK Virtual Scroll) permanece sendo o owner da rolagem vertical; o viewport horizontal é um contêiner externo que não interfere no scroll vertical.
  • Cabeçalho sticky continua funcional. Teste combinações com colunas sticky/virt para seu caso.
  • Para grids alternativos (ex.: Kendo), as mesmas regras de max-content/min-width: 100% se aplicam ao elemento de tabela interno.

Virtualização (CDK)

Quando behavior.virtualization.enabled estiver ativo, as linhas da tabela são renderizadas com cdk-virtual-scroll-viewport (cabeçalho permanece igual).

  • Propriedades:
    • itemHeight: altura da linha (px); padrão 44.
    • bufferSize: itens adicionais de buffer.
    • minContainerHeight: altura mínima do viewport (px ou CSS, ex.: 320 ou 50vh).
    • strategy: fixed | dynamic (atual uso visual não altera lógica de medição).
  • Observação: sticky/pinned em colunas pode ter limitações em conjunto com virtual scroll (mantido sob feature flag; caminho não‑virtual preservado como fallback).

Paginação (posição/estilo)

Concept Usage

Nota sobre estratégia (client vs server)

  • Se behavior.pagination.strategy não estiver definido, a tabela assume server automaticamente quando há resourcePath (dados remotos). Caso contrário, usa client.
  • O mesmo vale para behavior.sorting.strategy.

Duplo clique na linha

Ative em Comportamento → Interação.

  • Output: rowDoubleClick com payload { action: string; row: any }.
  • Ação: edit | view | custom (quando custom, use customAction no Behavior para definir o identificador).

Exemplo de uso (template do host):

<praxis-table
  [config]="tableConfig"
  [resourcePath]="'human-resources/departamentos'"
  (rowDoubleClick)="onRowDoubleClick($event)">
</praxis-table>
onRowDoubleClick(evt: { action: string; row: any }) {
  if (evt.action === 'edit') {
    // abrir editor
  } else if (evt.action === 'view') {
    // abrir detalhe somente leitura
  } else {
    // ação customizada
  }
}

Ordenação inicial (defaultSort)

  • Configure em behavior.sorting.defaultSort.
  • Aceita objeto único (coluna/direção) ou array para multi‑sort.

Exemplos:

sorting: {
  enabled: true,
  strategy: 'server',
  multiSort: false,
  defaultSort: { column: 'nome', direction: 'asc' },
}
sorting: {
  enabled: true,
  strategy: 'server',
  multiSort: true,
  defaultSort: [
    { column: 'status', direction: 'desc' },
    { column: 'nome', direction: 'asc' },
  ],
}

Observação: quando informado, o defaultSort é aplicado na carga inicial se não houver estado de ordenação ativo.

Coluna de ações (sticky)

Nota: por padrão a coluna de ações vem desabilitada. Habilite explicitamente em actions.row.enabled e defina as ações desejadas.

  • Fixe a coluna de ações no início/fim configurando actions.row.sticky:
actions: {
  row: {
    enabled: true,
    sticky: 'end', // true | 'start' | 'end'
    width: '120px',
    actions: [ /* ... */ ],
  },
}

Observação: em modo virtualizado, sticky pode ter limitações dependendo do layout.

Colunas de dados (sticky)

Fixe colunas específicas no início/fim usando columns[].sticky:

columns: [
  { field: 'id', header: 'ID', width: '80px', sticky: 'start' },
  { field: 'nome', header: 'Nome' },
  { field: 'status', header: 'Status', sticky: 'end' },
]
  • Valores aceitos: true | 'start' | 'end'.
  • true equivale a 'start' (fixa no início).
  • Dica: combine com width para evitar jitter de layout.

Onde configurar no Editor Visual:

  • Aba “Colunas” → grupo “Posição Fixa”: escolha entre Nenhum / Início / Fim.
  • Para a coluna de ações, use a aba “Barra de Ferramentas & Ações” → grupo “Coluna de Ações” → “Fixar coluna de ações”.

🔒 Verificação de Schema (ETag) e Notificações (somente em customização)

Quando já existe uma configuração salva (colunas presentes), a tabela não baixa o schema bruto do servidor para montar as colunas. Em vez disso, valida se há uma nova versão do schema usando ETag/If-None-Match. Notificações são exibidas somente quando o modo de customização está ativo (editModeEnabled = true).

Comportamento

  • Primeira vez (sem colunas):
    • Baixa o schema (200), gera as colunas e persiste config.meta (incluindo schemaId, serverHash, lastVerifiedAt).
  • Próximas vezes (colunas já existentes):
    • Faz uma verificação leve em /schemas/filtered com If-None-Match: "<serverHash>".
    • 304 Not Modified: atualiza config.meta.lastVerifiedAt e segue usando a configuração local.
    • 200 OK (hash mudou): atualiza config.meta.serverHash/lastVerifiedAt, marca estado schemaOutdated=true e (em modo de customização) exibe aviso e CTA para reconciliar. O schema bruto não é usado/armazenado nesta etapa.

Diagrama: Verificação de Schema via ETag

sequenceDiagram
  autonumber
  participant PT as PraxisTable
  participant GS as GenericCrudService (@praxisui/core)
  participant API as Backend (/schemas/filtered)

  opt Primeira vez (sem colunas)
    PT->>GS: getSchema() (gera colunas)
    GS->>API: GET /schemas/filtered (sem If-None-Match)
    API-->>GS: 200 + ETag/X-Schema-Hash
    GS-->>PT: FieldDefinition[] (normalized)
    PT->>PT: Persiste config + meta (serverHash, lastVerifiedAt)
  end

  opt Próximas vezes (colunas existentes)
    PT->>API: GET /schemas/filtered?path=... (If-None-Match: "<serverHash>")
    alt Igual (sem mudanças)
      API-->>PT: 304 Not Modified (sem body)
      PT->>PT: Atualiza lastVerifiedAt; segue usando config
    else Diferente (mudou)
      API-->>PT: 200 OK (com ETag/X-Schema-Hash)
      PT->>PT: Atualiza serverHash + lastVerifiedAt; schemaOutdated=true
      Note over PT: Em customização: mostrar banner/snackbar + badge e CTA “Reconciliar”
    end
  end

Inputs/Outputs

  • Inputs (efetivos apenas quando editModeEnabled = true):
    • notifyIfOutdated: 'inline' | 'snackbar' | 'both' | 'none' = 'both'
    • snoozeMs: number = 86400000 (24h)
    • autoOpenSettingsOnOutdated: boolean = false
  • Outputs:
    • schemaStatusChange: { outdated: boolean; serverHash?: string; lastVerifiedAt?: string; resourcePath?: string }
      • Emitido tanto na verificação leve (304/200) quanto no bootstrap do schema (primeira carga via loadSchema()).
    • metadataChange: { meta: any; reason: 'bootstrap'|'verification'|'applied' }
      • Emitido quando config.meta é atualizado (ex.: após bootstrap ou verificação ETag). Útil para sincronizar sidebars/bridges de metadados.

Fallback Global (opcional)

  • Quando os inputs do widget permanecem com os valores padrão da biblioteca e não há overrides locais equivalentes, a Tabela aplica como último fallback as preferências globais lidas via GlobalConfigService.getSchemaPrefsGlobal().
  • Cadeia de precedência (inalterada): @Inputs (widget) → Prefs do widget → Prefs da página → Prefs globais → Defaults.
  • Não há persistência no widget a partir das globais; o fallback é aplicado somente em memória.

Persistência por hash (ConfigStorage)

  • schemaIgnore:{tableId}:{serverHash} → ignora avisos para este hash.
  • schemaSnooze:{tableId}:{serverHash} → ISODate até quando não avisar (lembrar depois).
  • schemaNotified:{tableId}:{serverHash} → evita snackbar duplicado.

UX

  • Banner inline (acima da tabela) quando schemaOutdated=true, com ações:
    • Reconciliar (abre Configurações)
    • Lembrar depois (snooze)
    • Ignorar (silenciar para este hash)
  • Snackbar opcional (uma vez por hash) com ação “Reconciliar”.
  • Badge “!” na engrenagem com tooltip contextual: “Schema do servidor mudou — Reconciliar”.

Exemplo de uso

<praxis-table
  [editModeEnabled]="true"
  [notifyIfOutdated]="'both'"
  [snoozeMs]="12 * 60 * 60 * 1000"
  [autoOpenSettingsOnOutdated]="false"
  (schemaStatusChange)="onSchemaStatus($event)"
  resourcePath="employees"
  [config]="tableConfig">
</praxis-table>
onSchemaStatus(ev: { outdated: boolean; serverHash?: string; lastVerifiedAt?: string }) {
  if (ev.outdated) {
    console.log('Schema mudou. Hash:', ev.serverHash);
  }
}

Notas

  • A verificação leve não grava nem usa o schema bruto quando config.columns já existe.
  • Em ambientes sem customização (editModeEnabled=false), não há notificações visuais; ainda assim schemaStatusChange é emitido e config.meta.lastVerifiedAt atualizado.

Filtro Avançado (PraxisFilter)

Boas práticas para estabilidade

  • Evite literais em bindings para o carregador dinâmico:
    • Não use [fields]="[quickFieldMeta]"; prefira um array estável como quickFieldMetaArray atualizado apenas quando o metadata mudar.
  • Reutilize FormGroup quando possível. Se precisar trocar o FormGroup sem mudar os campos, deixe o DynamicFieldLoader reatribuir os controles (rebind-only) em vez de recriar componentes.
  • Evite recriar arrays/objetos desnecessariamente em ngOnChanges/ngAfterViewInit. Prefira atualizar valores (setValue, patchValue) e manter referências estáveis.
  • Observers (Resize/Mutation): atualize overlayOrigin e largura apenas quando houver mudanças reais; isso evita loops de CD.

Diagnóstico e Logs

  • O DynamicFieldLoader possui logs de diagnóstico que podem ser habilitados em tempo de execução definindo window.__PRAXIS_DEBUG_DFL__ = true no console do navegador.
  • Quando desabilitado (default), o carregador reduz a verbosidade de logs.

Comportamento do carregador (v20+)

  • Guardas internas evitam re-renderizações desnecessárias:
    • Se o snapshot do conteúdo dos campos (nome + controlType) for idêntico e o FormGroup não tiver mudado, a renderização é ignorada.
    • Se apenas o FormGroup mudou (mesmo snapshot de campos), os controles são reatribuídos aos componentes existentes (rebind-only), preservando o estado visual e evitando recriações.

Testes

  • Há testes cobrindo:
    • Reatribuição de FormControl em troca de FormGroup (select/multiselect/autocomplete).
    • Ignorar re-render quando apenas a referência do array muda mas o conteúdo é igual.
    • Recriar componentes quando controlType muda.

Fluxo de Schema e Metadados

  • O PraxisFilter busca schema do DTO de filtro via /schemas/filtered com ETag/If-None-Match e emite metaChanged com { schemaId, serverHash, context }.
  • O schema é normalizado e advancedConfig.metadata é preenchido para auditoria/telemetria.
  • Detalhes: docs/schemas/fluxo-schema.md (cliente/caching, 200/304, reconciliadores Form/Filter).

Resolução da chave primária (idField)

  • O backend anota o schema com x-ui.resource.idField (e idFieldValid) via /schemas/filtered.
  • A tabela adota o campo identificador automaticamente com a seguinte precedência:
    • @Input() idFieldcrudContext.idFieldconfig.meta.idField (persistido) → GenericCrudService.getResourceIdField() (derivado do schema) → 'id'.
    • Se config.meta.idField divergir do servidor, o componente alerta o usuário e mantém o valor do TableConfig até reconciliação.
  • A resolução ocorre no loadSchema() e também é considerada em tempo de execução para evitar corridas.
  • Para recursos cuja PK não é id, defina getIdFieldName() no controller backend correspondente.

Diagramas

Fluxo (Grid): adoção de schema e idField

sequenceDiagram
  autonumber
  participant PT as PraxisTable
  participant GS as GenericCrudService
  participant API as Backend

  PT->>GS: configure(resourcePath)
  PT->>GS: getSchema()
  GS->>API: GET {resource}/schemas → 302 → /schemas/filtered
  API-->>GS: 200/304 schema + x-ui.resource.idField
  GS->>GS: cache + lastResourceMeta.idField
  GS-->>PT: FieldDefinition[] (normalizado)
  Note over PT: idField = input || context || GS.getResourceIdField() || 'id'
  PT->>PT: construir colunas e renderizar

Fluxo (Delete): resolução do identificador

sequenceDiagram
  autonumber
  participant PT as PraxisTable
  participant GS as GenericCrudService
  participant API as Backend

  PT->>PT: key = getIdField() (precedência)
  PT->>PT: id = row[key] || row['id'] || heurísticas
  PT->>GS: delete(id)
  GS->>API: DELETE {resource}/{id}
  API-->>GS: 204 No Content
  GS-->>PT: sucesso → refresh

Troubleshooting rápido (idField)

  • A ação delete falhou por ID ausente: verifique se o schema contém x-ui.resource.idField e se a coluna correspondente existe no dataset.
  • O ID está em outra propriedade: defina @Input() idField ou crudContext.idField temporariamente; ajuste o backend com getIdFieldName() para persistir o comportamento.
  • Cache 304 sem idField aplicado: confirme que o serviço recebeu o body pelo menos uma vez (200) e que GenericCrudService.getResourceIdField() retorna o valor esperado.

Uso com Dados Locais (Client-Side)

Se você precisar fornecer os dados manualmente (por exemplo, de uma fonte que não é uma API Praxis), pode usar o input [data] e omitir o resourcePath. Neste modo, todas as operações (paginação, ordenação, filtro) são realizadas no lado do cliente.

import { PraxisTable } from "@praxisui/table";
import { TableConfig } from "@praxisui/core";

@Component({
  selector: "app-example",
  standalone: true,
  imports: [PraxisTable],
  template: ` <praxis-table [config]="tableConfig" [data]="employees"> </praxis-table> `,
})
export class ExampleComponent {
  // Configuração de colunas e comportamento é obrigatória neste modo
  tableConfig: TableConfig = {
    columns: [
      { field: "id", header: "ID", type: "number" },
      { field: "name", header: "Nome", type: "string" },
      { field: "email", header: "Email", type: "string" },
    ],
    behavior: {
      pagination: { enabled: true, pageSize: 10 },
      sorting: { enabled: true },
      filtering: { enabled: true },
    },
  };

  employees = [
    { id: 1, name: "João Silva", email: "joao@empresa.com" },
    { id: 2, name: "Maria Santos", email: "maria@empresa.com" },
    // ... mais dados
  ];
}

⚙️ Fluxo de Paginação e Filtros (Server-Side)

Quando a <praxis-table> é conectada a um resourcePath, as operações de paginação, ordenação e filtro são delegadas ao backend. Isso garante alta performance, pois apenas os dados visíveis na tela são trafegados pela rede.

Importante: se você não configurar explicitamente as estratégias de paginação/ordenação no TableConfig, a tabela resolve automaticamente como server quando há resourcePath. Se preferir operar no cliente, defina behavior.pagination.strategy = 'client' e/ou behavior.sorting.strategy = 'client' conscientemente.

O diagrama abaixo detalha a sequência de eventos, desde a interação do usuário na UI até a construção da consulta JPA no servidor.

sequenceDiagram
    participant UI as @praxisui/table (UI)
    participant CrudService as @praxisui/core (GenericCrudService)
    participant Controller as Backend (AbstractCrudController)
    participant Service as Backend (BaseCrudService)
    participant SpecBuilder as Backend (GenericSpecificationsBuilder)
    participant Repository as Spring Data JPA (JpaSpecificationExecutor)

    UI->>UI: Usuário clica na página 2 e<br>digita "Tech" no filtro de nome.

    UI->>UI: onPageChange({pageIndex: 1, pageSize: 10})<br>onFilterChange({nome: 'Tech'})

    UI->>UI: Chama fetchData() com:<br>filterCriteria = {nome: 'Tech'}<br>pageable = {pageNumber: 1, pageSize: 10, sort: 'nome,asc'}

    UI->>CrudService: Chama .filter({nome: 'Tech'}, pageable)

    activate CrudService
    CrudService->>CrudService: Cria HttpParams:<br>page=1, size=10, sort=nome,asc
    CrudService->>Controller: Requisição POST para /api/.../filter<br>Body: {nome: 'Tech'}<br>Params: ?page=1&size=10&sort=nome,asc
    deactivate CrudService

    activate Controller
    Controller->>Controller: Spring injeta o corpo no FilterDTO<br>e os params no objeto Pageable.
    Controller->>Service: Chama .filter(filterDTO, pageable)
    deactivate Controller

    activate Service
    Service->>SpecBuilder: Chama .buildSpecification(filterDTO)

    activate SpecBuilder
    SpecBuilder->>SpecBuilder: Itera nos campos do FilterDTO.<br>Encontra @Filterable no campo 'nome'.
    SpecBuilder->>SpecBuilder: Cria um Predicate JPA:<br> `criteriaBuilder.like(root.get("nome"), "%tech%")`
    SpecBuilder->>Service: Retorna a Specification JPA construída.
    deactivate SpecBuilder

    Service->>Repository: Chama .findAll(specification, pageable)

    activate Repository
    Repository->>Repository: Spring Data JPA executa a<br>query SQL com WHERE, LIMIT, OFFSET, ORDER BY.
    Repository-->>Service: Retorna um objeto Page<Entity> do BD.
    deactivate Repository

    Service-->>Controller: Retorna o Page<Entity>
    deactivate Service

    activate Controller
    Controller->>Controller: Mapeia Page<Entity> para Page<DTO><br>e encapsula em RestApiResponse.
    Controller-->>CrudService: Resposta HTTP 200 com<br>JSON do RestApiResponse.
    deactivate Controller

    activate CrudService
    CrudService-->>UI: Retorna Observable<Page<DTO>>
    deactivate CrudService

    UI->>UI: Atualiza a tabela com os novos dados e o paginador.

Pontos-Chave do Fluxo:

  • UI (@praxisui/table): Captura eventos do usuário e os traduz em objetos filterCriteria e pageable.
  • Serviço Frontend (@praxisui/core): O GenericCrudService serializa o pageable como parâmetros de URL e o filterCriteria como corpo de uma requisição POST.
  • Controller Backend: O AbstractCrudController recebe a requisição. O Spring Boot automaticamente popula o DTO de filtro com o corpo da requisição e o objeto Pageable com os parâmetros da URL.
  • Serviço Backend (praxis-metadata-core): O GenericSpecificationsBuilder inspeciona as anotações @Filterable no DTO de filtro para construir uma Specification JPA dinâmica.
  • Repositório (Spring Data JPA): O JpaSpecificationExecutor (geralmente estendido pelo seu repositório) usa a Specification e o Pageable para gerar e executar a consulta SQL final, otimizada para o banco de dados.

🎨 Edição Visual da Tabela: O Poder do Low-Code

A <praxis-table> vem com um poderoso editor de configuração visual que permite personalizar quase todos os aspectos da sua tabela em tempo real, sem escrever uma única linha de código. Ative o editor passando a propriedade [editModeEnabled]="true" para o componente.

A seguir, veja os principais recursos que você pode configurar visualmente:

1. Gerenciamento de Colunas

Controle total sobre as colunas da sua tabela. Dentro do editor, você pode:

  • Reordenar com Arrastar e Soltar: Simplesmente clique e arraste uma coluna para a posição desejada.
  • Alterar Visibilidade: Use a caixa de seleção ao lado de cada coluna para mostrá-la ou ocultá-la instantaneamente.
  • Editar Títulos e Largura: Clique em uma coluna para abrir suas propriedades e altere o texto do cabeçalho, defina uma largura fixa (ex: 150px) ou deixe-a automática.

2. Transformação de Dados Sem Código

Converta dados brutos em informações claras e formatadas para o usuário.

  • Formatação Automática: Selecione uma coluna e escolha seu "Tipo de Dado". Se escolher Moeda, os valores serão formatados como R$ 1.234,56. Se escolher Data, você pode selecionar formatos como dd/MM/yyyy ou 25 de janeiro de 2025.
  • Mapeamento de Valores: Transforme códigos e valores brutos em texto legível. Na seção "Mapeamento de Valores", você pode definir visualmente que o valor true deve ser exibido como "Ativo" e false como "Inativo", ou que o código 1 significa "Pendente" e 2 significa "Aprovado".

3. Colunas Calculadas com Fórmulas Visuais

Crie novas colunas dinamicamente a partir de dados existentes, sem precisar programar.

  • Concatenar Texto: Crie uma "Coluna Calculada", escolha a fórmula "Concatenar" e selecione os campos nome e sobrenome para criar uma coluna "Nome Completo".
  • Realizar Operações Matemáticas: Use a fórmula "Operação Matemática" para criar uma coluna que calcula preço * quantidade.
  • Criar Valores Condicionais (IF/ELSE): Com a fórmula "Condicional", você pode criar uma coluna "Nível de Risco" que exibe "Alto" se o valor for maior que 1000, e "Baixo" caso contrário.

4. Formatação Condicional (Regras de Estilo)

Destaque informações importantes aplicando estilos que mudam com base nos dados da linha.

  • Crie Regras Visuais: Na seção de "Formatação Condicional", crie uma nova regra.
  • Defina a Condição: Estabeleça a condição, por exemplo: "Quando a coluna status tiver o valor igual a 'Urgente'".
  • Aplique o Estilo: Use seletores de cor para definir que, quando a condição for verdadeira, a cor de fundo da célula ou da linha inteira deve se tornar vermelha e o texto, branco.

5. Comportamentos da Tabela

Habilite e configure as funcionalidades centrais da tabela com um clique. Na aba "Comportamento", você pode:

  • Ativar/Desativar Paginação: Com um único interruptor, ative a paginação para tabelas com muitos dados e defina quantos itens exibir por página.
  • Controlar Ordenação e Filtros: Habilite a capacidade dos usuários de ordenar colunas e filtrar os dados com simples caixas de seleção.
  • Gerenciar Seleção de Linhas: Permita que os usuários selecionem uma ou várias linhas para realizar ações em lote.

Editores Especializados

Behavior Editor

import { BehaviorConfigEditorComponent } from '@praxisui/table';

// Usar como componente standalone para edição específica
<behavior-config-editor
  [config]="tableConfig"
  (configChange)="onBehaviorChange($event)">
</behavior-config-editor>

Columns Editor

import { ColumnsConfigEditorComponent } from '@praxisui/table';

<columns-config-editor
  [config]="tableConfig"
  (configChange)="onColumnsChange($event)"
  (columnChange)="onColumnChange($event)">
</columns-config-editor>

🔧 Configuração Avançada

Performance com Virtualização

const highVolumeConfig: TableConfig = {
  columns: [...],
  performance: {
    virtualization: {
      enabled: true,
      itemHeight: 48,
      bufferSize: 10,
      minContainerHeight: 400,
      strategy: 'fixed'
    },
    lazyLoading: {
      threshold: 100,
      images: true,
      components: true
    }
  }
};

Acessibilidade Personalizada

const accessibleConfig: TableConfig = {
  columns: [...],
  accessibility: {
    enabled: true,
    announcements: {
      dataChanges: true,
      userActions: true,
      loadingStates: true,
      liveRegion: 'polite'
    },
    keyboard: {
      shortcuts: true,
      tabNavigation: true,
      arrowNavigation: true,
      skipLinks: true,
      focusTrap: false
    },
    highContrast: false,
    reduceMotion: false
  }
};

Aparência Customizada

const styledConfig: TableConfig = {
  columns: [...],
  appearance: {
    density: 'compact',
    borders: {
      showRowBorders: true,
      showColumnBorders: false,
      showOuterBorder: true,
      style: 'solid',
      width: 1,
      color: '#e0e0e0'
    },
    elevation: {
      level: 2,
      shadowColor: 'rgba(0, 0, 0, 0.1)'
    },
    spacing: {
      cellPadding: '8px 16px',
      headerPadding: '12px 16px'
    },
    typography: {
      fontWeight: '400',
      fontSize: '14px',
      headerFontWeight: '500',
      headerFontSize: '14px'
    }
  }
};

🎯 Event Handling

Eventos da Tabela

<praxis-table
  [config]="tableConfig"
  [data]="data"
  (rowClick)="onRowClick($event)"
  (rowSelect)="onRowSelect($event)"
  (bulkAction)="onBulkAction($event)"
  (configChange)="onConfigChange($event)"
  (dataFilter)="onDataFilter($event)"
  (dataSort)="onDataSort($event)"
  (pageChange)="onPageChange($event)">
</praxis-table>

Implementação dos Handlers

export class MyComponent {
  onRowClick(event: { row: any; index: number }) {
    console.log("Row clicked:", event.row);
  }

  onRowSelect(event: { selectedRows: any[]; isSelectAll: boolean }) {
    console.log("Selection changed:", event.selectedRows);
  }

  onBulkAction(event: { action: string; selectedRows: any[] }) {
    switch (event.action) {
      case "deleteSelected":
        this.deleteMultiple(event.selectedRows);
        break;
      // Handle other bulk actions
    }
  }

  onConfigChange(newConfig: TableConfig) {
    this.tableConfig = newConfig;
  }
}

🛠️ Utilitários e Helpers

Helper Functions

import { createDefaultTableConfig, isValidTableConfig, cloneTableConfig, mergeTableConfigs } from "@praxisui/core";

// Criar configuração padrão
const defaultConfig = createDefaultTableConfig();

// Validar configuração
if (isValidTableConfig(myConfig)) {
  // Configuração válida
}

// Clonar configuração
const clonedConfig = cloneTableConfig(originalConfig);

// Merge configurações
const mergedConfig = mergeTableConfigs(baseConfig, overrides);

Service Integration

import { TableConfigService } from '@praxisui/core';

@Component({...})
export class MyComponent {
  constructor(private configService: TableConfigService) {}

  ngOnInit() {
    // Usar serviço para gerenciar configuração
    this.configService.setConfig(this.tableConfig);

    // Verificar recursos disponíveis
    const hasMultiSort = this.configService.isFeatureEnabled('multiSort');
    const hasBulkActions = this.configService.isFeatureEnabled('bulkActions');
  }
}

🧪 Testes

Unit Tests

import { ComponentFixture, TestBed } from "@angular/core/testing";
import { PraxisTable } from "@praxisui/table";
import { TableConfig } from "@praxisui/core";

describe("PraxisTable", () => {
  let component: PraxisTable;
  let fixture: ComponentFixture<PraxisTable>;

  beforeEach(() => {
    TestBed.configureTestingModule({
      imports: [PraxisTable],
    });

    fixture = TestBed.createComponent(PraxisTable);
    component = fixture.componentInstance;
  });

  it("should create", () => {
    expect(component).toBeTruthy();
  });

  it("should handle configuration changes", () => {
    const config: TableConfig = {
      columns: [{ field: "test", header: "Test" }],
    };

    component.config = config;
    fixture.detectChanges();

    expect(component.config).toEqual(config);
  });
});

📋 Migration Guide

Migração da Arquitetura V1/V2

Se você estava usando as versões anteriores com dual architecture, aqui estão as principais mudanças:

Imports Atualizados

// Antes
import { TableConfigV1, TableConfigV2, TableConfigUnified } from "@praxisui/core";

// Depois
import { TableConfig } from "@praxisui/core";

Serviços Removidos

// Antes
import { TableConfigAdapterService } from "@praxisui/table";

// Depois - Não mais necessário
// Uso direto da configuração

Tipos Simplificados

// Antes
config: TableConfigUnified;

// Depois
config: TableConfig;

Breaking Changes

  • TableConfigAdapterService: Removido - uso direto da configuração
  • TableConfigMigrationService: Simplificado - funcionalidade integrada
  • TableConfigUnified: Renomeado para TableConfig

🔍 Troubleshooting

Problemas Comuns

Configuração não está funcionando

// Verificar se a configuração é válida
import { isValidTableConfig } from "@praxisui/core";

if (!isValidTableConfig(myConfig)) {
  console.error("Configuração inválida:", myConfig);
}

Performance Issues

// Habilitar virtualização para grandes datasets
const config: TableConfig = {
  // ...
  performance: {
    virtualization: {
      enabled: true,
      itemHeight: 48,
      bufferSize: 20,
    },
  },
};

Acessibilidade

// Garantir que acessibilidade está habilitada
const config: TableConfig = {
  // ...
  accessibility: {
    enabled: true,
    announcements: { dataChanges: true, userActions: true, loadingStates: true, liveRegion: "polite" },
  },
};

📚 API Reference

Interfaces Principais

TableConfig

Interface principal para configuração da tabela.

ColumnDefinition

Define configuração individual de colunas.

TableBehaviorConfig

Configurações de comportamento (paginação, ordenação, etc.).

TableAppearanceConfig

Configurações de aparência visual.

Para documentação completa da API, consulte a documentação da @praxisui/core.

🤝 Contribuição

Como Contribuir

  • Fork o projeto
  • Crie branch para feature (git checkout -b feature/nova-funcionalidade)
  • Commit mudanças (git commit -m 'Add: nova funcionalidade')
  • Push para branch (git push origin feature/nova-funcionalidade)
  • Abra Pull Request

Guidelines

  • Seguir Angular Style Guide
  • Adicionar testes para novas features
  • Manter documentação atualizada
  • Usar TypeScript strict mode

🔍 Exemplo de Integração com PraxisFilter

O PraxisFilter pode ser acoplado à barra de ferramentas da tabela. O exemplo abaixo mostra a busca de pessoas por CPF e status.

<praxis-filter [resourcePath]="'pessoas'" [formId]="'pessoas-filter'" [persistenceKey]="'pessoas-filter-v1'" [quickField]="'cpf'" [alwaysVisibleFields]="['status']" (submit)="onFilter($event)"></praxis-filter> <praxis-table [data]="tableData"></praxis-table>
onFilter(dto: any) {
  this.crud.configure('pessoas', ApiEndpoint.HumanResources);
  this.crud.filter(dto, this.pageable).subscribe(page => {
    this.tableData = page.content;
  });
}

⚙️ Painel de Configurações do Filtro

O PraxisFilter possui um painel de configurações acessível pelo ícone de engrenagem na barra do filtro ou programaticamente através do método openSettings(). Nesse painel é possível ajustar:

  • quickField – campo utilizado para a busca rápida
  • alwaysVisibleFields – campos que permanecem sempre visíveis
  • placeholder – texto exibido no campo de busca
  • showAdvanced – define se a seção avançada inicia aberta
@ViewChild(PraxisFilter) filter!: PraxisFilter;

abrirConfiguracoes() {
  this.filter.openSettings();
}

Ao aplicar ou salvar, as escolhas são validadas contra os metadados disponíveis. O componente exibe uma barra de progresso durante o processo de persistência e mensagens de sucesso ou erro via snack bar, garantindo uma experiência consistente.

Novos Inputs/Outputs (PraxisFilter)

  • Inputs (efetivos apenas quando editModeEnabled = true):
    • editModeEnabled: boolean — habilita o gate de customização para notificações de schema.
    • notifyIfOutdated: 'inline' | 'snackbar' | 'both' | 'none' = 'both' — canal de notificação quando o schema muda.
    • snoozeMs: number = 86400000 — tempo de soneca para avisos (ms).
    • autoOpenSettingsOnOutdated: boolean = false — abre Configurações ao detectar schema desatualizado.
  • Output:
    • schemaStatusChange: { outdated: boolean; serverHash?: string; lastVerifiedAt?: string; formId?: string } — emitido após verificação leve (304/200).

Fallback Global (opcional)

  • Quando os inputs do componente permanecem com os valores padrão e não há overrides locais, o Filter utiliza como último fallback as preferências globais via GlobalConfigService.getSchemaPrefsGlobal().
  • Cadeia de precedência (inalterada): @Inputs (widget) → Prefs do widget → Prefs da página → Prefs globais → Defaults.
  • O fallback global não é persistido no componente; serve apenas para defaults em memória.

Notas rápidas (Flow ETag no Filter):

  • Verificação leve sempre no init (sem baixar o corpo): usa ETag/If-None-Match em /schemas/filtered (path=.../filter, operation=post, schemaType=request, includeInternalSchemas=true).
  • 304: atualiza lastVerifiedAt; emite schemaStatusChange(outdated=false).
  • 200: atualiza serverHash/lastVerifiedAt; marca outdated=true apenas quando em customização; não aplica o schema automaticamente.
  • O corpo do schema é baixado apenas quando necessário para renderização (ex.: alwaysVisibleFields ou ao abrir o painel Avançado).

Formatação de Colunas (format)

Cada coluna pode declarar type e uma string de formatação format consumida pelo DataFormattingService. Os tipos suportados são: string, number, currency, percentage, date, boolean, custom.

Regra geral: a formatação só é aplicada quando há format não vazio e type !== 'custom'.

Tipos e padrões de format:

  • number (DecimalPipe)
    • Padrões: minInt.minFrac-maxFrac
    • Exemplos: 1.0-0, 1.2-2, 1.0-3|nosep (remove separador de milhar)
  • currency (CurrencyPipe)
    • Sintaxe: CURRENCY|DISPLAY|DECIMALS[|nosep]
    • Exemplos: BRL|symbol|2, USD|code|0, EUR|symbol|2|nosep
  • percentage (PercentPipe/DecimalPipe)
    • Sem multiplicador: 1.0-0 (PercentPipe)
    • Multiplicar por 100: 1.1-1|x100 (DecimalPipe×100 + %)
  • date (DatePipe)
    • Tokens Angular: shortDate, mediumDate, longDate, fullDate, short, shortTime
    • Padrões customizados: dd/MM/yyyy, yyyy-MM-dd, dd/MM/yyyy HH:mm
  • string (transformações + truncamento)
    • Transform: uppercase | lowercase | titlecase | capitalize | none
    • Transform + truncar: <transform>|truncate|<max>|<suffix>
    • Exemplos: uppercase|truncate|50|..., titlecase
  • boolean (pré-definidos ou custom)
    • Presets: true-false | yes-no | active-inactive | on-off | enabled-disabled
    • Custom: custom|Verdadeiro|Falso

Exemplos de ColumnDefinition:

{ field: 'salario', type: 'currency', format: 'BRL|symbol|2', header: 'Salário' }
{ field: 'desconto', type: 'percentage', format: '1.1-1|x100', header: 'Desconto' }
{ field: 'criadoEm', type: 'date', format: 'dd/MM/yyyy', header: 'Criado em' }
{ field: 'nome', type: 'string', format: 'titlecase|truncate|32|…', header: 'Nome' }
{ field: 'ativo', type: 'boolean', format: 'yes-no', header: 'Ativo' }

Observações:

  • |nosep remove separadores de milhar da saída formatada.
  • Para datas inválidas ou valores não numéricos, o serviço retorna o valor original (com aviso no console).
  • Colunas com renderizador custom não passam por formatação automática.

Exemplos práticos no workspace (rotas):

  • Regras Visuais (Simples): /table-rules-simple
  • Regras Visuais (Complexas): /table-rules-complex

📊 Roadmap

Próximas Versões

  • ✅ Arquitetura unificada (v2.0.0)
  • 🔄 Enhanced mobile support (v2.1.0)
  • 📋 Advanced export options (v2.2.0)
  • 🎨 Theme customization (v2.3.0)

📄 Licença

Apache-2.0 — consulte LICENSE para detalhes.

Parte do Praxis UI Workspace Versão: 2.0.0 (Unified Architecture) Compatibilidade: Angular 18+

Keywords

angular

FAQs

Package last updated on 07 Nov 2025

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts