Manual de Customização
Todas as informações para customizar o seu agilityflow.
- Segurança e Acesso
- Usuário
- Perfil de Acesso
- Grupo de Usuário
- Single Sign-On - Configurar integração com o AD (Active Directory)
- Single Sign-On - Configurar a integração com o ADFS (Active Directory Federation Services)
- Formulários
- Introdução
- Definição Básica
- Formulário com fluxo de etapas
- Divisão e agrupamento dos campos
- Campos e componentes do formulário
- Montar e organizar a tela de cadastro
- Configurar ações e os botões do menu do formulário
- Customização javascript
- Lista e consulta
- Relatórios para impressão e PDF
- Regras de Visibilidade e Desativação
- Lista de atributos de configuração por campos
- Regras de negócio (Automação)
- Restrição de acesso a Dados na Lista Principal e Regras de Filtros
- Devcenter - Customizar o Agilityflow
- Menu
- Relatório analítico / BI
- Dashboard
- Widget
- Tabela Relacional (N:N)
- Cache
- API de Integração GET e POST
- Variáveis de ambiente
- Change Request
- Visual Code Editor
- Formulário - customizar com HTML, C#, CSS e Javascript
- Quadros (Kanban)
- Listagem do Formulário - customizar com HTML, C#, CSS e Javascript
- Relatório / Dashboard - customizar colunas da tabale de dados com Html, C#, CSS e Javascript
- Configuração dos Campos
- Textbox
- Label Dinâmica
- Upload
- Lista de seleção (Combo)
- Pesquisa com auto completar
- Checkbox (Único)
- Lista aberta com escolha única (Radio)
- Fórmula
- Campo com Múltipla Escolha
- Botão Customizado
- Formulários Relacionados
- Componentes CsHtml
- Label com Query SQL
- Tabela de dados customizada através de programação: Query SQL, C#, HTML e CSS
- Campo de Assinatura
- Programação
- SQL Server (Query) - Dicas e Funções (Versões Mais Antigas do Agilityflow)
- Postgresql (Query) - Dicas e Funções (Versões Mais Recentes do Agilityflow)
- Programação em Html
- Programação em CSS
- Programação em Javascript
- Programação em C# - Na Regra de Negócio
- Programação em C# - Na API de integração (POST)
- Tabela de dados customizada através de programação: Query SQL, C#, HTML e CSS
- Single Sign-On
- Configurar integração com o AD (Active Directory)
- Configurar integração com o ADFS (Active Directory Federation Services)
- Outras Dicas
- Buscar o CEP nos Correios e preencher os campos de endereço automaticamente
- Automatizar a criação de tarefas em um Quadro de Tarefas ao salvar um formulário
- Problema de acentuação no retorno de um CSHtml que é usado com Javacript
- Database Performance
- Sincronizaçao de Contatos com a sua conta no Google
- Bulk Update - Atualização de dados em Massa
- Timezone (Fuso Horario do sistema)
- Alterar via C# o valor de um campo ao salvar um formulário
- Alerta para o usuario ao salvar um formulário (usando c#)
- Erro: Can't write CLR type System.String with handler type UuidHandler
- Evento javascript após o subsmit post do formulario (onAfterPostEvent)
- Forçar o salvamento de um Form
- Listagem: Como habiltar para atualizar a cada X segundos (Auto Refresh, Atualização Automática, Atualização Recorrente)
- Ativar e Inativar campos do formulario via Javascript
- Esconder e Mostrar campos do formulario via Javascript (visível e invisível)
- Esconder, Mostrar e Remover o toolbar de botões do formulario via Javascript
- Colocar ou Retirar a Obrigatoriedade de um Campo no Formulário via JavaScript
- Verificação de Estado de Formulários. Como saber se é um novo formulário ou um rascunho via javascript?
- Como permitir um usuário Gerenciar Usuário, Perfil e Grupo de Usuario não tendo o perfil MASTER
- Como customizar a mensagem de sucesso ou falha após o submit post do Formulário (via javascript)
- Estrutura de Armazenamento dos campos no banco de dados
- Executar uma Api do proprio agilityflow dentro de um Form ou dentro de uma outra Api
- Forçar via Javascript o Salvamento do Formulário
- Manipular o formulário "pai", dentro de um formulário filho
- Evento javascript ondataloaded na Lista Dinamica
- Como criar itens / tarefas automaticamente nos Checklists dos formulários?
- Customização e estilização dos botões do formulário
- Como ocultar um campo do formulário quando ele estiver em modo público?
- Criando ações complexas no botão de um formulário
- Ao salvar um form, pausar ação do sistema e atualizar a tela
- [Form] Como abrir outra página ou um lightbox / modal a partir estando em um Form ou Workflow
- Leitura de E-mail Automatizada e Monitoramento de Caixa de Entrada
- [Global Code] Como criar uma Classe Global em C#?
- [Custom Page] Como criar uma Classe em C# no Custom Page?
- [Global Code] Como buscar no banco de dados em uma C# class global
- [Global Code] Como customizar CSS, Javascript e C# Globalmente
- [Custom Page] Quais são as funções nativas do AgilityFlow disponíveis no JavaScript para utilizar em uma Custom Page? customPageContext
- [Custom Page] Como apresentar mensagens para o usuario
- [Custom Page] Como buscar a data atual
- [Custom Page] Como abrir outra página ou um lightbox / modal a partir do Custom Page
- [Custom Page] Buscar informações do banco de dados através (Query)
- [Global Code] Como declarar uma variável publica em todo o sistema
- [Custom Page] Como inserir, atualizar e deletar um registro em um determinado Form estando em um Custom Page
- [Custom Page] Como abrir outra página ou um lightbox / modal a partir do Custom Page
- [Form] Quais são as funções nativas do AgilityFlow disponíveis no JavaScript para utilizar em um Formulário? formContext
- [Custom Page] Como Chamar um Método Global no Custom Page?
- Como Obter Parâmetros da Query String com JavaScript
- Como escutar o evento javascript que ocorre antes de preencher uma tabela filha e depois de preencher
- Como remover os botões de editar e remover de cada linha de uma tabela filha e também o botão de adicionar um novo registro filho
- Como validar se um e-mail está no formato válido?
- Configuração de perfil de acesso para visualizar o Custom Menu. Quem poderá ver o item do menu?
- Como destacar informações importantes, como alertas, sucessos, erros no corpo de um Formulário? Adicione avisos coloridos no Formulário.
- Como fazer a cópia completa de um registro de um formulário? Incluindo as tabelas filhas
- Como consultar no banco de dados os campos de upload e acessar a imagem por URL?
- Como chamar uma API externa a partir do agilityflow
- Limitação ao usar campo do tipo Autocomplete com Numero Sequencial, "Identity" (bigint) na Descrição
- Abrindo Telas em Modo Standalone (sem menus, logo, etc.)
- Como desativar a paginação automática em Queries do AgilityFlow [disable(auto-pagination)]
- Como adicionar uma assinatura digital em um Report Print / template de Impressão / PDF
- Como adicionar e atualizar itens em uma tabela de formulário filho
Segurança e Acesso
O menu de Segurança e Acesso, é o local onde se criam usuários e onde é definido as permissões de acesso.
Usuário
É onde são criadas as contas para acesso ao sistema. Cada usuário tem suas informações divididos em 3 grupos:
Dados Pessoais
São os campos tais como nome, e-mail, data de nascimento, sexo e foto. Além disso, também é possível definir o usuário gestor.
Usuário Gestor
Esse usuário servirá para os casos de uma etapa em um fluxo de trabalho, ter como regra a aprovação do gestor do usuário da etapa anterior.
Por exemplo: em um fluxo de solicitação de reembolso, a primeira etapa é o cadastro da despesa para reembolso. A segunda etapa, pode ter como aprovador o gestor do usuário da primeira etapa. É exatamente o usuário informado no campo usuário gestor, que será usado nesse momento como o aprovador da etapa. Na prática, serviria para um funcionário solicitar o reembolso de uma despesa e essa solicitação, antes de ir para o financeiro, passasse pelo crivo do gestor desse funcionário.
Dados de Acesso
Aqui é definido o nome do usuário e a senha. Além disso, define-se aqui se conta está ativa ou não. Essa função, serve para desativar futuramente uma conta, sem precisar removê-la, podendo reativar a qualquer momento.
Perfil
Perfil é um conjunto de funcionalidades que esse usuário terá acesso. Para maiores detalhes, consulte a página de configuração de perfil desse manual.
Para atribuir um perfil a um usuário, basta selecionar o perfil desejado na lista de seleção e clicar no botão
.
É possível atribuir mais de um perfil por usuário.
Grupo de usuários
Grupo de usuários é um conjunto de outros usuários ao qual esse usuário vai pertencer. Para maiores detalhes, consulte a página de configuração grupos de usuário desse manual.
Um usuário, pode pertencer a n grupos de usuário.
Excluindo um usuário
Para excluir basta entrar na lista de Usuário, no menu Segurança e Acesso, localizado na barra vertical, selecionar um ou mais usuários, e em seguida, clicar no ícone
. Note que esse ícone fica inativo caso não haja nenhum usuário selecionado.
Outra forma, é clicando em um dos usuários. Quando isso é feito, abre-se os detalhes do usuário. O ícone de exclusão também encontra-se nessa tela.
Ao excluir um usuário, você não pode mais recuperar a conta excluída. Caso você acredite que essa conta será utilizada novamente no futuro, você pode desativá-la, mudando o campo "ativo" nas configurações do usuário.
Perfil de Acesso
O perfil de acesso é o nome que se dá no agilityflow, a um grupo de funcionalidades e permissões que um usuário pode ter.

Nessa tela, é possível definir o nome do perfil, e ainda associar usuários a ele.
O campo "Código(ID)" é preenchido automaticamente pelo sistema.
Funcionalidades

Primeiro, é necessário definir o tipo de funcionalidade. São duas opções:
Ao selecionar uma dessas opções, o campo Funcionalidade é habilitado com as opções referentes ao tipo escolhido.
Feito isso, as funções vão aparecer para serem configuradas. Todas elas tem como opção para configuração, as opções Sim e Não. Para Report a única opção disponível é "Pode Visualizar o Report?".
Para os formulários, mais opções estão disponíveis:
- Cadastrar
- Consultar
- Imprimir
- Editar
- Exportar Excel
Sempre ao criar um formulário novo, não se esqueça de adicionar ele aos perfis que devem acessá-lo.
Permite criar Board/Kanban
Caso marcado, os usuários associados a esse perfil poderão criar quadros (kanban) para os formulários.
Dashboards para esse perfil
Nessa opção, é possível associar dashboards para serem visualizados por esse perfil de usuário. Isso significa, que todos os dashboards aqui associados ficarão disponíveis para serem acessados por esse usuário.
Perfil com acesso TOTAL ao agilityflow
"Master"
Esse perfil concede acesso completo e irrestrito a plataforma. Tipicamente, pouquíssimos usuários devem ter esse perfil.
Grupo de Usuário

É a forma que se tem de agrupar usuários para serem utilizados em uma determinada ação no seu fluxo e/ou processo. Essa opção é útil para agrupar usuários com diferentes níveis, qualificações ou perfis de acesso. Com isso, é possível que algumas funções do Agilityflow sejam disponibilizadas a esse grupo específico, e não a todo um perfil, por exemplo.
Exemplo de utilização:
Suponhamos que dentro da sua empresa tenha um projeto temporário chamado Projeto X, e que apenas as pessoas que fazem parte desse projeto possam solicitar reembolso de jantar e transporte. Sendo que o Gestor seja o responsável por aprovar esse reembolso.
Para esse exemplo estamos supondo que você ainda não possua um formulário para solicitação de reembolso
Você acaba de definir que apenas os usuário que fazem parte do Projeto X, conseguirão cadastrar uma nova "Solicitação de reembolso" (definição feita no passo 5 acima). O único pré-requisito é que o perfil do usuário dê acesso a esse formulário "Solicitação de Reembolso" que criamos.
Single Sign-On - Configurar integração com o AD (Active Directory)
Para acessar os detalhes desse conteúdo, clique aqui.
Single Sign-On - Configurar a integração com o ADFS (Active Directory Federation Services)
Para acessar os detalhes desse conteúdo, clique aqui.
Formulários
Tudo o que você precisa saber sobre formulários no agilityflow.
Introdução
Os formulários têm uma importância única no agilityflow. É através dele, que informações serão inseridas no sistema. A partir daí, serão gerados fluxos de trabalho, os gráficos no dashboard, os relatórios e muito mais.
Para isso, basta clicar no ícone do Devcenter
localizado na Barra Vertical, e em seguida em Menu.

Ao clicar em "Consultar"
, é possível ver a lista de menus já existentes.
Clicando em "Novo Menu"
, o usuário irá criar um novo Menu na Barra Vertical.
Ao criar um novo formulário, será necessário definir uma série de informações, que darão a característica desejada a esse formulário.
Formulários Nativos
Os formulários nativos são formulários que o agilityflow trás por padrão. Como por exemplo, o formulário de cadastro de usuários. Essa parte do sistema também é construída usando o agilityflow.
Os fomulários nativos vem por padrão ocultados no devcenter. Para listá-los, basta clicar na opção "Mostrar formulários nativos do Agilityflow" na tela de consulta dos formulários.
Os formulários nativos são marcados com uma etiqueta, para fácil identificação.
Os formulários nativos, são formulários que existem no agilityflow e servem para a utilização do sistema. Por exemplo ao criar um usuário, é utilizado um formulário nativo para a obtenção dos dados do usuário.
Definição Básica
Nessa aba você configura as informações gerais da estrutura do seu formulário ou fluxo.
Abaixo detalhamos essas configurações.
Os campos Nome e ícone, são as primeiras definições na criação de um novo formulário.
Abaixo, um vídeo explicando como alterar o ícone de um formulário.
Uma definição importante, é o tipo do formulário. São dois os tipos disponíveis:
Tipos de Formulário
Formulário simples
É um formulário usado para cadastro e armazenagem de informações.
Formulário com fluxo de etapas
É um formulário também usado para cadastro e armazenagem de informações. Porém, baseado nessas informações, é criado um fluxo de trabalho onde pode se definir etapas de aprovação e interação entre usuários do sistema. Para mais detalhes sobre esse tipo de formulário, consulte o capítulo Formulário com Fluxo de Etapas.
O campo Descrição, permite que o usuário defina uma breve explicação sobre aquele formulário.
Caso você queira criar um novo menu, você deve criá-lo antes de criar o formulário, para que esse menu esteja disponível nesse campo.
Janela do formulário
É possível também, definir a forma como esse formulário vai abrir. São 3 formas:
Lightbox
É uma janela secundária sobreposta a uma janela principal, sem a criação de uma nova guia ou nova janela. Ao escolher essa opção, você também pode definir o tamanho do lightbox: fullscreen, grande, médio ou pequeno.
Na mesma página
Abre o formulário inteiro, na janela atual.
Uma nova aba do navegador
Abre o formulário inteiro, em uma nova janela.
Relacionamento com outros formulários
Nesse ponto, se define a possibilidade desse formulário ser incluído como um formulário relacionado a outro formulário.
Pode ser usado como tabela filha de um outro formulário (Tabela de Formulário Relacionado)
Ao marcar essa opção, esse formulário fica habilitado a ser incluído dentro de outros formulários.
Abrir apenas através de um formulário pai
A opção "Abrir apenas através de um formulário pai", inibe que esse formulário seja aberto da maneira convencional, permitindo apenas que ele seja aberto através de outro formulário.
Dados Técnicos
Esse é o nome da tabela que será gerado no banco de dados. Esse é o nome que será usado depois para a criação de relatórios e dashboards. Normalmente, não é necessário alterar o nome que o sistema sugere.
Formulário com fluxo de etapas
O formulário com fluxo de etapas, possui todas as características de um formulário comum. Todas as propriedades, características, campos e etc estão presentes em um fluxo com etapas.
Para entender melhor o seu funcionamento, consulte o capítulo Formulário com fluxo de etapas no manual do usuário.
A criação de um formulário com etapas segue os mesmos princípios da criação de um formulário comum. Abaixo, as diferenças.
Definição Básica
Deve-se primeiro marcar a opção formulário com fluxo de etapas, dentro dos dados básicos, na aba Definição Básica. Quando isso é feito, a aba para configuração das etapas "Etapas do Fluxo" é habilitada.
Etapas do Fluxo
Nesse ponto definimos as etapas do fluxo que esse formulário terá.
O que são etapas de um fluxo?
Etapas, são pontos de edição/revisão/inclusão de dados de um formulário. Em cada etapa, além de se modificar o formulário, há uma ação necessária a ser executada por um ou mais usuários definidos. As ações são: aprovar, retornar etapa ou reprovar.
Em qualquer fluxo, a primeira etapa é criada automaticamente pelo agilityflow. É a "Etapa inicial (cadastro)". Essa etapa é fixa e não é possível alterar.
Nesse ponto, é possível adicionar novas etapas. Ao clicar em "Adicionar Etapa", o usuário define o nome da etapa e o número máximo de dias que essa etapa tem para ser aprovada. Nessa tela também, é possível reordenar as etapas. Para isso, basta clicar no ícone
e arrastar a etapa para a posição desejada.
O que acontece com o histórico se eu removo uma etapa?
Qualquer fluxo já encerrado ou em andamento, não serão alterados e não terão o histórico afetado. Apenas os novos cadastrados a partir daquela data, é que terão seu comportamento modificado.
O mesmo acontece quando se altera o nome de uma etapa ou a ordem é modificada. Nada acontece com os fluxos encerrados ou em andamento. Apenas os novos são impactados.
Usuários com permissão para cadastrar (Etapa Inicial)
É onde são definidos os usuários que podem criar um novo registro e iniciar um novo fluxo.
Esses usuários podem ser adicionados individualmente, procurando pelo nome. Ao ser encontrado a conta do usuário desejada, clica-se em adicionar. O usuário entra na lista abaixo. Clicando no ícone
, é possível remover a conta da lista.
A mesma mecânica funciona para adicionar múltiplos usuários, usando o perfil de usuário ou grupo. Ao selecionar o perfil (ou grupo) desejado, todos os usuários associados estarão autorizados a fazer o cadastro.
Responsáveis da etapa
Provavelmente, a parte mais importante da definição de um fluxo de etapa, são os responsáveis por cada uma delas. Na prática, são as pessoas que garantirão que o processo controlado por esse fluxo, cumpram todos os requerimentos e entregue um resultado satisfatório, livre de erros e retrabalhos.
Para cada etapa, é preciso escolher os responsáveis pela aprovação. Isso pode ocorrer de duas formas:
Aprovação não dinâmica
É a opção padrão. Nela é necessário definir um aprovador, que pode ser de dois tipos.
A partir de uma lista pré-definida
Funciona da mesma forma que escolha dos usuários com permissão para cadastrar a etapa inicial.
O gestor do aprovador da etapa X
Todo usuário pode possuir um gestor cadastrado no seu usuário. É esse usuário que será o aprovador. Escolhendo essa opção, deverá também ser escolhida a etapa da qual seu responsável, terá seu gestor como responsável dessa etapa.
Aprovação dinâmica
Para que ocorra uma aprovação dinâmica, é necessário que se configurem regras. É possível existir mais de uma regra.
Cada regra tem um nome e uma descrição, que são textos escolhidos pelo usuário. Além disso, essa regra pode ser de dois tipos:
Condicional
Na regra condicional, uma determinada situação deve estar presente. São dois tipos de condição:
- Se o campo: qualquer campo do formulário pode ser escolhido e ser comparado com um valor fixo definido pelo usuário. Essa comparação pode ser igual, maior ou igual, menor ou igual, maior que, menor que, diferente de, conter ou não conter;
- Se o usuário: qualquer usuário do sistema pode ser escolhido e ser comparado (aprovou ou não aprovou) a uma etapa.
Para qualquer uma das regras, podem se adicionar mais condições.
Caso a condição se estabeleça, é necessário definir um método de aprovação:
- Aprovação automática: o fluxo é aprovado sem que nenhum usuário tenha que realizar uma ação no sistema;
- Não é automática (definir aprovadores): é necessário selecionar os aprovadores, assim como é feito na aprovação não dinâmica.
É importante definir a regra e a regra contrária. Por exemplo, caso se queira que haja uma aprovação automática quando o campo Valor for menor que 100, além dessa regra, é necessário criar a regra para quando o campo Valor for igual ou maior que 100.
Definida pelo aprovador
Há dois campos para ser preenchidos:
- O aprovador da etapa: escolhe-se o uma das etapas do fluxo. Isso servirá como base para a configuração do campo ação.
- Ação:
- Aprovará esta etapa também: o mesmo aprovador da etapa escolhida acima, aprovará essa também
- Define o aprovador dessa etapa através da lista pré-definida abaixo: escolhe-se os usuários que estarão disponíveis para serem selecionados pelo aprovador da etapa "X", definida no passo anterior.
Permissões de acesso
Nesse ponto, é possível definir quais processos os usuários podem visualizar:
Sim, o usuário pode visualizar APENAS os fluxos que participou
O usuário visualiza apenas os fluxos em que ele esteja envolvido, seja cadastrando o registro ou participando de alguma etapa do fluxo.
Não, o usuário pode visualizar TODOS os fluxos, incluindo os que não participou
O usuário visualiza todos os registros dos formulários, independente da sua participação ou não do fluxo.
Divisão e agrupamento dos campos
É possível criar um grupo de informações para manter organizado os campos do seu formulário. Por padrão, um grupo já vem criado chamado de Dados mas você pode alterá-lo e/ou criar outros.
Por exemplo, em um formulário de cadastro de cliente, você pode organizar os campos em Dados Pessoais, Endereço e Contato, e dentro desses grupos, colocar os campos referentes a cada um dos grupos.
Outra definição, além do nome, é a ordem que será mostrado na lista, e se ele deve aparecer aberto ou recolhido quando o formulário for visualizado. Para ordenar os grupos, basta clicar no ícone
e arrastar para a posição desejada.
Mesmo escolhendo uma das opções por padrão, o usuário poderá abrir ou fechar esse grupo quando quiser.
Ao remover um grupo de informação, todos os campos que pertencem a ele também são removidos.
Campos e componentes do formulário
Esse é o momento, onde podemos adicionar campos ao nosso formulário. Cada campo é inserido dentro de um grupo de informação, criado no passo anterior.
Uma vez criado, o campo só pode ser mudado do grupo de informações acessando o menu "Configurações".
Ao clicar em adicionar, aparecem os diversos tipos de campos, disponíveis no agilityflow:
Campo Textbox
Esse campo deve ser usado para qualquer dado que seja um texto ou um número. Depois, é possível definir mais detalhes, como uma máscara numérica, para telefone ou moeda, por exemplo. Para maiores detalhes, leia o capítulo de configuração do campo textbox.
Label Dinâmica
É um campo não editável pelo usuário e seu preenchimento ocorre através de um outro campo. Para maiores detalhes, leia o capítulo de configuração do campo Label Dinâmica.
Upload
Permite que o usuário envie arquivos do computador para o formulário. Quando o formulário é aberto pelo celular, é possível que o usuário acione a câmera para o envio de fotos. Nas configurações adicionais, é possível validar a quantidade de itens (maior, menor ou igual a "x" itens enviados) e também as extensões permitidas ou proibidas. Para maiores detalhes, leia o capítulo de configuração do campo Upload.
Lista de seleção (Combo)
Esse campo, permite que o usuário escolha uma opção pré-determinada. A origem dos dados pode ser através de duas formas:
Lista Estática
O usuário insere as opções nas configurações do campo. Com isso, o usuário que acessa o formulário não é pode criar novas opções.
Lista Dinâmica
Nessa opção, os dados têm como origem um outro formulário. Ao selecionar esse outro formulário, é necessário informar qual o campo desse formulário será exibido.
Esse campo não deve ser usado quando há muitas opções. Isso por que, todas as opções desse campo são lidas quando a página é carregada. Se houver muitos itens, o carregamento da página pode ser afetado. Para esses casos, usar o campo pesquisa com auto completar.
Para maiores detalhes, leia o capítulo de configuração do campo Lista de Seleção.
Pesquisa com auto completar
É similar ao Lista de Seleção, com a diferença que esse campo apenas tem os itens com origem em uma lista dinâmica. Além disso, as opções provenientes dessa lista, somente são mostradas após o usuário começar a digitar. Para maiores detalhes, leia o capítulo de configuração do campo Label Dinâmica.
Esse campo deve ser usado quando o número de itens seja elevado.
Checkbox (Único)
Esse campo permite o usuário responder a uma pergunta cuja resposta tem duas opções. Nesse campo, é possível definir o texto quando o campo está marcado, e quando o campo está desmarcado. O texto escolhido quando o campo está marcado, será mostrado na tela, enquanto o texto do campo quando está desmarcado, apenas será mostrado na listagem e no filtro de dados.
Para maiores detalhes, leia o capítulo de configuração do campo Checkbox.
Lista aberta com escolha única (Radio)
Esse campo é muito similar ao tipo Lista de Seleção, mudando apenas a forma como é apresentado. Abaixo, um exemplo do campo radio (Lista aberta com escolha única):

Quando a fonte dos dados for dinâmica, a opção de criar um novo item não está disponível no campo Lista aberta com escolha única (Radio).
Para maiores detalhes, leia o capítulo de configuração do campo Lista aberta com escolha única (Radio).
Fórmula
O campo de fórmula faz dois tipos de cálculos: com campos numéricos e com campos com data/hora. É na definição do campo que seleciona-se o tipo de cálculo. Ao escolher o tipo, serão mostrados os campos disponíveis para serem usados.
- Fórmula Numérica: é possível fazer as 4 operações aritméticas (soma, subtração, divisão e multiplicação) nesse campo. Para isso, basta selecionar um ou mais campos com a máscara do tipo numérico e escrever a fórmula.
- Fórmula por data/hora: nessa opção, é possível subtrair um campo do tipo data/hora, por outro campo do tipo data/hora. Como resultado, é possível obter:
-
Número de Dias
-
Número de Meses
-
Número de Anos
-
Número de Semanas
-
Número de Horas:Minutos
-
Para fórmula com datas, só é possível fazer a operação de subtração.
Para maiores detalhes, leia o capítulo de configuração do campo Fórmula.
Campo com Múltipla Escolha
Apesar do visual um pouco diferente, tem comportamento similar ao campo checkbox, mas permite a escolha de mais de uma opção. Para maiores detalhes, leia o capítulo de configuração do campo com Múltipla Escolha.
Botão Customizado
Caso seja necessário uma ação no formulário que não exista no agilityflow, é possível criar um botão. Esse botão, executa um código javascript personalizado, que deve ser criado pelo usuário. Para a configuração desse campo, é necessário conhecimento de javascript, já que qualquer ação com esse botão é 100% customizada.
Para maiores detalhes, leia o capítulo de configuração do campo Botão Customizado.
Tabelas (Formulários Relacionados)
É a inclusão de um formulário dentro de outro. Saiba mais, no capítulo de Formulários Relacionados do Manual de Customização do agilityflow.
Montar e organizar a tela de cadastro
Montar tela de cadastro
É necessário montar a estrutura da tela do formulário, com os grupos de informações e os campos.
Barra Horizontal

Confirmar Alterações
Sai da montagem da tela, salva a tela com as configurações atuais.
Fechar e Cancelar
Sai da montagem da tela, descartando as alterações.
Simular em Tela em outras Resoluções
Ao clicar em um dos 4 botões, você consegue ver como ficará a tela nas seguintes resoluções:
- Monitor
- Laptop
- Tablet
- Celular
Limpar Tela
Remove todos as estruturas da tela.
Na montagem da tela, existem 3 estruturas que podem ser utilizadas:
Montagem da Tela
Grupo de Informações
Cada grupo de informação criado no formulário estará disponível para ser usado como estrutura na tela. Esses grupos, quando adicionados na tela, funcionam como uma caixa que ajudam a separar os campos de outros grupos. Além disso, esse grupo pode ser fechado ou aberto pelo usuário, facilitando quando existe uma grande quantidade de campos no formulário.
No exemplo abaixo, é possível ver um formulário simples de cadastro de clientes, onde os grupos de informações estão adicionados como estruturas da tela.

Clicando no ícone
no canto superior direito do grupo de informações, recolhe o grupo de informações. Clicando no ícone
ocorre a expansão.
Entretanto, a inclusão dos grupos de informações como estruturas na tela é opcional. Abaixo, o mesmo formulário do exemplo acima, sem a inclusão dos grupos de informações.

Para adicionar um grupo de informações, basta arrastar para a área desejada da tela.
Diagramação (Colunas)
A tela do formulário é separada em colunas. Caso não seja adicionada nenhuma coluna, o padrão é ter uma coluna só. A tela é dividida em 12 unidades fictícias de medidas. Quando se adicionam colunas, é possível definir o tamanho de cada uma, de forma que a soma de todas nunca ultrapasse 12. Portanto, é possível adicionar um máximo de 12 colunas, cada uma com o tamanho 1.
O sistema sugere por padrão, as seguintes opções de quantidade de colunas e tamanho:
- 1 col: 12
- 2 col: 6 6
- 2 col: 8 4
- 2 col: 9 3
- 3 col: 4 4 4
- 3 col: 2 6 4
- 3 col: 6 4 2
- 4 col: 3 3 3 3
Ao adicionar qualquer uma das estruturas, é possível movê-la na tela usando o ícone
. Para apagar, use o. Caso queira duplicar a estrutura com o aspecto idêntico, clique em
.
Para alterar a quantidade de colunas dessa estrutura, clique em
. Isso vai abrir uma tela onde é possível distribuir as 12 unidades entre as colunas, assim como adicionar ou remover colunas.
É possível incluir um grupo de informação dentro de uma coluna, assim como também é possível dividir um grupo de informação com colunas. Além disso, é possível incluir um grupo de informação dentro de outro, assim como uma coluna dentro de outra.
Campos
Os campos estão disponíveis para serem incluídos logo abaixo da diagramação, e estão separados pelos respectivos grupos de informação.
Tanto os grupos de informações como as colunas, servem como estruturas de tela, onde os campos vão ser incluídos. Não é possível incluir os campos fora dessas estruturas.
Ao expandir um dos grupos, são exibidos os campos que pertencem a esse grupo. Basta arrastar o campo para o local desejado na tela.
Note que, mesmo incluído na tela, um campo pode não ser exibido devido as regras de visibilidade.
Configurar ações e os botões do menu do formulário

Configurar botões e algumas ações
Aqui, é possível configurar as opções da barra que é mostrada na tela de cadastro de um formulário (tela para criação ou visualização de um registro):
Mostrar botão 'Consultar'
Ligado por padrão, permite mostrar ou ocultar o botão de consulta (
). Ao clicar, na prática, a tela de cadastro é fechada e o usuário é enviado de volta ao menu principal, onde podem ser realizados os filtros para fazer a consulta.
Mostrar botão 'Salvar'
Ligado por padrão, permite mostrar ou ocultar o botão de Salvar.
Mostrar botão 'Salvar em Rascunho'
Ligado por padrão, permite mostrar ou ocultar o botão de Salvar em Rascunho.
Mostrar botão 'Excluir'
Ligado por padrão, permite mostrar ou ocultar o botão de Excluir (
). Esse botão só é exibido ao visualizar um registro já existente. Fica oculto quando se está criando um novo registro.
Mostrar botão 'Aprovar'
Ligado por padrão, permite mostrar ou ocultar o botão de Aprovar etapa (
). Esse botão só será exibido em formulários que tenham fluxos por etapa.
Mostrar botão 'Retornar etapa'
Ligado por padrão, permite mostrar ou ocultar o botão de Retornar etapa (
). Esse botão só será exibido em formulários que tenham fluxos por etapa.
Mostrar botão 'Reprovar'
Ligado por padrão, permite mostrar ou ocultar o botão de Reprovar etapa (
). Esse botão só será exibido em formulários que tenham fluxos por etapa.
Nomenclatura para o botão 'Salvar'
É possível alterar o texto do botão que vai ao lado do ícone
.
Nomenclatura para o botão 'Salvar rascunho':
É possível alterar o texto do botão que vai ao lado do ícone
.
Nomenclatura para o botão 'Aprovar'
É possível alterar o texto do botão que vai ao lado do ícone
.
Nomenclatura para o botão 'Aprovar' na primeira etapa
O botão aprovar pode ter um comportamento diferente na primeira etapa. É possível alterar o texto do botão que vai ao lado do ícone
.
Nomenclatura para o botão 'Retornar etapa'
É possível alterar o texto do botão que vai ao lado do ícone
.
Nomenclatura para o botão 'Reprovar'
É possível alterar o texto do botão que vai ao lado do ícone
.
Após salvar ou realizar qualquer ação com sucesso no formulário, o que deve acontecer
Permite definir o comportamento do formulário, quando se clica nos botões Salvar, Salvar em Rascunho ou Excluir. São eles:
- Redirecionar para a lista: é a ação padrão. Leva o usuário à tela padrão do formulário, com a lista dos registros;
- Redirecionar para a tela inicial do sistema: leva o usuário para a tela que é aberta ao fazer a entrada no sistema;
- Redirecionar para a criação de um novo cadastro: abre a tela de cadastro, para a criação de um novo registro;
- Redirecionar para a mesma tela em modo edição: salva as alterações, mas mantém aberta a tela de cadastro;
- Imprimir o relatório de impressão X: abre a tela de impressão do relatório selecionado.
Bloquear novos registros
Como bloquear o cadastro de novos registros em um formulário?
Com essa opção, é possível bloquear o cadastro de novos registros, não importando a permissão do usuário. São duas opções:
- Liberado para cadastro de novos registros (padrão);
- Bloqueado para cadastro de novos registros;
Ações customizadas (Menu interno)
As ações customizadas são formas de abrir um quadro (kanban), um relatório, uma lista de formulário ou um novo formulário, baseados em um registro. Ao clicar no menu
de um registro, as ações customizadas são mostradas.
Um formulário pode ter múltiplas ações customizadas, e elas são mostradas em lista, onde é possível ver o tipo, se está ativa ou não, reordenar, excluir ou configurar.
Essa ações fazem sentido, quando são utilizadas em um formulário que utiliza formulários relacionados. Com isso, é possível acessar um registro, e através de uma ação customizada, abrir um outro formulário que possua registros relacionados ao primeiro.
Para criar uma nova ação, basta clicar no botão "Adicionar Ação" e seguir os seguintes passos:

Ação
Nome da ação
Se define o nome da ação. Esse nome será exibido no menu dos registros.
Ativo
Se essa ação está disponível para ser utilizada ou não.
Tipo
São 4 opções:
- Abrir quadro (kanban): ao selecionar essa opção, é necessário escolher qual o quadro que será aberto. Feito isso, é possível já definir um filtro, onde se escolhe um campo que tenha alguma associação (pelo id do formulário) com o formulário do quadro escolhido
- Abrir relatório
- Abrir lista do formulário
- Abrir um novo formulário
Regras de visibilidade
Disponível na listagem
Indica se essa ação estará visível no menu
dos registros.
Disponível no formulário
Indica se essa ação estará visível como um botão, dentro do registro, quando o mesmo for aberto.
Regra condicional de visibilidade
É possível também, vincular a visibilidade de acordo com uma regra. A regra é definida pelo usuário, e sempre que existir uma regra criada, a ação só será exibida quando o resultado da regra for verdadeiro.
Customização javascript
Todos os campos do agilityflow possuem inúmeras customizações, que flexibilizam seu uso para o usuário. Entretanto, podem haver casos de customizações muito específicas, que o agilityflow não possua. Para esses casos, é possível inserir uma programação javascript no campo. Com isso, o agilityflow disponibiliza toda a flexibilidade do javascript para adequar o comportamento dos campos à sua necessidade.
Além disso, é possível programar que essa ação seja executada, não só para o clique, mas também para outras formas de interação com esse botão. São elas:
- On Page Load: ação é executada assim que a página carregar.
- On Blur
- On Change
- On Click
- On Focus
- On Input
- On KeyUp
- On Keydown
- On Mouseover
- On Mouseout
Lista e consulta
Nessa aba, é possível configurar as opção de listagem dos formulários, filtros padrão e quadros Kanban;
Listagem no formato de tabela de dados
A listagem principal dos dados do formulário é como os registros serão mostrados e como será a ordenação desses registros.
Como a tela principal do formulário irá mostrar uma lista de registros, nem sempre será possível mostrar todas as colunas do formulário. Por isso, precisamos selecionar as colunas serem mostradas e escolher uma ordenação. Também é possível definir os filtros que estarão disponíveis.
Colunas
Adiciona-se as colunas que se deseja exibir. É necessário ter pelo menos uma coluna adicionada. Para cada coluna adicionada, abrem-se 3 opções:
Posicionar Coluna
Ao clicar nesse ícone, basta arrastar a coluna para a ordem desejada. A ordem, que nessa tela é apresentada de cima pra baixo, na listagem do formulário é da esquerda para direita. Ou seja, quanto ainda pra cima está a coluna, mais à esquerda ela será apresentada na listagem.
Visível no Mobile
Pela limitação de largura das telas dos celulares, é possível ocultar algumas colunas, quando o formulário for aberto em um dispositivo móvel. Para isso, basta desmarcar a opção 'Visível no Mobile', que ver marcada por padrão.
Excluir
Remove a coluna da listagem.
Ordenação
É necessário adicionar uma ordenação padrão para cada formulário. Ao adicionar uma coluna nessa lista, a ordenação padrão do formulário é definida.
Ao adicionar mais de uma coluna, primeiro se ordena a listagem baseado no primeiro campo, depois no segundo e assim por diante.
Existem ainda, 3 opções de configuração para cada coluna:
Decrescente ou Crescente
Define o critério crescente ou decrescente de ordenação para essa coluna.
Ordenar Prioridade
Ao clicar nesse ícone, basta arrastar a coluna para a ordem desejada.
Excluir
Remove a coluna do critério de ordenação.
Filtros disponíveis para consulta dos dados
Filtros
Essa opção não é obrigatória e por padrão, todos os campos são adicionados no filtro.
Nessa opção, é possível habilitar ou não o filtro pelos campos do formulário. É possível também definir a ordem dos campos dentro da aba de filtro da listagem dos dados do formulário.
Definir os valores e regras iniciais
Filtro inicial fixo
Quando definido o filtro desse tipo, o filtro inicial será aplicado independente do usuário. São essas as opções a serem definidas
- Só minhas pendências: apenas os fluxos com pendências do usuário logado, serão exibidos;
- Todos: todos os fluxos serão exibidos;
- Apenas os que eu participei: apenas os fluxos cadastrados ou com participação pelo usuário logado, serão mostrados;
- Etapa atual: seleciona qual etapa do fluxo o filtro virá selecionado por padrão;
- Status: caso o formulário seja um formulário com etapas, seleciona o status dos fluxos:
- Em andamento
- Aprovado
- Reprovado
- Campos: todos os campos do formulário serão exibidos nessa opção, e cada um dos campos permitirá que haja um filtro inicial padrão;
- campo desativado para inclusão de novos filtros: quando marcada, essa opção previne o usuário de alterar ou incluir o filtro padrão inicial;
Filtro inicial com condicional por perfil e usuário
As definições do filtro em si, são exatamente idênticas à configuração acima. Entretanto, usar essa opção permite padronizar filtros de acordo com o usuário logado, ou o perfil (ou mais de um) do usuário logado;

Para isso, é necessário definir duas condições no mínimo. Uma inicial e outra para quando a condição inicial não for verdadeira.
Só Minhas Pendências
Quando o formulário possuir etapas, a opção "No filtro inicial, ao abrir a listagem, apresentar o filtro (checkbox) de "Só minhas pendências" marcado ou desmarcado:" será mostrada. Essa opção é uma definição de padrão de visualização.
Quando marcada, o usuário vai sempre ver por padrão, apenas suas pendências marcadas no filtro, podendo desligar Se assim desejar.
Essa opção afeta o comportamento para todos os usuários.
Quadros (Kanban)
Os detalhes para a criação e configuração podem ser visualizados no capítulo Quadros (Kanban).
Relatórios para impressão e PDF
Os relatórios para impressão é uma forma que podemos imprimir (ou gerar um PDF) os dados de um formulário (e de outros) em um formato pré-definido. É possível definir vários relatórios para um mesmo formulário. Isso é útil, quando se precisa das informações que constam em um formulário, mas como foco diferente.
Por exemplo, em um formulário de pedidos, é possível criar um relatório com os detalhes do pedido e um outro com detalhes apenas da entrega.
Qual a diferença entre o relatório para impressão e o relatório analítico?
A principal diferença é que no relatório para impressão é possível formatar a(s) página(s), dando uma apresentação customizada às informações.
Como foi dito, nos relatórios é possível criar um layout com imagens, logotipo da empresa e etc, dando uma outra roupagem aos dados do formulários quando são impressos.
A definição dos relatórios para impressão é feita como em um editor de texto comum. Para criar um formulário, clique no botão 'adicionar impressão'.
Título
É o nome que aparecerá na tela do formulário ao se clicar no ícone
.

Edição do documento
A área para edição do documento, funciona como um editor de texto clássico. É possível adicionar textos fixos, tabelas, imagens, quebra de linha e etc. Todos os recursos de um editor de texto estão disponíveis na barra superior:

Além desses recursos, outros dados estão disponíveis para serem adicionados:
Campos
Todos os campos do formulário ficam disponíveis para serem utilizados no relatório, com exceção do Botão Customizado. Para adicionar qualquer campo, basta arrastar para o relatório. Ao fazer isso, o nome do campo é adicionado ao lado do conteúdo, que é representado pelo @.

Para fazer a formatação do conteúdo, basta selecionar o conteúdo (que fica com um contorno amarelo) e aplicar a formatação normalmente.
Formulário Relacionado
Quando o formulário é relacionado, todos os registros desse formulário serão mostrados na listagem. É possível filtrar o conteúdo, clicando com o botão direito e selecionando a opção 'Editar Filtro de Dados'.
Além disso, as colunas que serão mostradas nessa tabela, são as mesmas que estão configuradas na listagem de dados desse formulário. Caso não queira a exibição de uma delas, basta remover a coluna da tabela. Para adicionar uma informação, basta criar uma coluna e arrastar o campo do formulário relacionado desejado.
Campo Upload
Ao posicionar o campo upload no relatório, e seu conteúdo for uma(s) imagem(ns), a(s) imagem(ns) será(ão) exibida(s) no relatório.
Log
Algumas informações internas do sistema estão também disponíveis para serem incluídas no relatório. São elas:
- Alterado por: nome do usuário que fez a última alteração no formulário;
- Criado por: nome do usuário que criou originalmente o formulário;
- Data Alteração: data e hora em que ocorreu a última alteração no formulário, no formato DD/MM/AAAA HH:mm;
- Data Criação: data e hora em que ocorreu a criação no formulário, no formato DD/MM/AAAA HH:mm;
Outras Variáveis
É a data atual, em diversos formatos:
- Data (DD/MM/AAAA): por exemplo 11/03/2019;
- Data (DD/MM/AAAA HH:mm): 11/03/2019 13:44;
- Data (DD de mês de AAAA): 11 de Março de 2019;
- Data (Dia da semana, DD de mês de AAAA): Segunda-Feira , 11 de Março de 2019;
Outras Fontes de dados
É um recurso que permite adicionar dados de outros registros ou formulários no relatório. A criação dessas outras fontes de dados, depende da composição de queries SQL nas tabelas dos formulários.
O agilityflow usa o SQL Server 2016. Para maiores informações, acesse a página do produto no site da Microsoft.
Na composição da query, é necessário usar os nomes as tabela informado nos Dados Técnicos do formulário e o nome informado no campo Coluna Banco de Dados SQL, na configuração dos campos.
Elas podem ser de dois tipos:
Tabela de Dados
A query retorna uma lista com várias colunas e linhas. Para o relatório, o elemento a ser adicionado é uma tabela. Ao clicar com o botão direito, é possível definir o agrupamento por um dos campos da query.
Variáveis
A query retorna uma lista com várias colunas mas apenas uma linha. Para o relatório, cada coluna é um elemento que pode ser adicionado ao relatório.
Para esse tipo de fonte de dados, é necessário usar o parâmetro 'top 1' no select.
Exemplo de Query
Cenário: um relatório do formulário de clientes onde se obtém os últimos 15 pedidos desse cliente em uma impressão.
SELECT TOP 15 pedido.log_data_criacao,
desc_ped,
valor_ped
FROM x_tbl_pedido AS pedido
INNER JOIN x_tbl_cliente AS cliente
ON pedido.id_cliente = cliente.id
WHERE cliente.id = @formularioid
ORDER BY pedido.log_data_criacao DESC
Na query acima, vamos exibir os campos log_data_criacao, desc_ped e valor_ped dos últimos 15 registros (pedidos) ta tabela x_tbl_pedido, cujo cliente do pedido seja igual ao cliente que o usuário está acessando no formulário de Clientes (x_tbl_cliente). A ordem dessa lista é decrescente baseada no campo log_data_criacao.
Regras de Visibilidade e Desativação
Em todos os campos da plataforma, é possível criar regras para tornar um campo visível, invisível, ativo ou inativo, e definir quando uma dessas ações deve ocorrer. É possível adicionar várias regras para cada campo.
Descrição
É um texto que ajuda a identificar a regra que se está criando. Muito útil quando existem múltiplas regras.
Ação
Ativar
Deixa o campo disponível para inserção de dados. É o estado padrão do campo.
Inativar
Deixa o campo indisponível para inserção de dados.
Visível
O campo é mostrado na tela, caso esteja inserido para tal, nas configurações de tela.
Invisível
O campo é não é mostrado na tela, mesmo que esteja inserido para tal, nas configurações de tela.
A partir da etapa / Até a etapa
Em formulários com etapas, é possível estabelecer que uma regra será aplicada em alguma(s) etapa(s). Para isso, basta selecionar as etapas nos campos "a partir da etapa" e "até a etapa", para definir em que momento do fluxo essa regra vai ser aplicada.
Quando
Define em que momento a ação deve acontecer.
Sempre
É o padrão do formulário.
Condicional
- Tipo de condição
Para fazer um validação condicional, estão disponíveis as seguintes condições:
- Se o campo: compara um campo com um valor, ou com outro campo.
Abaixo, uma tabela com os operadores disponíveis para as comparações:
Comparação por valor Comparação por outro campo For igual a É igual ao campo For maior ou igual a É diferente do campo For menor ou igual a For maior que For menor que For diferente de Conter Não conter É possível adicionar mais de um condição na mesma regra.
- Se é um novo formulário: regra será aplicada quando uma nova entrada no formulário estiver sendo criada.
- Se é edição de formulário: regra será aplicada quando uma entrada no formulário estiver sendo alterada.
- Se o campo: compara um campo com um valor, ou com outro campo.
Lista de atributos de configuração por campos
| Atributos dos campos e componentes do formulário |
Campo Textbox
|
Label Dinâmica Novo
|
Upload
|
Lista de seleção (Combo)
|
Pesqiusa com auto completar
|
Checkbox (Único)
|
Lista aberta com escolha única (Campo Radio)
|
Fórmula
|
Campo com Múltipla Escolha
|
Botão Customizado
|
Tabelas (Formulários Relacionados)
|
Tabelas Relacionais (N:N)
|
Componentes CsHtml
|
| Grupo de Informação | |||||||||||||
| Nome de Apresentação | |||||||||||||
| Tipo | |||||||||||||
| Campo de Texto Simples | |||||||||||||
| Campo de Texto Multi Linha | |||||||||||||
| Campo com criptografia MD5 (Ex: Senha) | |||||||||||||
| Campo Auto Numérico (Número Sequencial preenchido automaticamente) | |||||||||||||
| Texto ao lado do Checkbox | |||||||||||||
| Quando marcado | |||||||||||||
| Quando desmarcado | |||||||||||||
| Coluna Banco de Dados (SQL) | |||||||||||||
| Informações de ajuda | |||||||||||||
| Preenchimento Padrão | |||||||||||||
| Preencher Quando | |||||||||||||
| Valor Padrão | |||||||||||||
| Máscara | |||||||||||||
| Tipo de máscara | |||||||||||||
| Número | |||||||||||||
| Tipo de Número | |||||||||||||
| Inteiro | |||||||||||||
| Moeda (Real) | |||||||||||||
| Decimal (1 casa decimal) | |||||||||||||
| Decimal (2 casas decimais) | |||||||||||||
| Decimal (3 casas decimais) | |||||||||||||
| Decimal (4 casas decimais) | |||||||||||||
| Decimal (5 casas decimais) | |||||||||||||
| CPF | |||||||||||||
| CNPJ | |||||||||||||
| CEP | |||||||||||||
| Máscara Customizada | |||||||||||||
| Tipo de Customização | |||||||||||||
| Básica | |||||||||||||
| Avançada | |||||||||||||
| Máscara com 'Regular Expression' | |||||||||||||
| Telefone: País + DDD + Cel/Tel Brasil | |||||||||||||
| Telefone: DDD + Cel/Tel Brasil | |||||||||||||
| Telefone: Cel/Tel Brasil | |||||||||||||
| Data Data e hora no formato dd/mm/yyyy hh:mm | |||||||||||||
| Data e hora (Com Segundos) no formato dd/mm/yyyy hh:mm:ss | |||||||||||||
| Data sem hora no formato dd/mm/yyyy | |||||||||||||
| Hora no formato hh:mm | |||||||||||||
| Hora (Com Segundos) no formato hh:mm:ss | |||||||||||||
| Tamanho máximo de Preenchimento | |||||||||||||
| Preenchimento da Label Dinâmica | |||||||||||||
| Preencher a label dinâmica ao alterar o campo | |||||||||||||
| Campo de apresentação (Base de dados) | |||||||||||||
| Origem dos Dados | |||||||||||||
| Origem dos Itens | |||||||||||||
| Lista Dinâmica | |||||||||||||
| Lista Estática | |||||||||||||
| Carregamento de lista | |||||||||||||
| No carregamento inicial (On PageLoad) | |||||||||||||
| Na alteração do valor de um determinado campo (On Change) | |||||||||||||
| Base de dados | |||||||||||||
| Campo de apresentação (Base de dados) | |||||||||||||
| Origem dos Dados e Relacionamento com outros Formulários (Pai X Filho) | |||||||||||||
| Esse campo pode ser Relacionado a um formulario Pai e preenchido automáticamente pelo ID (Primary Key) do formulário pai | |||||||||||||
| Esconder campo quando o formulário for aberto através do formulario pai | |||||||||||||
| Definição da Fórmula | |||||||||||||
| Tipo de Cálculo | |||||||||||||
| Fórmula Numérica | |||||||||||||
| Fórmula por data/hora | |||||||||||||
| Fórmula | |||||||||||||
| Validação | |||||||||||||
| Obrigatório | |||||||||||||
| Obrigatório mesmo que por algum motivo o campo esteja marcado como invisível? | |||||||||||||
| Obrigatório a partir da etapa | |||||||||||||
| Valor do campo deve ser único em relação a todos os registros | |||||||||||||
| Valor do campo deve ser único em relação ao formulário PAI: | |||||||||||||
| Valor do campo deve ser único em relação APENAS ao CAMPO relacinoado do formulário PAI: | |||||||||||||
| Extensão Permitida | |||||||||||||
| Extensão não permitida | |||||||||||||
| Validação customizada | |||||||||||||
| Tipo de Validação | |||||||||||||
| Número igual e diferente | |||||||||||||
| Numerica: O valor digitado deve ser igual ao numero | |||||||||||||
| Numerica: O valor digitado deve ser diferente do numero | |||||||||||||
| Numerica: O valor digitado deve ser igual ao campo | |||||||||||||
| Numerica: O valor digitado deve ser diferente do campo | |||||||||||||
| Número máximo | |||||||||||||
| Numerica: O valor digitado nao pode ser maior que o numero | |||||||||||||
| Numerica: O valor digitado nao pode ser maior nem igual ao numero | |||||||||||||
| Numerica: O valor digitado nao pode ser maior que o campo | |||||||||||||
| Numerica: O valor digitado nao pode ser maior nem igual ao campo | |||||||||||||
| Número mínimo | |||||||||||||
| Numerica: O valor digitado nao pode ser menor que numero | |||||||||||||
| Numerica: O valor digitado nao pode ser menor nem igual ao numero | |||||||||||||
| Numerica: O valor digitado nao pode ser menor que o campo | |||||||||||||
| Numerica: O valor digitado nao pode ser menor nem igual ao campo | |||||||||||||
| Range numérico | |||||||||||||
| Numerica: O valor digitado tem que estar entre os numeros | |||||||||||||
| Numerica: O valor digitado NAO pode estar entre os numeros | |||||||||||||
| Texto igual e diferente | |||||||||||||
| Texto: O valor digitado deve ser igual ao texto | |||||||||||||
| Texto: O valor digitado deve ser diferente do texto | |||||||||||||
| Texto: O valor digitado deve ser igual ao campo | |||||||||||||
| Texto: O valor digitado deve ser diferente do campo | |||||||||||||
| Texto contém | |||||||||||||
| Texto: O valor digitado deve conter no minimo o texto | |||||||||||||
| Texto: O valor digitado NAO deve conter o texto | |||||||||||||
| Outros | |||||||||||||
| CNPJ | |||||||||||||
| CPF | |||||||||||||
| Avançado | |||||||||||||
| Regex | |||||||||||||
| Upload lista | |||||||||||||
| Upload: Upload de no máximo X itens | |||||||||||||
| Upload: Upload no mínimo X itens | |||||||||||||
| Upload: Upload exatamente X itens | |||||||||||||
| Seleção Lista | |||||||||||||
| Seleção: Selecionar no máximo X itens | |||||||||||||
| Seleção: Selecionar no mínimo X itens | |||||||||||||
| Seleção: Selecionar exatamente X itens | |||||||||||||
| Validar a partir da etapa | |||||||||||||
| Regras de Visibilidade e desativação | |||||||||||||
| Ação | |||||||||||||
| Ativar | |||||||||||||
| Inativar | |||||||||||||
| Visível | |||||||||||||
| Invisível | |||||||||||||
| Quando | |||||||||||||
| Sempre | |||||||||||||
| Condicional | |||||||||||||
| A partir da etapa | |||||||||||||
| Até a etapa | |||||||||||||
| Customização javascript | |||||||||||||
| Descrição | |||||||||||||
| Evento | |||||||||||||
| On Page Load | |||||||||||||
| On Blur | |||||||||||||
| On Change | |||||||||||||
| On Click | |||||||||||||
| On Focus | |||||||||||||
| On Input | |||||||||||||
| On KeyUp | |||||||||||||
| On KeyDown | |||||||||||||
| On Mouseover | |||||||||||||
| On Mouseout | |||||||||||||
| A partir da etapa | |||||||||||||
| Ordenação manual organizada pelo próprio usuário | |||||||||||||
| Customização da Lista | |||||||||||||
| Coluna Visível | |||||||||||||
| Prefixo | |||||||||||||
| Sufixo | |||||||||||||
| Informação no Rodapé | |||||||||||||
| Soma da Coluna | |||||||||||||
| Média da Coluna | |||||||||||||
| Mascara: Moeda (Real) | |||||||||||||
| Máscara: Decimal (1 casa decimal) | |||||||||||||
| Máscara: Decimal (2 casas decimais) | |||||||||||||
| Máscara: Decimal (3 casas decimais) | |||||||||||||
| Máscara: Decimal (4 casas decimais) | |||||||||||||
| Máscara: Decimal (5 casas decimais) | |||||||||||||
| Lista do formulário que podem ser apresentadas como Sub Lista | |||||||||||||
| Já abrir com as Sub Lista expandidas | |||||||||||||
| Sub Lista visível | |||||||||||||
| Apresentar nessa tabela de dados apenas os dados que foram cadastrados através desse campo da tela |
Regras de negócio (Automação)
As regras de negócio são regras condicionais que podem executar diversas ações. Essas regras de negócio devem ser sempre associadas a um formulário, e sua criação deve ser feita nas configurações do formulário desejado.
Criando as regras
Antes de mais nada, é necessário definir um nome para a regra. Esse é o nome que será apresentado depois, na construção da linha do tempo. As regras de automação, podem ter 3 partes.
Condicional (se)
É onde podemos testar uma ou várias condições. Essas condições referem-se a comparações de um valor com um campo. É possível adicionar as seguintes condições:
- Se: é uma comparação simples;
- Caso Contrário: é o que vai ocorrer, caso a condição "Se" não se satisfaça;
- Se/Caso Contrário: é uma possibilidade de se colocar uma segunda condição;

No exemplo acima, queremos dar um tratamento quando o campo 'Tipo de Entrega' for igual a 'Correios', outro quando for 'Mensageiro' e outro para todos os demais valores do campo.
Criar Formulário
A criação do formulário é o preenchimento do campos do formulário de destino com os valores do formulario de origem (onde a regra está sendo criada) ou com valores pré-definidos.
Esses valores pré-definidos, em casos de campos de textos, podem ser fixados quando se define a regra de criação do formulário. Já os campo de seleção, como lista de seleção, a lista aberta com escolha única (radio), a pesquisa com auto completar, e etc, podem ser atribuídos de outros campos que possuem as mesmas opções, ou selecionados de maneira fixa.
Query SQL (Fonte de Dados)
Usando essa opção, é possível fazer uma query sql em qualquer tabela do agilityflow e atribuir o resultado à uma variável, e usar o valor nas comparações e nos mapeamentos de formulários.
Ao criar a query, será preciso definir o nome da variável e da query. O nome da variável, será usado posteriormente para identificar o valor nas condições e mapeamentos.
A query, segue os padrões das queries utilizadas em outros pontos do agilityflow, e os detalhes podem ser vistos aqui. Uma diferença, é que o conteúdo da primeira linha e da primeira coluna (resultado da query) é atribuído à uma variável. Outra diferença, é que nessa query é obrigatório o uso do parâmetro "top 1".
No exemplo abaixo, existe um query que verifica a existência do usuário e, dependendo do resultado, toma uma ou outra ação:

É necessário colocar a execução da query antes do teste da variável na estrutura condicional (se).
Programação customizada
Uma forma de se customizar ainda mais o agilityflow é incluir programação em alguns pontos. A programação customizada permite que seja incluído qualquer código em C#, dando uma enorme flexibilidade de ações.
Momento de execução das regras
As regras precisam ser executadas em um determinado momento. Os momentos são esses:
- No carregamento inicial do formulário (OnPageLoad)
- Ao clicar no botão 'Salvar'
- Ao clicar no botão 'Deletar'
- Ao alterar o campo
Configuração da timeline
É quando as regras serão executadas. A timeline (linha do tempo) é uma ordem de acontecimentos onde as regras podem ser incluídas. Para o momento de alteração de campo, a timeline só tem um espaço. Para os demais momentos, são 3 espaços para a inclusão de regras:
- Antes de validar se o preenchimento dos campos está correto
- Depois de validar o preenchimento dos campos e Antes de salvar no banco de dados
- Depois de salvar no banco de dados
Reordenar as regras
Uma vez posicionada, as regras podem ser reordenadas. Basta clicar no ícone
e arrastar para a posição desejada.
Inativar uma regra
Para inativar uma regra, clique no menu à direita, e selecione a opção 'inativar nessa timeline'.
Feito isso, a regra recebe uma tarja vermelha com a indicação 'inativo'.
Restrição de acesso a Dados na Lista Principal e Regras de Filtros
Além de restrição do acesso a funcionalidades por Perfil, você pode em restringir o acesso a dados de uma determinada funcionalidade usando Filtros inicias.
Na lista principal por exemplo, você pode restringir acesso aos dados, definindo condicionais nos Valor e Regras Iniciais de Filtros, como na imagem abaixo.
Para isso acesse o seu Formulário ou Fluxo, clica na opção "Construir a tela de lista de Consulta", deois acesse "Filtros: Valor e regras inicias"
Você pode ir além e criar (sub)Queries, dentro das opções de filtro citadas acima. Essa é uma opção mais avançada e requer habilidade com SQL.
Em um fluxo de aprovação existe uma funcionalidade nativa que você consegue restringir o acesso nativamente, mostrando para o usuário apenas os fluxos em que ele participou, como na imagem abaixo
Se achar melhor, você pode entrar em contato com a gente e podemos detalhar como tudo isso funciona :-)
Devcenter - Customizar o Agilityflow
Área de customização de todos os recursos da plataforma
Menu
É possível criar menus na Barra Vertical / Menu Principal do agilityflow.
Para isso, basta clicar no ícone do Devcenter
localizado na Barra Vertical, e em seguida em Menu.

Ao clicar em "Consultar"
, é possível ver a lista de menus já existentes.
Clicando em "Novo Menu"
, o usuário irá criar um novo Menu na Barra Vertical.

Feito isso, basta escolher um nome e um ícone, e o novo menu está pronto.
Relatório analítico / BI
Os relatórios são uma forma de transformar os dados dentro do agilityflow, em informações valiosas. Os relatórios podem trazer uma série de dados de diferentes tabelas, com inúmeros cruzamentos, que possibilitam ao usuário do agilityflow, fazer uma série de análises e auxiliam na tomada de decisões estratégicas no seu negócio.
Para criar o relatório, é necessário dar um nome. Além disso, escolhe-se um ícone e o menu onde o relatório vai ficar, além de informar uma descrição. Existem também uma opção para desativar o relatório.
Os relatórios são divididos em painéis. Esses painéis, possuem elementos, assim como os widgets do dashboard. É possível adicionar múltiplos painéis.
Filtro
Todo relatório também possui uma área de filtros. Isso possibilita que os relatórios possam ter seus dados filtrados no momento em que o usuário o acessa. Isso possibilita expor informações e permitir que o usuário interaja com esses dados como lhe convir.
Apesar de útil, os filtros são opcionais em um relatório.
Ao adicionar os filtros, você deve criar campos para que o usuário interaja com o filtro. Ao criar um novo campo para o seu filtro, você deve preencher as seguintes informações:
Nome de Apresentação
É o nome que será mostrado ao usuário, e é como esse filtro será identificado na configuração do relatório.
Id do campo
É como esse valor será levado para as queries que montarão o relatório.
Ativo
Por padrão, é marcado como Sim. Habilita ou desabilita um filtro para ser usado no relatório.
Tipo
Como esse filtro é um campo, você deve informar de qual tipo é esse campo.
Texto Livre
É um campo que o usuário pode colocar qualquer texto
Data/Hora
Um campo contendo data e/ou hora. É também necessário definir um formato:
- Data e hora no formato dd/mm/yyyy hh:mm
- Data sem hora no formato dd/mm/yyyy
- Hora no formato hh:mm
Número
Campo com um valor numérico.
É também necessário definir um formato:
- Inteiro
- Moeda (Real)
- Decimal (1 casa decimal)
- Decimal (2 casas decimal)
- Decimal (3 casas decimal)
- Decimal (4 casas decimal)
- Decimal (5 casas decimal)
Lista para Seleção ou Pesquisa com Auto Completar
Para esses tipos, é necessário escolher a base de dados que será utilizada e o campo de apresentação. Além disso, é possível adicionar uma condição na base de dados.
Após a configuração do filtro, será criada uma variável. Essa variável está indicada com "@" e deverá ser usada na query juntamente com a Função Filter.
Definir os valores e regras iniciais para os campos do filtro
Após adicionar os campos do filtro (descritos acima), é possível definir valores padrões iniciais para os filtros. Além disso, é possível bloquear a alteração desse filtro, e também o fazê-lo dependendo do usuário ou perfil do usuário. Para maiores detalhes, veja o item definir os valores e regras iniciais dos filtros do capítulo lista e consulta nas configurações do formulário.
Painel
Todo painel tem um título. Esse título pode ou não ser exibido, clicando no ícone
.
Outra opção, é a cor do tema. Ela pode ser escolhida na opção tema. As opções de cores são:
- Branco (padrão)
- Cinza
- Azul
- Verde
- Roxo
- Vermelho
- Amarelo
Para alterar o tamanho de um widget, basta clicar em
e deixar com o tamanho desejado.
Elementos de um painel:
Label
É um texto, que pode ser fixo ou dinâmico. Caso seja dinâmico, o texto deve ser o resultado de uma query SQL. Essa query vai ter seu resultado atribuído à variáveis. Para utilizá-las, basta escrever @ e selecionar a variável. É possível combinar textos com variáveis.
Caso seja fixo, basta digitar o texto normalmente.

Além disso, é possível formatar o texto de várias maneiras, como definir o alinhamento vertical e horizontal do texto, tamanho e fonte.
E por fim, é possível que ao clicar no texto, o usuário seja levado a um link. Basta preencher a URL.
Ao posicionar qualquer elemento no painel, é possível redimensioná-lo usando o ícone
.
Ícone
É possível adicionar um ícone como elemento de um painel. Basta selecionar um ícone em uma das bibliotecas disponíveis. Ainda é possível editar alinhamento (vertical e horizontal), tamanho, cor e criar um link.
Imagem
Para fazer o upload de uma imagem, basta clicar no retângulo ou arrastar um arquivo até ele.
É possível formatar largura, altura e alinhamento (vertical e horizontal) e criar um link.
Gráfico
Ao se adicionar um gráfico, é possível escolher entre duas origem dos dados:
Criar uma tabela com dados Estáticos
Nessa opção, o usuário define os dados de maneira manual em uma tabela, como uma planilha. É possível adicionar dados em linhas e colunas, usando os botões
.
Ao clicar na opção 'Editar tipo e propriedades do gráfico' ou no ícone
, é possível definir o tipo do gráfico.

O sistema já sugere o gráfico mais recomendado na guia início. Clicando na aba Gráficos (ou em 'Mais »'), o sistema exibe todos os demais gráficos disponíveis.
Na aba Personalizar é possível editar as características do gráfico selecionado, como título, legenda, fonte, cores, entre outros.
Fonte de dados Dinâmica
Nesse caso, é necessário criar uma query para se obter os dados. As demais configurações, seguem o padrão do exemplo acima.
Tabela de Dados
Quando o elemento é a tabela de dados, a fonte para essa tabela, só pode ser dinâmica, ou seja, através de uma query.
Query
No exemplo abaixo, queremos uma tabela com a lista de autores cadastrados no sistema. A query está obtendo os campos 'id', 'nome', 'sexo' e 'nacionalidade' da tabela 'x_tbl_autor'.
select nome, sexo, nacionalidade from x_tbl_autor
Esse é um exemplo de um resultado dessa query:

Uma vez a query montada, é possível formatar a tabela.
Importante: caso o relatório que esteja sendo criado possua filtros, é necessário incluir a função Filter com a(s) variável(is) criadas no filtro.
A função filter tem a seguinte sintaxe:
Filter(variável, tabela, campo)
- variável: ao criar um filtro, é criada uma variável. A lista de variáveis está na tela de montagem da query;
- tabela: é a tabela onde esse filtro deve acontecer;
- campo: é o campo da tabela que será usado no filtro;
select nome, sexo, nacionalidade from x_tbl_autor
where
Filter (@sexo, x_tbl_autor, sexo) and
Filter (@nome, x_tbl_autor, nome)
No exemplo acima, existe dois filtros e suas variáveis (@sexo e @nome) que serão aplicados nos campos 'nome' e 'sexo' da tabela 'x_tbl_autor'.
Configuração das colunas da tabela
- Ordem das colunas: clique no ícone
e arraste a coluna para a posição desejada; - Nome de apresentação: edite o nome da coluna;
- Largura em %: deixe 'padrão' para uma divisão igual da largura entre as colunas. Caso contrário, informe em porcentagem a largura de cada coluna;
- Visível: ligador por padrão, é possível ocultar uma coluna sem precisar alterar a query;
- Prefixo: é possível incluir um texto antes dos valores dessa coluna;
- Sufixo: é possível incluir um texto depois dos valores dessa coluna;
- Informação no rodapé:
- Cálculo: é possível fazer um cálculo (numérico ou hora) e informar no rodapé da coluna. Os valores nessa coluna precisam ser do tipo inteiro ou decimal (para cálculo numérico) ou estar no formato de hora HH:mm (para cálculo em hora)
- Máscara: caso o cálculo seja numérico, escolha a máscara apropriada para o resultado. Para cálculo em hora, a máscara HH:mm é preenchida automaticamente.
Ordenação
Selecione o campo que será ordenada as informações, e escolha se a ordenação é crescente ou decrescente.
Paginação
Escolha a quantidade de registros por página.
Header
Permite mostrar ou não o cabeçalho da tabela;
Link da Linha
É possível redirecionar o usuário caso haja um click na linha. Esse link pode ser interno no agilityflow ou externo. Caso seja interno, é possível escolher se o link será aberto como:
- Um lightbox;
- Na mesma janela;
- Uma nova janela;
Tabelas de dados filha (Master e Detail)
Além de uma tabela, é possível agrupar uma tabela em cada linha dessa primeira tabela, configurada no exemplo acima.
Para isso, basta adicionar uma tabela de dados filha. Ao fazer isso, o mesmo processo de configuração de uma tabela de dados comum é iniciado, mas com uma diferença.
Caso essa tabela filha tenha relação com a tabela principal, basta obter a coluna id na query da tabela principal. Esse valor, é passado para a tabela filha, em uma variável chamada @master_id.
No exemplo acima, ao clicar no nome do autor, é apresentado a lista de livros cadastradas no sistema relacionados com esse autor. A query ficaria assim:
select x_tbl_livro.nome as NomeLivro, x_tbl_livro.ano as Ano from x_autor_livro
inner join x_tbl_livro on id_x_tbl_livro = x_tbl_livro.id
where id_x_tbl_autor = @master_id
A tabela filha, apesar de recomendado, não precisa ter relação com a tabela principal.
Dashboard
O dashboard é um painel que traz informações rápidas do sistema. É a tela inicial do agilityflow.
O propósito do dashboard é levar ao usuário informações de rápida visualização para uma tomada imediata de decisões.
Ao criar um Dashboard, é necessário informar um nome e uma descrição. Além disso, é necessário atribuir um ou mais perfis, que irão acessar esse dashboard.

Ao clicar em 'Montar Dashboard', basta adicionar os widgets que deverão aparecer nesse dashboard e clicar em confirmar.
Widget
Widget é um elemento gráfico de interação, e fornecem funcionalidades e/ou informações ao usuário.
No agilityflow, são os elementos que compõem um dashboard.
Ao se criar um widget, é necessário definir algumas informações básicas.
- Tipo: existem dois tipos de widgets:
- Nativo: o tipo Nativo é reservado para futuras implementações de widgets nativos do sistema, como o de rascunhos e o de pendências. Essa opção não deve ser utilizada.
- Customizado: é a opção que permite criar um widget sob-medida. Essa é a opção que deve ser utilizada.
- Nome: um nome para identificar o widget na montagem do dashboard.
- Descrição: um nome para ajudar na identificação do widget na montagem do dashboard.
- Categoria: escolha ou crie uma categoria, para organizar os widgets.
- Subcategoria: escolhe ou crie uma subcategoria, para organizar os widgets.

Ao adicionar o widget no dashboard, como no exemplo acima, é possível identificar o widget pelo nome (Pendências para aprovação), pela categoria (Fluxo de Aprovação), pela subcategoria (Aprovação) e pela descrição no quadro maior (em cinza).
- Ativo: é possível deixar um widget ativo ou inativo. Isso permite ao usuário não mais permitir o uso de um widget, sem a necessidade de removê-lo e posteriormente, caso necessário, ter que criá-lo novamente.
- Url (Mvc Action), altura e largura do Widget: essas opção estão disponíveis para widgets do tipo nativo. Não devem ser utilizadas.
Montar o Widget
Quando se seleciona o tipo customizado, o botão 'Montar o Widget' fica disponível. Ao clicar, é possível configurar as características do widget.
Todo widget tem um título. Esse título pode ou não ser exibido, usando a opção 'Mostrar Título do Box'.
Outra opção, é a cor do tema. Ela pode ser escolhida na opção tema. As opções de cores são:
- Branco (padrão)
- Cinza
- Azul
- Verde
- Roxo
- Vermelho
- Amarelo
Para alterar o tamanho de um widget
Adicionar elemento
Em um widget, é possível adicionar vários elementos, e de vários tipos.
Label
É um texto, que pode ser fixo ou dinâmico. Caso seja dinâmico, o texto deve ser o resultado de uma query SQL. Essa query vai ter seu resultado atribuído à variáveis. Para utilizá-las, basta escrever @ e selecionar a variável. É possível combinar textos com variáveis.
Caso seja fixo, basta digitar o texto normalmente.

Além disso, é possível formatar o texto de várias maneiras, como definir o alinhamento vertical e horizontal do texto, tamanho e fonte.
E por fim, é possível que ao clicar no texto, o usuário seja levado a um link. Basta preencher a URL.
Ao posicionar qualquer elemento no widget, é possível redimensioná-lo usando o ícone
.
Ícone
É possível adicionar um ícone como elemento de um widget. Basta selecionar um ícone em uma das bibliotecas disponíveis. Ainda é possível editar alinhamento (vertical e horizontal), tamanho, cor e criar um link.
Imagem
Para fazer o upload de uma imagem, basta clicar no retângulo ou arrastar um arquivo até ele.
É possível formatar largura, altura e alinhamento (vertical e horizontal) e criar um link.
Gráfico
Ao se adicionar um gráfico, é possível escolher entre duas origem dos dados:
Criar uma tabela com dados Estáticos
Nessa opção, o usuário define os dados de maneira manual em uma tabela, como uma planilha. É possível adicionar dados em linhas e colunas, usando os botões
.
Ao clicar na opção 'Editar tipo e propriedades do gráfico' ou no ícone
, é possível definir o tipo do gráfico.

O sistema já sugere o gráfico mais recomendado na guia início. Clicando na aba Gráficos (ou em 'Mais »'), o sistema exibe todos os demais gráficos disponíveis.
Na aba Personalizar é possível editar as características do gráfico selecionado, como título, legenda, fonte, cores, entre outros.
Fonte de dados Dinâmica
Nesse caso, é necessário criar uma query para se obter os dados. As demais configurações, seguem o padrão do exemplo acima.
Tabela de Dados
Quando o elemento é a tabela de dados, a fonte para essa tabela, só pode ser dinâmica, ou seja, através de uma query.
Query
No exemplo abaixo, queremos uma tabela com a lista de autores cadastrados no sistema. A query está obtendo os campos 'id', 'nome', 'sexo' e 'nacionalidade' da tabela 'x_tbl_autor'.
select nome, sexo, nacionalidade from x_tbl_autor
Esse é um exemplo de um resultado dessa query:

Uma vez a query montada, é possível formatar a tabela.
Configuração das colunas da tabela
- Ordem das colunas: clique no ícone
e arraste a coluna para a posição desejada; - Nome de apresentação: edite o nome da coluna;
- Largura em %: deixe 'padrão' para uma divisão igual da largura entre as colunas. Caso contrário, informe em porcentagem a largura de cada coluna;
- Visível: ligador por padrão, é possível ocultar uma coluna sem precisar alterar a query;
- Prefixo: é possível incluir um texto antes dos valores dessa coluna;
- Sufixo: é possível incluir um texto depois dos valores dessa coluna;
- Informação no rodapé:
- Cálculo: é possível fazer um cálculo (numérico ou hora) e informar no rodapé da coluna. Os valores nessa coluna precisam ser do tipo inteiro ou decimal (para cálculo numérico) ou estar no formato de hora HH:mm (para cálculo em hora)
- Máscara: caso o cálculo seja numérico, escolha a máscara apropriada para o resultado. Para cálculo em hora, a máscara HH:mm é preenchida automaticamente.
Ordenação
Selecione o campo que será ordenada as informações, e escolha se a ordenação é crescente ou decrescente.
Paginação
Escolha a quantidade de registros por página.
Header
Permite mostrar ou não o cabeçalho da tabela;
Link da Linha
É possível redirecionar o usuário caso haja um click na linha. Esse link pode ser interno no agilityflow ou externo. Caso seja interno, é possível escolher se o link será aberto como:
- Um lightbox;
- Na mesma janela;
- Uma nova janela;
Tabelas de dados filha (Master e Detail)
Além de uma tabela, é possível agrupar uma tabela em cada linha dessa primeira tabela, configurada no exemplo acima.
Para isso, basta adicionar uma tabela de dados filha. Ao fazer isso, o mesmo processo de configuração de uma tabela de dados comum é iniciado, mas com uma diferença.
Caso essa tabela filha tenha relação com a tabela principal, basta obter a coluna id na query da tabela principal. Esse valor, é passado para a tabela filha, em uma variável chamada @master_id.
No exemplo acima, ao clicar no nome do autor, é apresentado a lista de livros cadastradas no sistema relacionados com esse autor. A query ficaria assim:
select x_tbl_livro.nome as NomeLivro, x_tbl_livro.ano as Ano from x_autor_livro
inner join x_tbl_livro on id_x_tbl_livro = x_tbl_livro.id
where id_x_tbl_autor = @master_id
A tabela filha, apesar de recomendado, não precisa ter relação com a tabela principal.
Tabela Relacional (N:N)
O Conceito N:N
A tabela relacional N:N, trás um conceito importante e fundamental em banco de dados.
Diferente do relacionamento 1:N, que no agilityflow é utilizado nos formulários relacionados, onde uma entidade pode se relacionar com várias ocorrências de outra entidade, o relacionamento N:N ocorre quando vários registros de uma tabela (formulário) se relacionam com vários registros de uma outra tabela.
No relacionamento N:N, não há uma hierarquia de relacionamento.
Exemplo
Por exemplo, um autor pode escrever vários livros. Um livro pode ter vários autores.

Quando existe esse relacionamento, surge uma terceira tabela. A essa tabela, damos o nome de Tabela Relacional (N:N).
Criando uma tabela relacional (n:n)
Para criar uma tabela relacional (n:n) no agilityflow, primeiro crie ambos formulários comuns. Depois, no Devcenter, clique em Tabela Relacional (N:N) e em seguida em 'Novo'.
Dados
Descrição
Nome da Tabela Banco de dados SQL (Adicionar prefixo x)
Formulário relacionado 1 (FK1)
Formulário 1: escolha o primeiro formulário do relacionamento (a ordem não importa)
Título da tabela que será apresentado no formulário para o usuário: esse é o texto que será apresentado como título, quando o formulário 1 aparecer dentro do formulário 2.
Campo principal para o usuário buscar e associar ao formulário: o campo que será usado para o usuário fazer a associação
Tipo do campo principal: selecione sempre Lista de seleção (Combo)
Formulário relacionado 2 (FK2)
Formulário 2: escolha o segundo formulário do relacionamento (a ordem não importa)
Título da tabela que será apresentado no formulário para o usuário: esse é o texto que será apresentado como título, quando o formulário 2 aparecer dentro do formulário 1.
Campo principal para o usuário buscar e associar ao formulário: o campo que será usado para o usuário fazer a associação
Tipo do campo principal: selecione sempre Lista de seleção (Combo)
Clique em Salvar e pronto, a tabela está criada.
Não esqueça de adicionar a tabela relacional (N:N) criada agora, em ambos os formulários.
Cache
Para aumentar a performance da plataforma, o agilityflow gera cache de alguns dados no servidor. O cache é formado por dados que não mudam com frequência. Caso esses dados mudem, o cache é apagado e re-criado no próximo carregamento.
O que é armazenado em cache?
São esses dados:
- Formulários
- Relatórios
- Cofiguração das API's
- Dashboard e widgets
Para ilustrar, imagine a estrutura de um formulário, como seus campos, relatórios de impressão, listagem de dados e tela. Essas configurações não mudam com frequência, mas a sua leitura é custosa para o servidor. Por isso, no primeiro acesso, os dados de um formulário são armazenados em cache, para que na próxima leitura, não precise ser feito todo o acesso à base de dados para mostrar o formulário corretamente.
Posteriormente, ao fazer uma modificação no formulário, no salvamento, o servidor apaga os dados do cache, e os reescreve no primeiro acesso. Isso explica um tempo mais logo para o primeiro carregamento de um formulário após a criação ou modificação.
Como posso atualizar o cache do servidor?
De duas formas: a primeira é alterar qualquer um dos dados listados acima. Quando isso ocorre, apenas o cache relacionado ao dado alterado é atualizado.
A segunda forma, basta acessar a opção de Cache no devcenter, selecionar os dados que deseja apagar e clicar em "Atualizar Cache".

Existe uma periodicidade de alteração do cache?
Não. O cache somente é atualizado em umas das duas formas citadas acima.
API de Integração GET e POST
Para a documentação de programação em C# nas APIs de POST, clique aqui
Para Informações sobre o Timezone das Apis (fuso horário), clique aqui
O termo API vem da abreviação do termo em inglês Application Programming Interface ou Interface de Programação de Aplicativos, o que resumidamente, significa uma forma de dois sistemas se conectarem entre si.
O agilityflow possui API Rest para que outros sistemas e aplicativos se conectem e interajam com o agilityflow. Essa interação ocorre usando dois métodos:
- GET: para outros sistema consumirem os dados do Agilityflow (Buscar informações)
- POST: para inserir e atualizar dados de outros sistemas no Agilityflow (Input de informações)
Como posso configurar uma API no agilityflow?
Um pré-requisito para configurar uma API no agilityflow, é criar um usuário que tenha permissão para executar essa API remotamente.
Usuário da API
Para criar um usuário da API, basta acessar o devcenter, e no quadro da API, criar em 'Usuários da Api':
Ao clicar nessa tela, é apresentada a lista de usuários, onde é possível filtrar e interagir como em qualquer formulário. No topo, clique em 'Novo' e informe os seguintes dados:
- Nome: um nome para identificar o usuário. Sugestão: caso seja um sistema legado que irá chamar essa api, crie esse usuário com o nome do sistema legado.
- Login: nome do usuário;
- Chave de segurança: chave de acesso do usuário. Essa chave, ficará visível para que possa ser consultada e informada ao outro sistema que irá fazer uso da API;
- API: caso já exista uma API configurada, pode ser adicionada permissão a ela nesse momento;
Configurar uma API
Acesse API de integração no devcenter e clique em
e em seguida clique em "Novo". Preencha os dados que seguem:
- Nome: identifica a configuração da API;
- Método: Post ou Get. Mais informações no próximo capítulo;
- Tipo de execução: selecione síncrona. A opção assíncrona ainda não está implementada;
- Ativo: marque para deixar habilitada, ou desmarque para desabilitar a API;
- Usuário API: selecione os usuários de API com acesso à essa configuração, e clique em
.
Listar (Get) - Buscar de um formulário (versão sem uso de código)
Com esse método, você pode buscar qualquer tipo de informação de um determinado formulário.
No cadastro de API, marque o método como "Get" e clique na opção "Configurar API para Listagem"
Agora associe o usuário que você criou no passo anterior, para que ele tenha acesso de execução nessa API.
Na opção configurar API para listagem, selecione o formulário que você deseja recuperar os dados.
Filtros da API de GET pelo Id do formulário
Além da lista completa e paginada, você pode filtrar por ID ou por IDs.
Todos os Ids do agilityflow são no formato de GUID, exemplo de um id: "43837013-be24-4bc9-81c1-b4cdcb6eb3dc"
Você pode filtrar por um ou mais ids em uma mesma chamada de API, para isso, basta enviar o parâmetro id ou ids colocando os ids, divididos por virgula, exemplo:
id=43837013-be24-4bc9-81c1-b4cdcb6eb3dc,59a26b8b-6c32-4756-acb7-c1539baf65de,b9199893-7021-1446-f407-942c97d70b74
ou apenas 1 id
id = b9199893-7021-1446-f407-942c97d70b74
Filtros por campos do formulario
Você pode filtrar por qualquer campo do formulário, os comandos de filtro são similares aos comandos de consulta do sql server e devem estar entre chaves { }
filter={campo_de_numero>2 and campo_de_numero<20 and ( campo_texto='jose' or campo_texto like '%sei%' ) }
Lembre-se: que a url da API deve estar com os caracteres especiais com enconded, exemplo da query acima na url:
filter={(campo_de_numero%3E2%20and%20campo_de_numero%3C20)%20and%20(%20campo_texto=%27jose%27%20or%20campo_texto%20like%20%27%sei%%27%20)%20}
Paginação da API de GET
A paginação da API é feita a cada 10 registros, para buscar a próxima página é só enviar o parâmetro nextPage colocando o número da página que você deseja buscar, exemplo:
nextPage=2
Ordenação da API de GET
É possível ordernar os dados de retorno da API usando os 2 parâmetros abaixo, exemplo:
sortBy=id_do_campo
sortDirection=ASC ou sortDirection=DESC
Estrutura de retorno da API de GET
* por uma questão de performance da API. O campo TotalRecords não será mais retornado desde Jan/2024
{
"paging": {
"pageSize": 10, //tamanho da paginação, considere sempre 10
"pageNumber": 1 //página atual
"nextPage": 2 //próxima página a ser chamada
},
"result": [
{
"formId": "43837013-be24-4bc9-81c1-b4cdcb6eb3dc", //Campo Padrão: Id do formulário
"createdDate": "2020-03-10 22:41:28", //Campo Padrão: Data de criação do formulário
"createdBy": "59a26b8b-6c32-4756-acb7-c1539baf65de", //Campo Padrão: Id do Usuário responsável pela criação do formulário
"modifiedDate": "2020-03-10 22:47:58", //Campo Padrão: Data da última alteração do formulário
"modifiedBy": "59a26b8b-6c32-4756-acb7-c1539baf65de", //Campo Padrão: Id do Usuário responsável pela última alteração do formulário
"workflow": {
"currentSteps": [
{
"id": "ede6740b-b4b8-21f7-e9c3-4f765620a213", //Campo Padrão: Id da Etapa atual do fluxo
"name": "Tax Payment " //Campo Padrão: Nome da Etapa atual do fluxo
},
{
"id": "9c334289-47e8-49da-93a9-c2e4871e4c3d", //Campo Padrão: Id da Etapa atual do fluxo
"name": "Payment deal" //Campo Padrão: Nome da Etapa atual do fluxo
}
],
"status": "P", //Campo Padrão: Status do fluxo, será "A", "X" ou "P"
"statusName": "In progress", //Campo Padrão: Status Name será, "Approved", "Rejected", "In progress"
},
"data": { //Dados e campos do formulário: Muda de acordo com os campos do formulário
"name": "john",
"email": "john@example.com",
"age": "35",
}
}
]
}
Pronto! Agora é só executar.
Cadastrar (Post)
Com esse método, você pode inserir e atualizar dados nos formulários do seu Agilityflow, aqui você deve definir o mapeamento dos dados (DE - PARA) em C#, explicitando como será feito o cadastro dos dados, quando essa API for acionada.
No cadastro de API, marque o método como "Post" e clique na opção "Configurar API para Cadastro (Post)"
Agora associe o usuário que você criou no passo anterior, para que ele tenha acesso de execução nessa API.
Na opção configurar API, selecione o formulário que você deseja recuperar os dados.
O código abaixo exemplifica como configurar uma API de Cadastro
Para a documentação de programação em C# nas APIs de POST, clique aqui
public async Task RunAsync(){
//converte o conteúdo enviado no body da API para JSON
var json = Newtonsoft.Json.JsonConvert.DeserializeObject<dynamic>(content);
//guarda em uma variável o ID da estrutura do formulário Cliente
var idEstruturaFormulario_CLIENTE = Guid.Parse("0b56b66a-4f6f-4ded-ad04-016d7c0724e1");
await ApiContext.LogAsync("Log Message", "logtype");
if (json != null)
{
//verifica se o JSON recebido contém a propriedade "nome", "email" e "cel" que são necessários p cadastro
if (JsonHelper.HasProperty(json, "nome") && JsonHelper.HasProperty(json, "email") && JsonHelper.HasProperty(json, "cel")){
var values = new DataDictionary();
values.Add("nome", json["nome"].ToString());
values.Add("email", json["email"].ToString());
values.Add("cel", json["cel"].ToString());
//salva a informação no banco de dados
var id = await ApiContext.SaveEntityAsync(idEstruturaFormulario_CLIENTE, values);
}
}
await ApiContext.LogAsync("Log Message", "logtype");
}
Status Header de retorno de uma API
| Cod. | Mensagem | Descrição |
| 400 | BadRequest |
Houve algum erro inesperado pela API, verifica se em alguma programação existe um erro de sintaxe ou algo parecido. |
| 401 | Unauthorized |
Possíveis causas:
|
| 404 | Not Found |
Api não encontrada |
| 405 | Method Not Allowed |
Possíveis causas:
|
| 200 | Ok |
Deu tudo certo. |
Exemplos de execução da API
Exemplo GET via o software "POSTMAN"
Importe o JSON abaixo no seu Postman para executar os exemplos abaixo.
{
"info": {
"_postman_id": "bd36812d-37c9-4e08-9bc0-bdc28a073fcc",
"name": "Agilityflow API GET",
"schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
},
"item": [
{
"name": "1. Obter AccessToken",
"request": {
"method": "POST",
"header": [
{
"key": "Content-Type",
"value": "application/json"
}
],
"body": {
"mode": "raw",
"raw": "{\"username\": \"NOME_DO_USUARIO_API__COM_PERMISSAO_NESSA_API\",\"key\": \"CHAVE_DE_SEGURANÇA_DO_USUARIO_API__COM_PERMISSAO_NESSA_API\"}"
},
"url": {
"raw": "https://XXXXXXXXXXXXXXXXX.agilityflow.io/api/accesstoken?",
"protocol": "https",
"host": [
"XXXXXXXXXXXXXXXXX",
"agilityflow",
"io"
],
"path": [
"api",
"accesstoken"
],
"query": [
{
"key": "",
"value": "",
"disabled": true
},
{
"key": "",
"value": "",
"disabled": true
}
]
}
},
"response": []
},
{
"name": "2. Get API",
"protocolProfileBehavior": {
"disableBodyPruning": true
},
"request": {
"method": "GET",
"header": [
{
"key": "Authorization",
"value": "Bearer eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJodHRwOi8vc2NoZW1hcy5taWNyb3NvZnQuY29tL3dzLzIwMDgvMDYvaWRlbnRpdHkvY2xhaW1zL3VzZXJkYXRhIjoiOTdmZTM1NmItMDA5OC00ZTlhLTkwNTUtODMwMTA3YzM5NjA1IiwibmFtZWlkIjoibG9jYWxob3N0IiwibmJmIjoxNTY0NDI4NTk5LCJleHAiOjE1NjQ0Mjg2NTksImlhdCI6MTU2NDQyODU5OX0.ul7Emi7KDepfmRwWO91RQcTZQrc8r3xlMKJnLYcduEKeNRDGC7F15_-YojHfm1ogM32LjUV76MWxNXTLeJTrLw"
},
{
"key": "Content-Type",
"name": "Content-Type",
"type": "text",
"value": "application/json"
}
],
"body": {
"mode": "raw",
"raw": "{\n\n}"
},
"url": {
"raw": "https://XXXXXXXXXXXXXXXXX.agilityflow.io/api/data/g5e262bd-912a-4b1f-91cb-58815cfc5556?nextPage=1",
"protocol": "https",
"host": [
"XXXXXXXXXXXXXXXXX",
"agilityflow",
"io"
],
"path": [
"api",
"data",
"g5e262bd-912a-4b1f-91cb-58815cfc5556"
],
"query": [
{
"key": "nextPage",
"value": "1"
}
]
}
},
"response": []
}
]
}
Após a importação no Postman você precisará seguir alguns passos:
Passo 1
No Postman, abra o exemplo "1. Obter Accesstoken"
Passo 2
Você precisará fazer algumas mudanças.
(1) Troque o XXXXXX.agilityflow.io pelo seu subdomínio no agilityflow;
(2) Na aba "body", Troque o usuário e a chave de segurança da API que você criou. como na imagem abaixo:
Passo 3 - Obter Access token para execução da API
Por segurança, antes de cada execução de API é necessário que você gere um token para validação do usuário.
Então, agora execute essa API.
Copie o código retornado no JSON na propriedade "accessToken", usaremos esse código a seguir.
Passo 4
No Postman, abra o exemplo "2. Get API"
Passo 5
Você precisará fazer algumas mudanças.
(1) Troque o XXXXXX.agilityflow.io pelo seu subdomínio no agilityflow;
(2) Na aba "headers", clique no VALUE da Key "Authorization" e cole o código "accessToken" que geramos nos passos acima, após a palavra "Bearer ". Então o valor deverá ficar "Bearer Accesstoken_que_você_colou".

(3) Troque o Id da API "/data/g5e262bd-912a-4b1f-91cb-58815cfc5556" de exemplo pelo id da API que você acabou de criar no Agilityflow.

Então, agora execute a API para visualizar os dados retornados, você pode também consultar o Log de API do agilityflow para acompanhar todas as requisições
Exemplo em NODE de POST
Suponhamos que temos uma API no agilityflow que cadastra um cliente, as informações que a API espera é "NOME", "EMAIL" e "CEL" (celular).
O código abaixo demonstra como é feita a chamada da API através do NODE.
Para executar, é necessário ter o NODE instalado. O pacote utilizado é o "https".
Para rodar o script basta copia-lo, salvar em um arquivo com extensão .JS (exemplo: script.js) abrir o prompt de comando e executar o script da seguinte forma:
node "C:\teste\script.js"
Abaixo o script NODE:
Para configura só troque as 4 variáveis de configuração com as seguintes informações:
- hostname: substitua pela sua URL do seu agilityflow
- accessToken_Credential: aqui você coloca as credenciais (usuário da API) para execução
- apiID: id da api
- apiParameterBODY: json com as informações que você deseja enviar para API
var http = require("https");
//config
var hostname = 'demo123.agilityflow.io'; //substitua pela sua URL do seu agilityflow
var accessToken_Credential = { username: 'teste', key: 'teste' }; //aqui você coloca as credenciais (usuário da API) para execução
var apiID = 'e8b5b751-774d-4283-855c-fafb8e11236d'; //id da api
var apiParameterBODY = { nome: 'JOSE DA SILVA', email: 'josedasilva@email.com.br', cel: '1199887766' } //body json com as informações que você deseja enviar para API
//recuperar o access token
function ExecuteRecuperarAccessToken(){
var options = {
hostname: hostname,
// port: 443,
path: '/api/accesstoken',
method: 'POST',
headers: {
"Content-Type": "application/json",
"cache-control": "no-cache"
}
};
var req = http.request(options, function (res) {
var chunks = [];
res.on("data", function (chunk) {
chunks.push(chunk);
});
res.on("end", function () {
var body = Buffer.concat(chunks);
var obj = JSON.parse(body);
if(obj.success){
console.log("Recuperou o Access Token",obj.accessToken);
ExecuteAPI(obj.accessToken)
}else
LogErro("execução do access token", body.toString());
});
});
req.write(JSON.stringify(accessToken_Credential));
req.end();
}
//execute a API
function ExecuteAPI(accessToken){
var options = {
hostname: hostname,
// port: 443,
path: '/api/data/'+apiID,
method: 'POST',
headers: {
"Authorization": "Bearer " + accessToken,
"Content-Type": "application/json",
"cache-control": "no-cache"
}
};
var req_api = http.request(options, function (res_api) {
var chunks_api = [];
res_api.on("data", function (chunk) {
chunks_api.push(chunk);
});
res_api.on("end", function () {
var body = Buffer.concat(chunks_api);
var obj = JSON.parse(body);
if(obj.success){
console.log("Execução realizada com sucesso:" + body.toString());
}else
LogErro("execução da api", body.toString());
});
});
req_api.write(JSON.stringify(apiParameterBODY));
req_api.end();
}
function LogErro(local,log){
console.log('==================================================================================')
console.log('E R R O - ' + local)
console.log('----------------------')
console.log(log);
console.log('==================================================================================')
}
ExecuteRecuperarAccessToken();
Exemplo em PHP de POST
Suponhamos que temos uma API no agilityflow que cadastra um cliente, as informações que a API espera é "NOME", "EMAIL" e "CEL" (celular).
O código abaixo demonstra como é feita a chamada da API através do PHP.
<?php
// header('Content-Type: application/json');
if( !isset($_POST['nome']) || !isset($_POST['email']) || $_POST['nome'] == '' || $_POST['email'] == '')
{
echo '{"success": "false", "msg": "Informe o nome e o e-mail"}';
exit(0);
}
$nome = $_POST['nome'];
$email = $_POST['email'];
$novoLead = new StdClass();
$novoLead->nome = $nome ;
$novoLead->email = $email ;
$novoLead->cel = $_POST['cel'];
$novoLead_string = json_encode($novoLead);
//////////////////////////////////// 01. BUSCAR O ACCESS TOKEN
$curl = curl_init();
curl_setopt_array($curl, array(
CURLOPT_URL => "https://XXXXXXXXXXXXXXX.agilityflow.io/api/accesstoken",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
//------------- SLL
CURLOPT_SSL_VERIFYPEER => 0,
CURLOPT_SSL_VERIFYHOST => 0,
//--------------------------
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => "{\"username\": \"cadastrar_teste_1\",\"key\": \"cadastrar_teste_1\"}",
CURLOPT_HTTPHEADER => array(
"Content-Type: application/json",
"cache-control: no-cache"
),
));
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo '{"success": "false", "msg": "Não conseguimos finalizar seu cadastro. Por favor tente novamente. (0)" }';
exit(0);
}
$json_RESPONSE_ACCESS_TOKEN = json_decode($response);
if (!isset($json_RESPONSE_ACCESS_TOKEN->accessToken)){
echo '{"success": "false", "msg": "Não conseguimos finalizar seu cadastro. Por favor tente novamente. (1)" }';
exit(0);
}
//////////////////////////////////// 02. EXECUTA O POST
$curl = curl_init();
curl_setopt_array($curl, array(
CURLOPT_URL => "https://XXXXXXXXXXXXXXX.agilityflow.io/api/data/b3bf7ce3-f226-4500-83cd-2873b050c742",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
//------------- SLL
CURLOPT_SSL_VERIFYPEER => 0,
CURLOPT_SSL_VERIFYHOST => 0,
//--------------------------
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => $novoLead_string,
CURLOPT_HTTPHEADER => array(
"Authorization: bearer ".$json_RESPONSE_ACCESS_TOKEN->accessToken,
"Cache-Control: no-cache",
"Content-Type: application/json"
),
));
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo '{"success": "false", "msg": "Não conseguimos finalizar seu cadastro. Por favor tente novamente. (2)" }';
exit(0);
}
$json_RESPONSE_SUCCESS = json_decode($response);
if (!isset($json_RESPONSE_SUCCESS->success)){
echo '{"success": "false", "msg": "Não conseguimos finalizar seu cadastro. Por favor tente novamente. (3)" }';
exit(0);
}
if ($json_RESPONSE_SUCCESS->success == false){
echo '{"success": "false", "msg": "Não conseguimos finalizar seu cadastro. Por favor tente novamente. (4)" }';
exit(0);
}
echo '{"success": "true", "msg": "Obrigado, recebemos seus dados aqui e já já nos falamos..." }';
Exemplo POST via o software "POSTMAN"
Importe o JSON abaixo no seu Postman para executar os exemplos abaixo.
{
"info": {
"_postman_id": "39445fe2-1bea-46b2-9045-b32337b10030",
"name": "Agilityflow API",
"schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
},
"item": [
{
"name": "1. Obter Accesstoken",
"request": {
"method": "POST",
"header": [
{
"key": "Content-Type",
"value": "application/json"
}
],
"body": {
"mode": "raw",
"raw": "{\"username\": \"NOME_DO_USUARIO_API__COM_PERMISSAO_NESSA_API\",\"key\": \"CHAVE_DE_SEGURANÇA_DO_USUARIO_API__COM_PERMISSAO_NESSA_API\"}"
},
"url": {
"raw": "https://XXXXXXXXXXXXXXXXX.agilityflow.io/api/accesstoken?",
"protocol": "https",
"host": [
"XXXXXXXXXXXXXXXXX",
"agilityflow",
"io"
],
"path": [
"api",
"accesstoken"
],
"query": [
{
"key": "",
"value": "",
"disabled": true
},
{
"key": "",
"value": "",
"disabled": true
}
]
}
},
"response": []
},
{
"name": "2. Post API",
"request": {
"method": "POST",
"header": [
{
"key": "Authorization",
"value": "Bearer eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJodHRwOi8vc2NoZW1hcy5taWNyb3NvZnQuY29tL3dzLzIwMDgvMDYvaWRlbnRpdHkvY2xhaW1zL3VzZXJkYXRhIjoiOTdmZTM1NmItMDA5OC00ZTlhLTkwNTUtODMwMTA3YzM5NjA1IiwibmFtZWlkIjoibG9jYWxob3N0IiwibmJmIjoxNTY0NDI4NTk5LCJleHAiOjE1NjQ0Mjg2NTksImlhdCI6MTU2NDQyODU5OX0.ul7Emi7KDepfmRwWO91RQcTZQrc8r3xlMKJnLYcduEKeNRDGC7F15_-YojHfm1ogM32LjUV76MWxNXTLeJTrLw"
},
{
"key": "Content-Type",
"name": "Content-Type",
"value": "application/json",
"type": "text"
}
],
"body": {
"mode": "raw",
"raw": "{\n\n\t\t\t\"id\": \"345b65d7-4c99-426c-95fc-1dd8de76cc9d\",\n\t\t\t\"nome\": \"_123458910Cargo LEGALLLLL \"\n\t\n}"
},
"url": {
"raw": "https://XXXXXXXXXXXXXXXXX.agilityflow.io/api/data/b3bf7ce3-f226-4500-83cd-2873b050c742",
"protocol": "https",
"host": [
"XXXXXXXXXXXXXXXXX",
"agilityflow",
"io"
],
"path": [
"api",
"data",
"b3bf7ce3-f226-4500-83cd-2873b050c742"
]
}
},
"response": []
}
]
}
Após a importação no Postman você precisará seguir alguns passos:
Passo 1
No Postman, abra o exemplo "1. Obter Accesstoken"
Passo 2
Você precisará fazer algumas mudanças.
(1) Troque o XXXXXX.agilityflow.io pelo seu subdomínio no agilityflow;
(2) Na aba "body", Troque o usuário e chave de segurança da API que você criou. como na imagem abaixo:
Passo 3 - Obter Access token para execução da API
Por segurança, antes de cada execução de API é necessário que você gere um token para validação do usuário.
Então, agora execute essa API.
Copie o código retornado no JSON na propriedade "accessToken", usaremos esse código a seguir.
Passo 4
No Postman, abra o exemplo "2. Post API"
Passo 5
Você precisará fazer algumas mudanças.
(1) Troque o XXXXXX.agilityflow.io pelo seu subdomínio no agilityflow;
(2) Na aba "headers", clique no VALUE da Key "Authorization" e cole o código "accessToken" que geramos nos passos acima, após a palavra "Bearer ". Então o valor deverá ficar "Bearer Accesstoken_que_você_colou".

(3) Troque o Id da API "/data/b3bf7ce3-f226-4500-83cd-2873b050c742" de exemplo pelo id da API que você acabou de criar no Agilityflow.

(4) Na aba "body" você pode trocar os valores que você deseja inserir ou atualizar:

Então, agora execute essa API e entre no seu log de API do agilityflow para acompanhar e verificar se deu certo
Variáveis de ambiente
Nessa tela de variáveis de ambiente você definirá informações (variáveis globais) que ficarão disponíveis em diversas partes do seu sistema.
Suponha que você queira que a Data de Nascimento do usuário logado esteja disponível para acesso via Javascript nos seus formulários ou você quer usar essa informação em algum parâmetro de entrada de uma Query, em relatórios ou dashboards.
Para isso basta criar uma variável do tipo "SQL Simples (Valor único)"; defina o nome para a variável, nesse caso, utilize "var_dataNascimento"; marque como SIM a opção "Essa é uma Informação relacionada ao usuário logado e o valor pode variar de acordo com cada usuário".
No botão "Query Sql", defina a query Sql para buscar a Data de Nascimento do usuário logado. Exemplo da query:
select top 1 usu_dt_nasc as Value from tbl_usuario where id = @var_usuarioLogadoId and deletado = false
Salve e pronto. A partir de agora essa variável estará disponível em todo o seu ambiente. Para recuperar os valores da variável veja os itens mais abaixo.
Importante: os valores das variáveis de ambiente, ficam em cache, esse cache é renovado a cada 1 hora. Assim melhora a performance e evita excessos de consultas ao banco de dados. O cache é automaticamente renovado quando o usuário faz login e quando no formulário de criação da Variável de Ambiente você clica em "salvar".
Atenção: Nunca coloque dados sensíveis ou sigilosos em uma variável de ambiente.
Para recuperar os valores da variável de ambiente
Seguindo o exemplo acima, suponhamos que você queira agora recuperar o valor via Javascript.
Caso queira utilizar a variável em alguma situação específica ou em alguma parte do sistema que ela ainda não esteja disponível, fale com nossa equipe que estaremos prontos para te ajudar.
A forma correta seria via:
Em Javascript
Suponhamos que a variável criada tem o nome "var_dataNascimento". Utilize a função abaixo, ela retornará o valor da variável.
Recuperar o Valor:
var var_dataNascimento = GetEnvironmentVariable("var_dataNascimento")
Recuperar a Descrição (texto), no caso de variáveis do Tipo "Query com Id + Descrição":
var var_dataNascimento = GetEnvironmentVariable_Text("var_dataNascimento")
Em uma Query SQL
Suponhamos que a variável criada tem o nome "var_dataNascimento". Utilize o nome da variável como parâmetro de sua Query, como no exemplo abaixo.
select usu_nome from tbl_usuario where usu_dt_nasc = @var_dataNascimento and deletado = false
Em C# (na área de Regras de Negócio do Formulario)
Suponhamos que a variável criada tem o nome "var_dataNascimento". Utilize a função abaixo, ela retornará o valor da variável.
Recuperar o Valor:
FormContext.GetEnvironmentVariable("var_dataNascimento")
Recuperar a Descrição (texto), no caso de variáveis do Tipo "Query com Id + Descrição":
FormContext.GetEnvironmentVariable_Text("var_dataNascimento")
Em C# (nos componentes em cshtml)
Suponhamos que a variável criada tem o nome "var_dataNascimento". Utilize a função abaixo, ela retornará o valor da variável.
Recuperar o Valor:
PageContext.GetEnvironmentVariable("var_dataNascimento")
Recuperar a Descrição (texto), no caso de variáveis do Tipo "Query com Id + Descrição":
PageContext.GetEnvironmentVariable_Text("var_dataNascimento")
Em C# (nas API)
Suponhamos que a variável criada tem o nome "var_dataNascimento". Utilize a função abaixo, ela retornará o valor da variável.
Recuperar o Valor:
ApiContext.GetEnvironmentVariable("var_dataNascimento")
Recuperar a Descrição (texto), no caso de variáveis do Tipo "Query com Id + Descrição":
ApiContext.GetEnvironmentVariable_Text("var_dataNascimento")
Change Request
Permite enviar algumas funcionalidades de um ambiente para outro. Essa função é utilizada quando se tem mais de um ambiente, e usa-se o conceito de ambiente de desenvolvimento e outro como ambiente de produção.
É possível selecionar os formulários e tabelas associativas (Tabela Relacional N:N) que devem ser enviados a outros ambientes.
Além disso, é possível incluir scripts customizados para serem executados antes e depois da transferência dos objetos.
Ao transferir os formulários, apenas a estrutura é transferida e não o conteúdo.
Visual Code Editor
O agilityflow permite editar os formulários muito mais do que as configurações pré-definidas do formulário estabelecidas pelo sistema. Para fazer isso, é necessário utilizar o Visual Code Editor.
Nele, é possível modificar o formulário de 4 maneiras:
Style (CSS)
É possível utilizar todos os recursos do CSS para fazer as modificações do formulário.
Javascript
O javascript também está disponível para ser modificado. Além disso, já existem algumas facilidades criadas pelo agilityflow, que ficam disponíveis para uso.
C# (Server Side)
Inclua aqui, C# que atuarão no formulário.
Componentes CsHtml
Qualquer conteúdo Html pode ser criado atráves desses componentes. Entretanto, esses componentes precisam ser posicionados na tela de cadastro do formulário.
Formulário - customizar com HTML, C#, CSS e Javascript
O agilityflow também pode ser customizado através da Linguagem Html, CSS, Javascript e C# (csharp).
O html do agilityflow é baseado no Razor do framework .Net, isso é, você pode além de customizar com HTML, utilizar código C# (razor) para dar mais flexibilidade e poder ao seu componente Html.
O que e onde customizar?
Acesse a parte de Desenvolvimento do Formulário que você deseja customizar, para isso, entre na área de customização de um formulário e clique na opção Visual Code Editor, como na imagem abaixo:
No Visual Code editor, no menu esquerdo, serão apresentados as seguintes opções:
- Style (CSS): opção para customizar o CSS de todo o formulário.
- Javascript: opção para customizar o Javascript de todo o formulário.
- Componente CsHtml: opção para criar novos componentes em HTML
Style (CSS)
Nessa área, você pode criar customizações via linguagem CSS para todo o formulário, o seu uso é livre.
Levar em consideração o tratamento em CSS para a responsividade da plataforma em outros device, Mobile, Computador Desktop, Tablet, etc.
Javascript:
Nessa área, você pode criar customizações via linguagem Javascript para todo o formulário, o seu uso é livre.
Você pode utilizar jquery e outras bibliotecas já declaradas no código-fonte por padrão (veja lista mais abaixo).
Exemplo de utilização:
No código javascript abaixo, a regra impede que um formulário de projetos que esteja com o status "inativo", seja salvo:
var projeto = {
init: function () {
projeto._setEvents(); //registrar os eventos que são inerentes a esse bloco de código
},
_setEvents: function () {
//ao fazer o submit do formulário executa a função de validação de status
$('#formulario').on('submit', function (e) {
projeto.validarStatus();
})
},
validarStatus: function () {
//recupera através de jquery o valor do campo "Status do Projeto"
var status_projeto = $("#status_projeto").val();
//verifica se o tipo de envio que o formulário está requisitando no submit
//é do tipo "SALVAR" e se o status é "inativo"
//caso seja, inválida o submit e apresenta uma aviso para o usuário
if (Form.getFormActionOnSubmit() == ACTION_SALVAR && status_projeto == "inativo") {
//inválida o submit e apresenta uma aviso para o usuário
Form.invalidateForm({
msg: 'Um projeto inativo não pode ser salvo.'
});
}
}
}
projeto.init(); //iniciando e configurando
Abaixo estão listadas algumas funções nativas do agilityFlow para javascript:
Como utilizar funções Javascript dentro de um CSHTML
Caso você utilize Javascript dentro de um componente HTML (CSHTML), é necessário que o código esteja dentro da função DOM.ready (como no exemplo abaixo) para garantir que o seu código só execute após todo o carregamento de todos as funções Javascript
Recomendamos que dentro do arquivo CSHTML só tenha a "chamadas" para as funções que estejam programadas dentro do arquivo específico para o código Javascript.
<script>
DOM.ready(function () {
//seu código javascript aqui
});
</script>
Funções Javascript Nativas
Recuperar data do servidor:
GetDateNow()
A data e hora são obtidas dos servidores do Agilityflow, para assim garantir a confiabilidade da data e hora
Atenção: Lembre-se que no Javascript o retorno do método ".getMonth()" de um objeto Date, não refere-se ao mês e sim a Índice daquele mês no array de meses, sendo assim, o retorno desse método sempre será entre os valores 0 até 11 e não de 1 a 12
Exemplo de como configurar o valor inicial de um campo com a data atual.
Para esse exemplo, encare que o ID do campo que estamos preenchendo com a data atual é "data".
var exemplo1 = {
init: function () {
exemplo1.setToday();
},
//coloca a data atual no campo de data
setToday: function () {
if ($('#data').val() != "") return;
//data do servidor para garantir que seja uma data válida
var date = GetDateNow();
var day = date.getDate().toString().padLeft(2, '0');
var year = date.getFullYear();
var monthIndex = date.getMonth()
monthIndex++;
if (monthIndex > 12)
monthIndex = 1;
$('#data').val(day.toString().padLeft(2, '0') + '/' + monthIndex.toString().padLeft(2, '0') + '/' + year);
}
}
exemplo1.init();
Comparar uma data com a data atual (Hoje):
Essa comparação desconsidera a HORA
A função é: formContext.datetime.validation.compareToday(comparador, data)
Os possíveis comparadores são:
| Tipo |
Opção 1 (qualquer uma das opções)
|
Opção 2 (qualquer uma das opções)
|
|
maior que
|
>
|
greater
|
|
maior ou igual
|
>=
|
greater-or-equal
|
|
menor
|
<
|
less
|
|
menor ou igual
|
<=
|
less-or-equal
|
|
igual
|
==
|
equal
|
var greater = formContext.datetime.validation.compareToday('greater', '31/12/2000');
console.log('greater',greater);
var greater_or_equal = formContext.datetime.validation.compareToday('greater-or-equal', '31/12/2000');
console.log('greater-or-equal', greater_or_equal);
var less = formContext.datetime.validation.compareToday('less', '31/12/2000');
console.log('less',less);
var less_or_equal = formContext.datetime.validation.compareToday('less-or-equal', '31/12/2000');
console.log('less-or-equal', less_or_equal);
var equal = formContext.datetime.validation.compareToday('equal', '31/12/2000');
console.log('equal', equal);
Comparação entre datas. Comparar 2 datas:
Essa comparação desconsidera a HORA
A função é: formContext.datetime.validation.compare(data1, comparador, data2)
Os possíveis comparadores são:
| Tipo |
Opção 1 (qualquer uma das opções)
|
Opção 2 (qualquer uma das opções)
|
|
maior que
|
>
|
greater
|
|
maior ou igual
|
>=
|
greater-or-equal
|
|
menor
|
<
|
less
|
|
menor ou igual
|
<=
|
less-or-equal
|
|
igual
|
==
|
equal
|
var greater = formContext.datetime.validation.compare('31/01/2001','greater', '31/12/2000');
console.log('greater',greater);
var greater_or_equal = formContext.datetime.validation.compare('31/01/2001','greater-or-equal', '31/12/2000');
console.log('greater-or-equal', greater_or_equal);
var less = formContext.datetime.validation.compare('31/01/2001','less', '31/12/2000');
console.log('less',less);
var less_or_equal = formContext.datetime.validation.compare('31/01/2001','less-or-equal', '31/12/2000');
console.log('less-or-equal', less_or_equal);
var equal = formContext.datetime.validation.compare('31/01/2001','equal', '31/12/2000');
console.log('equal', equal);
Recuperar o ID do usuário logado:
GetUserId()
Recuperar o nome do usuário logado:
var nome = pageNavigation.getUserName();
var nomeCompleto = pageNavigation.getUserNameCompleto()
Recuperar os Perfis do usuário logado:
GetUserProfileId() //retorna um array com os Ids dos perfis ['xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx','xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx']
Função para identificar se o usuário logado tem um determinado perfil:
UserHasProfileId('xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx') //retorna true ou false
Expandir e Recolher um determinado painel de campos
var panelId = 'f175132d-5e85-778f-1354-cb2d339e6146';
//para alternar entre expandido e recolhido
formContext.panel.collapse.toggle(panelId)
//para recolher o painel
formContext.panel.collapse.hide(panelId)
//para expandir o painel
formContext.panel.collapse.show(panelId)
//para testar se o painel está recolhido ou não
formContext.panel.collapse.isCollapsed(panelId)
Recuperar os valores das "Variáveis de Ambiente"
Para saber mais sobre variáveis de ambiente entre em Variáveis de ambiente
var valor = GetEnvironmentVariable("nomeDaVariavel")
Recuperar a Descrição (texto), no caso de variáveis do Tipo "Query com Id + Descrição":
var text = GetEnvironmentVariable_Text("nomeDaVariavel")
Recuperar o VALOR preenchido de um campo no Formulário
var value = Form.getValueField("idDoCampo");
Recuperar o VALOR preenchido de um campo no Formulário PAI (formulário que abriu o formulário atual)
var value = Form.getValueField_parentIFrame("idDoCampo");
Recuperar o TEXTO preenchido de um campo no Formulário (Para os campos: Lista de Seleção e Pesquisa com Auto Completar)
var value = Form.getTextField("idDoCampo");
Recuperar o TEXTO preenchido de um campo no Formulário PAI (formulário que abriu o formulário atual) (Para os campos: Lista de Seleção e Pesquisa com Auto Completar)
var value = Form.getTextField_parentIFrame("idDoCampo");
Preencher um valor em um campo do Formulário
Parâmetros opcionais da função javascript
| Parâmetro opcional | Valor padrão | Opções de valores | Descrição |
| setOnlyIfFieldValueIsEmpty | false | true ou false |
Caso seja "true" a função só preencherá o valor do campo se o campo ainda NÃO estiver preenchido. Caso seja "false" a função preenche ou substitui o valor do campode qualquer maneira. |
//EXEMPLO 1: preenchendo o valor
Form.setValueField("idDoCampo", "value");
//EXEMPLO 2: preenchendo o valor e enviando os parametros opcionais para a função:
var options = { setOnlyIfFieldValueIsEmpty: true }
Form.setValueField("idDoCampo", "value", options);
Preencher um valor em um campo do Formulário PAI (formulário que abriu o formulário atual)
Parâmetros opcionais da função javascript
| Parâmetro opcional | Valor padrão | Opções de valores | Descrição |
| setOnlyIfFieldValueIsEmpty | false | true ou false |
Caso seja "true" a função só preencherá o valor do campo se o campo ainda NÃO estiver preenchido. Caso seja "false" a função preenche ou substitui o valor do campode qualquer maneira. |
//EXEMPLO 1: preenchendo o valor
Form.setValueField_parentIFrame("idDoCampo", "value");
//EXEMPLO 2: preenchendo o valor e enviando os parametros opcionais para a função:
var options = { setOnlyIfFieldValueIsEmpty: true }
Form.setValueField_parentIFrame("idDoCampo", "value", options);
Customizar evento de submit do formulário (Antes do post):
$('#formulario').on('submit', function (e) {
/*
função js para executar antes do
post e após a validação padrão do agilityflow
*/
})
No exemplo de javascript, nas linhas de 5 a 12 usamos o código para interceptar o submit e validar o status do projeto.
Forçar o Salvar do formulário:
Clique aqui para visualizar detalhes de Como forçar o salvamento de um Form
Escutar o evento de retorno de um submit no form:
Clique aqui para visualizar detalhes de Como escutar o evento de retorno de um submit no form
Invalidar o post/submit do formulário:
Para evitar que o formulário seja postado, você pode utilizar a seguinte função no evento de submit
$('#formulario').on('submit', function (e) {
//invalidar submit
Form.invalidateForm({
msg: 'Mensagem para o usuário.'
});
})
No exemplo de javascript, nas linhas de 23 a 26 usamos o código para bloquear o submit caso o status do projeto seja inválido.
Verificar qual foi o botão clicado pelo usuário no submit do formulário. Se foi o salvar, salvar rascunho, descartar, deletar, aprovar, retornar, reprovar e assim por diante...
Os tipos de ações que o usuário pode realizar em um formulário são:
- Salvar (ACTION_SALVAR)
- Salvar rascunho (ACTION_SALVAR_RASCUNHO)
- Descartar rascunho (ACTION_DESCARTAR_RASCUNHO)
- Aprovar (ACTION_APROVAR)
- Reprovar (ACTION_REPROVAR)
- Retornar (ACTION_RETORNAR)
- Deletar (ACTION_DELETAR)
- Salvar formulário filho (ACTION_SALVAR_FORMULARIO_FILHO)
- Deletar formulário filho (ACTION_DELETAR_FORMULARIO_FILHO)
- Descartar alterações formulário filho (ACTION_DESCARTAR_ALTERACOES_FORMULARIO_FILHO)
- Solicitar troca de aprovador na etapa (ACTION_SOLICITAR_TROCA_APROVADOR_ETAPA_DINAMICA)
- Salvar o novo aprovador definido para a etapa (ACTION_SALVAR_DEFINICAO_APROVADOR_ETAPA_DINAMICA)
Abaixo o exemplo para recuperar a ação:
$('#formulario').on('submit', function (e) {
var tipoAcao = Form.getFormActionOnSubmit();
if(tipoAcao == ACTION_SALVAR){
//ação para "Salvar"
}else if(tipoAcao == ACTION_SALVAR_RASCUNHO){
//ação para "Salvar rascunho"
}else if(tipoAcao == ACTION_DESCARTAR_RASCUNHO){
//ação para "Descartar rascunho"
}else if(tipoAcao == ACTION_APROVAR){
//ação para "Aprovar"
}else if(tipoAcao == ACTION_REPROVAR){
//ação para "Reprovar"
}else if(tipoAcao == ACTION_RETORNAR){
//ação para "Retornar"
}else if(tipoAcao == ACTION_DELETAR){
//ação para "Deletar"
}else if(tipoAcao == ACTION_SALVAR_FORMULARIO_FILHO){
//ação para "Salvar formulário filho"
}else if(tipoAcao == ACTION_DELETAR_FORMULARIO_FILHO){
//ação para "Deletar formulário filho"
}else if(tipoAcao == ACTION_DESCARTAR_ALTERACOES_FORMULARIO_FILHO){
//ação para "Descartar alterações formulário filho"
}else if(tipoAcao == ACTION_SOLICITAR_TROCA_APROVADOR_ETAPA_DINAMICA){
//ação para "Solicitar troca aprovador etapa dinâmica"
}else if(tipoAcao == ACTION_SALVAR_DEFINICAO_APROVADOR_ETAPA_DINAMICA){
//ação para "Salvar definicão de aprovador etapa dinâmica"
}
})
No exemplo de javascript, nas linha 21 usamos o código no IF para testar se o submit era do tipo "Salvar".
Mensagem e alerta para o usuário
No código abaixo mostra exemplo de como apresentar alertas na tela para o usuário.
//mensagem de sucesso
pageMsg.showMsgSuccess(msg, title);
//mensagem de aviso
pageMsg.showMsgWarning(msg, title);
//mensagem de erro
pageMsg.showMsgError(msg, title);
//esconder a mensagem
pageMsg.hideMsgs(true);
Recuperar um valor de uma QueryString
var value = getQuerystring('paramQuerystring1');
Você também pode usar o javascript nativo, detalhado nesse exemplo: Como Obter Parâmetros da Query String com JavaScript
Javascript - Formulário Filho
Javascript - Buscar o Json com o resultado e todos os campos de uma tabela filha
//o parametro 'f43330be-0467-7fee-1168-28c9e6d185f0' é o Id da Tabela
var json = formContext.childForm.datatable.getResultJson('f43330be-0467-7fee-1168-28c9e6d185f0');
Javascript - Atualizar uma Tabela Filha
//o parametro 'f43330be-0467-7fee-1168-28c9e6d185f0' é o Id da Tabela
formContext.childForm.datatable.refresh('f43330be-0467-7fee-1168-28c9e6d185f0');
Javascript - Buscar o total de itens em uma tabela filha
//o parametro 'f43330be-0467-7fee-1168-28c9e6d185f0' é o Id da Tabela
var total = formContext.childForm.datatable.totalRows('f43330be-0467-7fee-1168-28c9e6d185f0');
Javascript - Refazer a ordenação dos itens quando a tabela filha estiver liberada a ordenação manual via "Drag and Drop" (Arrastar e soltar)
//reordena os itens da tabela filha de acordo com a ordem dos ids passados no parametro @items_sorted
//o primeiro parametro, 'f43330be-0467-7fee-1168-28c9e6d185f0' é o Id da Tabela
// o segundo parametro "items_sorted" é a lista ordenada com os ids dos elementos que pertencem a tabela:
//[
// { formid: '', draftid: '' },
// { formid: '', draftid: '' },
// { formid: '', draftid: '' },
//]
formContext.childForm.datatable.setOrder('f43330be-0467-7fee-1168-28c9e6d185f0', items_sorted);
Javascript - Buscar todos os ids: "Id do Formulário" e "Id do Rascunho" dos itens listados em uma tabela filha
//o parametro 'f43330be-0467-7fee-1168-28c9e6d185f0' é o Id da Tabela
var ids = formContext.childForm.datatable.getAllChildIds('f43330be-0467-7fee-1168-28c9e6d185f0');
o restorno será nesse formato:
[
{
"formid": "5451ae4e-290a-4887-8099-6e9a026c0283",
"draftid": ""
},
{
"formid": "6c55eeef-427b-40ce-b415-dab11b4aa039",
"draftid": ""
},
{
"formid": "304cc8e2-47af-44d4-ba83-c0e4939e21fb",
"draftid": ""
}
]
Javascript - Disparo de Eventos na tabela Filha
| Objeto | Nome / evento | Exemplo de uso |
| Tabela de Dados do Formulário Filho. Que fica no Formulário Pai. |
before-data-load / Dispara antes de carregar os dados na tabela |
//id = id da tabela filha $('#id').on('before-data-load', function (e) { console.log('evento disparado antes de carregar os dados') }); |
| Tabela de Dados do Formulário Filho. Que fica no Formulário Pai. |
data-loaded / Dispara depois de carregar os dados na tabela |
//id = id da tabela filha $('#id').on('data-loaded', function (e, result_json) { console.log('evento disparado depois de carregar os dados') console.log('result_json',result_json) }); |
Javascript - Biblioteca
Abaixo estão listadas as biblioteca javascript que já estão importadas na página do formulário:
| bootstrap-daterangepicker/daterangepicker.js |
| bootstrap-daterangepicker/moment.min.js |
| bootstrap-select/bootstrap-select.js |
| bootstrap/bootstrap.js |
| guid.js |
| jquery.inputmask/4.0.0-beta.19/jquery.inputmask.bundle.js |
| jquery.mask.js |
| jquery.maskMoney.js |
| jquery.validate.js |
| jquery.webui-popover.js |
| jquery/jquery.js |
Criar Html (Componente Cshtml):
Abra o formulário que deseja customizar. Na barra superior desse formulário clique em "Visual Code Editor" como mostra figura abaixo:

Para criar um html, clique no botão "Novo Cshtml", como na figura abaixo:

Ao clicar, digite o nome do Html

Agora o novo html está criado, e será mostrado para edição no menu do lado esquerdo, como na imagem abaixo.

Clique no nome do Html para edita-lo.
No arquivo Html, é possível utilizar qualquer tag Html que você precisar. Para embelezar o seu html utilize a linguagem css na área "Style (CSS)", e para customizar com javascript, faça as customizações na área "Javascript".
Faça as edições necessárias, salve e posicione esse novo componente no seu formulário. (O passo a passo para posicionar o componente no formulário está descrito mais abaixo)
Posicionando o componente Html no formulário
Depois de criado o componente cshtml, salve todas as configurações e customizações realizadas no Visual Code Editor, através do botão
.
Agora volte para a edição do formulário e clique no botão

No box de opções de campos, o seu componente "ExemploHtml" já deverá estar listado, como mostra a imagem abaixo:

Clique no nome do componente, e logo em seguida em salvar 
Agora você deve posiciona-lo na tela, para isso basta clicar na opção
como mostra imagem abaixo.

Ao abrir a opção de montagem de tela, posicione e arraste o seu componente onde você preferir.
Agora salve e publique esse novo formulário! Pronto, o seu componente está criado.
Exemplo prático de customização html
No exemplo a seguir vamos apresentar uma mensagem em azul de bom dia ou boa tarde ou boa noite dependendo do horário atual.
Para descobrir qual a data e qual a mensagem a ser apresentada, usamos C# no cshtml.
Para deixar a mensagem azul, usamos CSS.
Nesse exemplo não utilizamos javascript para nenhuma ação, mas poderia ser utilizado caso fosse necessário.
Passo 1 - Definir o html
Crie o cshtml como descrito aqui.
Agora cole o código abaixo nesse novo html:
@{
string parteDoDia;
var hours = DateTime.Now.Hour;
if (hours > 16)
{
parteDoDia = "Boa noite";
}
else if (hours > 11)
{
parteDoDia = "Boa tarde";
}
else
{
parteDoDia = "Bom dia";
}
}
<div class="painel-msg-customizada">
<span>@parteDoDia,</span>
</div>
Passo 2 - Definir o CSS
Entre na área de CSS e cole o código abaixo:
.painel-msg-customizada{
display: block;
text-align: left;
padding-top: 10px;
}
.painel-msg-customizada span{
color: #0281ff;
display: block;
font-size: 17px;
font-weight: 500;
border-bottom: solid 2px #a4d2ff;
margin-bottom: 15px;
}
Passo 3 - Posicionar o html no formulário
Salve tudo no Visual Code Editor e posicione esse componente html, como descrito aqui.
Passo 4 - Salvar e publicar o formulário
Salve e publico o novo formulário.
Agora acesse esse formulário, o resultado deve ser igual ao print abaixo:

C# no componente CSHTML
Se você precisar de alguma informação do formulário, utilize a opção abaixo
C# - Propriedades
| string FormId | Id do registro, pode ser em branco ou nulo qdo for um rascunho |
| bool IsRascunho {get;} | Retorna true caso a linha seja um Rascunho |
| string DraftId | Id do rascunho |
C# - Recuperar (Get) valor dos campos
| string GetValue(string idColuna) |
retorna o valor do campo |
| int? GetInt(string idColuna) |
Retorna o valor do campo no tipo INT (inteiro), caso esse campo no formulário seja um número, se o valor for 10.000,99 Será retornado: 10000
|
| decimal? GetDecimal(string idColuna) | Retorna o valor do campo no tipo Decimal, caso esse campo no formulário seja um número, se o valor for 10.000,99
Será retornado: 10000.99 |
| DateTime? GetDateTime(string idColuna) | Retorna o valor do campo no tipo DateTime |
|
Guid? GetGuid(string idColuna)
|
Retorna o valor do campo no tipo Guid |
|
string GetText(string idColuna)
|
No caso de campos que são Lista Dinanica, exemplo Combo, Auto completo, radio etc.
No Json de Campos Preenchidos no Formulario, só terá o Value dos campos
Esse método retornará o Texto desse campo.
Exemplo:
Existe no formulário um campo chamado 'Produto', com o id definido como 'produto'.
Esse campo é do tipo 'AutoComplete' e listará os 'Produtos' por 'Nome'.
Quando o usuário salvar o formulário, no Json de envio não retornará o Nome do Produto, apenas o Id do produto selecionado (Esse id estará no formato de um GUID).
Para recuperar o Nome do produto, vc precisará executar esse método da seguinte forma:
var nomeProduto = PageContext.GetText("produto")
|
| Variável | Tipo | |
|
(deprecated) Model.FormularioCamposPreenchidos |
(deprecated) dynamic (Json) |
(deprecated: utilizar o método PageContext.GetValue descrito mais acima) Retorna um json com os campos preenchidos no formulário, exemplo: { "campo1": "xxxxx", "campo2": "yyyyy", "campo3": "zzzzz", }
Para resgatar a informação do campo1, utilize:
Para resgatar o id do formulário, utilize:
|
|
(deprecated) Model.Id
OU
Model.FormularioCamposPreenchidos["id"];
|
(deprecated) Guid
OU
string |
(deprecated) Para resgatar o id do formulário, utilize:
|
|
Model.FormularioTemporarioId
|
Guid |
Para resgatar o id temporario do formulário, utilize:
|
|
(deprecated) Model.RascunhoId |
(deprecated) Guid |
(deprecated) Para resgatar o id do rascunho, caso seja um |
|
Model.EstruturaFormularioId |
Guid |
Para resgatar o id da ESTRUTURA do formulário |
|
Quando estiver dentro do Formulário Filho: Model.FormularioIdPai |
Guid |
Para resgatar o id do formulário pai, quando estiver dentro de um formulário filho, utilize:
|
|
Quando estiver dentro do Formulário Filho: Model.FormularioTemporarioIdPai |
Guid |
Para resgatar o id temporário do formulário pai, quando estiver dentro de um formulário filho, utilize:
|
|
Quando estiver dentro do Formulário Filho: Model.EstruturaFormularioIdPai |
Guid |
Para resgatar o id temporário do formulário pai, quando estiver dentro de um formulário filho, utilize:
|
|
WFS.Common.AppSettings.StaticFilePath
|
string |
Retorna a url dos arquivos estaticos do agilityflow, exemplo, .js, .css, etc..
caso queira importar um arquivo JS que já exista na biblioteca de arquivos estaticos do agilityflow
<script src="@WFS.Common.AppSettings.StaticFilePath/js/xxxxx/yyyyyy.js?@WFS.Common.AppSettings.StaticFileVersion"></script>
|
|
WFS.Common.AppSettings.StaticFileVersion
|
string |
Utilize essa variável para limpar o cache do seu arquivo estático, sendo assim coloque ela como parametro de querystring do seu arquivo, exemplo:
caso queira importar um arquivo JS que já exista na biblioteca de arquivos estaticos do agilityflow
<script src="@WFS.Common.AppSettings.StaticFilePath/js/xxxxx/yyyyyy.js?@WFS.Common.AppSettings.StaticFileVersion"></script>
|
C# no Componente CSHTML - Testar se é umnovo formulário ou se é uma edição
Para saber se o formulário é um novo ou está para edição, apenas teste a variável de ID, como no exemplo abaixo:
Forma 1
@{
var isNovoFormulario = GuidHelper.IsNullOrEmpty(Model.Id);
}
Forma 2
@{
var isNovoFormulario = Model.Id.IsNullOrEmpty();
}
Exemplo
@{
var msg = "";
var formularioId = Model.Id;
if(formularioId.IsNullOrEmpty()){
msg = "é um novo formulario";
}else{
msg = "NÃO é um novo formulario";
}
}
<div>@msg</div>
C# no componente CSHTML - Testar se é um rascunho
@{
var msg = "";
var rascunhoId = Model.RascunhoId;
if(rascunhoId.IsNullOrEmpty()){
msg = "é um Rascunho";
}else{
msg = "NÃO é um Rascunho";
}
}
<div>@msg</div>
Criar uma Tabela de dados customizada através de programação: Query SQL, C#, HTML e CSS:
Abaixo está um exemplo de criação de uma tabela de dados buscando as informações através de uma Query SQL e apresentando no Html:
Para customizar o CSS e Javascript da tabela de dados, utilize áreas de customização já citadas nos itens acima
<h5 id="datatableTitle">Tasks</h5>
<a id="btnAdd" href="javascript:pageNavigation.openSimpleLightBox({ islookup: true, url:'@Model.GetBaseUrl()/fluxo/index/7f786f15-d644-4351-8763-46bc2923fd21' })"><i class="mdi mdi-plus"></i> Add task</a>
<table id="tasksTable" border="1">
<tr>
<th width="140px">Status</th>
<th>Team</th>
<th>Description</th>
<th>CreatedDate</th>
<th>ModifiedDate</th>
</tr>
@{
var applicationId = PageContext.FormId;
/* concatenando o parametro */
var dt = await PageContext.GetDataTableAsync(@"select
isnull(task.id,'') TaskId,
isnull(task.description,'') TaskDescription,
isnull(team.name,'') Team,
task.log_data_criacao CreatedDate,
task.log_data_alteracao ModifiedDate,
isnull(etp.etp_nome,'') CurrentStep,
frm_status_fluxo StatusFlow
from
x_tbl_application_task2 task
inner join tbl_formulario form
on task.id = form.frm_id
left join tbl_formulario_etapa etp
on form.etp_id_atual = etp.etp_id and etp.frm_id = form.frm_id
left join x_tbl_team team
on task.team = team.id
where
task.deletado = 0
and task.id_application = '"+applicationId+"' order by task.log_data_alteracao desc, task.log_data_criacao desc ");
/* passando como parametro */
/*var paramsQuery = new List<NpgsqlParameter>();
paramsQuery.Add(new NpgsqlParameter("@applicationId", applicationId){ NpgsqlDbType = NpgsqlTypes.NpgsqlDbType.Uuid });
var dt = await PageContext.GetDataTableAsync(@"select
isnull(task.id,'') TaskId,
isnull(task.description,'') TaskDescription,
isnull(team.name,'') Team,
task.log_data_criacao CreatedDate,
task.log_data_alteracao ModifiedDate,
isnull(etp.etp_nome,'') CurrentStep,
frm_status_fluxo StatusFlow
from
x_tbl_application_task2 task
inner join tbl_formulario form
on task.id = form.frm_id
left join tbl_formulario_etapa etp
on form.etp_id_atual = etp.etp_id and etp.frm_id = form.frm_id
left join x_tbl_team team
on task.team = team.id
where
task.deletado = 0
and task.id_application = @applicationId order by task.log_data_alteracao desc, task.log_data_criacao desc ", paramsQuery.ToArray());*/
foreach (DataRow dr in dt.Rows)
{
var ModifiedDate = dr["ModifiedDate"] == DBNull.Value ? "" : dr["ModifiedDate"].ToString();
var currentStep = dr["CurrentStep"].ToString();
var statusFlow = dr["StatusFlow"].ToString();
if(statusFlow == "A"){
currentStep = "APPROVED";
}else if(statusFlow == "X"){
currentStep = "REJECTED";
}
<text>
<tr class="task-row status-@currentStep" data-taskid='@dr["TaskId"].ToString()'>
<td><span class="st">@currentStep</span></td>
<td>@dr["Team"].ToString()</td>
<td>@dr["TaskDescription"].ToString()</td>
<td>@dr["CreatedDate"].ToString()</td>
<td>@dr["ModifiedDate"].ToString()</td>
</tr>
</text>
}
}
</table>
Recarregar no servidor um componente Html ao alterar uma determinada informação do formulário:
Você pode determinar alguns momentos para que as informações de um componente html sejam recarregadas do servidor.
Essa é uma opção vantajosa em situações em que você tenha consultas (queries) de banco de dados no dentro do componente Html e deseja que essa consulta seja atualizada em alguns momentos.
Apenas campos do tipo "Lista de seleção (Combo)" e "Pesquisa com auto completar" poderão disparar o recarregamento do Componente Cshtml
Exemplo para recarregar o componente cshtml
Suponhamos que você crie um formulário que contenha 2 campos, o primeiro é um combo de Perfil de Acesso no sistema e o segundo campo é um componente CsHtml que contenha uma tabela que mostre todos os usuários que possuam o perfil selecionado no primeiro campo de Perfil de Acesso. Então, todas vez que o campo Perfil de acesso for alterado, a tabela de usuários deve ser recarregada para mostrar só os usuários relacionados ao novo perfil alterado.
Para esse exemplo, crie um novo formulário. Nesse novo formulário, crie um combo chamado Perfil e abaixo crie um componente CShtml que apresente uma tabela com todos os usuários do perfil selecionado (copiar e colar código abaixo no novo componente).
Código para o Componente Cshtml que listará os usuários
<h5 id="datatableTitle">Usuários com esse perfil:</h5>
<table id="usuTable" border="1">
<tr>
<th width="140px">Nome</th>
<th>E-mail</th>
</tr>
@{
var perfilId = Model.FormularioCamposPreenchidos["perfil"];
if(perfilId != null && perfilId.ToString() != string.Empty){
//na query será utilizado no WHERE o id do perfil selecionado no combo
var query = @"select id, isnull(usu_nome,'') Nome, isnull(usu_email,'') Email from tbl_usuario u inner join tbl_perfil_usuario pu on u.id = pu.id_tbl_usuario and pu.deletado = 0 where u.deletado = 0 and pu.id_tbl_perfil = '"+perfilId+"' ";
var dt = await PageContext.GetDataTableAsync(query);
foreach (DataRow dr in dt.Rows)
{
<text>
<tr class="task-row" data-taskid='@dr["id"].ToString()'>
<td>@dr["Nome"].ToString()</td>
<td>@dr["Email"].ToString()</td>
</tr>
</text>
}
}
}
</table>
Agora adicione esse componente na tela abaixo do campo Perfil.
Clique para editar o componente e marque o checkbox "Ao alterar o campo Perfil", como na imagem abaixo.
Pronto, agora salve e acesse esse novo formulário criado.
Tente alterar o valor do combo Perfil, se tudo correr bem a tabela de usuários deverá ser recarregada toda vez que o campo perfil for alterado.
C# - Adicionar e Atualizar os itens a uma tabela de formulário filho:
Para esse exemplo, será necessário Associar um Formulário Filho a um Formulário Pai, considere que nesse exemplo o Formulário Filho tenha um campo de texto chamado "nome_filho".
O exemplo abaixo foi colocado dentro de um cshtml do formulário pai e ao criar um novo formulário adicionará um item ao formulário filho e logo em seguida atualizará o item apenas para a demonstração das funções
Caso a informação a ser adicionada ou atualizada seja um número, enviar sem separador de milhar e o separador de decimal deve ser "." (ponto), exemplo: para o valor de nove mil e quinhentos, deve ser enviado 9500.00. Para facilitar utilize a função PageContext.FormatNumberToString_EnglishFormat(999999.99, 2);
@{
//id da tabela
var tableid_relacaoFormularioPaiFilhoId = Guid.Parse("0dd874a9-9c39-4e4f-acc3-02015a60f6bb"); //table id DO FORMULÁRIO FILHO
//info do formulario filho
var campos_e_valores = new DataDictionary();
campos_e_valores["nome_filho"] = "Exemplo 01 - " + DateTime.Now;
campos_e_valores["valor_numerico"] = PageContext.FormatNumberToString_EnglishFormat(999999.99, 2);
//testa se é um form NOVO e se NÂO é RASCUNHO pois nesse exemplo quero inserir apenas para formulário NOVOS que não sejam RASCUNHOs
var isNovo = Model.Id.IsNullOrEmpty();
var isRascunho = !Model.RascunhoId.IsNullOrEmpty();
if(isNovo && !isRascunho){
//adiciona na tabela filha
//retorna o id do rascunho desse formlario filho, pois o ID final só será gerado ao Salvar o Formulario PAi
var formRascunhoId = PageContext.AddChildForm( tableid_relacaoFormularioPaiFilhoId, campos_e_valores);
//atualiza o item que acabamos de adicionar, apenas para demonstração
Guid? idFormularioFilho = null;
campos_e_valores["nome_filho"] = "Exemplo Atualizado 0123456789 - " + DateTime.Now;
PageContext.UpdateChildForm(
//se ainda não foi salvo pela primeira vez, o item só terá o Id do Rascunho
rascunhoId,
//se já foi salvo pela primeira vez, o item já terá o Id
//então passa aqui o id (nesse exemplo estamos passando null para atualizar apenas o
idFormularioFilho,
tableid_relacaoFormularioPaiFilhoId,
campos_e_valores);
}
}
C# - Obter o total de itens em uma tabela de formulário filho:
@{
//relacaoFormularioPaiFilhoId não é o id do formulario filho e sim o id do campo que gera ao adicionar o formulario filho ao formulario pai
var relacaoFormularioPaiFilhoId = Guid.Parse("f43330be-0467-7fee-1168-28c9e6d185f0"); //trocar esse id
var total = await PageContext.CountChildFormsAsync(relacaoFormularioPaiFilhoId);
}
C# - Enviar e Recuperar parâmetros extras na requisição ajax no partial view (cshtml)
Enviando um parâmetro extra via javascript
var idsItensPrecosCompostos = formContext.childForm.datatable.getAllChildIds('251c66c9-cb26-f3a8-d014-8a1dd4a6b6aa')
formContext.loadViewComponent("calcular_valor_custo_preco_composto", {
extraData: { idsItensPrecosCompostos: JSON.stringify(idsItensPrecosCompostos) } ,
onSuccess: function (response) {
console.log(response)
}
})
Recuperando um parâmetro extra via C# no CShtml.
Nesse exemplo, dentro do partial view "calcular_valor_custo_preco_composto", colocaremos esse código
@{
var json_idsItensPrecosCompostos = Request["idsItensPrecosCompostos"];
}
<div>@json_idsItensPrecosCompostos</div>
C# e Javascript - Trabalhando com Json
1. Enviando um parâmetro no formato JSON via Javascript. Para isso no código abaixo transformamos um Array em JSON usando o JSON.stringify(...)
var idsItensPrecosCompostos = formContext.childForm.datatable.getAllChildIds('251c66c9-cb26-f3a8-d014-8a1dd4a6b6aa')
formContext.loadViewComponent("calcular_valor_custo_preco_composto", {
extraData: { idsItensPrecosCompostos: JSON.stringify(idsItensPrecosCompostos) } ,
onSuccess: function (response) {
console.log(response)
}
})
2. Recuperando um parâmetro JSON via C# e convertendo em Objeto Json
Você poderá utilizar qualquer função que faça parte das Bibliotecas
| Newtonsoft.Json |
| Newtonsoft.Json.Linq |
Nesse exemplo, dentro do partial view "calcular_valor_custo_preco_composto", colocaremos esse código para transformar o parametro que era string em um objeto dinamico do tipo JSON:
@{
var json_idsItensPrecosCompostos = Request["idsItensPrecosCompostos"];
dynamic idsItensPrecosCompostos = Newtonsoft.Json.JsonConvert.DeserializeObject(json_idsItensPrecosCompostos);
}
3. Count no JSON
* o count vai existir em caso do JSON estar no formato de uma lista ( array ).
@{
var json_idsItensPrecosCompostos = Request["idsItensPrecosCompostos"];
dynamic idsItensPrecosCompostos = Newtonsoft.Json.JsonConvert.DeserializeObject(json_idsItensPrecosCompostos);
var total = idsItensPrecosCompostos.Count;
}
4. Looping no JSON
* o foreach vai existir em caso do JSON estar no formato de uma lista ( array ).
@{
var json_idsItensPrecosCompostos = Request["idsItensPrecosCompostos"];
dynamic idsItensPrecosCompostos = Newtonsoft.Json.JsonConvert.DeserializeObject(json_idsItensPrecosCompostos);
var draftids = new List<string>();
var formids = new List<string>();
foreach (var idItem in idsItensPrecosCompostos)
{
draftids.Add(idItem.draftid.ToString());
formids.Add(idItem.formid.ToString());
}
}
C# - Transformar Array List em uma string separada por virgula
@{
var itens = new List<string>() { "abacaxi", "mamão", "melão", "banana"};
var msg = String.Join(",",itens.ToArray());
}
@msg
C# - Criar um Json dinamicamente
@{
var list_InfoNomeEmail = new JArray() as dynamic;
var query = @"select nome, email from x_tbl_xxxxxxxxxxxxx where deletado = 0";
var dt = await PageContext.GetDataTableAsync(query);
foreach (DataRow dr in dt.Rows)
{
var nome = dr["nome"].ToString();
var email = dr["email"].ToString();
//cria o objeto e inclua na lista para depois ser transformado em json
dynamic infoNomeEmail = new JObject();
infoNomeEmail.nome = nome;
infoNomeEmail.email = email;
list_InfoNomeEmail.Add(infoNomeEmail);
}
//devolve os items em formato json
if(list_InfoNomeEmail.Count > 0){
//serializa para JSON
var formata_para_json = JsonConvert.SerializeObject(list_InfoNomeEmail);
//usa o Html.Raw para garantir a integridade dos caracteres no retorno
@Html.Raw(formata_para_json)
}
}
Quadros (Kanban)
No agilityflow, a visualização padrão é por listas. Cada linha da lista corresponde a um registro do formulário. As colunas exibidas são as que foram definidas na configuração do formulário, na listagem principal de dados.
Entretanto, dependendo da natureza das informações armazenadas no formulário, um outro tipo de visualização seja mais adequado. A visualização em quadros do agilityflow, visa melhorar a maneira de interação do usuário com os registros. Para isso, usamos o método Kanban, que é um método consagrado de mercado, e que é conhecido por ser um método de gestão visual para o controle de tarefas, processos e demandas.
Usando Um Quadro
Opções
Ao abrir um quadro, as opções principais estão no menu do canto superior direito:

Listagem Padrão
Alterna a visualização do formulário para o modo padrão.
Visualização Favorita
Ao clicar no ícone
ao lado de uma visualização, ela se torna a padrão do formulário. Com isso, sempre que o formulário for acessado, a primeira visualização será a que for definida como favorita.
Criar Outro Quadro
Abre a opção para se criar um novo quadro como explicado no capítulo criando um quadro abaixo.
Reordenar as colunas
É possível reordenar as colunas de um quadro. Basta clicar na coluna e arrastar para a posição desejada. O salvamento é feito de forma automática, e a ordem das colunas será sempre o último configurado.
Arrastando os Cards
Ao arrastar um card, o valor do campo que é usado para definir as colunas é alterado no registro também. Na prática, arrastar um card para outra coluna é o mesmo que abrir o registro e alterar o campo.
É possível também re-ordenar os cards dentro de uma mesma coluna, mudando assim a ordem em que os cards são exibidos.
Rascunhos
Os rascunhos podem ser exibidos em dois locais:
Na coluna a qual o registro pertence
Caso o registro já possua o campo da coluna preenchido, ele será exibido na coluna respectiva, com uma marcação de rascunho, como mostra a figura abaixo:

Na coluna Rascunhos Não Salvos
Caso não seja possível definir a coluna, o registro será mostrado em uma coluna chamada "Rascunhos Não Salvos".

Coluna "Não Definido"
Os registros que já foram salvos, mas o campo usado para definir as colunas do quadro não tenha sido preenchido, serão colocados em uma coluna chamada "Não Definido".

Adicionar Lista
Essa opção cria novas colunas na visualização. Na prática, é adicionado um registro na tabela dinâmica que o campo usado como base para colunas utiliza.
Configurar Ações
É possível criar ações pré-definidas, como explicadas aqui.
Filtro
Os filtros funcionam da mesma forma que na visualização padrão.
Criando um quadro
A criação do quadro pode ser através do devcenter, na opção Quadros (kanban), ou dentro do próprio formulário (caso o usuário tenha permissão) clicando no canto superior esquerdo onde é mostrada o tipo de listagem, e em seguida em "Criar Quadro":

Em seguida, é necessário informar qual o formulário será usado como origem dos dados.

Ao selecionar o formulário, outras opções serão apresentadas para configurar o novo quadro:

Campos de apresentação do card
Devido ao espaço limitado desse método, não é possível exibir todos os campos como na forma de listagem padrão. A exibição é limitada a dois campos, que serão apresentados como título e descrição. Abaixo, um exemplo de um cartão com os dois campos

Título do card
É o campo que será usado como título do card. Esse campo é mostrado em negrito, no topo.
Descrição do card
É o campo que virá abaixo do título.
Divisão das colunas/listas do quadro
O método Kanban utiliza colunas para separar e exibir os registros. Nessa opção, é possível definir o critério em que as colunas serão baseadas.
As colunas serão baseadas nas etapas do fluxo do formulário?
Quando o formulário informado na origem dos dados for um fluxo com etapas, essa opção estará disponível e as colunas serão as etapas do fluxo. Caso queira outro campo, é possível selecionar a opção "Não". Outros campos aparecerão para definir as colunas.
As colunas serão baseadas em um campo existente no formulário?
Deixar como sim padrão.
As colunas serão baseadas em qual campo
Selecione o campo do formulário utilizado para a definição das colunas. Nessa opção, apenas os campos com origem em uma lista dinâmica são permitidos, tais como Lista de Seleção, Lista com Autocompletar e Radio.
Outras configurações
Nome do quadro
Defina um nome para o quadro.
Como é possível ter vários quadros pro mesmo formulário, é importante a definição de um nome que explique o propósito do quadro
Ao clicar no card deverá abrir inicialmente a aba
São duas opções: formulário e acompanhamento.
Permitir o usuário criar outras listas/colunas (mostrar botão: "adicionar lista")
O botão adicionar lista fica na extrema direita, no final do quadro, e permite que o usuário crie novas colunas no Kanban. Ao clicar em adicionar lista, na prática, abre o formulário para a criação de um novo registro no formulário usado como fonte pelo campo informado na definição das colunas do quadro.
Seja cuidadoso na criação de um quadro kanban. Após a configuração inicial, não é possível alterá-lo. Caso seja necessário, será preciso criar um novo quadro.
Listagem do Formulário - customizar com HTML, C#, CSS e Javascript
O agilityflow permite customização através da Linguagem Html, CSS, Javascript e C# (csharp).
O html do agilityflow é baseado no Razor do framework .Net, isso é, você pode além de customizar com HTML, utilizar código C# (razor) para dar mais flexibilidade e poder ao seu componente Html.
Customizar a Listagem
Acesse a parte de Desenvolvimento do Formulário que você deseja customizar, para isso, entre na área de customização de um formulário e clique na opção Visual Code Editor, como na imagem abaixo:
Nessa área você poderá customizar a parte de Cadastro e de Listagem utilizando, Javascript, CSS e CSHTML (Razor C# + Html):
Para essa documentação vamos nos preocupar com a área de "List Page".
Nessa área podemos customizar toda página de Listagem Principal de dados, como no exemplo abaixo.
Voltando a área de desenvolvimento, no menu de customização da List Page, teremos sempre 2 arquivos padrões: CSS e Javascript.
O CSS é sempre colocado no topo da página, dentro da tag <HEAD> do Html
O Javascript é sempre colocado no final da página, antes do fechamento do </Body>
Customizar com CSS
Todo código CSS da página de Listagem Principal do Formulário, deve ficar no arquivo CSS da List Page.
Nessa área, você pode criar customizações via linguagem CSS para toda a listagem e o seu uso é livre.
Levar em consideração o tratamento em CSS para a responsividade da plataforma em outros device, Mobile, Computador Desktop, Tablet, etc.
CSS no Formulário Filho
O CSS feito para a página de Listagem Principal está colocado apenas no List Page do próprio formulário filho, dessa forma ele não será adicionado ao Formulário Pai, então para usar CSS nas tabelas que estão dentro de um formulário Pai, você deve entrar dentro da área de desenvolvimento do Formulário Pai abrir o arquivo CSS e ao invés de colocar no CSS da aba List Page, coloque o código na aba Form Page do formulário pai.
Customizar com Javascript
Todo código Javascript da página de Listagem Principal do Formulário, deve ficar no arquivo Javascript da List Page.
O agilityflow possui uma extensa biblioteca de funções prontas para customização em Javascript que você pode utilizar para diminuir o seu tempo de desenvolvimento.
Além disso nessa parte você está livre para criar funções e regras da forma que for mais conveniente.
O agilityflow disponibiliza uma biblioteca principal em Javascript para a tela de Listagem Princpal. Essa biblioteca está disponível no objeto "listContext" e abaixo estão descritos as propriedades e métodos pré-programados para facilitar na utilização:
Para utilizar qualquer método ou propriedade listadas abaixo, sempre utilizar antes a nomenclatura "listContext.". Exemplo: listContext.Metodo() ou listContext.Propriedade
Javascript - Bloquear e Desbloquear a abertura do lightbox do Formularío ao clicar na linha do grid
|
void blockLinkOpening()
|
para bloquear a abertura do link ao clicar na linha do grid
|
| void unlockLinkOpening() |
para desbloquear o bloqueio a abertura do link ao clicar na linha do grid |
Exemplo de uso
$(document).on('click', '.btn-exemplo-botao', function (e) {
//bloqueia a abertura da tela de visualização do formulário
listcontext.blockLinkOpening();
//aqui você pode colocar seu código
//apresenta uma mensagem
alert('Mensagem de Exemplo')
//desbloqueia a abertura da tela de visualização do formulário
listcontext.unlockLinkOpening(false);
})
Javascript - Idioma, Linguagem / Internationalization (i18n)
|
currentLanguage.isEnglish()
|
retorna true se for inglês |
|
currentLanguage.isPortuguese()
|
retorna true se for português |
|
currentLanguage.isSpanish()
|
returna true se for espanhol |
|
currentLanguage.getIIF_TextFromCurrentLanguage(text_ptBR, text_ENG ,text_ESP)
|
dependendo do idioma, retorna o texto passado em 1 dos 3 parâmetros |
|
currentLanguage.getNumberDecimalSeparator()
|
Se NAO for Brasil, retorna ".", pois o formato do número é assim: 999,999,999.999
Se for Brasil, retorna ",", pois o formato do número é assim: 999.999.999,999
|
Javascript - Conversão e Formatação de Números
| number.convertString_toNumber(strValueToConvert, [optional]qtdCasasDecimais) |
|
| number.convertNumber_toStringFormatted(numberToConvert,qtdCasasDecimais) |
|
| number.getNumberDecimalSeparator() |
Se NAO for Brasil, retorna ".", pois o formato do número é assim: 999,999,999.999
Se for Brasil, retorna ",", pois o formato do número é assim: 999.999.999,999
|
Javascript - Data
| datetime.getDateNow() | data atual, retorna objeto Date do Javascript |
| datetime.getFormattedDateTime() | retorna data no formato 'DD/MM/YYYY' |
| datetime.getFormattedDate() |
retorna 'DD/MM/YYYY HH:mm'
|
| datetime.getLastDayOfCurrentMonth() |
último dia do mês atual,
retorno será 'DD/MM/YYYY'
|
| datetime.getLastDayOfMonth(data) |
último dia do mês da data passada como parâmetro
passar a data ano formato 'DD/MM/YYYY'
retorno será 'DD/MM/YYYY'
|
Javascript -Validação e Comparação entre Datas
| datetime.validation.isCurrentMonthAndYear(data) |
verifica se a data é do mês e ano corrente
passar data no formato 'DD/MM/YYYY'
|
||||||||||||||||||
| datetime.validation.compare(date1,compare,date2) |
Comparação entre 2 datas
Passar as datas (date1 e date2) no formato 'DD/MM/YYYY'
O parâmetro compare pode ser:
|
||||||||||||||||||
| datetime.validation.compareToday(compare,date2) |
Comparação entre a data passado por parametro com a data atual
Passar as data (date2) no formato 'DD/MM/YYYY'
O parâmetro compare pode ser:
|
Javascript - Manipular Datas
| datetime.add.day(data, days) |
Adicionar dias a uma data
passar data no formato 'DD/MM/YYYY'
retorno será 'DD/MM/YYYY'
|
| datetime.add.month(data, months) |
Adicionar meses a uma data
passar data no formato 'DD/MM/YYYY'
retorno será 'DD/MM/YYYY'
|
| datetime.add.year(data, years) |
Adicionar anos a uma data
passar data no formato 'DD/MM/YYYY'
retorno será 'DD/MM/YYYY'
|
| datetime.add.hour(data, hours) |
Adicionar horas a uma data
passar data no formato 'DD/MM/YYYY HH:mm'
retorno será 'DD/MM/YYYY HH:mm'
|
| datetime.add.minute(data, minutes) |
Adicionar minutos a uma data
passar data no formato 'DD/MM/YYYY HH:mm'
retorno será 'DD/MM/YYYY HH:mm'
|
Javascript - Outros
|
isMobile
|
retorna true caso seja mobile
|
Javascript no Formulário Filho: Customizar com Javascript a tabela que está dentro de um Formulário Pai
O Javascript feito para a página de Listagem Principal está colocado apenas no List Page do próprio formulário filho, dessa forma ele não será adicionado ao Formulário Pai, então para usar Javascript nas tabelas que estão dentro de um formulário Pai, você deve entrar dentro da área de desenvolvimento do Formulário Pai abrir o arquivo Javascript e ao invés de colocar no Javascript da aba List Page, coloque o código na aba Form Page do formulário pai.
Atenção: o objeto listContext não está presente no Formulário Pai, ver detalhes mais abaixo para o uso das funções semelhantes
As funções e biblioteca citadas acima não estão presentes da mesma forma no caso de tabelas/listagens filhas e que estarão dentro de um formulário Pai.
A mudança mais impactante é que o listContext não está presente, sendo assim você deve utilizar as funções Javascript descritas nesse link na documentação do formContext e formcontext.childform que são funçoes da tela de Formulário
Javascript - Bibliotecas de terceiros
Abaixo estão listadas as biblioteca javascript que já estão importadas na página do formulário:
| jquery v1.11.3 |
| bootstrap |
| moment |
| guid |
| jquery.inputmask/4.0.0-beta.19 |
| bootstrap-daterangepicker |
Customizar as Colunas da Listagem
O arquivo de customização sempre deve ter o mesmo nome do ID do campo/coluna no formulário
Para esse exemplo, considere um Formulário chamado "Exemplo de Listagem Customizada" com o seguintes campos:
| Nome | Id do campo | Tipo de Campo |
| Data e Hora | data_e_hora | Campo com máscara Data e Hora |
| Decimal com 2 Casas | decimal_2casas | Campo Número - Decimal com 2 casas |
| Decimal com 3 Casas | decimal_3casas | Campo Número - Número Decimal com 3 casas |
| Campo de Texto | ||
| Nome | nome | Campo de Texto |
| Idade | idade | Campo Número - Inteiro |
Foram adicionados campos NUMÉRICOS e de DATA para mostrar como você pode utilizar esse tipo de informação para fazer condicionais com essas informações.
Agora entra na área de listagem e coloque os seguintes campos:
Repare que na listagem eu adicionei os campos de Log, "Data criação" e "Criado Por". Esses são campos gerados automaticamente pelo Agilityflow, e você também pode utilizar essas informações na customização das colunas.
Agora volte para a área de customização:
Agora precisamos criar os arquivos de customização para cada coluna.
Crie através do botão NOVO CSHTML um arquivo para cada coluna que incluímos na listagem. Para isso, utilize o id da coluna como o nome do arquivo. Suas configurações devem estar como na imagem abaixo:
Antes de mostrar cada exemplo, abaixo descrevemos alguns métodos e propriedades disponíveis no contexto de cada customização de coluna, para que você consiga entender o que podemos fazer.
Propriedade e Métodos C# disponíveis no contexto do CSHTML da Coluna
O agilityflow disponibiliza uma biblioteca C# de contexto para a customização das colunas. Essa biblioteca está disponível no objeto "ColumnContext" e abaixo estão descritos as propriedades e métodos pré-programados para facilitar na utilização:
Para utilizar qualquer método ou propriedade listadas abaixo, sempre utilizar antes a nomenclatura "ColumnContext.". Exemplo: ColumnContext.Metodo() ou ColumnContext.Propriedade
C# - Propriedades
| string FormId | Id do registro, pode ser em branco ou nulo qdo for um rascunho |
| bool IsRascunho {get;} | Retorna true caso a linha seja um Rascunho |
| string DraftId | Id do rascunho |
| int RowIndex {get;} | Retorna a posição da Linha na tabela, começando do 0 |
C# - Recuperar (Get) valor das colunas
| string GetText(string idColuna) |
Retorna uma string com o texto da coluna passada no parâmetro
Essa função já traz o campo formatado com a máscara que está definida no Formulário. Por exemplo, caso seja um campo decimal, ele já trará o valor formatado de acordo com o idioma 10.000,00 ou 10.000,00 (caso você precise utilizar esse valor em alguma soma ou condicional ,utilize o método GetDecimal ao invés de GetText) |
| string GetValue(string idColuna) |
retorna o ID ao invés do Texto.
* Apenas para campos que sejam uma Lista Dinâmica, Lista Estática, Checkbox ou um campo que tenha como apresentação um Texto de outra Base de Dados mas por trás esse campo é um ID. * caso não encontre ou o valor seja nulo retorna em branco ao invés de null |
| int? GetInt(string idColuna) |
Retorna o valor da coluna no tipo INT (inteiro), caso esse campo no formulário seja um número, se o valor for 10.000,99 Será retornado: 10000
|
| decimal? GetDecimal(string idColuna) | Retorna o valor da coluna no tipo Decimal, caso esse campo no formulário seja um número, se o valor for 10.000,99
Será retornado: 10000.99 |
| DateTime? GetDateTime(string idColuna) | Retorna o valor da coluna no tipo DateTime para valores que estão no formato de data dd/MM/yyyy ou dd/MM/yyyy hh:mm |
DICA: Nos métodos acima só estarão disponíveis informações dos campos que foram marcados para aparecer na listagem. Caso você precise usar uma informação mas não quer que ela se torne uma coluna da lista, adicione ela como disponível na listagem e marque ela como invisível. Veja mais detalhes aqui
C# - Customização visual da coluna ou linha
| void SetCelColor(string color) |
Pinta o fundo da célula da coluna Algumas cores já estão predefinidas seguindo padrão de tonalidade do agilityflow. Essas cores são: "red", "green", "yellow", "blue". Caso você julgue necessário você também pode utilizar cores no formato hexadecimal
if(dt_data_e_hora < DateTime.Now){
importante usar o @ na frente |
| void SetRowColor(string color) |
Pinta o fundo da linha da linha Algumas cores já estão predefinidas seguindo padrão de tonalidade do agilityflow. Essas cores são: "red", "green", "yellow", "blue". Caso você julgue necessário você também pode utilizar cores no formato hexadecimal
if(dt_data_e_hora < DateTime.Now){
importante usar o @ na frente |
C# - Variáveis Globais no contexto da listagem
Você pode precisar guardar informações no contexto geral da listagem.
Imagine que você queira fazer uma soma geral ou guardar uma informação que você já tratou na primeira linha e que agora você precisa utiliza-la na última coluna, da última linha. Simples, basta utilizar o método SetGlobalVariable para colocar uma informação no contexto e depois busca-la com o método GetGlobalVariable para
| void SetContextVariable(string key, string value) | Colocar uma variável e seu valor no contexto da listagem |
| string GetContextVariable(string key) | Recupera o valor de uma variável que esteja no contexto da listagem |
C# - Formatação Numérica
Se você está utilizando o método GetText(..) para buscar uma coluna numérica, esse metódo já retornará o número formatado e não será necessário nenhuma formatação adicional.
Se você está utilizando o método GetDecimal(..) ele não virá formatado pois ele retorna o tipo DECIMAL do C#, sendo assim, se você precisa do dado formatado você pode utilizar o GetText(..)
| string FormatDecimalToString(object numDecimal, string mascaraTipo = "dec2") |
formata object 999999999.55 para o formato da mascara de acordo com o idioma. - se for ingles, será 999,999,999.55 |
| string FormatNumberToString_EnglishFormat(object num, [optional]int? qtdCasasDecimais) |
converte decimal para string, porém sempre a string vem no formato Inglês. coloca a a mesma qtd de casas decimais, caso o parâmetro qtdCasasDecimais estivar em branco |
C# - Usuário logado
| string GetUsuarioLogadoNome() | retorna o nome do usuário logado |
| string GetUsuarioLogadoPrimeiroNome() | retorna o primeiro nome do usuário logado |
| string GetUsuarioLogadoPrimeiroESegundoNome() | retorna o primeiro e o segundo nome do usuário logado |
| string GetUsuarioLogadoEmail() | retorna o e-mail do usuário logado |
| Guid GetUsuarioLogadoId() | retorna o id do usuário logado |
C# - Idioma, Linguagem / Internationalization (i18n)
|
CurrentLanguage.IsEnglish()
|
retorna true se for inglês |
|
CurrentLanguage.IsPortuguese()
|
retorna true se for português |
|
CurrentLanguage.IsSpanish()
|
returna true se for espanhol |
|
CurrentLanguage.GetIIF_TextFromCurrentLanguage(text_ptBR, text_ENG ,text_ESP)
|
dependendo do idioma, retorna o texto passado em 1 dos 3 parâmetros |
C# - Geral
| string GetUrlBase() | Retorna a URL base onde o agilityflow está instalado |
| string GetEnvironmentVariable(string nomeDaVariavel) |
Retorna o valor de uma variável de ambiente Não é perimitir utilizar esse metodo nesse contexto |
| string GetEnvironmentVariable_Text(string nomeDaVariavel) |
Retorna o texto de uma variável de ambiente Não é perimitir utilizar esse metodo nesse contexto |
Elementos Visuais para deixar a tabela mais bonita
| Button |
|
|
| Small Text |
|
|
| Tag Red |
|
|
| Tag Outline Red |
|
|
| Tag Yellow |
|
|
| Tag Outline Yellow |
|
|
| Tag Blue |
|
|
| Tag Outline Blue |
|
|
| Tag Green |
|
|
| Tag Outline Green |
|
|
| Tag gray |
|
|
| Tag Outline gray |
|
|
| Avatar |
|
|
| Avatar |
|
|
| Rating |
|
|
| Rating |
|
|
| Rating Red |
|
|
| Rating Blue |
|
|
| Rating Green |
|
|
| Rating Gray |
|
|
| Rating Ball |
|
|
| Rating Ball |
|
|
| Rating Ball Red |
|
|
| Rating Ball Blue |
|
|
| Rating Ball Green |
|
|
| Rating Ball Gray |
|
|
| Break Line |
|
|
| Line |
|
|
Exemplos de customização
Agora que já sabemos os métodos que podemos utilizar para facilitar a customização, abaixo listamos alguns exemplos de como utiliza-los na prática.
Comparação por Data e Hora. Pintar a linha e coluna se a data e hora (DateTime) estiver atrasada
No arquivo de customização "data_e_hora", vamos criar uma regrinha:
- Vamos buscar a data e hora já no tipo DateTime para podermos usar na condicional
- Se a data estiver atrasada, colocaremos a linha em vermelho
- Se faltar até 5 dias a para chegar na data, colocaremos a célula da tabela em amarelo
@{
//buscar a data e hora já no tipo Datetime para podermos usar na condicional
var dt_data_e_hora = ColumnContext.GetDateTime("data_e_hora");
//se não for possível converter a data, ela sempre retornará null
if(dt_data_e_hora != null){
//se está atrasada, coloca em vermelho a linha
if(dt_data_e_hora < DateTime.Now){
@ColumnContext.SetRowColor("red")
//se em até 5 dias for ficar atrasado, coloca em amarelo a célula
}else if(dt_data_e_hora < DateTime.Now.AddDays(5)){
@ColumnContext.SetCelColor("yellow")
}
}
//e por fim mostramos a data e a hora na célula
}
@dt_data_e_hora
resultado:
Comparação Numérica e tipos Numéricos
No arquivo de customização "decimal_3casas", vamos criar uma regrinha:
- Vamos mostrar na coluna o valor do campo "Decimal com 3 Casas", buscando ele no formato string e usando o método GetText
- Vamos mostrar na coluna o valor do campo "Decimal com 3 Casas", buscando ele como tipo inteiro (ignorando as casas decimais) e usando o método GetInt
- Vamos mostrar na coluna o valor do campo "Decimal com 3 Casas", buscando ele no tipo decimal e usando o método GetDecimal
- Vamos fazer uma condicional para mostrar uma tag em verde escrito "é Maior que 10 mil" caso o valor do campo seja maior que 10.000,00
- Vamos fazer uma condicional para mostrar uma tag em vermelho escrito "é Menor que 10 mil" caso o valor do campo seja menor que 10.000,00
@ColumnContext.GetText("decimal_3casas")
<br>
@ColumnContext.GetInt("decimal_3casas")
<br>
@ColumnContext.GetDecimal("decimal_3casas")
<br>
@{
if(ColumnContext.GetDecimal("decimal_3casas") > 10000){
<text>
<tag-green>é MAIOR que 10 mil</tag-green>
</text>
}else{
<text>
<tag-red>é MENOR que 10 mil</tag-red>
</text>
}
}
resultado:
Coluna Invisível: Como acessar via GetText os dados de um campo do formulário que não está marcado para aparecer como coluna da lista?
Dica:
Apenas campos que estão marcados para serem colunas da lista podem ser acessados através do método ColumnContext.GetText(...),sendo assim se você quer acessar uma informação através do GetText mas não quer que essa informação seja uma coluna, deixe ela invisível para os usuários, seguindo o procedimento abaixo.
Seguindo nosso exemplo, na coluna NOME da listagem, eu quero concatenar o Nome e a Idade do usuário, porém como eu não coloquei a Idade para ser visível na lista, ela não estará acessível se eu não seguir esses passos:
ColumnContext.GetText("idade")
mas não será uma coluna da Listagem.
Adicionar um botão na listagem
No arquivo de customização "email", vamos criar uma regrinha:
- Vamos mostrar o valor do campo E-mail
- Vamos adicionar um botão que quando o usuário clicar apresentará a msg "Mensagem de Exemplo"
- Para esse exemplo, vamos precisar fazer uso do arquivo padrão "Javascript" do List Page
No arquivo de customização de "email", cole o código abaixo
@ColumnContext.GetText("email")
<br>
<button type="button" class="btn-list btn-exemplo-botao">Botão</button>
No arquivo Javascript da List Page, cole o código abaixo
$(document).on('click', '.btn-exemplo-botao', function (e) {
//bloqueia a abertura da tela de visualização do formulário
listcontext.blockLinkOpening();
//aqui você pode colocar seu código
//apresenta uma mensagem
alert('Mensagem de Exemplo')
//desbloqueia a abertura da tela de visualização do formulário
listcontext.unlockLinkOpening(false);
})
Formulário Filho: No caso dessa tabela também estar dentro de um Formulário Pai, algumas coisas mudam:
O Javascript feito acima está colocado apenas no List Page da página de Listagem, dessa forma ele não será adicionado ao Formulário Pai, então você deve entrar dentro da área de desenvolvimento do Formulário Pai abrir o arquivo Javascript e ao invés de colocar o código no Javascript da aba List Page, coloque ocódigo abaixo na aba Form Page do formulário pai.
No caso de Formulário Filho dentro de um formulário Pai, não existirá no Javascript a biblioteca listContext pois essa biblioteca só está presenta na tela de lista. Nesse caso precisaremos usar o formContext mas como estamos falando de um Formulário Filho, as funções referente a ele está dentro de formContext.childForm.xxxx()
Código para o mesmo funcionamento do botão mas agora no formulário Pai.
Observe que no código abaixo, além da mudança de local do Javascript, o listContext. foi substituido por formContext.childForm
$(document).on('click', '.btn-exemplo-botao', function (e) {
//bloqueia a abertura da tela de visualização do formulário
formcontext.childForm.blockLinkOpening();
//aqui você pode colocar seu código
//apresenta uma mensagem
alert('Mensagem de Exemplo')
//desbloqueia a abertura da tela de visualização do formulário
formcontext.childForm.unlockLinkOpening(false);
})
Resultado:
Quando o usuário, clicar no botão "Botão" ele receberá essa mensagem:
Como utilizar uma Variável de Contexto ou Variável Global para interagir e armazenar informações entre todas as linhas e colunas da mesma listagem
Para esse exemplo demonstraremos o uso dos métodos ColumnContext.GetGlobalVariable("variavel"); e ColumnContext.SetGlobalVariable("variavel", "valor");
No arquivo de customização "nome", vamos criar uma regrinha:
- Vamos mostrar o valor do campo Nome, concatenado com a palavra "Nome:"
- Vamos somar a idade da linha anterior com a linha atual, até a última linha ser a soma total das idades
- Vamos mostrar uma frase mostrando a posição da linha (RowIndex) concatenada com a idade total somada até aquele momento
@{
//recupera o total já gravado em uma variavel global
var str_idade_total = ColumnContext.GetGlobalVariable("idade");
//pega a idade referente a essa linha na tabela
//já puxa a idade no formato INT (número inteiro) para ser possível
//fazer a soma total sem precisar de conversão de número
var idade = @ColumnContext.GetInt("idade");
//se a idade não tiver sido preenchida no formulário, então considera ela como zero
if(idade == null)
{
idade = 0;
}
//se a idade total já estiver sido preenchida, então, soma com a idade dessa linha
//caso contrário ignora pois será o primeiro registro da linha e não precisará ser feito nenhuma soma
if(!string.IsNullOrEmpty(str_idade_total)){
idade = Convert.ToInt32(str_idade_total) + idade;
}
//coloca novamente a soma das idades totais na Variável Global, para ser recuparada na próxima linha
str_idade_total = idade.ToString();
ColumnContext.SetGlobalVariable("idade", str_idade_total);
}
Nome: @ColumnContext.GetText("nome")
<br>
Até o RowIndex @ColumnContext.RowIndex a Idade era de @str_idade_total anos
Customizar e acessar as colunas de Log: Data de criação, Data de Alteração, Criado por e Alterado por.
Para recuperar os campos de Log na listagem através do GetText(...) ou GetDateTime(...) utilizar os ids padrões de cada campo:
| Nome | ID |
| Data de criação | log_data_criacao |
| Data de Alteração | log_data_alteracao |
| Criado por | log_usu_criacao |
| Alterado por | log_usu_alteracao |
Relatório / Dashboard - customizar colunas da tabale de dados com Html, C#, CSS e Javascript
O agilityflow permite customização através da Linguagem Html, CSS, Javascript e C# (csharp).
O html do agilityflow é baseado no Razor do framework .Net, isso é, você pode além de customizar com HTML, utilizar código C# (razor) para dar mais flexibilidade e poder ao seu componente Html.
Customizar a Tabela de dados (Datatable)
Você pode utilizar tabela de dados nos Reports e/ou nos Dasboards.
Estando na editção e customização de uma Tabela de dados, na barra de botões, clique na opção Customizar via Código, como na imagem abaixo:
Nessa área você poderá customizar o Javascript, CSS e o CSHTML (Razor C# + Html):
Nessa área podemos customizar toda a tabela de dados, como no exemplo abaixo.
Voltando a área de desenvolvimento, no menu de customização, teremos sempre 2 arquivos padrões: CSS e Javascript.
O CSS é sempre colocado no topo da página, dentro da tag <HEAD> do Html
O Javascript é sempre colocado no final da página, antes do fechamento do </Body>
Customizar com CSS
Todo código CSS da tabela de dados deve ser colocado na aba Style (CSS)
Nessa área, você pode criar customizações via linguagem CSS para toda a listagem e o seu uso é livre.
Levar em consideração o tratamento em CSS para a responsividade da plataforma em outros device, Mobile, Computador Desktop, Tablet, etc.
Customizar com Javascript
Todo código Javascript da datatable, deve ficar no arquivo Javascript.
Customizar com Html e/ou C#
rie através do botão NOVO CSHTML um arquivo para cada coluna que incluímos na tabela de dados. Para isso, utilize o id da coluna como o nome do arquivo. Suas configurações devem estar como na imagem abaixo:
Antes de mostrar cada exemplo, abaixo descrevemos alguns métodos e propriedades disponíveis no contexto de cada customização de coluna, para que você consiga entender o que podemos fazer.
Propriedade e Métodos C# disponíveis no contexto do CSHTML da Coluna
O agilityflow disponibiliza uma biblioteca C# de contexto para a customização das colunas. Essa biblioteca está disponível no objeto "ColumnContext" e abaixo estão descritos as propriedades e métodos pré-programados para facilitar na utilização:
Para utilizar qualquer método ou propriedade listadas abaixo, sempre utilizar antes a nomenclatura "ColumnContext.". Exemplo: ColumnContext.Metodo() ou ColumnContext.Propriedade
C# - Propriedades
| int RowIndex {get;} | Retorna a posição da Linha na tabela, começando do 0 |
C# - Recuperar (Get) valor das colunas
| string GetText(string idColuna) |
Retorna uma string com o texto da coluna passada no parâmetro
|
| string GetValue(string idColuna) |
Retorna uma string com o texto da coluna passada no parâmetro |
| int? GetInt(string idColuna) |
Retorna o valor da coluna no tipo INT (inteiro), caso esse campo no formulário seja um número, se o valor for 10.000,99 Será retornado: 10000
|
| decimal? GetDecimal(string idColuna) | Retorna o valor da coluna no tipo Decimal, caso esse campo no formulário seja um número, se o valor for 10.000,99
Será retornado: 10000.99 |
| DateTime? GetDateTime(string idColuna) | Retorna o valor da coluna no tipo DateTime para valores que estão no formato de data dd/MM/yyyy ou dd/MM/yyyy hh:mm |
C# - Customização visual da coluna ou linha
| void SetCelColor(string color) |
Pinta o fundo da célula da coluna Algumas cores já estão predefinidas seguindo padrão de tonalidade do agilityflow. Essas cores são: "red", "green", "yellow", "blue". Caso você julgue necessário você também pode utilizar cores no formato hexadecimal
if(dt_data_e_hora < DateTime.Now){
importante usar o @ na frente |
| void SetRowColor(string color) |
Pinta o fundo da linha da linha Algumas cores já estão predefinidas seguindo padrão de tonalidade do agilityflow. Essas cores são: "red", "green", "yellow", "blue". Caso você julgue necessário você também pode utilizar cores no formato hexadecimal
if(dt_data_e_hora < DateTime.Now){
importante usar o @ na frente |
C# - Variáveis de contexto da tabela de dados
Você pode precisar guardar informações no contexto geral da listagem.
Imagine que você queira fazer uma soma geral ou guardar uma informação que você já tratou na primeira linha e que agora você precisa utiliza-la na última coluna, da última linha. Simples, basta utilizar o método SetGlobalVariable para colocar uma informação no contexto e depois busca-la com o método GetGlobalVariable para
| void SetContextVariable(string key, string value) | Colocar uma variável e seu valor no contexto da listagem |
| string GetContextVariable(string key) | Recupera o valor de uma variável que esteja no contexto da listagem |
C# - Formatação Numérica
| string FormatDecimalToString(object numDecimal, string mascaraTipo = "dec2") |
formata object 999999999.55 para o formato da mascara de acordo com o idioma. - se for ingles, será 999,999,999.55 |
| string FormatNumberToString_EnglishFormat(object num, [optional]int? qtdCasasDecimais) |
converte decimal para string, porém sempre a string vem no formato Inglês. coloca a a mesma qtd de casas decimais, caso o parâmetro qtdCasasDecimais estivar em branco |
C# - Usuário logado
| string GetUsuarioLogadoNome() | retorna o nome do usuário logado |
| string GetUsuarioLogadoPrimeiroNome() | retorna o primeiro nome do usuário logado |
| string GetUsuarioLogadoPrimeiroESegundoNome() | retorna o primeiro e o segundo nome do usuário logado |
| string GetUsuarioLogadoEmail() | retorna o e-mail do usuário logado |
| Guid GetUsuarioLogadoId() | retorna o id do usuário logado |
C# - Idioma, Linguagem / Internationalization (i18n)
|
CurrentLanguage.IsEnglish()
|
retorna true se for inglês |
|
CurrentLanguage.IsPortuguese()
|
retorna true se for português |
|
CurrentLanguage.IsSpanish()
|
returna true se for espanhol |
|
CurrentLanguage.GetIIF_TextFromCurrentLanguage(text_ptBR, text_ENG ,text_ESP)
|
dependendo do idioma, retorna o texto passado em 1 dos 3 parâmetros |
C# - Geral
| string GetUrlBase() | Retorna a URL base onde o agilityflow está instalado |
| string GetEnvironmentVariable(string nomeDaVariavel) |
Retorna o valor de uma variável de ambiente Não é perimitir utilizar esse metodo nesse contexto |
| string GetEnvironmentVariable_Text(string nomeDaVariavel) |
Retorna o texto de uma variável de ambiente Não é perimitir utilizar esse metodo nesse contexto |
Elementos Visuais para deixar a tabela mais bonita
| Button |
|
|
| Small Text |
|
|
| Tag Red |
|
|
| Tag Outline Red |
|
|
| Tag Yellow |
|
|
| Tag Outline Yellow |
|
|
| Tag Blue |
|
|
| Tag Outline Blue |
|
|
| Tag Green |
|
|
| Tag Outline Green |
|
|
| Tag gray |
|
|
| Tag Outline gray |
|
|
| Avatar |
|
|
| Avatar |
|
|
| Rating |
|
|
| Rating |
|
|
| Rating Red |
|
|
| Rating Blue |
|
|
| Rating Green |
|
|
| Rating Gray |
|
|
| Rating Ball |
|
|
| Rating Ball |
|
|
| Rating Ball Red |
|
|
| Rating Ball Blue |
|
|
| Rating Ball Green |
|
|
| Rating Ball Gray |
|
|
| Break Line |
|
|
| Line |
|
|
Exemplos de customização
Agora que já sabemos os métodos que podemos utilizar para facilitar a customização, abaixo listamos alguns exemplos de como utiliza-los na prática.
Comparação por Data e Hora. Pintar a linha e coluna se a data e hora (DateTime) estiver atrasada
No arquivo de customização "data_e_hora", vamos criar uma regrinha:
- Vamos buscar a data e hora já no tipo DateTime para podermos usar na condicional
- Se a data estiver atrasada, colocaremos a linha em vermelho
- Se faltar até 5 dias a para chegar na data, colocaremos a célula da tabela em amarelo
@{
//buscar a data e hora já no tipo Datetime para podermos usar na condicional
var dt_data_e_hora = ColumnContext.GetDateTime("data_e_hora");
//se não for possível converter a data, ela sempre retornará null
if(dt_data_e_hora != null){
//se está atrasada, coloca em vermelho a linha
if(dt_data_e_hora < DateTime.Now){
@ColumnContext.SetRowColor("red")
//se em até 5 dias for ficar atrasado, coloca em amarelo a célula
}else if(dt_data_e_hora < DateTime.Now.AddDays(5)){
@ColumnContext.SetCelColor("yellow")
}
}
//e por fim mostramos a data e a hora na célula
}
@dt_data_e_hora
resultado:
Comparação Numérica e tipos Numéricos
No arquivo de customização "decimal_3casas", vamos criar uma regrinha:
- Vamos mostrar na coluna o valor do campo "Decimal com 3 Casas", buscando ele no formato string e usando o método GetText
- Vamos mostrar na coluna o valor do campo "Decimal com 3 Casas", buscando ele como tipo inteiro (ignorando as casas decimais) e usando o método GetInt
- Vamos mostrar na coluna o valor do campo "Decimal com 3 Casas", buscando ele no tipo decimal e usando o método GetDecimal
- Vamos fazer uma condicional para mostrar uma tag em verde escrito "é Maior que 10 mil" caso o valor do campo seja maior que 10.000,00
- Vamos fazer uma condicional para mostrar uma tag em vermelho escrito "é Menor que 10 mil" caso o valor do campo seja menor que 10.000,00
@ColumnContext.GetText("decimal_3casas")
<br>
@ColumnContext.GetInt("decimal_3casas")
<br>
@ColumnContext.GetDecimal("decimal_3casas")
<br>
@{
if(ColumnContext.GetDecimal("decimal_3casas") > 10000){
<text>
<tag-green>é MAIOR que 10 mil</tag-green>
</text>
}else{
<text>
<tag-red>é MENOR que 10 mil</tag-red>
</text>
}
}
resultado:
Adicionar um botão na tabela de dados
No arquivo de customização "email", vamos criar uma regrinha:
- Vamos mostrar o valor do campo E-mail
- Vamos adicionar um botão que quando o usuário clicar apresentará a msg "Mensagem de Exemplo"
- Para esse exemplo, vamos precisar fazer uso do arquivo padrão "Javascript" do List Page
No arquivo de customização de "email", cole o código abaixo
@ColumnContext.GetText("email")
<br>
<button type="button" class="btn-list btn-exemplo-botao">Botão</button>
No arquivo Javascript da List Page, cole o código abaixo
$(document).on('click', '.btn-exemplo-botao', function (e) {
//aqui você pode colocar seu código
//apresenta uma mensagem
alert('Mensagem de Exemplo')
})
Quando o usuário, clicar no botão "Botão" ele receberá essa mensagem:
Como utilizar uma Variável de Contexto ou Variável Global para interagir e armazenar informações entre todas as linhas e colunas da mesma listagem
Para esse exemplo demonstraremos o uso dos métodos ColumnContext.GetGlobalVariable("variavel"); e ColumnContext.SetGlobalVariable("variavel", "valor");
No arquivo de customização "nome", vamos criar uma regrinha:
- Vamos mostrar o valor do campo Nome, concatenado com a palavra "Nome:"
- Vamos somar a idade da linha anterior com a linha atual, até a última linha ser a soma total das idades
- Vamos mostrar uma frase mostrando a posição da linha (RowIndex) concatenada com a idade total somada até aquele momento
@{
//recupera o total já gravado em uma variavel global
var str_idade_total = ColumnContext.GetGlobalVariable("idade");
//pega a idade referente a essa linha na tabela
//já puxa a idade no formato INT (número inteiro) para ser possível
//fazer a soma total sem precisar de conversão de número
var idade = @ColumnContext.GetInt("idade");
//se a idade não tiver sido preenchida no formulário, então considera ela como zero
if(idade == null)
{
idade = 0;
}
//se a idade total já estiver sido preenchida, então, soma com a idade dessa linha
//caso contrário ignora pois será o primeiro registro da linha e não precisará ser feito nenhuma soma
if(!string.IsNullOrEmpty(str_idade_total)){
idade = Convert.ToInt32(str_idade_total) + idade;
}
//coloca novamente a soma das idades totais na Variável Global, para ser recuparada na próxima linha
str_idade_total = idade.ToString();
ColumnContext.SetGlobalVariable("idade", str_idade_total);
}
Nome: @ColumnContext.GetText("nome")
<br>
Até o RowIndex @ColumnContext.RowIndex a Idade era de @str_idade_total anos
Customizar e acessar as colunas de Log: Data de criação, Data de Alteração, Criado por e Alterado por.
Para recuperar os campos de Log na listagem através do GetText(...) ou GetDateTime(...) utilizar os ids padrões de cada campo:
| Nome | ID |
| Data de criação | log_data_criacao |
| Data de Alteração | log_data_alteracao |
| Criado por | log_usu_criacao |
| Alterado por | log_usu_alteracao |
Configuração dos Campos
Detalhes sobre como customizar os campos de um formulário, de acordo com a sua necessidade.
Textbox
O campo textbox é o tipo de campo mais usado no agilityflow. Isso é devido à sua versatilidade graças às inúmeras máscaras disponíveis. Apesar do nome, é com o campo textbox que iremos armazenar números também.
Ao criar um campo textbox no formulário, é solicitado escolher um grupo de informações e informar um nome de apresentação. Caso seja necessário, as configurações abaixo, estão disponíveis para o campo:
Grupo de informações
Dentro das configurações, é possível alterar o grupo de informação ao qual o campo foi atribuído no momento da criação.
Nome de Apresentação
Mostra o nome de apresentação informado no momento da criação. Esse é o nome que será mostrado na tela para o usuário.
Tipo
Para o campo textbox, é possível definir um subtipo. São eles:
Campo de Texto Simples
É o tipo padrão. Permite que o usuário insira qualquer tipo de informação de texto, em uma linha única.
Campo de Texto Multi Linha
Similar ao Campo de Texto Simples, porém, com mais de uma linha. Ao selecionar essa opção, é possível escolher quantas linhas ficarão visíveis ao usuário.
Campo com criptografia MD5 (Ex: Senha)
Funciona para armazenar textos, que ao digitados, serem ocultados tendo seus caracteres substituídos. Ao selecionar esse subtipo, não é possível definir uma máscara.
Campo Auto Numérico (Número Sequencial preenchido automaticamente)
Nesse campo, o próprio agilityflow preenche o campo com um número sequencial. Esse valor, começa em 1 e vai se somando conforme se criam novos registros do formulário.
Coluna Banco de dados (SQL)
Esse é o nome interno, usado pelo sistema, a ser criado no banco de dados do agilityflow. É uma informação técnica e esse campo é preenchido automaticamente pelo sistema.
Na maioria dos casos, você não precisa alterar o nome sugerido pelo sistema.
Diferentemente do campo "Nome de Apresentação", esse campo não fica visível para o usuário.
Para que serve o campo Coluna Banco de dados (SQL)?
Esse campo vai ser utilizado ao criar reports e dashboards. É através dele, que poderemos extrair informações e expor usando esses recursos do sistema.
Informações de ajuda
Nesse campo é possível incluir um texto que ajudará o usuário a preenche-lo. Abaixo, um exemplo de dois campos: um campo sem informações de ajuda e outro com esse campo configurado:
Preenchimento Padrão
O preenchimento padrão, permite ao sistema, sugerir o preenchimento do campo. Isso é útil, quando o usuário, na maioria das vezes, vai preencher esse campo da mesma forma. Isso economiza o tempo do usuário no preenchimento das informações.
Mesmo que haja definido um preenchimento padrão, o campo fica disponível para que o usuário altere esse valor.
Preencher Quando
Nessa opção, o usuário define em que momento o sistema faz o preenchimento padrão do campo. São duas opções:
No carregamento inicial (On PageLoad)
Ao abrir o formulário, o campo já é preenchido automaticamente.
Na alteração do valor de um determinado campo (On Change)
O campo não é preenchido com o valor padrão, até que um campo seja alterado. É possível definir qual campo ao ser alterado, será o gatilho para o preenchimento padrão.
Valor Padrão
É o valor que será preenchido por padrão nesse campo.
Máscara
É a forma que o sistema utiliza para mostrar ao usuário, o conteúdo do campo de texto. Isso facilita a visualização da informação por parte do usuário. Por exemplo, é muito fácil ver o telefone "(11) 98765-4321" do que "11987654321".
Tipo de máscara
Existe uma série de máscaras disponíveis no agilityflow.
Número
Como criar um campo numérico?
Um número não deixa de ser um texto. Portanto, para criar um campo numérico basta criar um campo textbox e aplicar uma máscara de número.
- Tipo de Número
- Inteiro: o campo não aceita "," ou "." no seu conteúdo. Ao digitar um desses símbolos, o sistema ignora a digitação. Por exemplo, digitando "1,5", o sistema ignora a vírgula e preenche "15". Caso o usuário cole o valor "1,5541", o sistema ignora a vírgula e o conteúdo à direita da vírgula, aceitando o valor "1".
- Moeda (Real): coloca vírgula, deixando o campo com duas casas decimais;
- Decimal (1 casa decimal): coloca vírgula, deixando o campo com duas casas decimais;
- Decimal (2 casas decimais): coloca vírgula, deixando o campo com duas casas decimais;
- Decimal (3 casas decimais): coloca vírgula, deixando o campo com duas casas decimais;
- Decimal (4 casas decimais): coloca vírgula, deixando o campo com duas casas decimais;
- Decimal (5 casas decimais): coloca vírgula, deixando o campo com duas casas decimais;
CPF
Insere "." e "-" de acordo com o CPF brasileiro. Esse campo, apenas separa os dígitos e não faz validação se o CPF é válido ou não. Pra isso, é necessário incluir uma validação.
CNPJ
Insere "." e "-" de acordo com o CNPJ brasileiro. Esse campo, apenas separa os dígitos e não faz validação se o CNPJ é válido ou não. Pra isso, é necessário incluir uma validação.
CEP
Insere "-", separando o número de acordo com o formato do CEP brasileiro.
Para buscar o CEP automaticamente na base dos correios e preencher os campos de endereço, verifique o tutorial aqui nesse link
Máscara Customizada
A máscara customizada, permite o usuário crie sua própria máscara. O agilityflow, utiliza a biblioteca Inputmask do javascript, criada por Robin Herbots. A documentação completa pode ser acessada no github. Você só precisa ler essa documentação, caso opte por fazer uma customização avançada.
Tipo de Customização
- Básica: é um forma fácil de criar uma máscara não existente no agilityflow. A sintaxe utilizada é a seguinte:
9: caractere numérico (de "0" a "9");
a: caractere alfabético (de "a" a "z");
A: caractere alfabético (de "A" a "Z");
*: caractere alfanumérico (todos acima);
[]: quando usado, identifica um caractere opcional;
\\: Par usar um dos caracteres acima como caractere e não como sintaxe;
Exemplos:
Máscara Entrada Resultado (99) 9999[9]-9999 12123451234 (12) 12345-1234 (99) 9999[9]-9999 121234-1234 (12) 1234-1234 [9-]AAA-999 5ahg123 5-AHG-123 [9-]aaa-999 ahg123 ahg123 +999-\\9 123 +123-9 - Avançada: você pode usar todos os recursos da biblioteca Inputmask. A documentação completa pode ser acessada no github.
Máscara com 'Regular Expression'
Utiliza o padrão de expressões regulares, que é um padrão utilizado em programação para identificar cadeias de caracteres. Caso haja necessidade de formatar seu texto, procure saber mais sobre esse padrão, já que ele é extremamente completo, no que diz respeito a identificar textos.
Telefone: País + DDD + Cel/Tel Brasil
Sinal de "+", espaço, código do país com dois dígitos, espaço, código de área com dois dígitos entre parêntesis, espaço, telefone com 9 ou 8 dígitos, tendo um hífen separando após o 4 ou quinto dígito (seguindo o padrão brasileiros para telefones fixos e móveis). O sistema não aceita entrada que não tenha esse formato.
Ex: +55 (11) 98765-4321 ou +55 (81) 4321-1234
Telefone: DDD + Cel/Tel Brasil
Código de área com dois dígitos entre parêntesis, espaço, telefone com 9 ou 8 dígitos, tendo um hífen separando após o 4 ou quinto dígito (seguindo o padrão brasileiros para telefones fixos e móveis). O sistema não aceita entrada que não tenha esse formato.
Ex: (11) 98765-4321 ou (81) 4321-1234
Telefone: Cel/Tel Brasil
Telefone com 9 ou 8 dígitos, tendo um hífen separando após o 4 ou quinto dígito (seguindo o padrão brasileiros para telefones fixos e móveis). O sistema não aceita entrada que não tenha esse formato.
Ex: 98765-4321 ou 4321-1234
Como configurar um campo de data?
Data e hora no formato dd/mm/yyyy hh:mm
Formato de data onde o ano tem 4 dígitos, seguido de hora sem os segundos. O sistema não aceita entrada que não tenha esse formato.
Ex: 18/01/1981 23:52
Data e hora (Com Segundos) no formato dd/mm/yyyy hh:mm:ss
Formato de data onde o ano tem 4 dígitos, seguido de hora com os segundos. O sistema não aceita entrada que não tenha esse formato.
Ex: 18/01/1981 23:52:13
Data sem hora no formato dd/mm/yyyy
Formato de data onde o ano tem 4 dígitos. O sistema não aceita entrada que não tenha esse formato.
Ex: 18/01/1981
Como configurar um campo de hora?
Hora no formato hh:mm
Horário, sem os segundos. O sistema não aceita entrada que não tenha esse formato.
Ex: 19:37
Hora (Com Segundos) no formato hh:mm:ss
Horário, com os segundos. O sistema não aceita entrada que não tenha esse formato.
Ex: 19:37:22
Tamanho máximo de Preenchimento
Com esse campo é possível limitar o número máximo de caracteres a ser preenchido nesse campo.
Validação
Nessa parte, é possível configurar validações dos dados inseridos pelo usuário, garantindo um padrão de preenchimento.
Obrigatório
Como deixar um campo obrigatório?
Caso marcado como "sim", não permite o salvamento do fomulário sem o preenchimento desse campo. Ao marcar como "sim" essa opção, são abertos duas outras opções:
Obrigatório mesmo que por algum motivo o campo esteja marcado como invisível?
Use essa opção para fazer um campo definido como obrigatório, deixar sua obrigatoriedade caso ele esteja invisível.
Obrigatório a partir da etapa
Para os formulários com fluxo de etapas, é possível atrelar a obrigatoriedade de um campo à etapa em que se encontra o fluxo.
Valor do campo deve ser único em relação a todos os registros
O sistema, valida a inserção do campo, com os registros do mesmo campo, já salvos em outros formulários. Por exemplo, talvez exista uma necessidade de validação de um e-mail para o cadastro de um cliente. Caso o e-mail digitado já conste em outro registro, não será permitido o salvamento do formulário.
Valor do campo deve ser único em relação ao formulário PAI
Caso o formulário tenha uma relação com outro formulário (chamamos de formulário Pai), será validado que os dados inseridos são únicos, mas apenas para o registro filho.
Valor do campo deve ser único em relação APENAS ao CAMPO relacionado do formulário PAI
Caso haja, mais de um campo no formulário pai, relacionado ao mesmo formulário filho, a validação de valor único, ocorre apenas par cada campo do relacionamento.
Abaixo, um vídeo explica essas 3 últimas opções:
Regras de Visibilidade e desativação
Usando essas opções, é possível tornar um campo visível, invisível, ativo ou inativo, e definir quando uma dessas ações deve ocorrer. É possível adicionar várias regras para cada campo.
Descrição
É um texto que ajuda a identificar a regra que se está criando. Muito útil quando existem múltiplas regras.
Ação
Ativar
Deixa o campo disponível para inserção de dados. É o estado padrão do campo.
Inativar
Deixa o campo indisponível para inserção de dados.
Visível
O campo é mostrado na tela, caso esteja inserido para tal, nas configurações de tela.
Invisível
O campo é não é mostrado na tela, mesmo que esteja inserido para tal, nas configurações de tela.
A partir da etapa / Até a etapa
Em formulários com etapas, é possível estabelecer que uma regra será aplicada em alguma(s) etapa(s). Para isso, basta selecionar as etapas nos campos "a partir da etapa" e "até a etapa", para definir em que momento do fluxo essa regra vai ser aplicada.
Quando
Define em que momento a ação deve acontecer.
Sempre
É o padrão do formulário.
Condicional
- Tipo de condição
Para fazer um validação condicional, estão disponíveis as seguintes condições:
- Se o campo: compara um campo com um valor, ou com outro campo.
Abaixo, uma tabela com os operadores disponíveis para as comparações:
Comparação por valor Comparação por outro campo For igual a É igual ao campo For maior ou igual a É diferente do campo For menor ou igual a For maior que For menor que For diferente de Conter Não conter É possível adicionar mais de um condição na mesma regra.
- Se é um novo formulário: regra será aplicada quando uma nova entrada no formulário estiver sendo criada.
- Se é edição de formulário: regra será aplicada quando uma entrada no formulário estiver sendo alterada.
- Se o campo: compara um campo com um valor, ou com outro campo.
Customização Javascript
Caso a customização desejada, não esteja disponível, ainda assim é possível programá-la utilizando javascript. Para mais detalhes, acesse o capítulo sobre essa opção.
Label Dinâmica
Label Dinâmica é um campo de texto não editável, que é preenchido através de outro campo. Esse campo é muito útil, quando se tem um campo de lista de seleção (ou pesquisa com auto-completar) com uma fonte dinâmica e há a necessidade mostrar outros campos do formulário usado como fonte por esse campo.
No exemplo abaixo, o formulário tem uma lista de seleção de clientes. Os outros dois campos, são label dinâmicas com informações do formulário de cliente.
Ao mudar o campo de lista de seleção, a label dinâmica é preenchida automaticamente.
Grupo de informações
Dentro das configurações, é possível alterar o grupo de informação ao qual o campo foi atribuído no momento da criação.
Nome de Apresentação
Mostra o nome de apresentação informado no momento da criação. Esse é o nome que será mostrado na tela para o usuário.
Informações de ajuda
Nesse campo é possível incluir um texto que ajudará o usuário a preenche-lo. Abaixo, um exemplo de dois campos: um campo sem informações de ajuda e outro com esse campo configurado:
Preenchimento da Label Dinâmica
Aqui, estão as opções principais de configurações para a label dinâmica.
Preencher a label dinâmica ao alterar o campo
Nessa opção, apenas os campos Lista de Seleção com lista dinâmica, ou o campo Pesquisa com Auto Completar serão mostrados aqui. É esse campo que, ao ser alterado, preencherá a label dinâmica.
Campo de apresentação (Base de dados)
É o campo do formulário usado como fonte na lista de seleção (ou pesquisa com auto completar) será usado para o preenchimento.
Regras de Visibilidade e desativação
Usando essas opções, é possível tornar um campo visível, invisível, ativo ou inativo, e definir quando uma dessas ações deve ocorrer. É possível adicionar várias regras para cada campo.
Descrição
É um texto que ajuda a identificar a regra que se está criando. Muito útil quando existem múltiplas regras.
Ação
Visível
O campo é mostrado na tela, caso esteja inserido para tal, nas configurações de tela.
Invisível
O campo é não é mostrado na tela, mesmo que esteja inserido para tal, nas configurações de tela.
A partir da etapa / Até a etapa
Em formulários com etapas, é possível estabelecer que uma regra será aplicada em alguma(s) etapa(s). Para isso, basta selecionar as etapas nos campos "a partir da etapa" e "até a etapa", para definir em que momento do fluxo essa regra vai ser aplicada.
Quando
Define em que momento a ação deve acontecer.
Sempre
É o padrão do formulário.
Condicional
- Tipo de condição
Para fazer um validação condicional, estão disponíveis as seguintes condições:
- Se o campo: compara um campo com um valor, ou com outro campo.
Abaixo, uma tabela com os operadores disponíveis para as comparações:
Comparação por valor Comparação por outro campo For igual a É igual ao campo For maior ou igual a É diferente do campo For menor ou igual a For maior que For menor que For diferente de Conter Não conter É possível adicionar mais de um condição na mesma regra.
- Se é um novo formulário: regra será aplicada quando uma nova entrada no formulário estiver sendo criada.
- Se é edição de formulário: regra será aplicada quando uma entrada no formulário estiver sendo alterada.
- Se o campo: compara um campo com um valor, ou com outro campo.
Upload
Esse campo é utilizado para o envio de arquivos.
Grupo de informações
Dentro das configurações, é possível alterar o grupo de informação ao qual o campo foi atribuído no momento da criação.
Nome de Apresentação
Mostra o nome de apresentação informado no momento da criação. Esse é o nome que será mostrado na tela para o usuário.
Informações de ajuda
Nesse campo é possível incluir um texto que ajudará o usuário a preenche-lo. Abaixo, um exemplo de dois campos: um campo sem informações de ajuda e outro com esse campo configurado:
Validação
Nessa parte, é possível configurar validações dos dados inseridos pelo usuário, garantindo um padrão de preenchimento.
Obrigatório
Caso marcado como "sim", não permite o salvamento do fomulário sem o preenchimento desse campo. Ao marcar como "sim" essa opção, são abertos duas outras opções:
Obrigatório mesmo que por algum motivo o campo esteja marcado como invisível?
Use essa opção para fazer um campo definido como obrigatório, deixar sua obrigatoriedade caso ele esteja invisível.
Obrigatório a partir da etapa
Para os formulários com fluxo de etapas, é possível atrelar a obrigatoriedade de um campo à etapa em que se encontra o fluxo.
Extensão Permitida
É possível adicionar uma lista branca, com as extensões permitidas.
Extensão não permitida
É possível adicionar uma lista negra, com as extensões não permitidas.
Validação Customizada
Tipo de Validação
- Upload de no máximo X itens: é possível definir um limite de arquivos;
- Upload no mínimo X itens: é possível definir um mínimo de arquivos;
- Upload exatamente X itens: é possível definir uma quantidade específica de arquivos;
Validar a partir da etapa
Em formulários com etapas, é possível estabelecer que uma validação será aplicada em alguma(s) etapa(s). Para isso, basta selecionar a etapa no campo "validar a partir da etapa".
Regras de Visibilidade e desativação
Usando essas opções, é possível tornar um campo visível, invisível, ativo ou inativo, e definir quando uma dessas ações deve ocorrer. É possível adicionar várias regras para cada campo.
Descrição
É um texto que ajuda a identificar a regra que se está criando. Muito útil quando existem múltiplas regras.
Ação
Ativar
Deixa o campo disponível para inserção de dados. É o estado padrão do campo.
Inativar
Deixa o campo indisponível para inserção de dados.
Visível
O campo é mostrado na tela, caso esteja inserido para tal, nas configurações de tela.
Invisível
O campo é não é mostrado na tela, mesmo que esteja inserido para tal, nas configurações de tela.
A partir da etapa / Até a etapa
Em formulários com etapas, é possível estabelecer que uma regra será aplicada em alguma(s) etapa(s). Para isso, basta selecionar as etapas nos campos "a partir da etapa" e "até a etapa", para definir em que momento do fluxo essa regra vai ser aplicada.
Quando
Define em que momento a ação deve acontecer.
Sempre
É o padrão do formulário.
Condicional
-
Tipo de condição
Para fazer um validação condicional, estão disponíveis as seguintes condições:
- Se o campo: compara um campo com um valor, ou com outro campo.
Abaixo, uma tabela com os operadores disponíveis para as comparações:
Comparação por valor Comparação por outro campo For igual a É igual ao campo For maior ou igual a É diferente do campo For menor ou igual a For maior que For menor que For diferente de Conter Não conter É possível adicionar mais de um condição na mesma regra.
- Se é um novo formulário: regra será aplicada quando uma nova entrada no formulário estiver sendo criada.
- Se é edição de formulário: regra será aplicada quando uma entrada no formulário estiver sendo alterada.
- Se o campo: compara um campo com um valor, ou com outro campo.
Lista de seleção (Combo)
Esse campo, permite que o usuário escolha uma opção pré-determinada.
Grupo de informações
Dentro das configurações, é possível alterar o grupo de informação ao qual o campo foi atribuído no momento da criação.
Nome de Apresentação
Mostra o nome de apresentação informado no momento da criação. Esse é o nome que será mostrado na tela para o usuário.
Coluna Banco de dados (SQL)
Esse é o nome interno, usado pelo sistema, a ser criado no banco de dados do agilityflow. É uma informação técnica e esse campo é preenchido automaticamente pelo sistema.
Na maioria dos casos, você não precisa alterar o nome sugerido pelo sistema.
Diferentemente do campo "Nome de Apresentação", esse campo não fica visível para o usuário.
Para que serve o campo Coluna Banco de dados (SQL)?
Esse campo vai ser utilizado ao criar reports e dashboards. É através dele, que poderemos extrair informações e expor usando esses recursos do sistema.
Informações de ajuda
Nesse campo é possível incluir um texto que ajudará o usuário a preenche-lo. Abaixo, um exemplo de dois campos: um campo sem informações de ajuda e outro com esse campo configurado:
Origem dos Dados
Como existe uma lista de opções pré-determinadas, é necessário definir a origem dos dados.
Origem dos Itens
São duas as possibilidades:
1. Lista Dinâmica (Utilização recomendada) : Nessa opção, os dados têm como origem um outro formulário. Ao selecionar esse outro formulário, é necessário informar qual o campo desse formulário será exibido.
2. Lista Estática: O usuário insere as opções nas configurações do campo. Com isso, o usuário que acessa o formulário não pode criar novas opções. Ao criar as opções, além do nome, é possível definir a ordem em que aparecerão na lista de seleção. Outra opção, é o Id Customizado (Banco de Dados). Essa opção, normalmente não precisa ser preenchido. Entretanto, em alguns casos, esse id pode ser customizado. Isso pode ser útil, para a criação de dashboard e reports, para montar mais facilmente as queries.
Sugerimos que o campo de Lista de seleção (combo) não seja usado quando há muitas itens pois todas as opções desse campo são lidas quando a página é carregada. Se houver muitos itens, o carregamento da página pode ser afetado. Para esses casos, usar o campo Pesquisa com auto completar.
Configuração de uma Lista Dinâmica
Abaixo estão descritos os campos básicos de preenchimento para definição de uma lista dinâmica.
Abra a tela de edição do campo e clique na aba Origem dos Dados

Campos para preenchimento:
Origem dos dados
Defina como "Lista Dinâmica"
Quando os dados serão carregados?
Quando a lista é dinâmica, é possível definir algumas opções relativas ao carregamento da lista. Esse carregamento pode ocorrer de duas maneiras.
No carregamento inicial (On PageLoad): Assim que o formulário é carregado, as opções da lista de seleção também são carregados imediatamente.
Na alteração do valor de um determinado campo (On Change): As opções só serão carregadas quando um determinado campo mudar. Isso é útil, para uma lista de seleção selecionar níveis de outra lista de seleção. Ex: seleciona-se primeiro o estado e só depois, é selecionada a cidade. Esse campo Lista de Cidade, apenas é carregado quando o outro campo Lista de Estados é alterado. Para isso, é necessário também adicionar uma condição na base de dados.
Qual será a Base de dados
É o formulário que servirá de fonte para a Lista Dinâmica.
Campo de apresentação (Base de dados)
Essa é a informação que será apresentada para o usuário na apresentação do combo. Esse campo é referente ao formulário que foi selecionado no campo Qual será a Base de dados.
Ordenar os itens pelo campo
A ordenação padrão do itens do combo é alfabética. Entretanto há casos onde queremos alterar essa ordem. Para isso, podemos utilizar um segundo campo como critério de ordenação, que não o campo de exibição. Como exemplo, vamos usar um formulário que só tem o campo nome, e os seguintes dados?
| Prioridade |
| Alta |
| Baixa |
| Média |
Ao usarmos o campo prioridade como critério de ordenação, os itens serão apresentados na ordem alfabética (Alta, Baixa e Média), quando o mais intuitivo seria apresentar a ordem como (Baixa, Média, Alta).
Para isso, podemos criar um campo chamado 'Ordem' nesse formulário, e incluir números. Dessa forma:
| Prioridade | Ordem |
| Alta | 3 |
| Baixa | 2 |
| Média | 1 |
Feito isso, o campo Campo de Apresentação continua sendo o campo 'Prioridade', mas o campo selecionado para ordenação é o 'Ordem'. Com isso, os itens serão apresentados na ordem (Baixa, Média e Alta).
Condição na Base de Dados
Na condição, pode-se escolher um dos campos da Base de dados para ser usado em uma comparação por valor (É igual a, É diferente de, Conter e Não conter) ou por outro campo (É igual ao campo ou É diferente do campo) desse formulário.
Caso esse formulário possa ser usado como tabela filha de outro formulário, essas duas opções são habilitadas:
Esse campo pode ser Relacionado a um formulário Pai e preenchido automaticamente pelo ID (Primary Key) do formulário pai
Caso esse formulário possa ser incluído como filho de um formulário pai, ative essa opção e selecione qual formulário que preencherá automaticamente esse campo. Para mais detalhes sobre esse funcionamento, veja detalhes na configuração de Formulários Relacionados.
Esconder campo quando o formulário for aberto através do formulário pai
Quando esse formulário estiver incluído em um formulário pai, ative essa opção para que esse campo fique oculto, mesmo que esteja configurado para ser exibido na tela.
Validação
Nessa parte, é possível configurar validações dos dados inseridos pelo usuário, garantindo um padrão de preenchimento.
Como deixar um campo obrigatório?
Obrigatório
Caso marcado como "sim", não permite o salvamento do fomulário sem o preenchimento desse campo. Ao marcar como "sim" essa opção, são abertos duas outras opções:
Obrigatório mesmo que por algum motivo o campo esteja marcado como invisível?
Use essa opção para fazer um campo definido como obrigatório, deixar sua obrigatoriedade caso ele esteja invisível.
Obrigatório a partir da etapa
Para os formulários com fluxo de etapas, é possível atrelar a obrigatoriedade de um campo à etapa em que se encontra o fluxo.
Valor do campo deve ser único em relação a todos os registros
O sistema, valida a inserção do campo, com os registros do mesmo campo, já salvos em outros formulários. Por exemplo, talvez exista uma necessidade de validação de um e-mail para o cadastro de um cliente. Caso o e-mail digitado já conste em outro registro, não será permitido o salvamento do formulário.
Valor do campo deve ser único em relação ao formulário PAI
Caso o formulário tenha uma relação com outro formulário (chamamos de formulário Pai), será validado que os dados inseridos são únicos, mas apenas para o registro filho.
Valor do campo deve ser único em relação APENAS ao CAMPO relacionado do formulário PAI
Caso haja, mais de um campo no formulário pai, relacionado ao mesmo formulário filho, a validação de valor único, ocorre apenas par cada campo do relacionamento.
Abaixo, um vídeo explica essas 3 últimas opções:
Regras de Visibilidade e desativação
Usando essas opções, é possível tornar um campo visível, invisível, ativo ou inativo, e definir quando uma dessas ações deve ocorrer. É possível adicionar várias regras para cada campo.
Descrição
É um texto que ajuda a identificar a regra que se está criando. Muito útil quando existem múltiplas regras.
Ação
Ativar
Deixa o campo disponível para inserção de dados. É o estado padrão do campo.
Inativar
Deixa o campo indisponível para inserção de dados.
Visível
O campo é mostrado na tela, caso esteja inserido para tal, nas configurações de tela.
Invisível
O campo é não é mostrado na tela, mesmo que esteja inserido para tal, nas configurações de tela.
A partir da etapa / Até a etapa
Em formulários com etapas, é possível estabelecer que uma regra será aplicada em alguma(s) etapa(s). Para isso, basta selecionar as etapas nos campos "a partir da etapa" e "até a etapa", para definir em que momento do fluxo essa regra vai ser aplicada.
Quando
Define em que momento a ação deve acontecer.
Sempre
É o padrão do formulário.
Condicional
- Tipo de condição
Para fazer um validação condicional, estão disponíveis as seguintes condições:
- Se o campo: compara um campo com um valor, ou com outro campo.
Abaixo, uma tabela com os operadores disponíveis para as comparações:
Comparação por valor Comparação por outro campo For igual a É igual ao campo For maior ou igual a É diferente do campo For menor ou igual a For maior que For menor que For diferente de Conter Não conter É possível adicionar mais de um condição na mesma regra.
- Se é um novo formulário: regra será aplicada quando uma nova entrada no formulário estiver sendo criada.
- Se é edição de formulário: regra será aplicada quando uma entrada no formulário estiver sendo alterada.
- Se o campo: compara um campo com um valor, ou com outro campo.
Customização Javascript
Caso a customização desejada, não esteja disponível, ainda assim é possível programá-la utilizando javascript. Para mais detalhes, acesse o capítulo sobre essa opção.
Pesquisa com auto completar
Esse campo, é muito similar ao campo Lista de Seleção e permite que o usuário escolha uma opção pré-determinada.
Abaixo é possível comparar ambos campos, com a mesma fonte dinâmica de dados:
Grupo de informações
Dentro das configurações, é possível alterar o grupo de informação ao qual o campo foi atribuído no momento da criação.
Nome de Apresentação
Mostra o nome de apresentação informado no momento da criação. Esse é o nome que será mostrado na tela para o usuário.
Coluna Banco de dados (SQL)
Esse é o nome interno, usado pelo sistema, a ser criado no banco de dados do agilityflow. É uma informação técnica e esse campo é preenchido automaticamente pelo sistema.
Na maioria dos casos, você não precisa alterar o nome sugerido pelo sistema.
Diferentemente do campo "Nome de Apresentação", esse campo não fica visível para o usuário.
Para que serve o campo Coluna Banco de dados (SQL)?
Esse campo vai ser utilizado ao criar reports e dashboards. É através dele, que poderemos extrair informações e expor usando esses recursos do sistema.
Informações de ajuda
Nesse campo é possível incluir um texto que ajudará o usuário a preenche-lo. Abaixo, um exemplo de dois campos: um campo sem informações de ajuda e outro com esse campo configurado:
Origem dos Dados
Como existe uma lista de opções pré-determinadas, é necessário definir a origem dos dados.
Origem dos Itens
São duas as possibilidades:
1. Lista Dinâmica (Utilização recomendada) : Nessa opção, os dados têm como origem um outro formulário. Ao selecionar esse outro formulário, é necessário informar qual o campo desse formulário será exibido.
2. Lista Estática: O usuário insere as opções nas configurações do campo. Com isso, o usuário que acessa o formulário não pode criar novas opções. Ao criar as opções, além do nome, é possível definir a ordem em que aparecerão na lista de seleção. Outra opção, é o Id Customizado (Banco de Dados). Essa opção, normalmente não precisa ser preenchido. Entretanto, em alguns casos, esse id pode ser customizado. Isso pode ser útil, para a criação de dashboard e reports, para montar mais facilmente as queries.
Configuração de uma Lista Dinâmica
Abaixo estão descritos os campos básicos de preenchimento para definição de uma lista dinâmica.
Abra a tela de edição do campo e clique na aba Origem dos Dados

Campos para preenchimento:
Origem dos dados
Defina como "Lista Dinâmica"
Quando os dados serão carregados?
Quando a lista é dinâmica, é possível definir algumas opções relativas ao carregamento da lista. Esse carregamento pode ocorrer de duas maneiras.
No carregamento inicial (On PageLoad): Assim que o formulário é carregado, as opções da lista de seleção também são carregados imediatamente.
Na alteração do valor de um determinado campo (On Change): As opções só serão carregadas quando um determinado campo mudar. Isso é útil, para uma lista de seleção selecionar níveis de outra lista de seleção. Ex: seleciona-se primeiro o estado e só depois, é selecionada a cidade. Esse campo Lista de Cidade, apenas é carregado quando o outro campo Lista de Estados é alterado. Para isso, é necessário também adicionar uma condição na base de dados.
Qual será a Base de dados
É o formulário que servirá de fonte para a Lista Dinâmica.
Campo de apresentação (Base de dados)
Essa é a informação que será apresentada para o usuário na apresentação do combo. Esse campo é referente ao formulário que foi selecionado no campo Qual será a Base de dados.
Ordenar os itens pelo campo
A ordenação padrão do itens do combo é alfabética. Entretanto há casos onde queremos alterar essa ordem. Para isso, podemos utilizar um segundo campo como critério de ordenação, que não o campo de exibição. Como exemplo, vamos usar um formulário que só tem o campo nome, e os seguintes dados?
| Prioridade |
| Alta |
| Baixa |
| Média |
Ao usarmos o campo prioridade como critério de ordenação, os itens serão apresentados na ordem alfabética (Alta, Baixa e Média), quando o mais intuitivo seria apresentar a ordem como (Baixa, Média, Alta).
Para isso, podemos criar um campo chamado 'Ordem' nesse formulário, e incluir números. Dessa forma:
| Prioridade | Ordem |
| Alta | 3 |
| Baixa | 2 |
| Média | 1 |
Feito isso, o campo Campo de Apresentação continua sendo o campo 'Prioridade', mas o campo selecionado para ordenação é o 'Ordem'. Com isso, os itens serão apresentados na ordem (Baixa, Média e Alta).
Condição na Base de Dados
Na condição, pode-se escolher um dos campos da Base de dados para ser usado em uma comparação por valor (É igual a, É diferente de, Conter e Não conter) ou por outro campo (É igual ao campo ou É diferente do campo) desse formulário.
O vídeo abaixo mostra a configuração da lista de seleção, mas também se aplica para o campo Pesquisa com Auto completar. O processo de configuração e o comportamento é idêntico.
Caso esse formulário possa ser usado como tabela filha de outro formulário, essas duas opções são habilitadas:
Esse campo pode ser Relacionado a um formulário Pai e preenchido automaticamente pelo ID (Primary Key) do formulário pai
Caso esse formulário possa ser incluído como filho de um formulário pai, ative essa opção e selecione qual formulário que preencherá automaticamente esse campo. Para mais detalhes sobre esse funcionamento, veja detalhes na configuração de Formulários Relacionados.
Esconder campo quando o formulário for aberto através do formulário pai
Quando esse formulário estiver incluído em um formulário pai, ative essa opção para que esse campo fique oculto, mesmo que esteja configurado para ser exibido na tela.
Validação
Nessa parte, é possível configurar validações dos dados inseridos pelo usuário, garantindo um padrão de preenchimento.
Como deixar um campo obrigatório?
Obrigatório
Caso marcado como "sim", não permite o salvamento do fomulário sem o preenchimento desse campo. Ao marcar como "sim" essa opção, são abertos duas outras opções:
Obrigatório mesmo que por algum motivo o campo esteja marcado como invisível?
Use essa opção para fazer um campo definido como obrigatório, deixar sua obrigatoriedade caso ele esteja invisível.
Obrigatório a partir da etapa
Para os formulários com fluxo de etapas, é possível atrelar a obrigatoriedade de um campo à etapa em que se encontra o fluxo.
Valor do campo deve ser único em relação a todos os registros
O sistema, valida a inserção do campo, com os registros do mesmo campo, já salvos em outros formulários. Por exemplo, talvez exista uma necessidade de validação de um e-mail para o cadastro de um cliente. Caso o e-mail digitado já conste em outro registro, não será permitido o salvamento do formulário.
Valor do campo deve ser único em relação ao formulário PAI
Caso o formulário tenha uma relação com outro formulário (chamamos de formulário Pai), será validado que os dados inseridos são únicos, mas apenas para o registro filho.
Valor do campo deve ser único em relação APENAS ao CAMPO relacionado do formulário PAI
Caso haja, mais de um campo no formulário pai, relacionado ao mesmo formulário filho, a validação de valor único, ocorre apenas par cada campo do relacionamento.
Abaixo, um vídeo explica essas 3 últimas opções:
Regras de Visibilidade e desativação
Usando essas opções, é possível tornar um campo visível, invisível, ativo ou inativo, e definir quando uma dessas ações deve ocorrer. É possível adicionar várias regras para cada campo.
Descrição
É um texto que ajuda a identificar a regra que se está criando. Muito útil quando existem múltiplas regras.
Ação
Ativar
Deixa o campo disponível para inserção de dados. É o estado padrão do campo.
Inativar
Deixa o campo indisponível para inserção de dados.
Visível
O campo é mostrado na tela, caso esteja inserido para tal, nas configurações de tela.
Invisível
O campo é não é mostrado na tela, mesmo que esteja inserido para tal, nas configurações de tela.
A partir da etapa / Até a etapa
Em formulários com etapas, é possível estabelecer que uma regra será aplicada em alguma(s) etapa(s). Para isso, basta selecionar as etapas nos campos "a partir da etapa" e "até a etapa", para definir em que momento do fluxo essa regra vai ser aplicada.
Quando
Define em que momento a ação deve acontecer.
Sempre
É o padrão do formulário.
Condicional
- Tipo de condição
Para fazer um validação condicional, estão disponíveis as seguintes condições:
- Se o campo: compara um campo com um valor, ou com outro campo.
Abaixo, uma tabela com os operadores disponíveis para as comparações:
Comparação por valor Comparação por outro campo For igual a É igual ao campo For maior ou igual a É diferente do campo For menor ou igual a For maior que For menor que For diferente de Conter Não conter É possível adicionar mais de um condição na mesma regra.
- Se é um novo formulário: regra será aplicada quando uma nova entrada no formulário estiver sendo criada.
- Se é edição de formulário: regra será aplicada quando uma entrada no formulário estiver sendo alterada.
- Se o campo: compara um campo com um valor, ou com outro campo.
Customização Javascript
Caso a customização desejada, não esteja disponível, ainda assim é possível programá-la utilizando javascript. Para mais detalhes, acesse o capítulo sobre essa opção.
Checkbox (Único)
Esse campo permite o usuário responder a uma pergunta cuja resposta tem duas opções.
Grupo de informações
Dentro das configurações, é possível alterar o grupo de informação ao qual o campo foi atribuído no momento da criação.
Nome de Apresentação
Mostra o nome de apresentação informado no momento da criação. Esse é o nome que será mostrado na tela para o usuário.
Texto ao lado do Checkbox
Nesse campo, é possível definir o texto quando o campo está marcado, e quando o campo está desmarcado. O texto escolhido quando o campo está marcado, será mostrado na tela, enquanto o texto do campo quando está desmarcado, apenas será mostrado na listagem e no filtro de dados.

Quando marcado
Texto a ser exibido ao lado do campo. Quando estiver marcado, esse texto será mostrado na listagem de dados.

Quando desmarcado
Esse texto não será exibido quando estiver desmarcado, mas será mostrado na listagem de dados.

Coluna Banco de dados (SQL)
Esse é o nome interno, usado pelo sistema, a ser criado no banco de dados do agilityflow. É uma informação técnica e esse campo é preenchido automaticamente pelo sistema.
Na maioria dos casos, você não precisa alterar o nome sugerido pelo sistema.
Diferentemente do campo "Nome de Apresentação", esse campo não fica visível para o usuário.
Para que serve o campo Coluna Banco de dados (SQL)?
Esse campo vai ser utilizado ao criar reports e dashboards. É através dele, que poderemos extrair informações e expor usando esses recursos do sistema.
Informações de ajuda
Nesse campo é possível incluir um texto que ajudará o usuário a preenche-lo. Abaixo, um exemplo de dois campos: um campo sem informações de ajuda e outro com esse campo configurado:
Validação
Nessa parte, é possível configurar validações dos dados inseridos pelo usuário, garantindo um padrão de preenchimento.
Como deixar um campo obrigatório?
Obrigatório
Caso marcado como "sim", não permite o salvamento do fomulário sem o preenchimento desse campo. Ao marcar como "sim" essa opção, são abertos duas outras opções:
Obrigatório mesmo que por algum motivo o campo esteja marcado como invisível?
Use essa opção para fazer um campo definido como obrigatório, deixar sua obrigatoriedade caso ele esteja invisível.
Obrigatório a partir da etapa
Para os formulários com fluxo de etapas, é possível atrelar a obrigatoriedade de um campo à etapa em que se encontra o fluxo.
Regras de Visibilidade e desativação
Usando essas opções, é possível tornar um campo visível, invisível, ativo ou inativo, e definir quando uma dessas ações deve ocorrer. É possível adicionar várias regras para cada campo.
Descrição
É um texto que ajuda a identificar a regra que se está criando. Muito útil quando existem múltiplas regras.
Ação
Ativar
Deixa o campo disponível para inserção de dados. É o estado padrão do campo.
Inativar
Deixa o campo indisponível para inserção de dados.
Visível
O campo é mostrado na tela, caso esteja inserido para tal, nas configurações de tela.
Invisível
O campo é não é mostrado na tela, mesmo que esteja inserido para tal, nas configurações de tela.
A partir da etapa / Até a etapa
Em formulários com etapas, é possível estabelecer que uma regra será aplicada em alguma(s) etapa(s). Para isso, basta selecionar as etapas nos campos "a partir da etapa" e "até a etapa", para definir em que momento do fluxo essa regra vai ser aplicada.
Quando
Define em que momento a ação deve acontecer.
Sempre
É o padrão do formulário.
Condicional
- Tipo de condição
Para fazer um validação condicional, estão disponíveis as seguintes condições:
- Se o campo: compara um campo com um valor, ou com outro campo.
Abaixo, uma tabela com os operadores disponíveis para as comparações:
Comparação por valor Comparação por outro campo For igual a É igual ao campo For maior ou igual a É diferente do campo For menor ou igual a For maior que For menor que For diferente de Conter Não conter É possível adicionar mais de um condição na mesma regra.
- Se é um novo formulário: regra será aplicada quando uma nova entrada no formulário estiver sendo criada.
- Se é edição de formulário: regra será aplicada quando uma entrada no formulário estiver sendo alterada.
- Se o campo: compara um campo com um valor, ou com outro campo.
Customização Javascript
Caso a customização desejada, não esteja disponível, ainda assim é possível programá-la utilizando javascript. Para mais detalhes, acesse o capítulo sobre essa opção.
Lista aberta com escolha única (Radio)
Esse campo é muito similar ao tipo Lista de Seleção, mudando apenas a forma como é apresentado. Abaixo, um exemplo do campo radio (Lista aberta com escolha única):

Grupo de informações
Dentro das configurações, é possível alterar o grupo de informação ao qual o campo foi atribuído no momento da criação.
Nome de Apresentação
Mostra o nome de apresentação informado no momento da criação. Esse é o nome que será mostrado na tela para o usuário.
Coluna Banco de dados (SQL)
Esse é o nome interno, usado pelo sistema, a ser criado no banco de dados do agilityflow. É uma informação técnica e esse campo é preenchido automaticamente pelo sistema.
Na maioria dos casos, você não precisa alterar o nome sugerido pelo sistema.
Diferentemente do campo "Nome de Apresentação", esse campo não fica visível para o usuário.
Para que serve o campo Coluna Banco de dados (SQL)?
Esse campo vai ser utilizado ao criar reports e dashboards. É através dele, que poderemos extrair informações e expor usando esses recursos do sistema.
Informações de ajuda
Nesse campo é possível incluir um texto que ajudará o usuário a preenche-lo. Abaixo, um exemplo de dois campos: um campo sem informações de ajuda e outro com esse campo configurado:
Origem dos Dados
Como existe uma lista de opções pré-determinadas, é necessário definir a origem dos dados.
Origem dos Itens
São duas as possibilidades:
1. Lista Dinâmica (Utilização recomendada) : Nessa opção, os dados têm como origem um outro formulário. Ao selecionar esse outro formulário, é necessário informar qual o campo desse formulário será exibido.
2. Lista Estática: O usuário insere as opções nas configurações do campo. Com isso, o usuário que acessa o formulário não pode criar novas opções. Ao criar as opções, além do nome, é possível definir a ordem em que aparecerão na lista de seleção. Outra opção, é o Id Customizado (Banco de Dados). Essa opção, normalmente não precisa ser preenchido. Entretanto, em alguns casos, esse id pode ser customizado. Isso pode ser útil, para a criação de dashboard e reports, para montar mais facilmente as queries.
Configuração de uma Lista Dinâmica
Abaixo estão descritos os campos básicos de preenchimento para definição de uma lista dinâmica.
Abra a tela de edição do campo e clique na aba Origem dos Dados

Campos para preenchimento:
Origem dos dados
Defina como "Lista Dinâmica"
Quando os dados serão carregados?
Quando a lista é dinâmica, é possível definir algumas opções relativas ao carregamento da lista. Esse carregamento pode ocorrer de duas maneiras.
No carregamento inicial (On PageLoad): Assim que o formulário é carregado, as opções da lista de seleção também são carregados imediatamente.
Na alteração do valor de um determinado campo (On Change): As opções só serão carregadas quando um determinado campo mudar. Isso é útil, para uma lista de seleção selecionar níveis de outra lista de seleção. Ex: seleciona-se primeiro o estado e só depois, é selecionada a cidade. Esse campo Lista de Cidade, apenas é carregado quando o outro campo Lista de Estados é alterado. Para isso, é necessário também adicionar uma condição na base de dados.
Qual será a Base de dados
É o formulário que servirá de fonte para a Lista Dinâmica.
Campo de apresentação (Base de dados)
Essa é a informação que será apresentada para o usuário na apresentação do combo. Esse campo é referente ao formulário que foi selecionado no campo Qual será a Base de dados.
Ordenar os itens pelo campo
A ordenação padrão do itens do combo é alfabética. Entretanto há casos onde queremos alterar essa ordem. Para isso, podemos utilizar um segundo campo como critério de ordenação, que não o campo de exibição. Como exemplo, vamos usar um formulário que só tem o campo nome, e os seguintes dados?
| Prioridade |
| Alta |
| Baixa |
| Média |
Ao usarmos o campo prioridade como critério de ordenação, os itens serão apresentados na ordem alfabética (Alta, Baixa e Média), quando o mais intuitivo seria apresentar a ordem como (Baixa, Média, Alta).
Para isso, podemos criar um campo chamado 'Ordem' nesse formulário, e incluir números. Dessa forma:
| Prioridade | Ordem |
| Alta | 3 |
| Baixa | 2 |
| Média | 1 |
Feito isso, o campo Campo de Apresentação continua sendo o campo 'Prioridade', mas o campo selecionado para ordenação é o 'Ordem'. Com isso, os itens serão apresentados na ordem (Baixa, Média e Alta).
Condição na Base de Dados
Na condição, pode-se escolher um dos campos da Base de dados para ser usado em uma comparação por valor (É igual a, É diferente de, Conter e Não conter) ou por outro campo (É igual ao campo ou É diferente do campo) desse formulário.
O vídeo abaixo mostra a configuração da lista de seleção, mas também se aplica para o campo Lista aberta com escolha única (Radio). O processo de configuração e o comportamento é idêntico.
Validação
Nessa parte, é possível configurar validações dos dados inseridos pelo usuário, garantindo um padrão de preenchimento.
Como deixar um campo obrigatório?
Obrigatório
Caso marcado como "sim", não permite o salvamento do fomulário sem o preenchimento desse campo. Ao marcar como "sim" essa opção, são abertos duas outras opções:
Obrigatório mesmo que por algum motivo o campo esteja marcado como invisível?
Use essa opção para fazer um campo definido como obrigatório, deixar sua obrigatoriedade caso ele esteja invisível.
Obrigatório a partir da etapa
Para os formulários com fluxo de etapas, é possível atrelar a obrigatoriedade de um campo à etapa em que se encontra o fluxo.
Valor do campo deve ser único em relação a todos os registros
O sistema, valida a inserção do campo, com os registros do mesmo campo, já salvos em outros formulários. Por exemplo, talvez exista uma necessidade de validação de um e-mail para o cadastro de um cliente. Caso o e-mail digitado já conste em outro registro, não será permitido o salvamento do formulário.
Valor do campo deve ser único em relação ao formulário PAI
Caso o formulário tenha uma relação com outro formulário (chamamos de formulário Pai), será validado que os dados inseridos são únicos, mas apenas para o registro filho.
Valor do campo deve ser único em relação APENAS ao CAMPO relacionado do formulário PAI
Caso haja, mais de um campo no formulário pai, relacionado ao mesmo formulário filho, a validação de valor único, ocorre apenas par cada campo do relacionamento.
Abaixo, um vídeo explica essas 3 últimas opções:
Regras de Visibilidade e desativação
Usando essas opções, é possível tornar um campo visível, invisível, ativo ou inativo, e definir quando uma dessas ações deve ocorrer. É possível adicionar várias regras para cada campo.
Descrição
É um texto que ajuda a identificar a regra que se está criando. Muito útil quando existem múltiplas regras.
Ação
Ativar
Deixa o campo disponível para inserção de dados. É o estado padrão do campo.
Inativar
Deixa o campo indisponível para inserção de dados.
Visível
O campo é mostrado na tela, caso esteja inserido para tal, nas configurações de tela.
Invisível
O campo é não é mostrado na tela, mesmo que esteja inserido para tal, nas configurações de tela.
A partir da etapa / Até a etapa
Em formulários com etapas, é possível estabelecer que uma regra será aplicada em alguma(s) etapa(s). Para isso, basta selecionar as etapas nos campos "a partir da etapa" e "até a etapa", para definir em que momento do fluxo essa regra vai ser aplicada.
Quando
Define em que momento a ação deve acontecer.
Sempre
É o padrão do formulário.
Condicional
- Tipo de condição
Para fazer um validação condicional, estão disponíveis as seguintes condições:
- Se o campo: compara um campo com um valor, ou com outro campo.
Abaixo, uma tabela com os operadores disponíveis para as comparações:
Comparação por valor Comparação por outro campo For igual a É igual ao campo For maior ou igual a É diferente do campo For menor ou igual a For maior que For menor que For diferente de Conter Não conter É possível adicionar mais de um condição na mesma regra.
- Se é um novo formulário: regra será aplicada quando uma nova entrada no formulário estiver sendo criada.
- Se é edição de formulário: regra será aplicada quando uma entrada no formulário estiver sendo alterada.
- Se o campo: compara um campo com um valor, ou com outro campo.
Customização Javascript
Caso a customização desejada, não esteja disponível, ainda assim é possível programá-la utilizando javascript. Para mais detalhes, acesse o capítulo sobre essa opção.
Fórmula
Com o campo de fórmula, é possível fazer cálculos com valores dos campos disponíveis no formulário, além de utilizar valores fixos na composição da fórmula.
O campo de fórmula faz dois tipos de cálculos: com campos numéricos e com campos com data/hora. É na definição do campo que seleciona-se o tipo de cálculo.
Grupo de informações
Dentro das configurações, é possível alterar o grupo de informação ao qual o campo foi atribuído no momento da criação.
Nome de Apresentação
Mostra o nome de apresentação informado no momento da criação. Esse é o nome que será mostrado na tela para o usuário.
Coluna Banco de dados (SQL)
Esse é o nome interno, usado pelo sistema, a ser criado no banco de dados do agilityflow. É uma informação técnica e esse campo é preenchido automaticamente pelo sistema.
Na maioria dos casos, você não precisa alterar o nome sugerido pelo sistema.
Diferentemente do campo "Nome de Apresentação", esse campo não fica visível para o usuário.
Para que serve o campo Coluna Banco de dados (SQL)?
Esse campo vai ser utilizado ao criar reports e dashboards. É através dele, que poderemos extrair informações e expor usando esses recursos do sistema.
Informações de ajuda
Nesse campo é possível incluir um texto que ajudará o usuário a preenche-lo. Abaixo, um exemplo de dois campos: um campo sem informações de ajuda e outro com esse campo configurado:
Máscara
É a forma que o sistema utiliza para mostrar ao usuário, o conteúdo do campo de texto. Isso facilita a visualização da informação por parte do usuário. Por exemplo, é muito fácil ver o telefone "(11) 98765-4321" do que "11987654321".
Tipo de máscara
Existe uma série de máscaras disponíveis no agilityflow.
Número
Como criar um campo numérico?
Um número não deixa de ser um texto. Portanto, para criar um campo numérico basta criar um campo textbox e aplicar uma máscara de número.
- Tipo de Número
- Inteiro: o campo não aceita "," ou "." no seu conteúdo. Ao digitar um desses símbolos, o sistema ignora a digitação. Por exemplo, digitando "1,5", o sistema ignora a vírgula e preenche "15". Caso o usuário cole o valor "1,5541", o sistema ignora a vírgula e o conteúdo à direita da vírgula, aceitando o valor "1".
- Moeda (Real): coloca vírgula, deixando o campo com duas casas decimais;
- Decimal (1 casa decimal): coloca vírgula, deixando o campo com duas casas decimais;
- Decimal (2 casas decimais): coloca vírgula, deixando o campo com duas casas decimais;
- Decimal (3 casas decimais): coloca vírgula, deixando o campo com duas casas decimais;
- Decimal (4 casas decimais): coloca vírgula, deixando o campo com duas casas decimais;
- Decimal (5 casas decimais): coloca vírgula, deixando o campo com duas casas decimais;
Definição da Fórmula
São as configurações para os cálculos.
Tipo de Cálculo
Ao escolher o tipo, serão mostrados os campos disponíveis para serem usados.
Fórmula Numérica
é possível fazer as 4 operações aritméticas (soma, subtração, divisão e multiplicação) nesse campo. Para isso, basta selecionar um ou mais campos com a máscara do tipo numérico e escrever a fórmula.
Fórmula por data/hora
Fórmula por data/hora: nessa opção, é possível subtrair um campo do tipo data/hora, por outro campo do tipo data/hora. Como resultado, é possível obter:
-
Número de Dias
-
Número de Meses
-
Número de Anos
-
Número de Semanas
-
Número de Horas:Minutos
Para fórmula com datas, só é possível fazer a operação de subtração.
Fórmula
É a composição da fórmula. Basta começar a digitar o nome dos campos que estão mostrados logo abaixo e compor a fórmula. Esses campos são mostrados, de acordo com a máscara dos demais campos disponíveis do formulário. Além dos campos, é possível fazer a utilização dos operadores matemáticos.
Regras de Visibilidade e desativação
Usando essas opções, é possível tornar um campo visível, invisível, ativo ou inativo, e definir quando uma dessas ações deve ocorrer. É possível adicionar várias regras para cada campo.
Descrição
É um texto que ajuda a identificar a regra que se está criando. Muito útil quando existem múltiplas regras.
Ação
Visível
O campo é mostrado na tela, caso esteja inserido para tal, nas configurações de tela.
Invisível
O campo é não é mostrado na tela, mesmo que esteja inserido para tal, nas configurações de tela.
A partir da etapa / Até a etapa
Em formulários com etapas, é possível estabelecer que uma regra será aplicada em alguma(s) etapa(s). Para isso, basta selecionar as etapas nos campos "a partir da etapa" e "até a etapa", para definir em que momento do fluxo essa regra vai ser aplicada.
Quando
Define em que momento a ação deve acontecer.
Sempre
É o padrão do formulário.
Condicional
- Tipo de condição
Para fazer um validação condicional, estão disponíveis as seguintes condições:
- Se o campo: compara um campo com um valor, ou com outro campo.
Abaixo, uma tabela com os operadores disponíveis para as comparações:
Comparação por valor Comparação por outro campo For igual a É igual ao campo For maior ou igual a É diferente do campo For menor ou igual a For maior que For menor que For diferente de Conter Não conter É possível adicionar mais de um condição na mesma regra.
- Se é um novo formulário: regra será aplicada quando uma nova entrada no formulário estiver sendo criada.
- Se é edição de formulário: regra será aplicada quando uma entrada no formulário estiver sendo alterada.
- Se o campo: compara um campo com um valor, ou com outro campo.
Customização Javascript
Caso a customização desejada, não esteja disponível, ainda assim é possível programá-la utilizando javascript. Para mais detalhes, acesse o capítulo sobre essa opção.
Campo com Múltipla Escolha
Apesar do visual um pouco diferente, tem comportamento similar ao campo checkbox, mas permite a escolha de mais de uma opção.
Grupo de informações
Dentro das configurações, é possível alterar o grupo de informação ao qual o campo foi atribuído no momento da criação.
Nome de Apresentação
Mostra o nome de apresentação informado no momento da criação. Esse é o nome que será mostrado na tela para o usuário.
Coluna Banco de dados (SQL)
Esse é o nome interno, usado pelo sistema, a ser criado no banco de dados do agilityflow. É uma informação técnica e esse campo é preenchido automaticamente pelo sistema.
Na maioria dos casos, você não precisa alterar o nome sugerido pelo sistema.
Diferentemente do campo "Nome de Apresentação", esse campo não fica visível para o usuário.
Para que serve o campo Coluna Banco de dados (SQL)?
Esse campo vai ser utilizado ao criar reports e dashboards. É através dele, que poderemos extrair informações e expor usando esses recursos do sistema.
Informações de ajuda
Nesse campo é possível incluir um texto que ajudará o usuário a preenche-lo. Abaixo, um exemplo de dois campos: um campo sem informações de ajuda e outro com esse campo configurado:
Origem dos Dados
Como existe uma lista de opções pré-determinadas, é necessário definir a origem dos dados.
Origem dos Itens
São duas as possibilidades:
1. Lista Dinâmica (Utilização recomendada) : Nessa opção, os dados têm como origem um outro formulário. Ao selecionar esse outro formulário, é necessário informar qual o campo desse formulário será exibido.
2. Lista Estática: O usuário insere as opções nas configurações do campo. Com isso, o usuário que acessa o formulário não pode criar novas opções. Ao criar as opções, além do nome, é possível definir a ordem em que aparecerão na lista de seleção. Outra opção, é o Id Customizado (Banco de Dados). Essa opção, normalmente não precisa ser preenchido. Entretanto, em alguns casos, esse id pode ser customizado. Isso pode ser útil, para a criação de dashboard e reports, para montar mais facilmente as queries.
Configuração de uma Lista Dinâmica
Abaixo estão descritos os campos básicos de preenchimento para definição de uma lista dinâmica.
Abra a tela de edição do campo e clique na aba Origem dos Dados

Campos para preenchimento:
Origem dos dados
Defina como "Lista Dinâmica"
Quando os dados serão carregados?
Quando a lista é dinâmica, é possível definir algumas opções relativas ao carregamento da lista. Esse carregamento pode ocorrer de duas maneiras.
No carregamento inicial (On PageLoad): Assim que o formulário é carregado, as opções da lista de seleção também são carregados imediatamente.
Na alteração do valor de um determinado campo (On Change): As opções só serão carregadas quando um determinado campo mudar. Isso é útil, para uma lista de seleção selecionar níveis de outra lista de seleção. Ex: seleciona-se primeiro o estado e só depois, é selecionada a cidade. Esse campo Lista de Cidade, apenas é carregado quando o outro campo Lista de Estados é alterado. Para isso, é necessário também adicionar uma condição na base de dados.
Qual será a Base de dados
É o formulário que servirá de fonte para a Lista Dinâmica.
Campo de apresentação (Base de dados)
Essa é a informação que será apresentada para o usuário na apresentação do combo. Esse campo é referente ao formulário que foi selecionado no campo Qual será a Base de dados.
Ordenar os itens pelo campo
A ordenação padrão do itens do combo é alfabética. Entretanto há casos onde queremos alterar essa ordem. Para isso, podemos utilizar um segundo campo como critério de ordenação, que não o campo de exibição. Como exemplo, vamos usar um formulário que só tem o campo nome, e os seguintes dados?
| Prioridade |
| Alta |
| Baixa |
| Média |
Ao usarmos o campo prioridade como critério de ordenação, os itens serão apresentados na ordem alfabética (Alta, Baixa e Média), quando o mais intuitivo seria apresentar a ordem como (Baixa, Média, Alta).
Para isso, podemos criar um campo chamado 'Ordem' nesse formulário, e incluir números. Dessa forma:
| Prioridade | Ordem |
| Alta | 3 |
| Baixa | 2 |
| Média | 1 |
Feito isso, o campo Campo de Apresentação continua sendo o campo 'Prioridade', mas o campo selecionado para ordenação é o 'Ordem'. Com isso, os itens serão apresentados na ordem (Baixa, Média e Alta).
Condição na Base de Dados
Na condição, pode-se escolher um dos campos da Base de dados para ser usado em uma comparação por valor (É igual a, É diferente de, Conter e Não conter) ou por outro campo (É igual ao campo ou É diferente do campo) desse formulário.
O vídeo abaixo mostra a configuração da lista de seleção, mas também se aplica para o campo Campo com Múltipla Escolha. O processo de configuração e o comportamento é idêntico.
Validação
Nessa parte, é possível configurar validações dos dados inseridos pelo usuário, garantindo um padrão de preenchimento.
Como deixar um campo obrigatório?
Obrigatório
Caso marcado como "sim", não permite o salvamento do fomulário sem o preenchimento desse campo. Ao marcar como "sim" essa opção, são abertos duas outras opções:
Obrigatório mesmo que por algum motivo o campo esteja marcado como invisível?
Use essa opção para fazer um campo definido como obrigatório, deixar sua obrigatoriedade caso ele esteja invisível.
Obrigatório a partir da etapa
Para os formulários com fluxo de etapas, é possível atrelar a obrigatoriedade de um campo à etapa em que se encontra o fluxo.
Tipo de Validação
Para o campo com múltipla escolha, é possível fazer uma validação relativo à quantidade de itens marcados.
- Selecionar no máximo X itens: define um limite máximo de itens marcados;
- Selecionar no mínimo X itens: define um limite mínimo de itens marcados;
- Selecionar exatamente X itens: define um número exato de itens marcados;
Regras de Visibilidade e desativação
Usando essas opções, é possível tornar um campo visível, invisível, ativo ou inativo, e definir quando uma dessas ações deve ocorrer. É possível adicionar várias regras para cada campo.
Descrição
É um texto que ajuda a identificar a regra que se está criando. Muito útil quando existem múltiplas regras.
Ação
Ativar
Deixa o campo disponível para inserção de dados. É o estado padrão do campo.
Inativar
Deixa o campo indisponível para inserção de dados.
Visível
O campo é mostrado na tela, caso esteja inserido para tal, nas configurações de tela.
Invisível
O campo é não é mostrado na tela, mesmo que esteja inserido para tal, nas configurações de tela.
A partir da etapa / Até a etapa
Em formulários com etapas, é possível estabelecer que uma regra será aplicada em alguma(s) etapa(s). Para isso, basta selecionar as etapas nos campos "a partir da etapa" e "até a etapa", para definir em que momento do fluxo essa regra vai ser aplicada.
Quando
Define em que momento a ação deve acontecer.
Sempre
É o padrão do formulário.
Condicional
- Tipo de condição
Para fazer um validação condicional, estão disponíveis as seguintes condições:
- Se o campo: compara um campo com um valor, ou com outro campo.
Abaixo, uma tabela com os operadores disponíveis para as comparações:
Comparação por valor Comparação por outro campo For igual a É igual ao campo For maior ou igual a É diferente do campo For menor ou igual a For maior que For menor que For diferente de Conter Não conter É possível adicionar mais de um condição na mesma regra.
- Se é um novo formulário: regra será aplicada quando uma nova entrada no formulário estiver sendo criada.
- Se é edição de formulário: regra será aplicada quando uma entrada no formulário estiver sendo alterada.
- Se o campo: compara um campo com um valor, ou com outro campo.
Customização Javascript
Caso a customização desejada, não esteja disponível, ainda assim é possível programá-la utilizando javascript. Para mais detalhes, acesse o capítulo sobre essa opção.
Botão Customizado
Caso seja necessário uma ação no formulário que não exista no agilityflow, é possível criar um botão. Esse botão, executa um código javascript personalizado, que deve ser criado pelo usuário. Para a configuração desse campo, é necessário conhecimento de javascript, já que qualquer ação com esse botão é 100% customizada.
Grupo de informações
Dentro das configurações, é possível alterar o grupo de informação ao qual o campo foi atribuído no momento da criação.
Nome de Apresentação
Mostra o nome de apresentação informado no momento da criação. Esse é o nome que será mostrado na tela para o usuário.
Regras de Visibilidade e desativação
Usando essas opções, é possível tornar um campo visível, invisível, ativo ou inativo, e definir quando uma dessas ações deve ocorrer. É possível adicionar várias regras para cada campo.
Descrição
É um texto que ajuda a identificar a regra que se está criando. Muito útil quando existem múltiplas regras.
Ação
Ativar
Deixa o campo disponível para inserção de dados. É o estado padrão do campo.
Inativar
Deixa o campo indisponível para inserção de dados.
Visível
O campo é mostrado na tela, caso esteja inserido para tal, nas configurações de tela.
Invisível
O campo é não é mostrado na tela, mesmo que esteja inserido para tal, nas configurações de tela.
A partir da etapa / Até a etapa
Em formulários com etapas, é possível estabelecer que uma regra será aplicada em alguma(s) etapa(s). Para isso, basta selecionar as etapas nos campos "a partir da etapa" e "até a etapa", para definir em que momento do fluxo essa regra vai ser aplicada.
Quando
Define em que momento a ação deve acontecer.
Sempre
É o padrão do formulário.
Condicional
- Tipo de condição
Para fazer um validação condicional, estão disponíveis as seguintes condições:
- Se o campo: compara um campo com um valor, ou com outro campo.
Abaixo, uma tabela com os operadores disponíveis para as comparações:
Comparação por valor Comparação por outro campo For igual a É igual ao campo For maior ou igual a É diferente do campo For menor ou igual a For maior que For menor que For diferente de Conter Não conter É possível adicionar mais de um condição na mesma regra.
- Se é um novo formulário: regra será aplicada quando uma nova entrada no formulário estiver sendo criada.
- Se é edição de formulário: regra será aplicada quando uma entrada no formulário estiver sendo alterada.
- Se o campo: compara um campo com um valor, ou com outro campo.
Customização Javascript
A parte mais importante do botão customizado é a programação em javascript. É com ela que o botão será capaz de executar alguma ação no formulário.
Com a customização em Javascript, as possibilidade são inúmeras. Qualquer que seja o código javascript, ele pode ser usado aqui.
Exemplo de código
Posso abrir o WhatsApp pelo agilityflow?
No exemplo abaixo, o botão customizado está configurado para abrir o WhatsApp Web e iniciar uma conversa com o número cadastrado no formulário.
var fone = $("#telefone").val();
if (fone !== null)
fone = fone.replaceAll(/\(/,"").replaceAll(/\)/,"").replaceAll(/-/,"").replaceAll(/ /,"");
window.open("https://web.whatsapp.com/send?phone="+fone);
Explicando o código
var fone = $("#telefone").val();
Obtém-se o valor do campo telefone, e o armazena na variável chamada fone. Note que esse nome é exatamente o nome definidos na configuração Coluna Banco de dados (SQL).
if (fone !== null)
fone = fone.replaceAll(/\(/,"").replaceAll(/\)/,"").replaceAll(/-/,"").replaceAll(/ /,"");
Nesse ponto, checa se o valor é nulo. Caso não seja, limpa o número, removendo parêntesis e hifens.
window.open("https://web.whatsapp.com/send?phone="+fone);
Formulários Relacionados
Basicamente, um formulário relacionado é um formulário dentro de outro formulário.
Como criar um formulário relacionado?
Para criar um formulário relacionado, você deve criar um formulário comum, como qualquer outro. Além disso é necessário adicionar dois componentes adicionais:
- Ativar a opção de relacionamento com outros formulários:

Na definição básica do formulário, deve-se ativar a opção "Pode ser usado como tabela filha de um outro formulário (Tabela de Formulário Relacionado)". A opção "Abrir apenas através de um formulário pai", inibe que esse formulário seja aberto da maneira convencional, permitindo apenas que ele seja aberto através de outro formulário.
- Criar um campo de relacionamento com o formulário Pai:
Isso é fundamental para exista a relação entre os dois formulários. Para isso, é necessário criar um campo de autocompletar ou lista de seleção, com uma fonte dinâmica de dados, usando o formulário pai como fonte. Feito isso, escolhe-se um campo para que seja mostrado (de preferência o campo com maior importância desse formulário) e marca-se as seguintes duas opções:
- Esse campo pode ser Relacionado a um formulário Pai e preenchido automaticamente pelo ID (Primary Key) do formulário pai: essa opção deve ser marcada, para que o sistema automaticamente preencha essa opção. como esse formulário, vai ser aberto através do formulário pai, o preenchimento fica sendo automático e transparente para o usuário.
- Esconder campo quando o formulário for aberto através do formulário pai (opcional): como esse campo vai ser preenchido automaticamente pelo formulário, podemos ocultar quando o formulário for aberto pelo formulário pai.
- Esse campo pode ser Relacionado a um formulário Pai e preenchido automaticamente pelo ID (Primary Key) do formulário pai: essa opção deve ser marcada, para que o sistema automaticamente preencha essa opção. como esse formulário, vai ser aberto através do formulário pai, o preenchimento fica sendo automático e transparente para o usuário.
No exemplo abaixo, temos um formulário chamado Clientes, que é um cadastro de pessoas jurídicas. Para cada cadastro, queremos incluir N contatos com nomes de pessoas físicas que trabalham nessa empresa.
Para fazer isso, criamos um formulário chamado Contatos. Nas definições básicas desse formulário, marcamos a opção "Pode ser usado como tabela filha de um outro formulário (Tabela de Formulário Relacionado)". Além dos campos necessários para o cadastro dos contatos, criamos um campo chamado Relacionamento_Clientes, que é o campo que vai se relacionar com o formulário Clientes (formulário Pai). A configuração desse campo fica assim:

Quando o formulário filho está configurado dessa forma, ele fica disponível para ser adicionado no formulário pai:

O uso é transparente para o usuário, não percebendo essa amarração entre os formulários.
Abaixo, as demais configurações de um formulário relacionado:
Grupo de informações
Dentro das configurações, é possível alterar o grupo de informação ao qual o campo foi atribuído no momento da criação.
Nome de Apresentação
Mostra o nome de apresentação informado no momento da criação. Esse é o nome que será mostrado na tela para o usuário.
Ordenação manual organizada pelo próprio usuário através de Arrastar e Soltar (Drag and Drop)
Permite ao usuário, ordenar as entradas do formulário relacionado.
Customização da Lista
Essas opções, permitem configurar aspectos da lista do formulário relacionado que serão exibidos
Coluna Visível
Caso não seja necessário, uma ou mais colunas podem ser ocultadas da visualização dentro do formulário pai. Isso ajuda na organização dos dados que são mostrados na tela.
Prefixo
Adiciona um texto opcional antes do conteúdo do campo.
Sufixo
Adicional um texto opcional após o conteúdo do campo.
Informação no Rodapé
No rodapé, é possível exibir uma informação extra, baseada nos campos numéricos do formulário relacionado. São elas:
- Soma da Coluna
Faz a soma de todos os valores dessa coluna e exibe o total. - Média da Coluna
Faz a média de todos os valores dessa coluna e exibe o resultado.
Caso uma dessas opções seja selecionada, é preciso selecionar uma máscara para o rodapé.
- Moeda (Real)
- Decimal (1 casa decimal)
- Decimal (2 casas decimais)
- Decimal (3 casas decimais)
- Decimal (4 casas decimais)
- Decimal (5 casas decimais)
Lista do formulário que podem ser apresentadas como Sub Lista
Caso o formulário relacionado, contenha outro formulário relacionado, essas opções serão apresentadas.
Já abrir com as Sub Lista expandidas
O formulário relacionado que pertence a esse, será apresentado com a lista expandida. Essa configuração dá a opção do usuário definir o comportamento padrão. Isso é útil, caso hajam muitos dados, e nem todos precisam estar visíveis no primeiro momento, deixando a leitura do formulário mais simples.
Sub Lista visível
Aqui o usuário seleciona quais formulários relacionados devem estar visíveis.
Apresentar nessa tabela de dados apenas os dados que foram cadastrados através desse campo da tela
Essa opção permite ao usuário mostrar apenas os dados cadastrados através do formulário pai, e não os registros cadastrados pelo formulário filho, mesmo que quando feito, tenha sido colocado o relacionamento com algum registro do formulário pai.
Componentes CsHtml
Para acessar os detalhes desse conteúdo, clique aqui.
Label com Query SQL
Label com Query SQL é um campo de texto não editável, que é preenchido através de uma Query SQL definida por você. Esse campo é muito útil, quando se tem um campo de lista de seleção (ou pesquisa com auto-completar) com uma fonte dinâmica e há a necessidade mostrar outros campos do formulário usado como fonte por esse campo. Também pode ser útil para gerar um SUM, AVG e outras funções do SQL.
No exemplo abaixo, o formulário tem uma lista de seleção de clientes. Os outros dois campos, são Label com Query SQL com informações do formulário de cliente.
Ao mudar o campo de lista de seleção, a label com Query SQL é preenchida automaticamente.
Tabela de dados customizada através de programação: Query SQL, C#, HTML e CSS
Para acessar os detalhes desse conteúdo, clique aqui.
Campo de Assinatura
O campo de assinatura, permite que um usuário "desenhe" sua assinatura através do dedo (no celular) ou do mouse (no computador), ao final essa assinatura se transformará em uma imagem.
Grupo de informações
Dentro das configurações, é possível alterar o grupo de informação ao qual o campo foi atribuído no momento da criação.
Nome de Apresentação
Mostra o nome de apresentação informado no momento da criação. Esse é o nome que será mostrado na tela para o usuário.
Regras de Visibilidade e desativação
Usando essas opções, é possível tornar um campo visível, invisível, ativo ou inativo, e definir quando uma dessas ações deve ocorrer. É possível adicionar várias regras para cada campo.
Descrição
É um texto que ajuda a identificar a regra que se está criando. Muito útil quando existem múltiplas regras.
Ação
Ativar
Deixa o campo disponível para inserção de dados. É o estado padrão do campo.
Inativar
Deixa o campo indisponível para inserção de dados.
Visível
O campo é mostrado na tela, caso esteja inserido para tal, nas configurações de tela.
Invisível
O campo é não é mostrado na tela, mesmo que esteja inserido para tal, nas configurações de tela.
A partir da etapa / Até a etapa
Em formulários com etapas, é possível estabelecer que uma regra será aplicada em alguma(s) etapa(s). Para isso, basta selecionar as etapas nos campos "a partir da etapa" e "até a etapa", para definir em que momento do fluxo essa regra vai ser aplicada.
Quando
Define em que momento a ação deve acontecer.
Sempre
É o padrão do formulário.
Condicional
- Tipo de condição
Para fazer um validação condicional, estão disponíveis as seguintes condições:
- Se o campo: compara um campo com um valor, ou com outro campo.
Abaixo, uma tabela com os operadores disponíveis para as comparações:
Comparação por valor Comparação por outro campo For igual a É igual ao campo For maior ou igual a É diferente do campo For menor ou igual a For maior que For menor que For diferente de Conter Não conter É possível adicionar mais de um condição na mesma regra.
- Se é um novo formulário: regra será aplicada quando uma nova entrada no formulário estiver sendo criada.
- Se é edição de formulário: regra será aplicada quando uma entrada no formulário estiver sendo alterada.
- Se o campo: compara um campo com um valor, ou com outro campo.
Programação
Informações aprofundadas sobre o uso de JavaScript, C# e Query (SQL) no agilityflow.
SQL Server (Query) - Dicas e Funções (Versões Mais Antigas do Agilityflow)
IMPORTANTE: Essa documentação é referente as versões antes de 2024 que são mais antigas do agilityflow e que utilizam o Banco de Dados SQL SERVER. O agilityflow nas últimas versões está utilizando POSTGRESQL .
No agilityflow você pode buscar os dados utilizando SQL, através de queries. As queries devem ser compatíveis com SQL Server. Além disso existem alguns padrões que você deve seguir para obter um melhor resultado no agilityflow. Abaixo estão alguns detalhes importantes.
Tratamento de Registros Deletados
IMPORTANTE:
É de extrema importância o tratamento de registros deletados, usando as regras abaixo.
Já está no nosso Roadmap o tratamento automático dos deletados, enquanto isso, o tratamento se torna obrigatório pelo desenvolvedor.
Para manter a integridade dos dados, o agilityflow nunca apaga um registro de uma tabela. Apenas o marca como deletado. Portanto, para qualquer query, é preciso excluir os deletados da lista.
Essa marcação é feita com campo deletado. Se o valor for 0, significa que ele não foi deletado e está visível no sistema. Caso esteja 1, significa que o registro já foi excluído e não é possível mais vê-lo na listagem principal do sistema.
Exemplo 1, sem o tratamento de deletados:
select usu_nome, usu_email from tbl_usuario
Resultado:

Exemplo 2, com o tratamento de deletados:
select usu_nome, usu_email from tbl_usuario
where deletado = 0
Resultado:

Campo do tipo Datetime (Data e Hora)
Sempre que um campo de texto com máscara do tipo data é criado, o sistema cria uma cópia com o mesmo nome seguido de "__datetime__" essa informação é gravada em uma coluna no banco de dados do tipo datetime, ao invés de varchar. Esses campos são criados para facilitar o uso tipado do dado nas queries
Exemplo de campo Datetime
Por exemplo, se o campo se chama "data_e_hora", haverá um outro chamado "data_e_hora__datetime__" e o conteúdo estará no formato padrão do sql server, YYYY-MM-DD hh:mm:ss
O campo "data_e_hora" estará sempre como varchar e o "data_e_hora__datetime__" estará como datetime
Campo do tipo Numérico (decimal, float, double, int, number)
Sempre que um campo de texto com máscara do tipo número é criado, o sistema cria uma cópia com o mesmo nome seguido de "__number__" essa informação é gravada em uma coluna no banco de dados do tipo numeric(18,6), ao invés de varchar. Esses campos são criados para facilitar o uso tipado do dado nas queries
Exemplo de campo numérico
Por exemplo, se o campo se chama "numero_exemplo", haverá um outro chamado "numero_exemplo__number__" e o conteúdo estará no formato padrão do sql server.
O campo "numero_exemplo" estará sempre como varchar e o "numero_exemplo__number__" estará como numeric(18,6)
Formatação de números
Nome da Função
format(number,format,idioma)
Parâmetro: number
Pode ser um número inteiro ou um decimal
Parâmetro: format
Aqui você passa a formatação que deve ser retornada:
'n0' = retorna o número sem nenhuma casa decimal
'n1' = retorna o número com 1 casa decimal
'n2' = retorna o número com 2 casas decimais
'n3' = retorna o número com 3 casas decimais
'n4' = retorna o número com 4 casas decimais
'n5' = retorna o número com 5 casas decimais
'n6' = retorna o número com 6 casas decimais
Parâmetro: idioma - @sysCurrentLanguage
Aqui você precisa passar o idioma do usuário logado, pois alguns idiomas invertem o . (ponto) e a , (virgula) do número.
O agilityflow guarda o idioma do usuário dentro da variável @sysCurrentLanguage então apenas passe no parâmetro esse variável.
Exemplo de utilização
Abaixo o número será formato para 5 casas decimais, no padrão do idioma do usuário logado.
select FORMAT(5800000.888, 'n5', @sysCurrentLanguage)
Retorno para o usuário que está logado no agilityflow em português ou espanhol
| 5.800.000,88800 |
Retorno para o usuário que está logado no agilityflow usando em inglês
| 5,800,000.88800 |
Funções de data no SQL Server
As principais funções para manipular datas são: GETDATE, DATEPART, DATEADD e DATEDIFF.
Um detalhe importante é que as funções de data trabalham referenciando unidades de data. As mais comuns são:
- year(ano);
- month(mês);
- day(dia);
GETDATE ( )
A função GETDATE retorna a data e a hora atuais do sistema.
SELECT GETDATE()
DATEPART (unidade, data)
A função DATEPART retorna a parte especificada de uma data como um inteiro. Observe os exemplos:
SELECT DATEPART ( YEAR , '2024-02-01' )
Reposta: 2024
SELECT DATEPART ( MONTH, '2024-02-01' )
Reposta: 2
SELECT DATEPART ( DAY, '2024-02-01' )
Reposta: 1
DATEADD (unidade, numero_unid, data)
A função DATEADD retorna uma nova data através da soma do número de unidades especificadas pelo valor unidade a uma data. Observe os exemplos:
SELECT DATEADD ( DAY ,6, '2024-02-01' )
Reposta: 2024-02-07
SELECT DATEADD ( MONTH ,6, '2024-02-01' )
Reposta: 2024-08-01
SELECT DATEADD ( YEAR ,6, '2024-02-01' )
Reposta: 2030-02-01
DATEDIFF (unidade, data1, data2)
A função DATEDIFF calcula a diferença entre as datas data2 e data1, retornando o resultado como um inteiro, cuja unidade é definida pelo valor unidade. Observe os exemplos:
SELECT DATEDIFF ( DAY , '2024-02-01' , '2024-05-25' )
Reposta: 114 (dias)
SELECT DATEDIFF ( MONTH , '2024-02-01' , '2024-05-25' )
Reposta: 3 (meses)
SELECT DATEDIFF ( YEAR , '2024-02-01' , '2026-05-25' ) )
Reposta: 2 (anos)
Sabendo disso, para por exemplo saber o número de dias vivido por você até hoje é:
SELECT DATEDIFF(DAY, suadata, GETDATE())
suadata deve ser substituída pela sua data de nascimento.
Outro exemplo interessante é mostrado através do código SQL abaixo. Usando funções de data, exibimos, para cada cliente, a idade em dias, meses e em anos (idade do cliente na data atual e em 31 de dezembro).
Observe a lógica utilizada no comando CASE. Neste caso, é testado se o cliente já fez aniversário, comparando o mês em que ele nasceu com o mês corrente e comparando o dia em que ele nasceu com o dia corrente. Se essa comparação for verdadeira, basta diminuir o ano atual do ano de nascimento do cliente. Caso contrário (o cliente ainda não fez aniversário), temos que diminuir 1 do valor anterior.
SELECT NOME, NASCIMENTO,
DATEDIFF(DAY,NASCIMENTO,GETDATE())AS DIASVIVIDOS,
DATEDIFF(MONTH,NASCIMENTO,GETDATE()) AS MESESVIVIDOS,
CASE WHEN
DATEPART(MONTH,NASCIMENTO)<= DATEPART(MONTH,GETDATE()) AND
DATEPART(DAY,NASCIMENTO)<= DATEPART(DAY,GETDATE())
THEN
(DATEDIFF(YEAR,NASCIMENTO,GETDATE()))
ELSE
(DATEDIFF(YEAR,NASCIMENTO,GETDATE()))- 1
END AS IDADEATUAL,
DATEDIFF(YEAR,NASCIMENTO,GETDATE())AS IDADE3112
FROM CLIENTE
Relatório
Relatório - Filtro
Sempre que um relatório possuir um filtro, é necessário incluir esse filtro na query que gera os dados do relatório.
Não importa como é a query, ela deve incluir a cláusula where, como a chamada da função Filter. Essa função, possui 3 parâmetros:
Filter (variável_filtro, tabela, campo)
- variável_filtro: é a variável que o agilityflow criou, após a configuração do filtro.
- tabela: nome da tabela (definido nos Dados Técnicos) onde se encontra o dado a ser filtrado.
- campo: é o nome do campo (conforme informado no campo Coluna Banco de Dados SQL) onde a informação que o filtro utiliza se encontra.
No exemplo abaixo, a query lista os campos usu_nome, usu_email e usu_sexo da tabela do sistema de usuário (tbl_usuario) e se inclui a função Filter, usando a variável @sexo aplicada no campo usu_sexo.
select usu_nome, usu_email, usu_sexo from tbl_usuario
where Filter(@sexo, tbl_usuario, usu_sexo)
Exemplo de relatório sem filtro
Baseado na query acima, mas sem filtro configurado no relatório.
select usu_nome, usu_email, usu_sexo from tbl_usuario

Exemplo de relatório com filtro
O mesmo exemplo acima, com o filtro no campo sexo.

select usu_nome, usu_email, usu_sexo from tbl_usuario
where Filter(@sexo, tbl_usuario, usu_sexo)
Caso seja criado um novo filtro, basta colocar "and" depois do primeiro Filter, e colocar o segundo Filter. Não importa a quantidade de filtros, desde que sejam adicionados todos os Filter e os and.
select usu_nome, usu_email, usu_sexo from tbl_usuario
where Filter(@sexo, tbl_usuario, usu_sexo) and
Filter(@nome, tbl_usuario, usu_nome) and
Filter(@email, tbl_usuario, usu_email)
Relatório - Tabela de Dados
Para as tabelas de dados, existem algumas regrinhas para a customização via Query Sql
1 - Lembre-se de tratar os dados que já foram deletados, usando no where "...deletado = 0.."
2 - Não pode conter 'Order by' no select. Essa informação será controlada automaticamente pelo agilityflow e você poderá manipular essa informação na tela de configuração, como na imagem abaixo.
3 - Não pode conter o controle de 'Top' no select. Essa informação será controlada automaticamente pelo agilityflow e você poderá manipular essa informação na tela de configuração, como na imagem abaixo.
4 - Não pode conter regras de paginação. Essa informação será controlada automaticamente pelo agilityflow e você poderá manipular essa informação na tela de configuração, como na imagem abaixo.
Relatório - Gráfico
Para gráficos, existem algumas regrinhas para a customização via Query Sql
1 - Lembre-se de tratar os dados que já foram deletados, usando no where "...deletado = 0.."
2 - A query precisa iniciar com 'select top ' e o máximo do Top para essa query é 100
3 - Diferentemente da query da tabela de dados, nessa query pode sim conter regras de 'Order by'
Relatório - Label
Para as labels do relatório, existem algumas regrinhas para a customização via Query Sql
1 - Lembre-se de tratar os dados que já foram deletados, usando no where "...deletado = 0.."
2 - A query precisa iniciar com 'select top ' e o máximo do Top para essa query é 1
3 - Diferentemente da query da tabela de dados, nessa query pode sim conter regras de 'Order by'
Formulário
Lista Dinâmica - Regras
Os campos que são carregados com Lista dinâmica, podem ser customizados utilizando Query:
Algumas regras importantes:
1 - O resultado final da query precisa sempre ser os dados do formulário que você usou como base de dados
2 - Lembre-se de tratar os dados que já foram deletados, usando no where "...deletado = 0.."
3 - A query deve retornar duas colunas com os seguintes alias: "Name" e "Value". O "Name" deve ser a mesma coluna definida no campo de apresentação (Nome) e o "Value", deve ser a coluna "id" do formulário definido como base de dados (Cliente). Exemplo:
4 - Na query, o campo de apresentação "Name" pode ser um campo concatenado entre outras colunas.
Exemplo simples:
SELECT Id as Value, [CAMPO_DE_APRESENTACAO] as Name FROM [TABELA] where deletado = 0
Report Print - Relatório de Impressão
Para as labels do relatório, existem algumas regrinhas para a customização via Query Sql
Para acessar a customização, clique no botão "Adicionar Outras Fontes de Dados" e selecione o tipo:
- Variáveis: para retornar uma query com apenas 1 linha e várias colunas, cada coluna se torna um campo separado para ser utilizado no relatório
- Tabela de Dados: para retornar uma tabela com diversas colunas e diversas linhas e usa-las em conjunto em uma tabela
Algumas regras importantes:
1 - Lembre-se de tratar os dados que já foram deletados, usando no where "...deletado = 0.."
2 - Utilizar no "where" da query, o parâmetro @formularioid para filtrar pelo formulário que está sendo solicitada a impressão, caso contrário trará informações de formulários aleatórios.
3 - A query precisa iniciar com 'select top ' e o máximo do Top para essa query quando for uma query do tipo:
- Tabela de Dados é 500,
- Variáveis é 1
4 - Essa query pode sim conter regras de 'Order by'
Postgresql (Query) - Dicas e Funções (Versões Mais Recentes do Agilityflow)
IMPORTANTE: Essa documentação é referente as versões pós 2023 do agilityflow que utilizam o Banco de Dados Postgresql. O agilityflow nas últimas versões está utilizando POSTGRESQL .
No agilityflow você pode buscar os dados utilizando SQL, através de queries. As queries devem ser compatíveis com SQL Server. Além disso existem alguns padrões que você deve seguir para obter um melhor resultado no agilityflow. Abaixo estão alguns detalhes importantes.
Tratamento de Registros Deletados
IMPORTANTE:
É de extrema importância o tratamento de registros deletados, usando as regras abaixo.
Já está no nosso Roadmap o tratamento automático dos deletados, enquanto isso, o tratamento se torna obrigatório pelo desenvolvedor.
Para manter a integridade dos dados, o agilityflow nunca apaga um registro de uma tabela. Apenas o marca como deletado. Portanto, para qualquer query, é preciso excluir os deletados da lista.
Essa marcação é feita com campo deletado. Se o valor for FALSE, significa que ele não foi deletado e está visível no sistema. Caso esteja TRUE, significa que o registro já foi excluído e não é possível mais vê-lo na listagem principal do sistema.
Exemplo 1, sem o tratamento de deletados:
select usu_nome, usu_email from tbl_usuario
Resultado:

Exemplo 2, com o tratamento de deletados:
select usu_nome, usu_email from tbl_usuario
where deletado = false
Resultado:

Campo do tipo Date, Timestamp e Datetime (Data e Hora)
Sempre que um campo de texto com máscara do tipo data é criado, o sistema cria uma cópia com o mesmo nome seguido de "__datetime__" essa informação é gravada em uma coluna no banco de dados do tipo "date" quando for uma coluna sem hora ou "timestamp without time zone" quando for uma coluna com hora , ao invés de varchar. Esses campos são criados para facilitar o uso tipado do dado nas queries
Exemplo de campo Datetime
Por exemplo, se o campo se chama "data_e_hora", haverá um outro chamado "data_e_hora__datetime__" e o conteúdo estará no formato padrão do sql server, YYYY-MM-DD hh:mm:ss
O campo "data_e_hora" estará sempre como varchar e o "data_e_hora__datetime__" estará como timestamp
data_e_hora | data_e_hora__datetime__
2027-01-31 23:5959 2027-01-31 23:5959
2027-01-31 23:5959 2027-01-31 23:5959
2027-01-31 23:5959 2027-01-31 23:5959
Campo do tipo Numérico (decimal, float, double, int, number)
Sempre que um campo de texto com máscara do tipo número é criado, o sistema cria uma cópia com o mesmo nome seguido de "__number__" essa informação é gravada em uma coluna no banco de dados do tipo numeric(18,6), ao invés de varchar. Esses campos são criados para facilitar o uso tipado do dado nas queries
Exemplo de campo numérico
Por exemplo, se o campo se chama "numero_exemplo", haverá um outro chamado "numero_exemplo__number__" e o conteúdo estará no formato padrão do sql server.
O campo "numero_exemplo" estará sempre como varchar e o "numero_exemplo__number__" estará como numeric(18,6)
numero_exemplo | numero_exemplo__number__
999.99 999.99
123.89 123.89
Formatação de números
Nome da Função
format_number(number,format,idioma)
Parâmetro: number
Pode ser um número inteiro ou um decimal
Parâmetro: format
Aqui você passa a formatação que deve ser retornada:
'0' = retorna o número sem nenhuma casa decimal
'1' = retorna o número com 1 casa decimal
'2' = retorna o número com 2 casas decimais
'3' = retorna o número com 3 casas decimais
'4' = retorna o número com 4 casas decimais
'5' = retorna o número com 5 casas decimais
'6' = retorna o número com 6 casas decimais
Parâmetro: idioma - @sysCurrentLanguage
Aqui você precisa passar o idioma do usuário logado, pois alguns idiomas invertem o . (ponto) e a , (virgula) do número.
O agilityflow guarda o idioma do usuário dentro da variável @sysCurrentLanguage então apenas passe no parâmetro esse variável.
Exemplo de utilização
Abaixo o número será formato para 5 casas decimais, no padrão do idioma do usuário logado.
select format_number(5800000.888, '5', @sysCurrentLanguage)
Retorno para o usuário que está logado no agilityflow em português ou espanhol
| 5.800.000,88800 |
Retorno para o usuário que está logado no agilityflow usando em inglês
| 5,800,000.88800 |
Funções de data no Postgresql
As principais funções para manipular datas são: GETDATE, DATEPART, DATEADD e DATEDIFF.
Um detalhe importante é que as funções de data trabalham referenciando unidades de data. As mais comuns são:
- year(ano);
- month(mês);
- day(dia);
CURRENT_TIMESTAMP)
A função CURRENT_TIMESTAMP retorna a data e a hora atuais do sistema.
SELECT CURRENT_TIMESTAMP
Extrair parte de uma data
A função EXTRACT retorna a parte especificada de uma data como um inteiro. Observe os exemplos:
SELECT EXTRACT(YEAR FROM '2024-02-01'::DATE)
Reposta: 2024
SELECT EXTRACT(MONTH FROM '2024-02-01'::DATE)
Reposta: 2
SELECT EXTRACT(DAY FROM '2024-02-01'::DATE)
Reposta: 1
Adicionar dias em uma data
A função abaixo retorna uma nova data através da soma do número de unidades especificadas pelo valor unidade a uma data. Observe os exemplos:
SELECT '2024-02-01'::DATE + INTERVAL '7 days';
Reposta: 2024-02-07
Calcular a diferença entre datas (date diff)
A função abaixo calcula a diferença entre as datas data2 e data1, retornando o resultado como um inteiro, cuja unidade é definida pelo valor unidade. Observe os exemplos:
SELECT EXTRACT(DAY FROM '2024-02-01'::DATE - '2023-10-10'::DATE);
Reposta: 114 (dias)
Cálculo de idade em anos, meses e dias
SELECT DATE_PART('year', AGE(NOW(), '1990-05-15')) AS idade_anos;
Relatório
Como fazer Filtro nos Relatórios?
Sempre que um relatório possuir um filtro, é necessário incluir esse filtro na query que gera os dados do relatório.
Não importa como é a query, ela deve incluir a cláusula where, como a chamada da função Filter. Essa função, possui 3 parâmetros:
Filter (variável_filtro, tabela, campo)
- variável_filtro: é a variável que o agilityflow criou, após a configuração do filtro.
- tabela: nome da tabela (definido nos Dados Técnicos) onde se encontra o dado a ser filtrado.
- campo: é o nome do campo (conforme informado no campo Coluna Banco de Dados SQL) onde a informação que o filtro utiliza se encontra.
No exemplo abaixo, a query lista os campos usu_nome, usu_email e usu_sexo da tabela do sistema de usuário (tbl_usuario) e se inclui a função Filter, usando a variável @sexo aplicada no campo usu_sexo.
select usu_nome, usu_email, usu_sexo from tbl_usuario
where Filter(@sexo, tbl_usuario, usu_sexo)
Exemplo de relatório sem filtro
Baseado na query acima, mas sem filtro configurado no relatório.
select usu_nome, usu_email, usu_sexo from tbl_usuario

Exemplo de relatório com filtro
O mesmo exemplo acima, com o filtro no campo sexo.

select usu_nome, usu_email, usu_sexo from tbl_usuario
where Filter(@sexo, tbl_usuario, usu_sexo)
Caso seja criado um novo filtro, basta colocar "and" depois do primeiro Filter, e colocar o segundo Filter. Não importa a quantidade de filtros, desde que sejam adicionados todos os Filter e os and.
select usu_nome, usu_email, usu_sexo from tbl_usuario
where Filter(@sexo, tbl_usuario, usu_sexo) and
Filter(@nome, tbl_usuario, usu_nome) and
Filter(@email, tbl_usuario, usu_email)
Relatório - Tabela de Dados
Para as tabelas de dados, existem algumas regrinhas para a customização via Query Sql
1 - Lembre-se de tratar os dados que já foram deletados, usando no where "...deletado = false.."
2 - Não pode conter 'Order by' no select. Essa informação será controlada automaticamente pelo agilityflow e você poderá manipular essa informação na tela de configuração, como na imagem abaixo.
3 - Não pode conter o controle de 'Limit' no select. Essa informação será controlada automaticamente pelo agilityflow e você poderá manipular essa informação na tela de configuração, como na imagem abaixo.
4 - Não pode conter regras de paginação. Essa informação será controlada automaticamente pelo agilityflow e você poderá manipular essa informação na tela de configuração, como na imagem abaixo.
Relatório - Gráfico
Para gráficos, existem algumas regrinhas para a customização via Query Sql
1 - Lembre-se de tratar os dados que já foram deletados, usando no where "...deletado = false.."
2 - A query precisa conter 'limit ' e o máximo do limit para essa query é 100
3 - Diferentemente da query da tabela de dados, nessa query pode sim conter regras de 'Order by'
Relatório - Label
Para as labels do relatório, existem algumas regrinhas para a customização via Query Sql
1 - Lembre-se de tratar os dados que já foram deletados, usando no where "...deletado = false.."
2 - A query precisa conter 'limit ' e o máximo do limit para essa query é 1
3 - Diferentemente da query da tabela de dados, nessa query pode sim conter regras de 'Order by'
Formulário
Lista Dinâmica - Regras
Os campos que são carregados com Lista dinâmica, podem ser customizados utilizando Query:
Algumas regras importantes:
1 - O resultado final da query precisa sempre ser os dados do formulário que você usou como base de dados
2 - Lembre-se de tratar os dados que já foram deletados, usando no where "...deletado = false.."
3 - A query deve retornar duas colunas com os seguintes alias: "Name" e "Value". O "Name" deve ser a mesma coluna definida no campo de apresentação (Nome) e o "Value", deve ser a coluna "id" do formulário definido como base de dados (Cliente). Exemplo:
4 - Na query, o campo de apresentação "Name" pode ser um campo concatenado entre outras colunas.
Exemplo simples:
SELECT Id as Value, CAMPO_DE_APRESENTACAO as Name FROM [TABELA] where deletado = false
Report Print - Relatório de Impressão
Para as labels do relatório, existem algumas regrinhas para a customização via Query Sql
Para acessar a customização, clique no botão "Adicionar Outras Fontes de Dados" e selecione o tipo:
- Variáveis: para retornar uma query com apenas 1 linha e várias colunas, cada coluna se torna um campo separado para ser utilizado no relatório
- Tabela de Dados: para retornar uma tabela com diversas colunas e diversas linhas e usa-las em conjunto em uma tabela
Algumas regras importantes:
1 - Lembre-se de tratar os dados que já foram deletados, usando no where "...deletado = false.."
2 - Utilizar no "where" da query, o parâmetro @formularioid para filtrar pelo formulário que está sendo solicitada a impressão, caso contrário trará informações de formulários aleatórios.
3 - A query precisa conter 'limit ' e o máximo do limit para essa query quando for uma query do tipo:
- Tabela de Dados é 500,
- Variáveis é 1
4 - Essa query pode sim conter regras de 'Order by'
Programação em Html
Para acessar os detalhes desse conteúdo, clique aqui.
Programação em CSS
Para acessar os detalhes desse conteúdo, clique aqui.
Programação em Javascript
Para acessar os detalhes desse conteúdo, clique aqui.
Programação em C# - Na Regra de Negócio
IMPORTANTE: as variáveis e métodos descritos aqui só funcionarão na programação C# na Regra de Negócio do formulário. Para a programação C# nas APIs clique aqui.
O agilityflow permite a customização em C#, além de já disponibilizar diversas bibliotecas e funções para facilitar sua programação, incluindo acesso a dados, validações, envio de e-mail, notificação, entre outras.
Abaixo mostramos alguns exemplos, se o material abaixo não for suficiente , entre em contato com nossa equipe.
C# - Propriedades
| Variável | Tipo | |
| IsNovoFormulario | bool | retorna true, caso seja um novo formulário, e false caso contrário. |
| IdFormulario | Guid |
retorna o ID do formulário |
| CurrentStatusFluxo | StatusFluxo? (Enum) |
Variável disponível apenas para Workflow
Nessa ENUM será retornado o Status do fluxo. As opções podem ser:
Exemplo de utilização:
|
|
(deprecated) FormularioCamposPreenchidos |
(deprecated) dynamic (Json) |
(deprecated: utilizar o método FormContext.GetValue descrito mais abaixo) retorna um json com os campos do preenchidos no formulário, exemplo: { "campo1": "xxxxx", "campo2": "yyyyy", "campo3": "zzzzz", }
Para resgatar a informação do campo1, utilize:
|
C# - Buscar e preencher valor de um campo
| Método | Retorno | |
|
FormContext.SetValue(string idCampo, string value)
|
void |
Esse método preencherá um campo com um novo Valor (passado por paramêtro)
Para valores que são Datas, utilizar o padrão dd/MM/aaaa HH:mm:ss: Exemplo: 31/12/2010 22:55
Para valores Numéricos, o número deve estar no formato com ponto no separador decimal e sem utilização de virgulas. Exemplo para 2 milhões e 50 centavos: 2000000.50
|
| FormContext.GetValue(string idCampo) | string |
Esse método retornará o Valor de um determinado campo |
| FormContext.GetText(string idCampo) | string |
Esse método retornará o Texto de um determinado campo, utilizado apenas se o campo for um campo de lista dinâmica, exemplo: Combo, Auto complete, Campo de Múltipla escolha, radio etc.
|
| FormContext.GetInt(string idColuna) |
int? |
Retorna o valor da coluna no tipo INT (inteiro), caso esse campo no formulário seja um número, se o valor for 10.000,99 Será retornado: 10000 |
| FormContext.GetDecimal(string idColuna) | decimal? |
Retorna o valor da coluna no tipo Decimal, caso esse campo no formulário seja um número, se o valor for 10.000,99 Será retornado: 10000.99
|
| FormContext.GetDateTime(string idColuna) | DateTime? |
Retorna o valor da coluna no tipo DateTime para valores que estão no formato de data dd/MM/yyyy ou dd/MM/yyyy hh:mm
|
C# - Buscar Rascunho por Id
| Método | Retorno | |
|
FormContext.GetDrafJsontById(string draftid) FormContext.GetDrafJsontById(Guid?draftid) |
dynamic |
|
C# - Executar uma consulta SQL (Query SQL)
| Método | Retorno | |
| await FormContext.GetDataTableAsync(string sql, params DbParameter[] parameters) | DataTable |
Permite retornar informações dos bancos de dados através de uma query. |
C# - Inserir (salvar/criar), alterar, deletar e aprovar outros formulários
| Método | Retorno | |
| await FormContext.SaveEntityAsync(Guid estruturaformularioid_ASerCriadoOuAtualizado, DataDictionary campos_e_valores) | Guid |
Salva (Insere e Atualiza) as informações de um formulário no bancos de dados.
Para atualizar um registro, no parâmetro campos_e_valores, apenas adicione um parâmetro chamado "id" com o id do elemento que você deseja atualizar.
Obs: Para cadastrar valores numéricos, o números devem estar no formato com ponto no separador decimal: 999999.99 sem utilização de virgulas.
|
| await FormContext.ApproveEntityAsync(Guid estruturaformularioid_ASerAprovado, DataDictionary campos_e_valores) | Guid |
Avança uma etapa em um formulário com Workflow. As regras de usuário aprovador, permissão de aprovação e responsabilidade por uma etapa devem ser validadas antes desse método ser executado.
Obs: Para cadastrar valores numéricos, o números devem estar no formato com ponto no separador decimal: 999999.99 sem utilização de virgulas.
|
| await FormContext.DeleteEntityAsync(Guid formularioid) | void |
Deletar um um registro |
C# - Apresentar mensagem para o usuário
| Método | Retorno | |
|
FormContext.WarningMessage(string message) |
void |
Apresenta um aviso para o usuário |
C# - Buscar informações do usuário logado
| Método | Retorno | |
| FormContext.GetUsuarioLogadoNome(); |
string | Nome Completo do usuário logado |
| FormContext.GetUsuarioLogadoPrimeiroNome(); | string | Primeiro nome do usuário logado |
| FormContext.GetUsuarioLogadoPrimeiroESegundoNome(); | string | Primeiro e Segundo nome do usuário logado |
| FormContext.GetUsuarioLogadoEmail(); | string | E-mail do usuário logado |
| FormContext.GetUsuarioLogadoId(); | Guid | Id do usuário logado |
C# - Buscar variáveis de ambiente
| Método | Retorno | |
|
FormContext.GetEnvironmentVariable(string nomeVariavel) ou FormContext.GetEnvironmentVariable_Text(string nomeVariavel) ** |
string |
Recupera o Valor de uma variável de ambiente.
** Recupera a Descrição (texto), no caso de variáveis do Tipo "Query com Id + Descrição": |
C# - Formatação Numérica
Se você está utilizando o método GetValue(..) para buscar o valor de um campo numérico, esse método já retornará o número formatado e não será necessário nenhuma formatação adicional.
Se você está utilizando o método GetDecimal(..) ele não virá formatado pois ele retorna o tipo DECIMAL do C#, sendo assim, se você precisa do dado formatado você pode utilizar o GetText(..)
| string FormContext.FormatDecimalToString(object numDecimal, string mascaraTipo = "dec2") |
formata object 999999999.55 para o formato da mascara de acordo com o idioma. - se for ingles, será 999,999,999.55 |
| string FormContext.FormatNumberToString_EnglishFormat(object num, [optional]int? qtdCasasDecimais) |
converte decimal para string, porém sempre a string vem no formato Inglês. coloca a a mesma qtd de casas decimais, caso o parâmetro qtdCasasDecimais estivar em branco |
C# - Gerar log
| Método | Retorno | |
|
FormContext.Log(string log, string logTipo) |
void |
Cria um log na tabela de log geral, o log pode ser consultado entrando na Área de Customização e clicando na opção "Log Geral >> consultar Log"
|
C# - Métodos Úteis
| Método | Retorno | |
| FormContext.GetUrlBase()
|
Retorna a URL base da sua aplicação exemplo:
https://suaempresa.agilityflow.io/
*A url sempre virá com uma barra no final / |
Método principal para utilização da Programação em C# na opção "Regra de Negócio"
A única regra é que o método se chame Execute, não tenha parâmetros de entrada e o retorno seja void.
Exemplo:
public void Execute(){
//aqui você pode programar
}
//aqui você pode programar outros métodos
Exemplos
Recuperando dados do banco de dados através de uma query SQL
//parametros da query
var paramsQuery = new List<NpgsqlParameter>();
paramsQuery.Add(new NpgsqlParameter("@param1", "xxx"));
paramsQuery.Add(new NpgsqlParameter("@param2", "yyy"));
paramsQuery.Add(new NpgsqlParameter("@param3", "zzz"));
//query usando (nolock) nas tabelas para evitar problema com a transação que está ativa
var sql = "select column1,column2,column3 from table (nolock) where column1 = @param1 or column2 = @param2 or column3 = @param3 ";
//executar no banco de dados
var dt = await FormContext.GetDataTableAsync(sql, paramsQuery.ToArray());
//percorrendo as linhas de retorno da tabela
foreach (DataRow dr in dt.Rows)
{
if (dr["column1"] != DBNull.Value)
FormContext.WarningMessage(dr["column1"].ToString());
}
Modificando os campos do próprio formulário que está sendo salvo
//concatenando o texto "abcdef" ao campo de texto chamado "texto_simples"
var texto_simples = FormContext.GetValueField("texto_simples");
texto_simples += " abcdef ";
FormContext.SetValue("texto_simples",texto_simples);
//colocando uma data fixa em um campo de data chamado "data_e_hora"
var data_e_hora = "31/01/2023 22:55";
FormContext.SetValue("data_e_hora",data_e_hora);
//colocando um valor decimal fixo em um campo de data chamado "moeda"
var moeda = "2000000.50";
FormContext.SetValue("moeda",moeda);
//somando 200 dias a um campo de data chamado "data_e_hora_2"
var dt_data_e_hora = FormContext.GetDateTime("data_e_hora_2");
if(dt_data_e_hora != null){
var nova_data = dt_data_e_hora.Value.AddDays(200);
FormContext.SetValue("data_e_hora_2", nova_data);
}
//somando 900.12 a um campo de moeda chamado "moeda2"
var num_moeda = FormContext.GetDecimal("moeda2");
if(num_moeda != null){
var novo_valor = num_moeda.Value + 9000000.12m;
FormContext.SetValue("moeda2",novo_valor);
}
Salvando/Criar um outro formulário através do método SaveEntityAsync
* Para cadastrar valores numéricos, o números devem estar no formato com ponto no separador decimal: 999999.99 sem utilização de virgulas.
//guarda em uma variável o ID da E S T R U T U R A do formulário de pessoa
var idEstruturaFormulario_PESSOA = Guid.Parse("0b56b66a-4f6f-4ded-ad04-016d7c0724e1");
var values = new DataDictionary();
values.Add("nome", FormContext.GetValue("nome"));
values.Add("email", FormContext.GetValue("email"));
//salva a informação no banco de dados
await FormContext.SaveEntityAsync(idEstruturaFormulario_PESSOA, values);
Atualizar um outro formulário através do método SaveEntityAsync
* Para cadastrar valores numéricos, o números devem estar no formato com ponto no separador decimal: 999999.99 sem utilização de virgulas.
//guarda em uma variável o ID da E S T R U T U R A do formulário de pessoa
var idEstruturaFormulario_PESSOA = Guid.Parse("0b56b66a-4f6f-4ded-ad04-016d7c0724e1");
var values = new DataDictionary();
values.Add("id", "33f6bdf8-26d9-42b9-94ae-ad44c62725b5"); //insere aqui o ID do registro que você deseja atualizar
values.Add("nome", FormContext.GetValue("nome"));
values.Add("email", FormContext.GetValue("email"));
//salva a informação no banco de dados
await FormContext.SaveEntityAsync(idEstruturaFormulario_PESSOA, values);
Caso você queira atualizar informações do próprio formulário que está sendo salvo, utilize a função SetValue, descrita mais acima nos métodos da Classe FormContext
Aprovar um outro formulário através do método ApproveEntityAsync
* Para cadastrar valores numéricos, o números devem estar no formato com ponto no separador decimal: 999999.99 sem utilização de virgulas.
//guarda em uma variável o ID da E S T R U T U R A do formulário de pessoa
var idEstruturaFormulario_PESSOA = Guid.Parse("0b56b66a-4f6f-4ded-ad04-016d7c0724e1");
var values = new DataDictionary();
values.Add("nome", FormContext.GetValue("nome"));
values.Add("email", FormContext.GetValue("email"));
//salva a informação no banco de dados
await FormContext.ApproveEntityAsync(idEstruturaFormulario_PESSOA, values);
Salvando um outro formulário com Tabela Associativa através do método SaveEntityAsync
* Para cadastrar valores numéricos, o números devem estar no formato com ponto no separador decimal: 999999.99 sem utilização de virgulas.
//guarda em uma variável o ID da E S T R U T U R A do formulário de pessoa
var idEstruturaFormulario_PESSOA = Guid.Parse("0b56b66a-4f6f-4ded-ad04-016d7c0724e1");
var values = new DataDictionary();
values.Add("nome", json["nome"].ToString());
values.Add("email", json["email"].ToString());
//no caso do campo do formulário ser uma tabela associativa (tabela relacional N:N)
var idCampoTabelaAssociativa = "70b6f362-2587-4fd2-a2fb-148bd0caf437";
//itens da tabela associativa que serão adicionados
var idItem1 = "51cf02f1-3787-4dca-8a2c-e219a5ce1298";
var idItem2 = "f999f103-c775-4245-92d3-034cb3ded5e4";
var idItem3 = "XXXXf103-c775-4245-92d3-034cb3ded5e4";
var idItem4 = "YYYYf103-c775-4245-92d3-034cb3ded5e4";
var idsJuntos_ConcatenadosComVirgula = idItem1 + "," + idItem2 + "," + idItem3 + "," + idItem4 + ",";
//adiciona
values.Add(idCampoTabelaAssociativa, idItem1); //adiciona idItem1
values.Add(idCampoTabelaAssociativa, idItem2); //adiciona idItem2
values.Add(idCampoTabelaAssociativa, idItem3); //adiciona idItem3
values.Add(idCampoTabelaAssociativa, idItem4); //adiciona idItem4
values.Add("tabela_associativa_added-"+idCampoTabelaAssociativa,idsJuntos_ConcatenadosComVirgula);// itens concatenados com virgula
values.Add("tabela_associativa_removed-"+idCampoTabelaAssociativa,"");//em branco
values.Add("tabela_associativa_colunas_adicionais-"+idCampoTabelaAssociativa,"");//em branco
//---------------------------------------
//salva a informação no banco de dados
await FormContext.SaveEntityAsync(idEstruturaFormulario_PESSOA, values);
Para recuperar o Texto de um campo que seja uma Lista Dinâmica (Combo, Auto completar, Múltipla seleção, Radio):
Suponhamos que você tenha um formulário de Pedido e nesse formulário você tenha um campo chamado 'Produto'.
Esse campo é do tipo 'Pesquisa com Auto Completar' e listará os 'Produtos' por 'Nome'.
Quando o usuário salvar o formulário, no Json de envio não retornará o Nome do Produto, apenas o Id do produto selecionado (Esse id estará no formato de um GUID).
Para recuperar o Nome do produto, você precisará executar o método GetText da seguinte forma:
var nomeProduto = FormContext.GetText("produto");
Recuperar os valores das "Variáveis de Ambiente"
Para saber mais sobre variáveis de ambiente entre em Variáveis de ambiente
var valorDaVariavel = FormContext.GetEnvironmentVariable("var_nomeDaVariavel");
Recuperar a Descrição (texto), no caso de variáveis do Tipo "Query com Id + Descrição":
var textDaVariavel = FormContext.GetEnvironmentVariable_Text("var_nomeDaVariavel");
Enviar Mensagem para o usuário: A execução do código abaixo apresentará uma mensagem para o usuário
FormContext.WarningMessage("Exemplo de mensagem para o usuário");
O código C# se encerrará no exato momento em que for chamado o método para apresentação de mensagem.
Retorno da mensagem
Envio de e-mail
Responsável pelo envio de e-mail
| Método | Retorno | |
| EmailSender.SendToGrupoUsuario(Guid grupoUsuarioId, string subject, string htmlContent) | void | Enviar um e-mail para um determinado Grupo de Usuario |
| EmailSender.SendEmail(string toEmail, string subject, string htmlContent) | void | Enviar um e-mail |
| EmailSender.SendEmail(string toEmail, string subject, string htmlContent, string ccEmail) | void | Enviar um e-mail, com copia (CC) |
Enviar e-mail para um Grupo de Usuário
Antes de iniciar, crie um "Grupo de Usuário" no menu "Segurança e Acesso". Depois de criado, associe os usuários que receberão e-mail ao novo grupo de usuário que você acabou de criar.
Pegue o ID desse novo Grupo de usuário. Você vai precisar dele para enviar o e-mail.
var grupoUsuarioId = Guid.Parse("af7c9275-0e23-4b64-a433-f238bb457005"); //substitua o ID "af7c9275-0e23-4b64-a433-f238bb457005" pelo Id do grupo de usuario que você deseja enviar o e-mail
var assunto = "Novo E-mail para um Grupo de usuario ";
var html = "Olá Grupo, <BR><BR> Teste para envio de e-mail para um Grupo de Usuário no AgilityFlow!";
EmailSender.SendToGrupoUsuario(grupoUsuarioId, assunto, html);
Enviar e-mail
var htmlContent = "<strong>Olá,</strong> teste envio de e-mail.";
var emailTo = "john@email.com";
var subject = "Subject do E-mail";
EmailSender.SendEmail(emailTo, subject, htmlContent);
Programação em C# - Na API de integração (POST)
As informações descritas abaixo referem-se as APIs de POST
IMPORTANTE: as variáveis e métodos descritos aqui só funcionarão na programação C# na API de integração. Para a programação C# nas Regras de Negócio de um formulário clique aqui
O agilityflow permite a customização da API em C#, além de já disponibilizar diversas bibliotecas e funções para facilitar sua programação, incluindo acesso a dados, validações, envio de e-mail, notificação, entre outras.
Para cada requisição na API é criada uma transação de banco de dados, essa transação é única em toda execução da API e é gerenciada automaticamente pelo Agilityflow, caso você prefira, você pode fazer esse gerenciamento seguindo esses passos, veja mais detalhes aqui
Abaixo mostramos alguns exemplos, se o material abaixo não for suficiente , entre em contato com nossa equipe.
Variáveis disponíveis
| Variável | Tipo | |
| content | string |
Conteúdo enviado no Body da API
No caso se ser enviado uma string com o JSON, por exemplo no formato: { nome: 'José', email: 'jose@xxxx.com'} Você pode converter essa string para JSON e utilizá-la como object
|
Classe JsonHelper e outras para auxiliar o tratamento de JSON
Para utilizar execute JsonHelper.NomeDoMetodo(....)
| Método | Retorno | |
| HasProperty(dynamic json, string nomePropriedade) |
bool (true or false) |
Testa se o JSON tem uma determinada propriedade. Por exemplo, a sua API espera receber o JSON no formato: { nome: 'José', email: 'jose@xxxx.com'}
Porém recebe o JSON formato: { nomecompleto: 'José da Silva', idade: '21'}
Como a propriedade NOME e EMAIL não existem no JSON recebido, o seu programa pode dar erro. Para evitar o erro, utilize o método HasProperty(...) Como no exemplo abaixo:
|
Newtonsoft.Json.JsonConvert.DeserializeObject<dynamic>(content); |
dynamic |
converte o conteúdo string para json
|
Métodos Disponíveis no contexto da API
| Método | Retorno | |
| await ApiContext.GetDataTableAsync(string sql, params DbParameter[] parameters) | DataTable |
Recuperar informações dos bancos de dados através de uma query sql. |
| await ApiContext.SaveEntityAsync(Guid estruturaformularioid_ASerCriadoOuAtualizado, DataDictionary campos_e_valores) | Guid |
Salva as informações de um formulário no bancos de dados.
Obs: Para cadastrar valores numéricos, o números devem estar no formato com ponto no separador decimal: 999999.99 sem utilização de virgulas. Caso seja necessário, utilizar o .ToString() para formatar um campo decimal, não use. Utilize a conversão usando o string.Format, como no exemplo abaixo:
|
| await ApiContext.ApproveEntityAsync(Guid estruturaformularioid_ASerAprovado, DataDictionary campos_e_valores) | Guid |
Avança uma etapa em um formulário com Workflow. As regras de usuário aprovador, permissão de aprovação e responsabilidade por uma etapa devem ser validadas antes desse método ser executado.
Obs: Para cadastrar valores numéricos, o números devem estar no formato com ponto no separador decimal: 999999.99 sem utilização de virgulas. Caso seja necessário, utilizar o .ToString() para formatar um campo decimal, não use. Utilize a conversão usando o string.Format, como no exemplo abaixo:
|
| await ApiContext.DeleteEntityAsync(Guid formularioId) | void |
deletar um formulario |
|
ApiContext.GetEnvironmentVariable(string nomeVariavel) ou ApiContext.GetEnvironmentVariable_Text(string nomeVariavel) ** |
string |
Recupera o Valor de uma variável de ambiente.
** Recupera a Descrição (texto), no caso de variáveis do Tipo "Que |
|
await ApiContext.LogAsync(string log, string logTipo) |
void |
Cria um log na tabela de log geral, o log pode ser consultado entrando na Área de Customização e clicando na opção "Log Geral >> consultar Log"
** Além do Log Padrão da API que o sistema gera, você pode gerar esses Logs customizados para o seu próprio controle.
|
|
await ApiContext.DbTransaction_BeginTransactionAsync()
await ApiContext.DbTransaction_CommitAsync()
await ApiContext.DbTransaction_RollbackAsync()
|
void |
Para gerenciar a transação de banco de dados manualmente. Leia os detalhes aqui mais abaixo
|
|
ApiContext.GetUrlBase() |
void |
Retorna a URL base da sua aplicação exemplo:
https://suaempresa.agilityflow.io/
*A url sempre virá com uma barra no final / |
Recuperando dados do banco de dados através de uma query SQL
//parametros da query
var paramsQuery = new List<SqlParameter>();
paramsQuery.Add(new SqlParameter("@param1", "xxx"));
paramsQuery.Add(new SqlParameter("@param2", "yyy"));
paramsQuery.Add(new SqlParameter("@param3", "zzz"));
//query usando (nolock) nas tabelas para evitar problema com a transação que está ativa
var sql = "select column1,column2,column3 from table (nolock) where column1 = @param1 or column2 = @param2 or column3 = @param3 ";
//executar no banco de dados
var dt = await ApiContext.GetDataTableAsync(sql, paramsQuery.ToArray());
//percorrendo as linhas de retorno da tabela
foreach (DataRow dr in dt.Rows)
{
if (dr["column1"] != DBNull.Value){
var xx = dr["column1"].ToString();
}
}
Salvando os dados recebidos através do método SaveEntityAsync
* Para cadastrar valores numéricos, o números devem estar no formato com ponto no separador decimal: 999999.99 sem utilização de virgulas.
public void Execute(){
//opcional para registrar no log de controle
await ApiContext.LogAsync("Entrou da API", "log_api_xpto");
//converte o conteúdo enviado no body da API para JSON
var json = Newtonsoft.Json.JsonConvert.DeserializeObject<dynamic>(content);
//guarda em uma variável o ID da E S T R U T U R A do formulário de pessoa
var idEstruturaFormulario_PESSOA = Guid.Parse("0b56b66a-4f6f-4ded-ad04-016d7c0724e1");
if (json != null)
{
//verifica se o JSON recebido contém a propriedade "nome", "email" e "cel" que são necessários p cadastro
if (JsonHelper.HasProperty(json, "nome") && JsonHelper.HasProperty(json, "email") && JsonHelper.HasProperty(json, "perfil")){
var values = new DataDictionary();
values.Add("nome", json["nome"].ToString());
values.Add("email", json["email"].ToString());
//no caso do campo do formulário ser uma tabela associativa (tabela relacional N:N)
var idCampoTabelaAssociativa = "70b6f362-2587-4fd2-a2fb-148bd0caf437";
if (json["perfil"].ToString() == "todos_os_perfis" ) {
var idPerfilAdmin = "51cf02f1-3787-4dca-8a2c-e219a5ce1298";
var idPerfilColaborador = "f999f103-c775-4245-92d3-034cb3ded5e4";
var idPerfisConcatenadosComVirgula = idPerfilAdmin + "," + idPerfilColaborador + ",";
//adiciona os perfis
values.Add(idCampoTabelaAssociativa, idPerfilAdmin); //adiciona perfil de admin
values.Add(idCampoTabelaAssociativa, idPerfilColaborador); //adiciona perfil de colaborador
values.Add("tabela_associativa_added-"+idCampoTabelaAssociativa,idPerfisConcatenadosComVirgula);// perfis concatenados com virgula
values.Add("tabela_associativa_removed-"+idCampoTabelaAssociativa,"");//em branco, se fosse pra remover, era só colocar os perfis concatenados com virgula
//---------------------------------------
}
else if (json["perfil"].ToString() == "apenas_colaborador" ) {
var idPerfilColaborador = "f999f103-c775-4245-92d3-034cb3ded5e4";
var idPerfilConcatenadoComVirgula = idPerfilColaborador + ",";
//adiciona o perfil
values.Add(idCampoTabelaAssociativa, idPerfilColaborador); //adiciona perfil de colaborador
values.Add("tabela_associativa_added-"+idCampoTabelaAssociativa,idPerfilConcatenadoComVirgula);// perfis concatenados com virgula
values.Add("tabela_associativa_removed-"+idCampoTabelaAssociativa,"");//em branco, se fosse pra remover, era só colocar os perfis concatenados com virgula
//---------------------------------------
}
//salva a informação no banco de dados
await ApiContext.SaveEntityAsync(idEstruturaFormulario_PESSOA, values);
}
}
//opcional para registrar no log de controle
await ApiContext.LogAsync("Saiu da API", "log_api_xpto");
}
Aprovando uma etapa através do método ApproveEntityAsync
public void Execute(){
//opcional para registrar no log de controle
await ApiContext.LogAsync("Entrou da API", "log_api_xpto");
//converte o conteúdo enviado no body da API para JSON
var json = Newtonsoft.Json.JsonConvert.DeserializeObject<dynamic>(content);
//guarda em uma variável o ID da E S T R U T U R A do formulário de pessoa
var idEstruturaFormulario_PESSOA = Guid.Parse("0b56b66a-4f6f-4ded-ad04-016d7c0724e1");
if (json != null)
{
//verifica se o JSON recebido contém a propriedade "nome", "email" e "cel" que são necessários p cadastro
if (JsonHelper.HasProperty(json, "nome") && JsonHelper.HasProperty(json, "email") && JsonHelper.HasProperty(json, "perfil")){
var values = new DataDictionary();
values.Add("nome", json["nome"].ToString());
values.Add("email", json["email"].ToString());
values.Add("id", json["id"].ToString());
//no caso do campo do formulário ser uma tabela associativa (tabela relacional N:N)
var idCampoTabelaAssociativa = "70b6f362-2587-4fd2-a2fb-148bd0caf437";
if (json["perfil"].ToString() == "todos_os_perfis" ) {
var idPerfilAdmin = "51cf02f1-3787-4dca-8a2c-e219a5ce1298";
var idPerfilColaborador = "f999f103-c775-4245-92d3-034cb3ded5e4";
var idPerfisConcatenadosComVirgula = idPerfilAdmin + "," + idPerfilColaborador + ",";
//adiciona os perfis
values.Add(idCampoTabelaAssociativa, idPerfilAdmin); //adiciona perfil de admin
values.Add(idCampoTabelaAssociativa, idPerfilColaborador); //adiciona perfil de colaborador
values.Add("tabela_associativa_added-"+idCampoTabelaAssociativa,idPerfisConcatenadosComVirgula);// perfis concatenados com virgula
values.Add("tabela_associativa_removed-"+idCampoTabelaAssociativa,"");//em branco, se fosse pra remover, era só colocar os perfis concatenados com virgula
//---------------------------------------
}
else if (json["perfil"].ToString() == "apenas_colaborador" ) {
var idPerfilColaborador = "f999f103-c775-4245-92d3-034cb3ded5e4";
var idPerfilConcatenadoComVirgula = idPerfilColaborador + ",";
//adiciona o perfil
values.Add(idCampoTabelaAssociativa, idPerfilColaborador); //adiciona perfil de colaborador
values.Add("tabela_associativa_added-"+idCampoTabelaAssociativa,idPerfilConcatenadoComVirgula);// perfis concatenados com virgula
values.Add("tabela_associativa_removed-"+idCampoTabelaAssociativa,"");//em branco, se fosse pra remover, era só colocar os perfis concatenados com virgula
//---------------------------------------
}
//salva a informação no banco de dados
await ApiContext.ApproveEntityAsync(idEstruturaFormulario_PESSOA, values);
}
}
//opcional para registrar no log de controle
await ApiContext.LogAsync("saiu da API", "log_api_xpto");
}
Recuperar os valores das "Variáveis de Ambiente"
Para saber mais sobre variáveis de ambiente entre em Variáveis de ambiente
var valorDaVariavel = ApiContext.GetEnvironmentVariable("var_nomeDaVariavel");
Recuperar a Descrição (texto), no caso de variáveis do Tipo "Query com Id + Descrição":
var textDaVariavel = ApiContext.GetEnvironmentVariable_Text("var_nomeDaVariavel");
Envio de e-mail
Responsável pelo envio de e-mail
| Método | Retorno | |
| EmailSender.SendToGrupoUsuario(Guid grupoUsuarioId, string subject, string htmlContent) | void | Enviar um e-mail para um determinado Grupo de Usuario |
| EmailSender.SendEmail(string toEmail, string subject, string htmlContent) | void | Enviar um e-mail |
| EmailSender.SendEmail(string toEmail, string subject, string htmlContent, string ccEmail) | void | Enviar um e-mail, com copia (CC) |
Enviar e-mail para um Grupo de Usuário
Antes de iniciar, crie um "Grupo de Usuário" no menu "Segurança e Acesso". Depois de criado, associe os usuários que receberão e-mail ao novo grupo de usuário que você acabou de criar.
Pegue o ID desse novo Grupo de usuário. Você vai precisar dele para enviar o e-mail.
var grupoUsuarioId = Guid.Parse("af7c9275-0e23-4b64-a433-f238bb457005"); //substitua o ID "af7c9275-0e23-4b64-a433-f238bb457005" pelo Id do grupo de usuario que você deseja enviar o e-mail
var assunto = "Novo E-mail para um Grupo de usuario ";
var html = "Olá Grupo, <BR><BR> Teste para envio de e-mail para um Grupo de Usuário no AgilityFlow!";
EmailSender.SendToGrupoUsuario(grupoUsuarioId, assunto, html);
Enviar e-mail
var htmlContent = "<strong>Olá,</strong> teste envio de e-mail.";
var emailTo = "john@email.com";
var subject = "Subject do E-mail";
EmailSender.SendEmail(emailTo, subject, htmlContent);
Método principal para utilização da Programação em C# na api de post
A única regra é que o método se chame Execute, não tenha parâmetros de entrada e o retorno seja void.
Exemplo:
public void Execute(){
//aqui você pode programar
}
Gerenciar as transações de Banco de dados manualmente
Caso você escolha por gerenciar as transactions de banco de dados manualmente, você precisará obrigatoriamente utilizar as 3 funções abaixo:
Atenção: Configuração recomendada apenas para especialista.
- ApiContext.DbTransaction_BeginTransaction() Para abrir uma transação, antes de iniciar as alterações no banco de dados
- ApiContext.DbTransaction_Commit() Para finalizar e confirmar com sucesso as alterações no banco de dados
- ApiContext.DbTransaction_Rollback() Para finalizar e desfazer as alterações no banco de dados
Exemplo de uso:
Atenção: Utilize as transactions sempre dentro de TRY e CATCH
Podem ser abertas uma ou mais transações na mesma API. Você ficará responsável por todas as aberturas e encerramentos das transações criadas.
public async Task RunAsync(){
//converte o conteúdo enviado no body da API para JSON
var json = Newtonsoft.Json.JsonConvert.DeserializeObject<dynamic>(content);
//guarda em uma variável o ID da E S T R U T U R A do formulário de pessoa
var idEstruturaFormulario_PESSOA = Guid.Parse("0b56b66a-4f6f-4ded-ad04-016d7c0724e1");
try
{
await ApiContext.DbTransaction_BeginTransactionAsync(); //ABRE A TRANSAÇÃO, DENTRO DO TRY CATCH
var values = new DataDictionary();
values.Add("nome", "exemplo1_PRIMEIRA_transacao");
await ApiContext.SaveEntityAsync(idEstruturaFormulario_PESSOA, values); //salva a informação no banco de dados
await ApiContext.DbTransaction_CommitAsync(); //CONFIRMA A TRANSAÇÃO, DENTRO DO TRY CATCH
}
catch
{
await ApiContext.DbTransaction_RollbackAsync(); //DESFAZ A TRANSAÇÃO, DENTRO DO CATCH em caso de erro
throw;
}
//mais código
//...
//mais código
//...
//mais código
//...
//mais código
//...
try
{
await ApiContext.DbTransaction_BeginTransactionAsync(); //ABRE A TRANSAÇÃO, DENTRO DO TRY CATCH
var values2 = new DataDictionary();
values2.Add("nome", "exemplo2_SEGUNDA_transacao");
await ApiContext.SaveEntityAsync(idEstruturaFormulario_PESSOA, values2); //salva a informação no banco de dados
await ApiContext.DbTransaction_CommitAsync(); //CONFIRMA A TRANSAÇÃO, DENTRO DO TRY CATCH
}
catch
{
await ApiContext.DbTransaction_RollbackAsync(); //DESFAZ A TRANSAÇÃO, DENTRO DO CATCH em caso de erro
throw;
}
}
Tabela de dados customizada através de programação: Query SQL, C#, HTML e CSS
Para acessar os detalhes desse conteúdo, clique aqui.
Single Sign-On
Como configurar o Single Sign-On (SSO) utilizando o AD e o ADFS.
Configurar integração com o AD (Active Directory)
Você pode utilizar os seus usuários do Active Directory para login no agilityflow, assim o usuário de rede será único, e fará um single sign-on nas aplicações do agilityflow.
Para isso iremos fornecedor 2 scripts ASP clássico e você deve configura-los no seu servidor. Abaixo segue os procedimentos para essa instalação.
O script será hospedado no servidor IIS e terá acesso ao Active Directory para autenticar usuários no Agilityflow.
Se você quiser configurar o SSO usando o padrão universal SAML, consulte nesse link, sobre o uso do SAML no Agilityflow através do ADFS.
Recomendação importante: Após finalizar a configuração do AD no Agilityflow. Faça o teste em uma guia anônima do seu navegador antes de fazer o logout da sua sessão atual do Agilityflow. Assim você conseguirá fazer as mudanças necessárias no Agilityflow caso sua configuração não esteja correta. Caso você faça o logout, entre em contato conosco para auxiliarmos no passo a passo.
Pré-requisitos
- Uma instância do Active Directory instalada no seu servidor. Você pode seguir as etapas fornecidas neste artigo para configurar e instalar o AD no seu servidor
- Garantir que todos os usuários do AD tenham o atributo de endereço de e-mail preenchido. O Agilityflow utiliza o e-mail e o login do usuário como identificador para autenticação. Portanto, além do login, é necessário que o usuário tenha o endereço de e-mail preenchido no Active Directory.
Caso você receba do Agilityflow a mensagem “O usuário 'xxxx' não tem o e-mail cadastrado no AD. ”, verifique se o endereço de e-mail está configurado para esse usuário no Active Directory, se não estiver, fale com o seu administrador de rede. Abaixo estão descritos os procedimentos para configuração do e-mail do usuário no AD.
Para preencher o e-mail do usuário no AD: acesse o seu Active Directory, no painel esquerdo clique em Users, agora no painel da direita, clique com o botão direito no usuário que deseja alterar o e-mail, clique em "Properties" e no campo "E-mail" inclua o e-mail do usuário. As imagens abaixo ilustram esse passo a passo:
Selecione o usuário:

Altere o e-mail:

Clique em OK e o e-mail estará incluído nesse usuário.
Esse procedimento será necessário para todos os usuários que não estão com e-mail configurado no AD.
PASSO 1: Instalando o Internet Information Services (IIS)
O Internet Information Server (Gerenciador do IIS) deve ser configurado no seu Windows Server para hospedar o arquivo de script ASP Clássico, que acessará as informações do usuário no Active Directory.
O IIS Server deve estar instalado no mesmo domínio do Active Directory que contém os usuários.
Você pode seguir as etapas fornecidas neste artigo para instalar o IIS no Windows Server 2012. Escolha as opções a seguir ao instalar a função IIS no servidor.
-
Web Server (IIS)
-
Security
- Windows Authentication
-
Application Development
- ASP
-
Security
-
Management Tools
- IIS Management Console
Você precisa do Windows Authentication e também do ASP no seu servidor para hospedar e rodar o script ASP clássico que forneceremos a seguir e que será o responsável pelo login dos usuários do Active Directory no Agilityflow. Portanto, se você já instalou o IIS, verifique se esses recursos estão instalados.
PASSO 2: Editando o arquivo de script ASP clássico
1. Baixe os arquivos default.asp e config.asp que estão disponíveis na área de configuração do seu ambiente no agilityflow.
Os arquivos para download você encontra nesse link: https://<SEU_AMBIENTE>.agilityflow.io/configuration ou através do menu: Customizar Agilityflow → Single Sign-On, AD e ADFS. → depois na ABA: "Autenticação de usuário" → "AD" você encontrará o link para download.

2. Abra o arquivo config.asp e atribua esses valores às variáveis:
-
agilityflowUrl: url onde o seu sistema do agilityflow está hospedado, geralmente as aplicações ficam na url: https://<SEU_AMBIENTE>.agilityflow.io/ . é importante que a url termine com a barra /
- LDAP_UserName_WithAccessToReader: Nome de usuário da conta do AD que tem pelo menos privilégio de leitura para todos os usuários no AD. (preencha com no formato: "dominioDaMinhaEmpresa\usuarioadmin")
-
LDAP_UserPassword_WithAccessToReader: Senha dessa conta de usuário
- agilityflowADToken: token de segurança gerado pelo agilityflow que será o código de segurança com o seu AD. Esse token pode ser copiado através do menu: Customizar Agilityflow → Single Sign-On, AD e ADFS → depois na ABA: "Autenticação de usuário" → "AD" copiei do campo "Token"

Exemplo de preenchimento do arquivo config.asp
agilityflowUrl = "https://nomedaempresa.agilityflow.io"
LDAP_UserName_WithAccessToReader = "dominioDaMinhaEmpresa\usuarioadmin"
LDAP_UserPassword_WithAccessToReader = "xxxxxxxxxx"
agilityflowADToken = "xxxxxxxxxxxxxxxxxxxxxxxxxx"
PASSO 3: Configurando o script ASP no IIS
- Crie um website ou um application dentro do seu website padrão no IIS. Para criar um novo website no IIS, consulte a seção Criar um novo website neste artigo.
- Clique no website e clique duas vezes em ASP no painel direito. Defina a opção Enable Parent Paths para true.

- Clique no website novamente e clique duas vezes em Authentication. Clique com o botão direito do mouse em Windows Authentication e clique em Enable. Desative todos os outros tipos de autenticação. O IIS usará a autenticação integrada do Windows (Integrated Windows Authentication). Para tornar isso possível, o IIS Server deve ser instalado no domínio do Active Directory que contém os usuários.
- Agora clique com o botão direito do mouse no website, clique em Explore e cole os 2 arquivos - default.asp e config.asp que já estão configurados.
PASSO 4: Configurar o Single Sign-on no Agilityflow

Pronto, agora abra uma guia anônima do seu navegador e tente realizar o login no agilityflow.
Se você enfrentar algum problema durante a configuração, entre em contato conosco.
Pronto, as configurações foram finalizadas.
Recomendação importante: Após finalizar a configuração do AD no Agilityflow. Faça o teste em uma guia anônima do seu navegador antes de fazer o logout da sua sessão atual do Agilityflow. Assim você conseguirá fazer as mudanças necessárias no Agilityflow caso sua configuração não esteja correta. Caso você faça o logout, entre em contato conosco para auxiliarmos no passo a passo.
Configurar integração com o ADFS (Active Directory Federation Services)
O agilityflow oferece suporte Single Sign-on (SSO) por meio do SAML 2.0. O ADFS é um serviço fornecido pela Microsoft como uma função padrão do Windows Server que fornece um login da Web usando as credenciais existentes do Active Directory.
Com essa configuração você pode utilizar os seus usuários do Active Directory para login no agilityflow, assim o usuário da rede será usado no single sign-on do agilityflow.
Recomendação importante: Após finalizar a configuração do ADFS no agilityflow. Faça o teste em uma guia anônima do seu navegador antes de fazer o logout da sua sessão atual do agilityflow. Assim você conseguirá fazer as mudanças necessárias no agilityflow caso sua configuração não esteja correta. Caso você faça o logout, entre em contato conosco para auxiliarmos no passo a passo.
Pré-requisitos
- Uma instância do Active Directory instalada no seu servidor. Você pode seguir as etapas fornecidas neste artigo para configurar e instalar o AD no seu servidor.
- Uma instância do ADFS instalada no seu servidor. Você pode seguir as etapas fornecidas neste artigo para configurar e instalar o ADFS no seu servidor
- Garantir que todos os usuários do AD tenham o atributo de endereço de e-mail preenchido. O agilityflow utiliza o e-mail e o login do usuário como identificador para autenticação. Portanto, além do login, é necessário que o usuário tenha o endereço de e-mail preenchido no Active Directory.
Então, caso você receba do agilityflow a mensagem “O usuário 'xxxx' não tem o e-mail cadastrado no AD. ”, verifique se o endereço de e-mail está configurado para esse usuário no Active Directory, se não estiver, fale com o seu administrador de rede. Abaixo estão descritos os procedimentos para configuração do e-mail do usuário no AD.
Para preencher o e-mail do usuário no AD: acesse o seu Active Directory, no painel esquerdo clique em Users, agora no painel da direita, clique com o botão direito no usuário que deseja alterar o e-mail, clique em "Properties" e no campo "E-mail" inclua o e-mail do usuário. As imagens abaixo ilustram esse passo a passo:
Selecione o usuário:

Altere o e-mail:

Clique em OK e o e-mail estará incluído nesse usuário.
Esse procedimento será necessário para todos os usuários que não estão com e-mail configurado no AD.
PASSO 1: Configurar o ADFS
Neste ponto, você deve estar pronto para configurar a conexão do ADFS com sua conta do agilityflow. A conexão entre o ADFS e o agilityflow é definida usando um Relying Party Trust (RPT).
Abra o AD FS Management, no menu da esquerda, abra a guia Trust Relationships, clique com o botão direito em Relying Party Trusts e então clique em Add Relying Party Trust

1. Isso inicia o assistente de configuração do Relying Party Trust. Clique em Start.

2. No passo Select Data Source, selecione a última opção: Enter Data About the Party Manually.

3. No passo Specify Display Name, insira um nome para esse Relying Party Trust. Informe o nome agilityflow.

4. No passo Choose Profile, mantenha a opção ADFS FS profile

5. No passo Configure Certificate, mantenha as configurações da forma que estão e clique em Next.

6. No passo Configure URL, marque a opção Enable support for the SAML 2.0 WebSSO protocol e em Relying party SAML 2.0 SSO service URL informe https://<SEU_AMBIENTE>.agilityflow.io/adfs/
7. No passo Configure identifiers informe https://<SEU_AMBIENTE>.agilityflow.io/adfs/ em Relying party trust identifier e clique em Add, na sequencia, clique em Next.
8. No passo Configure Multi-factor Authentication Now?, mantenha as configurações da forma que estão e clique em Next.

9. No passo Choose Issuance Authorization Rules, mantenha a opção Permit all users to access the relying party marcada e clique em Next.

10. No passo Ready to Add Trust, mantenha as configurações da forma que estão e clique em Next.

11. No passo Finish, mantenha marcada a opção Open the Edit Claim Rules dialog for this relying party trust when the wizard closes e clique em Close;

12. Na nova janela que abrirá, clique em Add rule

13. No passo Choose Rule Type, no campo Claim rule Template selecione a opção Send LDAP Attributes as Claims e clique em Next.

14. No passo Configura Claim Rule preencha da seguinte forma:
Em Claim rule name informe "LDAP E-mail, Username". Em Attribute store selecione Active Directory. Na tabela Mapping of LDAP attributes to outgoing claim types preencha da seguinte forma:
| LDAP Attribute | Outgoing claim type |
| SAM-Account-Name | Name ID |
| E-Mail-Addresses | E-Mail Address |
Depois clique em Finish e OK

15. Depois de confirmar e fechar o Claim Rules dialog, Vá até a lista de Relying Party Trusts e clique com o botão direito em agilityflow e selecione a opção Properties.

16. Na aba Advanced, selecione SHA-256 no campo Secure hash algorithm.

17. Na aba Endpoints, clique em Add SAML para adicionar um novo endpoint
18. Na nova janela que abrirá chamada Add an Endpoints, preencha os campos da seguinte forma:
- Em Endpoint type escolha SAML Logout
- Em Binding mantenha a opção POST
- Em Trusted URL informe a URL concatenando as seguintes informações
1. O endereço da web do seu servidor ADFS, exemplo: "https://www.seudominio.com"
2. O endpoint SAML configurado no ADFS. Por padrão (se você não alterou essa configuração) será: "/adfs/ls"
3. E por fim, concatene os parâmetros "?wa=wsignout1.0"
A sua url final deverá ficar parecida com essa : https://www.seudominio.com/adfs/ls?wa=wsignout1.0
Após isto, clique em OK;

19. Isto conclui a configuração do ADFS, clique em Apply e depois em OK;
PASSO 2: Configurar o Single Sign-on no agilityflow
Recomendação importante: Após finalizar a configuração do ADFS no agilityflow. Faça o teste em uma guia anônima do seu navegador antes de fazer o logout da sua sessão atual do agilityflow. Assim você conseguirá fazer as mudanças necessárias no agilityflow caso sua configuração não esteja correta. Caso você faça o logout, entre em contato conosco para auxiliarmos no passo a passo.
Acesse via browser a sua instância do agilityflow.
Salve e pronto, as configurações foram finalizadas.
Se você enfrentar algum problema durante a configuração, entre em contato conosco.
Recomendação importante: Após finalizar a configuração do ADFS no agilityflow. Faça o teste em uma guia anônima do seu navegador antes de fazer o logout da sua sessão atual do agilityflow. Assim você conseguirá fazer as mudanças necessárias no agilityflow caso sua configuração não esteja correta. Caso você faça o logout, entre em contato conosco para auxiliarmos no passo a passo.
Outras Dicas
Buscar o CEP nos Correios e preencher os campos de endereço automaticamente
Para facilitar o preenchimento dos campos de endereço é possível configurar para que o campo de CEP dispare uma consulta na base dos Correios e preencha os campos de endereço.
Informações que são possíveis preencher automaticamente através do CEP:
- Rua,
- Bairro,
- Cidade,
- Estado,
- Sigla do Estado,
- DDD da região,
- Número De - Até (Intervalo numérico da região)
Configuração:
2. Na área de customização, edite o formulário que deseja configurar a busca pelo CEP
3. Já dentro do formulário acesse a área de customização em Javascript, como na imagem abaixo
4. Cole a função Javascript e altere apenas os parâmetros que estão em amarelo no código abaixo. Na tabela um pouco mais abaixo os parâmetros estão descritos com mais detalhes
formContext.buscaCEP.configurar(
'id_campo_cep',
{
uf_sigla: 'id_do_campo_uf_sigla',
uf_nome: 'id_do_campo_uf_nome',
logradouro: 'id_do_campo_logradouro',
bairro: 'id_do_campo_bairro',
cidade: 'id_do_campo_cidade',
numero_de_ate: 'id_do_campo_numero_de_ate',
ddd_da_regiao: 'id_do_campo_ddd_da_regiao'
}
);
Parâmetros da função
| Parametro | Retorno de exemplo | ||
| "id_campo_cep" | obrigatório | Esse é o campo principal, troque esse parâmetro pelo id do campo que será digitado o CEP | |
| uf_sigla | pode estar em branco |
Troque esse parâmetro pelo id do campo que deve ser preenchido a SIGLA do Estado |
SP |
| uf_nome | pode estar em branco | Troque esse parâmetro pelo id do campo que deve ser preenchido com o nome completo do Estado | São Paulo |
| logradouro | pode estar em branco | Troque esse parâmetro pelo id do campo que deve ser preenchido com o Logradouro (Avenida, Rua etc..) | Avenida Paulista |
| bairro | pode estar em branco | Troque esse parâmetro pelo id do campo que deve ser preenchido com o Bairro | Bela Vista |
| cidade | pode estar em branco | Troque esse parâmetro pelo id do campo que deve ser preenchido com a Cidade | São Paulo |
| numero_de_ate | pode estar em branco |
Troque esse parâmetro pelo id do campo que deve ser preenchido com a Número Importante: esse campo não deve ter máscara numérica, pois ele retorna um intervalo De XXX até YYY |
de 1047 a 1865 - lado ímpar |
| ddd_da_regiao | pode estar em branco | Troque esse parâmetro pelo id do campo que deve ser preenchido com o DDD da região, por exemplo, no caso de São Paulo, ele retornará 11 | 11 |
5. Publique o seu formulário e teste.
Pronto, já deve estar funcionando.
Callbacks para customização avançada:
Existem 3 callbacks que você pode chamar no Javascript:
- callback_before - Antes de fazer a busca -
- callback_onSucess - No sucesso do retorno
- callback_onError - No Erro da busca
Abaixo está o exemplo do código que você pode utilizar
formContext.buscaCEP.configurar(
'id_campo_cep',
{
uf_sigla: 'id_do_campo_uf_sigla',
uf_nome: 'id_do_campo_uf_nome',
logradouro: 'id_do_campo_logradouro',
bairro: 'id_do_campo_bairro',
cidade: 'id_do_campo_cidade',
numero_de_ate: 'id_do_campo_numero_de_ate',
ddd_da_regiao: 'id_do_campo_ddd_da_regiao'
},
{
callback_before: function() {
alert('before')
},
callback_onSucess: function (dados) {
alert('callback_onSucess')
console.log(dados)
},
callback_onError: function () {
alert('error')
}
}
);
Ficou alguma dúvida ? Fale com a gente
Automatizar a criação de tarefas em um Quadro de Tarefas ao salvar um formulário
O agilityflow através de sua Regras de Negócios pré-definidas, consegue te ajudar na automatização de processos.
No vídeo abaixo apresentamos como criar uma tarefa em um quadro, com data de entrega e responsável ao salvar um formulário.
Problema de acentuação no retorno de um CSHtml que é usado com Javacript
Em algumas situações será necessário tratar caso a caso a acentuação de textos no CSHTML.
Para isso utilize a função nativa do .NET (C#):
Html.Raw(...)
Exemplo de uso, imaginamos que toda vez que o usuário entrar em um formulário a descrição do produto seja apresentado em um alert em javascript:
Para isso, criamos um cshtml, e adicionamos no formulário com o seguinte código.
@{
/*
* FUNÇÃO EM C# PARA BUSCAR A DESCRIÇÃO NO BANCO DE DADOS
*/
var id_produto = Model.FormularioCamposPreenchidos["produto"];
var descricao = "";
if(id_produto != null && id_produto.ToString() != string.Empty){
var query = @"select isnull(p.descricao,'') descricao from x_tbl_produtos p where p.deletado = 0 and p.id = '"+id_produto+"' ";
var dt = await PageContext.GetDataTableAsync(query);
if(dt.Rows.Count > 0)
{
var dr = dt.Rows[0];
descricao = dr["descricao"].ToString().Replace("'","");
}
}
/*
* ABAIXO ESTÁ A FUNÇÃO EM JAVASCRIPT APRESENTAR A DESCRIÇÃO EM UM ALERT
*/
}
<script>
DOM.ready(function () {
//nesse momento eu quero apresenta um alert com a descrição do produto, para garantir que a acentuação esteja correta, utilizo Html.Raw
alert('@Html.Raw(descricao)');
});
</script>
Database Performance
SQL Server - Performance / Index
Help about order by index:
Nonclustered Indexa
Sincronizaçao de Contatos com a sua conta no Google
Sincronização de Contatos no AgilityFlow com o Google Contatos
O AgilityFlow oferece uma funcionalidade avançada que permite aos usuários realizar a sincronização de seus contatos de forma prática e eficiente com o Google Contatos. Essa integração simplifica o gerenciamento de informações de contatos, proporcionando uma experiência mais fluída e organizada para os usuários.
Como funciona a integração com o Google Contatos no AgilityFlow:
-
Acesso à Configuração: Ao acessar as configurações do AgilityFlow, os usuários encontrarão a opção de integração com o Google Contatos. Essa seção é projetada para ser intuitiva, facilitando a configuração da sincronização.
-
Autorização do Google: Para iniciar o processo de integração, será necessário conceder permissões ao AgilityFlow para acessar os contatos no Google. Ao clicar na opção de sincronização, os usuários serão redirecionados para a tela de consentimento do Google.
Tela de Consentimento: Nessa tela, o usuário verá uma descrição clara das permissões que o AgilityFlow solicita para realizar a sincronização de contatos. Isso pode incluir acesso básico a informações de contatos, como nomes e endereços de e-mail. O usuário deve revisar essas permissões e, se concordar, autorizar a integração.
-
Configuração de Sincronização: Após a autorização, os usuários podem personalizar as configurações de sincronização de contatos. Isso pode incluir opções para escolher grupos específicos de contatos a serem sincronizados, definir a frequência da sincronização automática, e outras preferências personalizadas.
-
Sincronização Automática e Manual: Uma vez configurada, a sincronização pode ocorrer automaticamente em intervalos definidos ou ser iniciada manualmente pelos usuários. Isso garante flexibilidade para atender às necessidades individuais de cada usuário.
Essa integração simplificada com o Google Contatos no AgilityFlow proporciona uma gestão eficiente dos contatos, eliminando a necessidade de atualizações manuais e oferecendo uma visão unificada e atualizada de todas as informações de contato. A interface amigável e a transparência no processo de consentimento garantem uma experiência de usuário segura e descomplicada.
Importante: o agilityflow não remove nenhum contato da sua lista do Google Contatos e não atualiza nenhum contato que não tenha sido gerado pela nossa base de dado
Bulk Update - Atualização de dados em Massa
Com o exemplo abaixo é possível atualizar varios dados de um ou mais forms com apenas 1 clique.
Criar um form com as informações que estarão no Where do Bulk Update e também os campos que deverão ser atualizados.
Exemplo:
Criar uma regra de negócio ao "Salvar" da seguinte forma:
Abaixo está o código C# para colocar no item de programação da Regra de Negócio(acima) responsável por executar o Bulk Update (Atualização em massa):
IMPORTANTÍSSIMO: os scripts do SqlScript, atualizam o registro na RAIZ, isso é, direto no banco de dados, sendo assim, não executa nenhuma trigger, regra de negocio, controle de alteração, log de alteração etc.. que esteja vinculado(a) aos dados que estão sendo atualizados. TENHA CUIDADO.
ATENÇÃO: as informações dos formulários são sempre gravados em 2 tabelas. (1) tbl_formulario e (2) a tabela "oficial" de cada estrutura de formulário, então é OBRIGATÓRIO, atualizar os dados nas 2 estruturas conforme exemplo abaixo. Na tbl_formulario é criado um JSON com todos os dados, então o que vc precisa atualizar é a propriedade dentro do json do formulario que fica na coluna tbl_formulario frm_json (o exemplo abaixo mostra como fazer essa atualização)
public async Task ExecuteAsync()
{
var where_status = FormContext.GetValue("where_status");
var organization = FormContext.GetValue("organization");
var update_to_status = FormContext.GetValue("update_to_status");
var update_to_substatus = FormContext.GetValue("update_to_substatus");
/*
* O AgilityFlow grava todas as informações em JSON na tabela TBL_FORMULARIO
* e também grava na tabela única da entidade.
* Para fazer o bulk update, é necessário atualizar as 2 tabelas.
* Importante também registrar que esse procedimento não executará nenhuma regra de negócio da aplicação.
*/
// SQL update para atualizar o JSON na tbl_formulario
var sql_tbl_form = @$"
UPDATE tbl_formulario
SET frm_json = jsonb_set(
jsonb_set(frm_json::jsonb, '{{status}}', to_jsonb(@update_to_status)),
'{{sub_status}}', to_jsonb(@update_to_substatus)
)
WHERE frm_id IN (
SELECT id FROM x_tbl_message_queue
WHERE organization = @organization
AND status = @where_status
);";
// SQL update para atualizar na tabela única da entidade
var sql_tbl_message = @$"
UPDATE x_tbl_message_queue
SET status = @update_to_status, sub_status = @update_to_substatus
WHERE organization = @organization
AND status = @where_status;";
var sql = $"{sql_tbl_form} {sql_tbl_message}";
// Criando os parâmetros explicitamente
var parameters = new DbParameter[]
{
new NpgsqlParameter("@update_to_status", update_to_status),
new NpgsqlParameter("@update_to_substatus", update_to_substatus),
new NpgsqlParameter("@organization", organization),
new NpgsqlParameter("@where_status", where_status)
};
await FormContext.SqlScript.ExecuteAsync(sql, parameters);
}
Timezone (Fuso Horario do sistema)
A plataforma pode ser configurada para visualizar as horas em qualquer Timezone
O servidor está configurado SEMPRE para UTC.
O banco de dados grava todas as informações SEMPRE como UTC.
A plataforma pode ser configurada para visualizar as horas em qualquer Timezone (a nível de tenant).
Cada usuario pode ter o seu próprio Timezone para visualizaão dos dados e a plataforma também terá um timezone padrão.
Por exemplo. Se sua equipe está em São Paulo - Brasil e outra em NY - Estados Unidos, vc pode configurar uma timezone padrão para a plataforma, exemplo, America/Sao_Paulo e também pode configurar para que cada usuario visualize a hora de acordo com sua localidade. Independente da forma que visualizará a informação será salva no banco de dados como UTC.
Importante dizer é que no C#, em caso de uso do DateTime.Now ou derivados. A data sempre estará em UTC. Para converter, use a extensão .ToUserTimeZone
Exemplo:
//exemplo: retorna 22/07/2024 22:37:00
var utcDate = DateTime.Now;
//exemplo: caso o TimeZone do user seja America/Sao_Paulo (-3) retornaria 22/07/2024 19:37:00
var userTimezoneDate = DateTime.Now.ToUserTimeZone();
Api e Api User
Nas execuções de API sempre prevalecerá o Timezone definido no momento do cadastrado no User API
Em caso de Api, você pode definir o Timezone da execução no cadastro do Usuario de API, será esse timezone que o sistema considerará ao executar uma API
Acesse o Cadastro de Usuário de Api (Api User) e defina o timezone como na imagem abaixo:
Programação na API com C# (Custom code)
Na Api C#, em caso de uso do DateTime.Now ou derivados. A data sempre estará em UTC. Para converter para a Timezone do User que está executando a API, utilize a extensão .ToUserTimeZone como no exemplo abaixo.
//exemplo: retorna 22/07/2024 22:37:00
var utcDate = DateTime.Now;
//exemplo: caso o TimeZone do user seja America/Sao_Paulo (-3) retornaria 22/07/2024 19:37:00
var userTimezoneDate = DateTime.Now.ToUserTimeZone();
No método C# ApiContext.SaveEntityAsync, o sistema automaticamente irá converter as datas recebidas por parametro para UTC no momento de salvar no banco de dados, então é importante que a API receba a data no Timezone definido nas configurações do Usuário de API. Exemplo:
Se vc tem uma entidaide chamada Tarefa, e nessa tarefa você tem um campo de Data de entrega que vc gostaria que fosse a data 27/12/2024 23:55:55 no horario de São Paulo.
1. Você deve configurar o seu Usuario de API para ter o TimeZone de São Paulo.
2. Você deve mandar a data com o horario 27/12/2024 23:55:55
3. Você não deve se preocupar com a conversão para UTC ao salvar no banco de dados, pois a conversão será feita automaticamente pelo sistema.
Alterar via C# o valor de um campo ao salvar um formulário
Caso vc precise aplicar algumas regras como mudar o valor de um campo via C# ao salvar um formulário, você pode aplicar as seguintes regras:
Crie uma regra como na imagem abaixo
Dentro da regra, adicione uma opção de Programação via C# como na imagem abaixo
Esse é um código de exemplo:
// Declaração padrão do método assíncrono chamado ExecuteAsync
public async Task ExecuteAsync(){
// Verifica se NAO é um formulario novo
if(!IsNovoFormulario){
// Declaração de uma variável chamada new_sub_status e atribui a ela o valor enviado pelo usuario naquele momento
var new_sub_status = FormContext.GetValue("sub_status");
// Declaração de uma variável chamada old_sub_status e inicializa com uma string vazia que colocaremos a informação antiga que ja constava do banco de dados
var old_sub_status = "";
// Cria uma lista de parâmetros para a consulta SQL (Postgresql)
var paramsQuery = new List<NpgsqlParameter>();
// Adiciona um novo parâmetro NpgsqlParameter à lista com o nome "@frm_id" e o valor IdFormulario
paramsQuery.Add(new NpgsqlParameter("@frm_id", IdFormulario));
// Declaração de uma string contendo a consulta SQL
var sql = "select sub_status from x_tbl_message_queue_sub_status where id = @frm_id limit 1 ";
// Executa a consulta SQL de forma assíncrona e armazena o resultado em um DataTable
var dt = await FormContext.GetDataTableAsync(sql, paramsQuery.ToArray());
// Itera sobre as linhas do DataTable encontrada (sempre será 1, limit 1
foreach (DataRow dr in dt.Rows)
{
// Verifica se o valor da coluna "sub_status" não é DBNull
if (dr["sub_status"] != DBNull.Value)
// Atribui o valor da coluna "sub_status" à variável old_sub_status
old_sub_status = dr["sub_status"].ToString();
}
//criei aqui uma regrinha simples só pra demonstração:
// Verifica se old_sub_status termina com "1"
if(old_sub_status.EndsWith("1")){
// Define o valor de "sub_status" no FormContext com new_sub_status concatenado com " 2"
FormContext.SetValue("sub_status", new_sub_status + " 2");
}else{
// Define o valor de "sub_status" no FormContext com new_sub_status concatenado com " 1"
FormContext.SetValue("sub_status", new_sub_status + " 1");
}
} // Fim do bloco if
} // Fim do método ExecuteAsync
Alerta para o usuario ao salvar um formulário (usando c#)
Caso vc precise aplicar algumas regras como enviar uma msg de alerta para o usuario ao salvar um formulário, você pode aplicar as seguintes regras:
Ao enviar uma mensagem de Warning usando o FormContext.WarningMessage("Mensagem de exemplo") o sistema interrompe o salvamento
Crie uma regra como na imagem abaixo
Dentro da regra, adicione uma opção de Programação via C# como na imagem abaixo
public async Task ExecuteAsync(){
FormContext.WarningMessage("Mensagem de exemplo");
}
Erro: Can't write CLR type System.String with handler type UuidHandler
Alguns campos no Postgresql são do tipo UUID, como LIsta Dinamica, Autocomplete, Radio button, entre outros.
Se vc tentar enviar um valor em branco ou diferente de um UUID para esse tipo de campo pode aparecer essa mensagem.
Obrigatoriamente enviar um valor no formato UUID / GUID
Sugestão:
Se for por exemplo pra deixar um status em branco.
Cria um status "[em branco]" na tabela de relacionamento e usa o ID desse novo status para salvar no campo UUID
Evento javascript após o subsmit post do formulario (onAfterPostEvent)
Esse evento dispara sempre após o submit de um formulário.
Nome do evento: onAfterPostEvent
Como escutar o evento de retorno de um submit no form?
//ouvindo o evento de retorno
document.addEventListener('onAfterPostEvent', function(event) {
//para validar se foi sucesso ou falha, usar a seguinte variavel
console.log('success', event.detail.success);
//enviamos mais alguns detalhes
console.log('response', event.detail.response);
//formAction, com essa variavel é possivel saber se foi um post para salvar, deletar, descartar rascunho, salvar rascunho etc..
//olhar todas as opções de formAction na documentação mais abaixo
console.log('formAction', event.detail.formAction);
});
Como forçar o salvamento e escutar o evento de retorno de um submit no form?
function ForceSaveForm(){
//ouvindo o evento de retorno
document.addEventListener('onAfterPostEvent', function(event) {
//para validar se foi sucesso ou falha, usar a seguinte variavel
console.log('success', event.detail.success);
//enviamos mais alguns detalhes
console.log('response', event.detail.response);
//formAction, com essa variavel é possivel saber se foi um post para salvar, deletar, descartar rascunho, salvar rascunho etc..
//olhar todas as opções de formAction na documentação mais abaixo
console.log('formAction', event.detail.formAction);
});
//solicitar o salvamento do iframe pai
//ESSA FUNÇÃO SÓ É NECESSARIO CASO VOCÊ QUERIA FORÇAR O SALVAR
formContext.form.save();
}
Como forçar o salvamento e escutar o evento de retorno de um submit no form pai?
function SaveParentForm(){
//recuperando o iframe pai
var iframePai = getIframePaiIntance()
//ouvindo o evento de retorno
iframePai.document.addEventListener('onAfterPostEvent', function(event) {
//para validar se foi sucesso ou falha, usar a seguinte variavel
console.log('success', event.detail.success);
//enviamos mais alguns detalhes
console.log('response', event.detail.response);
//formAction, com essa variavel é possivel saber se foi um post para salvar, deletar, descartar rascunho, salvar rascunho etc..
//olhar todas as opções de formAction na documentação mais abaixo
console.log('formAction', event.detail.formAction);
});
//solicitar o salvamento do iframe pai
//ESSA FUNÇÃO SÓ É NECESSARIO CASO VOCÊ QUERIA FORÇAR O SALVAR
iframePai.formContext.form.save();
}
O parametro numérico "formAction" que retorna no evento pode ser:
- ACTION_SALVAR = 1;
- ACTION_SALVAR_RASCUNHO = 2;
- ACTION_DESCARTAR_RASCUNHO = 3;
- ACTION_APROVAR = 4;
- ACTION_REPROVAR = 5;
- ACTION_RETORNAR = 6;
- ACTION_DELETAR = 7;
- ACTION_SALVAR_FORMULARIO_FILHO = 8;
- ACTION_DELETAR_FORMULARIO_FILHO = 9;
- ACTION_DESCARTAR_ALTERACOES_FORMULARIO_FILHO = 10;
- ACTION_SOLICITAR_TROCA_APROVADOR_ETAPA_DINAMICA = 11;
- ACTION_SALVAR_DEFINICAO_APROVADOR_ETAPA_DINAMICA = 12;
Forçar o salvamento de um Form
Como forçar o salvamento no submit do form
function forceSaveForm(){
//solicitar o salvamento
formContext.form.save();
}
Como forçar o salvamento no submit do form pai
function forceSaveParentForm(){
var iframePai = getIframePaiIntance()
//solicitar o salvamento do iframe pai
iframePai.formContext.form.save();
}
Como forçar o salvamento e escutar o evento de retorno
function forceSaveForm(){
//ouvindo o evento de retorno
document.addEventListener('onAfterPostEvent', function(event) {
//para validar se foi sucesso ou falha, usar a seguinte variavel
console.log('success', event.detail.success);
//enviamos mais alguns detalhes
console.log('response', event.detail.response);
//formAction, com essa variavel é possivel saber se foi um post para salvar, deletar, descartar rascunho, salvar rascunho etc..
//olhar todas as opções de formAction na documentação mais abaixo
console.log('formAction', event.detail.formAction);
});
//solicitar o salvamento do iframe pai
formContext.form.save();
}
O parametro numérico "formAction" que retorna no evento são:
- ACTION_SALVAR = 1;
- ACTION_SALVAR_RASCUNHO = 2;
- ACTION_DESCARTAR_RASCUNHO = 3;
- ACTION_APROVAR = 4;
- ACTION_REPROVAR = 5;
- ACTION_RETORNAR = 6;
- ACTION_DELETAR = 7;
- ACTION_SALVAR_FORMULARIO_FILHO = 8;
- ACTION_DELETAR_FORMULARIO_FILHO = 9;
- ACTION_DESCARTAR_ALTERACOES_FORMULARIO_FILHO = 10;
- ACTION_SOLICITAR_TROCA_APROVADOR_ETAPA_DINAMICA = 11;
- ACTION_SALVAR_DEFINICAO_APROVADOR_ETAPA_DINAMICA = 12;
Listagem: Como habiltar para atualizar a cada X segundos (Auto Refresh, Atualização Automática, Atualização Recorrente)
Para habilitar a atualização recorrente a cada X segundo utilize a função javascript abaixo dentro do formulário:
listContext.table.setRecurrentRefresh(15);
ou
listContext.table.setAutoRefresh(15);
Exemplo de como ficaria a configuração para atualizar a cada 15 segundos na listagem de um Formulário
Ativar e Inativar campos do formulario via Javascript
formcontext.field.disable("idDoCampo") formcontext.field.enable("campo")formcontext.field.disable(["campo","campo","campo"])formcontext.field.enable(["campo","campo","campo"])formcontext.field.disableAll()formcontext.field.enableAll()Esconder e Mostrar campos do formulario via Javascript (visível e invisível)
formcontext.field.hide("idDoCampo") formcontext.field.show("campo")formcontext.field.hide(["campo","campo","campo"])formcontext.field.show(["campo","campo","campo"])formcontext.field.hideAll()formcontext.field.showAll()Esconder, Mostrar e Remover o toolbar de botões do formulario via Javascript
Para Esconder a barra de botões: formcontext.form.toolbar.hide()
Para Mostrar a barra de botões:formcontext.form.toolbar.show()
Para Remover a barra de botões:formcontext.form.toolbar.remove()
Colocar ou Retirar a Obrigatoriedade de um Campo no Formulário via JavaScript
Nesta seção, você aprenderá a marcar um campo como obrigatório e a remover ou restaurar essa obrigatoriedade conforme necessário, utilizando JavaScript.
É importante para todo o campo que você deseja trabalhar com obrigatoriedade, que ele esteja por padrão marcado como obrigatório no formulário, sendo assim, acesse as configurações do formulario, acesse o campo e o marque como Obrigatório na seção de validação.
Pré requisito para uso das funções descritas aqui nesse documento:
Para todo o campo que você deseja trabalhar com obrigatoriedade condicional, que ele esteja por padrão marcado como obrigatório no formulário, sendo assim, acesse as configurações do formulario, acesse o campo e o marque como Obrigatório na seção de validação.
Como funciona?
Para atingir o objetivo de tirar ou remover a obrigatoriedade em deteminada situação, vou deve usar as funções abaixo, lembrando que por padrão o campo deve estar inicialmente marcado como Obrigatório
Removendo a Obrigatoriedade de um Campo
Se houver a necessidade de remover a obrigatoriedade de um campo em determinadas situações, você pode utilizar a função ignoreRequired do objeto formContext.field.required. Esta função desativa temporariamente a obrigatoriedade de um campo.
Exemplo de uso no Javascript:formContext.field.required.ignoreRequired("campoTexto");
Neste exemplo, o campo de texto identificado por "campoTexto" deixará de ser obrigatório.
Restaurando a Obrigatoriedade de um Campo
Se, em algum momento, precisar restaurar a obrigatoriedade de um campo, utilize a função unsetIgnoreRequired do mesmo objeto. Isso faz com que o campo volte a ser obrigatório.
formContext.field.required.unsetIgnoreRequired("campoTexto");
Este código restaura a obrigatoriedade do campo de texto identificado por "campoTexto".
Verificação de Estado de Formulários. Como saber se é um novo formulário ou um rascunho via javascript?
Esta documentação explica como utilizar as funções formContext.form.isNew() e formContext.form.isDraft() para determinar o estado de um formulário, ou seja, se ele é um novo formulário, um rascunho ou uma edição de um rascunho.
Essa funçao javascript deve ser utilizado dentro de um formulario na customização de código em Javascript.
Objetivo
O objetivo dessas funções é ajudar a identificar o estado atual do formulário e executar ações específicas com base em seu estado. Os estados podem ser:
- Novo Formulário: O formulário acabou de ser criado e nunca foi salvo.
- Rascunho: O formulário foi salvo como rascunho e pode estar em edição.
- Edição de um Rascunho: O formulário está sendo editado e é uma versão salva anteriormente como rascunho.
Funções Utilizadas
formContext.form.isNew()
Essa função retorna um valor booleano que indica se o formulário atual é novo.
- true: Se o formulário é novo (nunca foi salvo).
- false: Se o formulário já foi salvo previamente.
formContext.form.isDraft()
Essa função também retorna um valor booleano e indica se o formulário está em estado de rascunho.
- true: Se o formulário é um rascunho.
- false: Se o formulário não é um rascunho.
Exemplo de Uso
Aqui está um exemplo prático de como utilizar as funções isNew() e isDraft():
var isNewForm = formContext.form.isNew();
var isDraftForm = formContext.form.isDraft();
if(isNewForm){
console.log('This is a new form');
}
if(isDraftForm){
console.log('This is a draft form');
}
if(isNewForm && !isDraftForm){
console.log('This is a new form and not a draft form');
}
if(!isNewForm && isDraftForm){
console.log('This is an edition form and a draft form');
}
if(!isNewForm && !isDraftForm){
console.log('This is an edition form and not a draft form');
}
Explicação do Código
-
Verificando se é um Novo Formulário:
if (isNewForm) { console.log('This is a new form'); }Aqui, se a função
isNew()retornartrue, significa que o formulário é novo e nunca foi salvo. O código exibe a mensagem "This is a new form". -
Verificando se é um Rascunho:
if (isDraftForm) { console.log('This is a draft form'); }Se a função
isDraft()retornartrue, significa que o formulário está em estado de rascunho. O código exibe a mensagem "This is a draft form". -
Verificando se o Formulário é Novo e Não é um Rascunho:
if (isNewForm && !isDraftForm) { console.log('This is a new form and not a draft form'); }Essa condição verifica se o formulário é novo (
isNewForm === true) e não está em estado de rascunho (isDraftForm === false). Neste caso, o código exibe "This is a new form and not a draft form". -
Verificando se o Formulário é uma Edição de um Rascunho:
if (!isNewForm && isDraftForm) { console.log('This is an edition form and edition of a draft form'); }Essa condição verifica se o formulário já foi salvo antes (
isNewForm === false) e está em estado de rascunho (isDraftForm === true). Ou seja, é uma edição de um formulário previamente salvo como rascunho. -
Verificando se o Formulário é uma Edição (sem rascunho):
if (!isNewForm && !isDraftForm) { console.log('This is an edition form and not a draft form'); }Essa condição verifica se o formulário já foi salvo antes (
isNewForm === false) e não está em estado de rascunho (isDraftForm === false). Ou seja, é uma edição de um formulário e nao está salvo como rascunho.
Resumo
Essas duas funções são essenciais para verificar o estado atual de um formulário, e a partir delas, você pode:
- Saber se o formulário é novo e nunca foi salvo.
- Determinar se o formulário foi salvo como rascunho.
- Diferenciar entre novos formulários, rascunhos, edições e edições de rascunhos.
Com base nessas informações, você pode executar ações específicas, como mostrar mensagens, habilitar/desabilitar funcionalidades, ou realizar diferentes tipos de validações.
Como permitir um usuário Gerenciar Usuário, Perfil e Grupo de Usuario não tendo o perfil MASTER
Crie um perfil com as funcionalidades abaixo e associe o perfil ao usuario que terá essa permissão:
- Funcionalidades Por PErfil de Acesso
- Grupo de Usuario
- Perfil de acesso
- Usuário
Ao logar, o usuario com esse perfil associado visualizará as opções de Gerenciamento de Usuario, Perfil e Grupo de usuario dentro do Menu Segurança e Acesso, como na imagem abaixo:
Como customizar a mensagem de sucesso ou falha após o submit post do Formulário (via javascript)
Acesse a customização de um formulário. Ao acessar, entre na Aba "Configurações", em seguida, expanda "Outras Configurações" e defina um nome para a função javascript que será executada após o post.
O nome da função javascript deve ser preenchida no campo "Executar a função Javascript abaixo após salvar ou executar qualquer ação bem-sucedida no formulário:" como mostra em azul na imagem abaixo.
zoom do campo da imagem anterior:
No exemplo, foi definido o nome "executeAfterPost" para o nome da função javascript.
Abaixo segue um exemplo da função e a explicação comentada em cada linha.
ATENÇÃO: nessa função é necessário testar se o formAction é a opção salvar. o formAction é retornado como parametro da função. Para checar utilize a função js formContext.form.action.isSave(formAction)
function executeAfterPost(formId, response, formAction) {
//verifica se é o formAction de Salvar (essa função pode ser chamada em varios formAction, por isso é imoprtante checar se é salvar)
if (formContext.form.action.isSave(formAction)) {
//testar se deu sucesso no envio do form
if(response.success){
//funçao para desabilitar a mensagem nativa do sistema
formContext.form.disableNativeSuccessMsg();
//colocar a msg de sucesso
formContext.msg.success('Salvouu legal com sucesso', 'Sucesso');
}
}
}
Estrutura de Armazenamento dos campos no banco de dados
No sistema, os campos são armazenados em dois locais diferentes, em um JSON com todos os campos juntos e na tabela da entidade.
-
JSON do Formulário
- O sistema gera um JSON contendo todos os dados de cada formulário, incluindo os campos numéricos, inteiros e de data e hora, e armazena esse JSON na tabela
tbl_formulario. - Esse JSON serve como um registro completo das informações enviadas pelo usuário, sendo útil também para auditoria de dados.
- O sistema gera um JSON contendo todos os dados de cada formulário, incluindo os campos numéricos, inteiros e de data e hora, e armazena esse JSON na tabela
-
Tabela da Entidade - Campo VARCHAR
- Este campo armazena o valor recebido em "string", sem conversões. O tipo VARCHAR foi mantido por questões de compatibilidade com o sistema legado.
-
Tabela da Entidade - Campos tipados
- Campos booleanos, são gravados como smallint (0 ou 1), com exceção do campo "deletado", esse esta gravado como true or false
- Campos com tipos específicos, como numéricos, inteiros e de data e hora, têm uma coluna adicional que armazena o valor tipado e convertido:
-
Numéricos e Inteiros: Os campos numéricos possuem o sufixo
__number__e os inteiros seguem a mesma estrutura, facilitando operações e consultas. Exemplo:campo__number__. O tipo do campo é numeric no postgresql -
Data e Hora (Datetime): Os campos de data e hora possuem o sufixo
__datetime__. Exemplo:campo__datetime__. o tipo do campo édatepara campos que sõ tem Data etimestamppara campos com date e hora
-
Numéricos e Inteiros: Os campos numéricos possuem o sufixo
Observações Importantes
-
Exibição de Dados: Na listagem, é sempre utilizado o campo com o sufixo tipado (
__number__ou__datetime__), pois ele contém o valor devidamente convertido, garantindo precisão nas operações. -
Máscara de Formatação no Formulário: No formulário de entrada de dados, uma máscara em JavaScript é aplicada ao
campo, formatando o valor conforme o padrão do JSON. Essa máscara pode causar discrepâncias se houver uma incompatibilidade entre os formatos de entrada e o armazenamento no PostgreSQL.
Possíveis Problemas e Soluções
-
Diferença no Valor Armazenado: Para valores numéricos, caso o valor enviado pela API contenha vírgulas (por exemplo, "3,31"), pode ocorrer uma interpretação incorreta durante a conversão para o formato numérico, transformando o valor
3,31em331. - Recomendações: Nas Apis, e regras, sempre manter o padrao no formato ingles 99999.99 com ponto. Sugere-se validar e formatar os dados enviados para garantir que o sistema receba sempre o formato correto. A padronização dos dados de entrada evita diferenças entre os valores no campo VARCHAR e nos campos tipados com sufixo.
Executar uma Api do proprio agilityflow dentro de um Form ou dentro de uma outra Api
No FormContext
Chamando uma Api Post e não aguardando a resposta (Assincronamente).
public async Task ExecuteAsync(){
await FormContext.InternalApi.ExecutePostAsynchronouslyAsync("rest-api/teste",
new { valorr= 334455.66, email="exemplo@email.com.br" },
new ExecutePostAsynchronouslyOptions() {
AuthUser = "MUDAR AQUI PELO API USER LOGIN",
AuthKey = "MUDAR AQUI PELO API USER KEY",
});
}
Chamando uma Api Post e aguardando a resposta (Sincronamente).
public async Task ExecuteAsync(){
var result = await FormContext.InternalApi.ExecutePostSynchronouslyAsync("rest-api/teste",
new { valorr= 33445566.77, email="exemplo@email.com.br" },
new ExecutePostSynchronouslyOptions() {
AuthUser = "MUDAR AQUI PELO API USER LOGIN",
AuthKey = "MUDAR AQUI PELO API USER KEY",
});
//verificar se foi sucesso ou nao
var isSuccess = result.IsSuccess;
//se quiser o retorno no formato string
var str = result.GetString();
//se quiser o retorno no formato Json
var json = result.GetJson();
FormContext.Log($"isSuccess: {isSuccess} | - str: {str}" ,"debug");
}
No PageContext
Chamando uma Api Post e não aguardando a resposta (Assincronamente).
public async Task ExecuteAsync(){
await PageContext.InternalApi.ExecutePostAsynchronouslyAsync("rest-api/teste",
new { valorr= 334455.66, email="exemplo@email.com.br" },
new ExecutePostAsynchronouslyOptions() {
AuthUser = "MUDAR AQUI PELO API USER LOGIN",
AuthKey = "MUDAR AQUI PELO API USER KEY",
});
}
Chamando uma Api Post e aguardando a resposta (Sincronamente).
public async Task ExecuteAsync(){
var result = await PageContext.InternalApi.ExecutePostSynchronouslyAsync("rest-api/teste",
new { valorr= 33445566.77, email="exemplo@email.com.br" },
new ExecutePostSynchronouslyOptions() {
AuthUser = "MUDAR AQUI PELO API USER LOGIN",
AuthKey = "MUDAR AQUI PELO API USER KEY",
});
//verificar se foi sucesso ou nao
var isSuccess = result.IsSuccess;
//se quiser o retorno no formato string
var str = result.GetString();
//se quiser o retorno no formato Json
var json = result.GetJson();
FormContext.Log($"isSuccess: {isSuccess} | - str: {str}" ,"debug");
}
No ApiContext
IMPORTANTE: Caso o usuário da API que está consumindo esta outra API tenha acesso a ambas, não será necessário fornecer os parâmetros AuthUser e AuthKey.
Chamando uma Api Post e não aguardando a resposta (Assincronamente).
public async Task RunAsync(){
await ApiContext.InternalApi.ExecutePostAsynchronouslyAsync("rest-api/teste",
new { valorr= 334455.66, email="exemplo@email.com.br" },
new ExecutePostAsynchronouslyOptions() {
/* ATENÇÃO: Caso o usuário da API que está consumindo esta outra API
tenha acesso a ambas, não será necessário
fornecer os parâmetros AuthUser e AuthKey.*/
AuthUser = "MUDAR AQUI PELO API USER LOGIN",
AuthKey = "MUDAR AQUI PELO API USER KEY",
});
}
Chamando uma Api Post e aguardando a resposta (Sincronamente).
public async Task RunAsync(){
var result = await ApiContext.InternalApi.ExecutePostSynchronouslyAsync("rest-api/teste",
new { valorr= 33445566.77, email="exemplo@email.com.br" },
new ExecutePostSynchronouslyOptions() {
/* ATENÇÃO: Caso o usuário da API que está consumindo esta outra API
tenha acesso a ambas, não será necessário
fornecer os parâmetros AuthUser e AuthKey.*/
AuthUser = "MUDAR AQUI PELO API USER LOGIN",
AuthKey = "MUDAR AQUI PELO API USER KEY",
});
//verificar se foi sucesso ou nao
var isSuccess = result.IsSuccess;
//se quiser o retorno no formato string
var str = result.GetString();
//se quiser o retorno no formato Json
var json = result.GetJson();
FormContext.Log($"isSuccess: {isSuccess} | - str: {str}" ,"debug");
}
Forçar via Javascript o Salvamento do Formulário
Forçar o salvamento via Javascript:
formContext.form.save()
Forçar o salvamento via Javascript:
formContext.parentWindow.formContext.form.save()formContext.form.save()
Manipular o formulário "pai", dentro de um formulário filho
No formContext do javascript existe uma propriedade chamada parentWindow ou parentFrame:
formContext.parentWindow
Dessa forma você terá acesso a todas os javascript e objetos do formulário pai.
Por exemplo, para buscar um campo do formulario pai:
var value = formContext.parentWindow.formContext.field.getValue("campoid")
Para salvar o formulário pai via javascript:
formContext.parentWindow.formContext.form.save()
Evento javascript ondataloaded na Lista Dinamica
No exemplo abaixo considere uma Lista Dinamica com o id "orcamento":
$('#orcamento').on('ondataloaded', function (data) {
var orcamento = formContext.field.getValue('orcamento');
if (orcamento == "") {
}
});
Como criar itens / tarefas automaticamente nos Checklists dos formulários?
Com esse exemplo, vc será capaz de criar itens / tarefas na aba Checklists dos formulários.
Como na imagem abaixo:
Nesse exemplo, vamos inserir registros em 2 tabelas.
- tbl_formulario_checklist Essa tabela tabela conteém o nome do checklist e a relação com o formulario que será apresentado
- tbl_formulario_checklist_item Essa tabela contém todas os itens de um checklist
No exemplo, eu criei 2 forms, sendo o form Inspeção um Workflow e o Inspeção Itens sendo filho do Inspeção
| Inspeção | Form onde ao salvar será criada as task | x_inspection |
| Inspeção Itens |
Form onde está tudo que foi inspecionado.
Os itens que estiverem PENDING, será gerado uma tarefa no checklist do form ao aprovar. |
x_inspection_item |
As etapas do Workflow são:
- Solicitação de inspeção
- Execução da Inspeção
- [Business Rules] Criação do Checklist de Pendências
- Execução da Lista de Pendências
- Finalização
Abaixo está o código utilizado na Regra de Negócio do FormContext que deve foi adicionada dentro da etapa [Business Rules] Criação do Checklist de Pendências do Workflow, logo após a etapa de Execução da Inspeção.
public async Task ExecuteAsync(){
var userId = FormContext.GetUsuarioLogadoId();
var recordId = FormContext.FormId;
var checklistId = System.Guid.NewGuid();
var inspectionTypeId = Guid.Parse(FormContext.GetValue("inspection_type_id"));
var paramsQuery = new List<NpgsqlParameter>();
paramsQuery.Add(new NpgsqlParameter("@id", checklistId));
paramsQuery.Add(new NpgsqlParameter("@formularioId", IdFormulario));
paramsQuery.Add(new NpgsqlParameter("@recordId", recordId));
paramsQuery.Add(new NpgsqlParameter("@userId", userId));
paramsQuery.Add(new NpgsqlParameter("@inspectionTypeId", inspectionTypeId));
await FormContext.SqlScript.ExecuteAsync(@"
insert into tbl_formulario_checklist (
id,
efr_id,
frm_id,
tmp_form_id,
nome,
ordem,
log_data_criacao,
log_usu_criacao
)
select
@id,
@formularioId,
@recordId,
uuid_generate_v4(),
""name"" || ' - verify while inspecting',
1,
CURRENT_DATE,
@userId
from x_inspection_type where id = @inspectionTypeId limit 1
", paramsQuery.ToArray());
var paramsQueryItem = new List<NpgsqlParameter>();
paramsQueryItem.Add(new NpgsqlParameter("@checklistId", checklistId));
paramsQueryItem.Add(new NpgsqlParameter("@userId", userId));
paramsQueryItem.Add(new NpgsqlParameter("@inspectionTypeId", inspectionTypeId));
await FormContext.SqlScript.ExecuteAsync(@"
insert into tbl_formulario_checklist_item (
id,
id_checklist,
checked,
nome,
ordem,
log_data_criacao,
log_usu_criacao
)
select uuid_generate_v4(), @checklistId, 0, ""name"", 1, CURRENT_DATE, @userId
FROM x_inspection_item
where inspection_type_id = @inspectionTypeId and status = 'pending'
limit 200", paramsQueryItem.ToArray());
}
Customização e estilização dos botões do formulário
Através da tela de configuração do formulario, você pode customizar os icones, as cores e o local onde o botão pode aparecer em um formulário, e o resultado fica como o mostrado na imagem abaixo
Como ocultar um campo do formulário quando ele estiver em modo público?
Usando CSS
Suponhamos que você tenha um formulário chamado Solicitação de Orçamento e deseja ocultar os campos Status e Identity apenas quando esse Formulário estiver sendo apresentado no "modo/ambiente" Público (Website, Form Público, Portal Público), basta aplicar o CSS abaixo.
Levando em consideração que na estrutura do formulário, todos os elementos que compõem os campos possuem a classe CSS no formato .item-[id do campo]. Isso significa que, para ocultar um campo específico, você pode utilizar essa classe no seletor CSS.
Quando o formulário estiver no modo público, a tag <html> conterá a classe public-portal. Com isso, você pode esconder os campos desejados da seguinte forma:
html.public-portal .item-identity{
display: none
}
html.public-portal .item-status{
display: none
}
Dessa forma, sempre que o formulário estiver público, os campos Status e Identity serão ocultados automaticamente.
Usando Javascript
//Qualquer uma dessas funções javascript pode te ajudar
//a função javascript retorna se o form está no modo Publico ou não
var isPublicPortal = formContext.isPublicPortal();
//OU
//a função javascript retorna se o form está no modo Publico ou não
var isPublicForm = formContext.isPublicForm();
Criando ações complexas no botão de um formulário
Opção 1, usando o c# direto no cshtml
Nesse exemplo vamos supor que temos 2 formulários
- Solicitção de Orçamento
- Orçamento
Dentro do Solicitação de Orçamento você tem um botão chamado "Criar Orçamento" e ao clicar nesse Criar orçamento você quer criar um novo Formulário de Orçamento.
No Formulário Solciitação de Orçamento, crie um javascript como esse exemplo:
function criarOrcamento() {
formContext.loadAjax("criarOrcamento", {
onSuccess: function (e) {
//pageMsg.showMsgSuccess("Orcamento criado", "Sucesso");
var jsonResult = JSON.parse(e);
if (!jsonResult.success) {
pageMsg.showMsgError(jsonResult.msg, "Falha");
} else {
var idEstruturaFormToRedirect = "74ad209b-ee6a-4ae3-9920-2caad2bc7451";
window.location.href = formContext.url.getBaseUrl() + "#/fluxo/index/" +idEstruturaFormToRedirect+ "/" + jsonResult.idOrcamento;
}
},
onError: function (err) {
pageMsg.showMsgError("Erro ao criar o Orcamento", "Falha");
}
});
}
No onclick do botão "Criar Orçamento" chame a função javascript
criarOrcamento()
Agora crie um Componente Cshtml, chamando CriarOrcamento
Dentro do componente coloque uma programação em C#.
C#
@{
var success = false;
var msg = "";
var tel = PageContext.GetValue("seu_telefone");
Guid? idOrcamento = null;
if (!string.IsNullOrWhiteSpace(tel))
{
// Verifica se o cliente já existe
var query = $"SELECT id FROM x_tbl_clientes WHERE telefone = '{tel}' AND deletado = false LIMIT 1";
var dtCliente = await PageContext.GetDataTableAsync(query);
var clienteExiste = dtCliente.Rows.Count > 0;
Guid idCliente;
//se o cliente ainda nao existir, cria um cliente
if (!clienteExiste)
{
var idFormularioCliente = Guid.Parse("cb4019ad-c731-42b9-8624-bb9c0fe5bf78");
var valuesCliente = new DataDictionary
{
{ "nome", PageContext.GetValue("seu_nome") },
{ "email", PageContext.GetValue("email") },
{ "instagram", PageContext.GetValue("instagram") },
{ "telefone", tel }
};
idCliente = await PageContext.SaveEntityAsync(idFormularioCliente, valuesCliente);
}
else
{
idCliente = Guid.Parse(dtCliente.Rows[0]["id"].ToString());
}
// Criação do orçamento
var idFormularioOrcamento = Guid.Parse("74ad209b-ee6a-4ae3-9920-2caad2bc7451");
var valuesOrcamento = new DataDictionary
{
{ "solicitacao", PageContext.FormId },
{ "radiosolicitacao", "dcef9208-3a3e-3f34-90f9-e514af597d93" },
{ "numero_convidado_adultos", PageContext.GetValue("qtd_adultos") },
{ "numero_convidado_criancas", PageContext.GetValue("qtd_criancas") },
{ "datahora", PageContext.GetValue("datahora_do_evento") },
{ "local", PageContext.GetValue("local_do_evento") },
{ "status", "6d5257d2-034a-459a-b57a-cc4800e74fb0" },
{ "tipo_de_orcamento", PageContext.GetValue("tipo_de_evento") },
{ "cliente", idCliente.ToString() }
};
idOrcamento = await PageContext.SaveEntityAsync(idFormularioOrcamento, valuesOrcamento);
success = true;
}
else
{
msg = "O telefone não pode estar em branco";
}
}
{"success": @success.ToString().ToLower(), "msg": "@msg", "idOrcamento": "@idOrcamento" }
Opção 2, usando regra de negócio
Nesse exemplo vamos supor que temos 2 formulários
- Solicitção de Orçamento
- Orçamento
Dentro do Solicitação de Orçamento você tem um botão chamado "Criar Orçamento" e ao clicar nesse Criar orçamento você quer salvar o formulário de Solicitação de Orçamento mudando o status dele para "Orçamento Criado" e ao mesmo tempo, já criar um novo Formulário de Orçamento.
Importante, coloque uma regra no formulário de Solicitação de Orçamento pra deixar invisível o botão de "Criar Orçamento" sempre que já tiver um orçamento criado, ou seja, que o status seja igual ao "Orçamento Criado";
No Formulário Solciitação de Orçamento, crie um javascript como esse exemplo:
function criarOrcamento() {
pageMsg.showMsgSuccess("Criando orçamento...");
formContext.field.setValue("status", "041cc896-6048-4b56-a9ac-033f6144253c");//coloca o status "orçamento em criação", supondo que o staus "orçamento em criação" é esse id 041cc896-6048-4b56-a9ac-033f6144253c
setTimeout(function () {
formContext.form.save();
}, 500); //espera 500ms pra seguir o salvamento
}
No onclick do botão "Criar Orçamento" chame a função javascript
criarOrcamento()
Agora nas regras de negocio, crie uma regra para criar um registro novo de orçamento ao SALVAR.
Coloque um If pra enviar o orçamento apenas se o status seja "orçamento em criação"
Dentro do if coloque uma programação em C#.
C#
@{
//muda o status da SOlicitçaão de ORçamento pra "Orçamento Criado"
FormContext.SetValue("status", "9041cc899-7045-cb56-b9ac-033f61442599");//coloca o status "orçamento criado", supondo que o staus "orçamento criado" é esse id 9041cc899-7045-cb56-b9ac-033f61442599
var tel = FormContext.GetValue("seu_telefone");
if (!string.IsNullOrWhiteSpace(tel))
{
// Verifica se o cliente já existe
var query = $"SELECT id FROM x_tbl_clientes WHERE telefone = '{tel}' AND deletado = false LIMIT 1";
var dtCliente = await FormContext.GetDataTableAsync(query);
var clienteExiste = dtCliente.Rows.Count > 0;
Guid idCliente;
//se o cliente ainda nao existir, cria um cliente
if (!clienteExiste)
{
var idFormularioCliente = Guid.Parse("cb4019ad-c731-42b9-8624-bb9c0fe5bf78");
var valuesCliente = new DataDictionary
{
{ "nome", FormContext.GetValue("seu_nome") },
{ "email", FormContext.GetValue("email") },
{ "instagram", FormContext.GetValue("instagram") },
{ "telefone", tel }
};
idCliente = await FormContext.SaveEntityAsync(idFormularioCliente, valuesCliente);
}
else
{
idCliente = Guid.Parse(dtCliente.Rows[0]["id"].ToString());
}
// Criação do orçamento
var idFormularioOrcamento = Guid.Parse("74ad209b-ee6a-4ae3-9920-2caad2bc7451");
var valuesOrcamento = new DataDictionary
{
{ "solicitacao", FormContext.FormId },
{ "radiosolicitacao", "dcef9208-3a3e-3f34-90f9-e514af597d93" },
{ "numero_convidado_adultos", FormContext.GetValue("qtd_adultos") },
{ "numero_convidado_criancas", FormContext.GetValue("qtd_criancas") },
{ "datahora", FormContext.GetValue("datahora_do_evento") },
{ "local", FormContext.GetValue("local_do_evento") },
{ "status", "6d5257d2-034a-459a-b57a-cc4800e74fb0" },
{ "tipo_de_orcamento", FormContext.GetValue("tipo_de_evento") },
{ "cliente", idCliente.ToString() }
};
}
else
{
FormContext.WarningMessage("O telefone não pode estar em branco");
}
}
Ao salvar um form, pausar ação do sistema e atualizar a tela
Configure o nome da função javascript para ser chamada após qualquer ação de sucesso no formulário, como na imagem abaixo:
Na customização javascript coloque esse código. agora ao salvar, o form continuará na mesma tela, apresentará uma msg de sucesso e fará um refresh da página
function afterOnSave(formId, response, formAction) {
if(formAction != 1) return; //1 é salvar
formContext.msg.showMsgSuccess("Form salvo com sucesso", "Ok");
//ao salvar um novo, nao sair do lightbox que da aberto mas abrir um novo
setTimeout(function () { window.location = window.location }, 300);
return false;
}
Para saber mais sobre esse evento javascript que ocorre após o subsmit post do formulario (onAfterPostEvent), clique aqui
[Form] Como abrir outra página ou um lightbox / modal a partir estando em um Form ou Workflow
function openLightBox(tamanho, url) {
var __baseUrl = customPageContext.url.getBaseUrl();
url = __baseUrl + url;
formContext.openLightBox(url, tamanho)
}
//Abrir lightbox tela cheia
//Abrir um custom page
openLightBox('fullscreen', 'custompage/6d6d2752-5fcd-4303-aa1b-1ab9e32b38d3')
//Abrir lightbox tamanho grande
//Abrir um form de cadastro
openLightBox('g', 'fluxo/index/0153b02c-d4d8-4747-9a69-45aafa113f81/1f25c74f-a048-4d83-86eb-f31b9608b615')
//Abrir lightbox tamanho médio
//Abrir um list de um form
openLightBox('m', 'fluxo/list/0153b02c-d4d8-4747-9a69-45aafa113f81')
//Abrir lightbox tamanho pequeno
//abrir um board
openLightBox('p', '/b/YKYZ92/custom-code')
Leitura de E-mail Automatizada e Monitoramento de Caixa de Entrada
O AgilityFlow permite a automação do monitoramento de uma caixa de e-mail (por exemplo, atendimento@yyy.com). Sempre que uma nova mensagem for recebida, o sistema pode acionar eventos automaticamente, como:
- Cadastro de um formulário
- Acionamento de uma API
- Execução de uma tarefa
- Entre outras automações personalizadas
Como Configurar
Para habilitar essa funcionalidade, entre em contato com o seu especialista AgilityFlow.
[Global Code] Como criar uma Classe Global em C#?
#GlobalCode
IMPORTANTE: a class não pode ser instanciada diretamente, ex: new MyClass() utilize CreateInstanceMyClass() que é gerado automaticamente
IMPORTANTE: a class não pode ter construtor definido
Como definir e instanciar uma classe C# que está definida no Global Code?
Entre em Global Code na área de configuração, na aba C# GlobalClass e clique em Novo C#.
Crie um C# chamado "Document"
No código C#, copie e cole o código abaixo, repare que foi criado manualmente o metodo fora da classe chamado CreateDocument com 2 parametros que instancia a classe Document, através dele criaremos a instancia quando formos usar a classe Document, mas o Agilityflow também gera um metodo padrão chamado CreateInstanceDocument sem parametro para gerar a instancia, caso você precise.
Importante: para toda classe criada no agilityflow, o sistema gera automaticamente um metodo de criação da instancia dessa classe com o nome CreateInstanceXXXXX onde o XXXX é o nome da classe, se for uma classe chamada Document, ele cria Document CreateInstanceDocument(), sempre sem parametros de entrada
//crie uma classe
public class Document{
public string Title {get;set;}
public string Description {get;set;}
public async Task<List<UserClass>> ListUserExamplesAsync(){
var userNames = new List<UserClass>();
var dt = await GlobalContext.GetDataTableAsync("select coalesce(usu_nome,'') as name from tbl_usuario where deletado = false limit 5");
for(var i = 0; i < dt.Rows.Count; i++){
//repare que pra criar a instancia da classe UserClass, eu utilizo o metodo CreateInstance
var userClass = CreateInstance<UserClass>();
userClass.Name = dt.Rows[i]["name"].ToString();
userNames.Add(userClass);
}
return userNames;
}
}
public class UserClass{
public string Name {get;set;}
}
//caso queira, crie um metodo para fazer a instancia dessa classe
public Document CreateDocument(string title, string description ){
var doc = CreateInstance<Document>();
doc.Title = title;
doc.Description = description;
return doc;
}
Como instanciar uma classe do Global Code entre outras classes do Global Code?
Suponahmos que você tenha uma classe chamada OutraClasseGlobal no Global Code
public class OutraClasseGlobal{
public string Nome {get;set;}
}
Para instanciar essa classe OutraClasseGlobal dentro do pŕoprio Global Code você tem as opções abaixo:
CreateInstance<T>()
public class MinhaClasseGlobal{
public void Metodo()[
var classe2 = CreateInstance<OutraClasseGlobal>();
}
}
Como usar em outras partes do sistema essa classe C# Global (em outros contextos) ?
Por ser uma classe Global, você pode utilizar em qualquer lugar que possa executar C# no sistema, exemplos: Apis, Forms, Reports, Kanban, etc..
Para Utilizar, por exemplo dentro de um Cshtml de um form, você tem essas opções:
Opção 01: Chamando o metodo que o agilityflow gera automaticamente (recomendado):
Importante: para toda classe criada no agilityflow, o sistema gera automaticamente um metodo de criação da instancia dessa classe com o nome CreateInstanceXXXXX onde o XXXX é o nome da classe, se for uma classe chamada Document, ele cria Document CreateInstanceDocument()
@{
//instanciando uma class q foi declarada dentro do Global dinamicamente
var documentClass01 = GlobalClass.CreateInstanceDocument();
var json = JsonConvert.SerializeObject( new { documentClass01 });
}
@json
Opção 02: Chamando o metodo nativo do agiltyflow para instanciar classes:
@{
//instanciando uma class q foi declarada dentro do Global dinamicamente
var documentClass02 = GlobalClass.CreateInstance("Document");
var json = JsonConvert.SerializeObject( new { documentClass02 });
}
@json
Opção 03: Caso você crie um metodo manualmente que intancie a classe, exemplo o metodo criado no exemplo anterior CreateDocument (que você mesmo criou) :
@{
//instanciando uma class q foi declarada dentro do Global dinamicamente
var documentClass01 = GlobalClass.CreateDocument("string title", "string description");
var json = JsonConvert.SerializeObject( new { documentClass01 });
}
@json
Regras e Limitações:
- Para toda classe criada no agilityflow, o sistema gera automaticamente um metodo de criação da instancia dessa classe como nome CreateInstanceXXXXX onde o XXXX é o nome da classe, se for uma classe chamada Document, ele cria Document CreateInstanceDocument(), porém sempre sem parametros de entrada, você pode gerar manualmente um metodo com o mesmo nome mas com outros parametros de entrada, exemplo Document CreateDocument(string title, string description )
A classe não deve ter construtor, para instanciar, utilize o metodo CreateInstance<MyClass>() - Fora da área do C# do Global Code, você não tem acesso ao "Tipo" da classe que você criar. Então fora do seu class c# de Global Code você nao vai conseguir usar esse "Tipo",ex: como ToList<MyClass>() ou por exemplo em uma referencia implicita no foreach,:
-
//forma ERRADA se estiver FORA e consumindo o GlobalCode, (se estiver dentro do GlobalCode, você pode referenciar normalmente) //referenciar explicitamente o UserClass no foreach var userExamples = await GlobalClass.ListUserExamplesAsync(); foreach(UserClass user in userExamples){ <text> @user.Name </text> } //forma CORRETA se estiver FORA e consumindo o GlobalCode, (se estiver dentro do GlobalCode, você pode referenciar normalmente) //referenciar implicitamente o UserClass no foreach, usando var ou dynamic var userExamples = await GlobalClass.ListUserExamplesAsync(); foreach(var user in userExamples){ <text> @user.Name </text> }
[Custom Page] Como criar uma Classe em C# no Custom Page?
#CustomPage
IMPORTANTE: a class não pode ser instanciada diretamente, ex: new MyClass() utilize CreateInstanceMyClass() que é gerado automaticamente
IMPORTANTE: a class não pode ter construtor definido
Como definir e instanciar uma classe C# ?
Importante: para toda classe criada no agilityflow, o sistema gera automaticamente um metodo de criação da instancia dessa classe com o nome CreateInstanceXXXXX onde o XXXX é o nome da classe, se for uma classe chamada Document, ele cria Document CreateInstanceDocument(), sempre sem parametros de entrada
//crie uma classe
public class Document{
public string Title {get;set;}
public string Description {get;set;}
public async Task<List<UserClass>> ListUserExamplesAsync(){
var userNames = new List<UserClass>();
var dt = await CustomPageContext.GetDataTableAsync("select coalesce(usu_nome,'') as name from tbl_usuario where deletado = false limit 5");
for(var i = 0; i < dt.Rows.Count; i++){
//repare que pra criar a instancia da classe UserClass, eu utilizo o metodo CreateInstance
var userClass = CreateInstance<UserClass>();
userClass.Name = dt.Rows[i]["name"].ToString();
userNames.Add(userClass);
}
return userNames;
}
}
public class UserClass{
public string Name {get;set;}
}
//caso queira, crie um metodo para fazer a instancia dessa classe
public Document CreateDocument_01(string title, string description ){
var doc = CreateInstance<Document>();
doc.Title = title;
doc.Description = description;
return doc;
}
Como instanciar uma classe do Custom Page entre outras classes do Custom Page?
Suponahmos que você tenha uma classe chamada OutraClasseNoCustomPage no Custom Page
public class OutraClasseNoCustomPage{
public string Nome {get;set;}
}
Para instanciar essa classe OutraClasseNoCustomPage dentro do pŕoprio Custom Page você tem as opções abaixo:
CreateInstance<T>()
public class MinhaClasseCustomPage{
public void Metodo()[
var classe2 = CreateInstance<OutraClasseNoCustomPage>();
}
}
Como usar no CShtml a Classe C# criada?
CreateInstanceXXXXX()
Importante: para toda classe criada no agilityflow, o sistema gera automaticamente um metodo de criação da instancia dessa classe com o nome CreateInstanceXXXXX onde o XXXX é o nome da classe, se for uma classe chamada Document, ele cria Document CreateInstanceDocument()
@{
//instanciando uma class q foi declarada dentro do CustomPage dinamicamente
var documentClass01 = CustomPageClass.CreateInstanceDocument();
var json = JsonConvert.SerializeObject( new { documentClass01 });
}
@json
Opção 02: Chamando o metodo nativo do agiltyflow para instanciar classes:
@{
//instanciando uma class q foi declarada dentro do CustomPage dinamicamente
var documentClass02 = CustomPageClass.CreateInstance("Document");
var json = JsonConvert.SerializeObject( new { documentClass02 });
}
@json
Opção 03: Caso você crie um metodo manualmente que intancie a classe, exemplo o metodo criado no exemplo anterior CreateDocument_01 (que você mesmo criou) :
O método CreateDocument_01 você que precisaria criar (exemplo criado acima)
@{
//instanciando uma class q foi declarada dentro do CustomPage dinamicamente
var documentClass01 = CustomPageClass.CreateDocument_01("string title", "string description");
var json = JsonConvert.SerializeObject( new { documentClass01 });
}
@json
Regras e Limitações:
- Para toda classe criada no agilityflow, o sistema gera automaticamente um metodo de criação da instancia dessa classe como nome CreateInstanceXXXXX onde o XXXX é o nome da classe, se for uma classe chamada Document, ele cria Document CreateInstanceDocument(), porém sempre sem parametros de entrada, você pode gerar manualmente um metodo com o mesmo nome mas com outros parametros de entrada, exemplo Document CreateDocument(string title, string description )
A classe não deve ter construtor, para instanciar, utilize o metodo CreateInstance<MyClass>() - Fora da área do C# do Custom Page, você não tem acesso ao "Tipo" da classe que você criar. Então fora do seu class c# de Custom Page você nao vai conseguir usar esse "Tipo",ex: como ToList<MyClass>() ou por exemplo em uma referencia implicita no foreach,:
-
//forma ERRADA se estiver FORA e consumindo o CustomPage, (se estiver dentro do CustomPage, você pode referenciar normalmente) //referenciar explicitamente o UserClass no foreach var userExamples = await CustomPageClass.ListUserExamplesAsync(); foreach(UserClass user in userExamples){ <text> @user.Name </text> } //forma CORRETA se estiver FORA e consumindo o CustomPage, (se estiver dentro do CustomPage, você pode referenciar normalmente) //referenciar implicitamente o UserClass no foreach, usando var ou dynamic var userExamples = await CustomPageClass.ListUserExamplesAsync(); foreach(var user in userExamples){ <text> @user.Name </text> }
[Global Code] Como buscar no banco de dados em uma C# class global
#GlobalCode
Como fazer query?
Entre em Global Code na área de configuração, na aba C# GlobalClass e clique em Novo C#.
Crie um C# chamado "GetData"
No código C#, coloque o código abaixo, crie apenas um metodo que faça uma query na tabela de usuarios
//nesse exemplo eu faço uma query na tabela de usuarios
public async Task<List<string>> GetUsersAsync(){
var userNames = new List<string>();
var dt = await GlobalContext.GetDataTableAsync("select coalesce(usu_nome,'') as name from tbl_usuario where deletado = false limit 10");
for(var i = 0; i < dt.Rows.Count;i++){
userNames.Add(dt.Rows[i]["name"].ToString());
}
return userNames;
}
Como usar no sistema essa classe C# Global?
Por ser uma classe Global, você pode utilizar em qualquer lugar que possa executar C# no sistema, exemplos: Apis, Forms, Reports, Kanban, etc..
Para Utilizar, por exemplo dentro de um Cshtml de um form:
Opção 02: Chamando o metodo nativo do agiltyflow para instanciar classes:
@{
var users = await GlobalClass.GetUsersAsync();
var json = JsonConvert.SerializeObject( new { users });
}
@json
[Global Code] Como customizar CSS, Javascript e C# Globalmente
#GlobalCode
Todas as opções mostradas na imagem abaixo podem ser customizadas no Agilityflow.
No caso de C#, por ser Global, você pode criar classes e metodos e utiliza-los em qualquer lugar que possa executar C# no sistema, exemplos: Apis, Forms, Reports, Kanban, etc..
Em todos as opçoes abaixo você pode customizar o CSS e o Javascript. Por exemplo, se na opção Forms, você definir uma função javascript essa função estará disponível em todos os formulários do seu sistema, assim também funciona para o CSS.
Funções e Métodos Nativos em C#
Dezenas de métodos nativos estão disponiveis para sua customização na classe GlobalCotext.
Funções e Métodos Nativos em Javascript
Dezenas de métodos nativos estão disponiveis para sua customização na classe globalCotext.
[Custom Page] Quais são as funções nativas do AgilityFlow disponíveis no JavaScript para utilizar em uma Custom Page? customPageContext
Introdução
Este script fornece um conjunto de funções para manipulação de contexto de página, carregamento dinâmico de componentes e arquivos, manipulação de mensagens, conversão de números e datas, e interação com URLs base.
Constantes
emptyGuid
Uma string que representa um GUID vazio:
var emptyGuid = "00000000-0000-0000-0000-000000000000";
Estrutura Principal
customPageContext
Objeto que gerencia funções relacionadas ao contexto da página.
parentFrame
Identifica e armazena a referência do iframe pai.
customPageContext.parentFrame
isMobile()
Retorna true se o dispositivo for móvel.
customPageContext.isMobile();
redirectTo(url)
Redireciona a página para a URL informada.
customPageContext.redirectTo('https://example.com');
openLightBox(link, tamanholightbox, titulo)
Abre um lightbox com a URL especificada.
customPageContext.openLightBox('/pagina.html', 'm', 'Exemplo');
Carregamento de Componentes CSHTML
Funções para carregar componentes de forma dinâmica:
customPageContext.loadCsHtmlComponent(componentName, options);
customPageContext.loadHtmlComponent(componentName, options);
customPageContext.loadPartialView(componentName, options);
customPageContext.loadViewComponent(componentName, options);
customPageContext.loadAjax(componentName, options);
customPageContext.loadAjaxComponent(componentName, options);
Veja um exemplo de uso para Inserir, Atualizar ou deletar um registro em um Formulário, clicando aqui
Exemplo passando parâmetros para o cshtml:
function loadPartialToUpdateRegister() {
var cshtmlPartialName = "[coloque aqui o nome do partial cshtml que vc fez as regras de atualizar]";
customPageContext.loadCsHtmlComponent(cshtmlPartialName,
{
placeholderId: 'result_cshtml', //parametro opcional, se o cshtml retornar algum html e vc quiser, vc pode colocar o retorno dentro de algum placeholder, div, etc..
extraData: {
idRegistro: $('#guidRegistro').val(),
nome: $('#nome').val(),
email: $('#email').val()
},
onSuccess: function (result) {
customPageContext.msg.success("Executado com sucesso", "Confirmação");
},
onError: function (error) {
customPageContext.msg.error("Execução não realizada", "Erro");
console.log('error', error)
}
}
)
}
Carregamento de Arquivos JavaScript
addJavascriptFile(options)
Adiciona um arquivo JavaScript à página de forma assíncrona e executa um callback após o carregamento.
-
Parâmetros:
-
options(Object): Objeto com as propriedades:-
file_url(String): URL do arquivo JavaScript. -
callback_onload(Function): Função a ser executada após o carregamento do arquivo.
-
-
-
Exemplo:
customPageContext.addJavascriptFile({ file_url: "https://www.exemplo.com/script.js", callback_onload: function() { console.log("Script carregado!"); } });
Manipulação de URLs
url.getBaseUrl()
Retorna a URL base do sistema.
-
Retorno:
-
String com a URL base.
-
-
Exemplo:
console.log("URL base:", customPageContext.url.getBaseUrl());
url.getStaticFileUrl()
Retorna a URL base para arquivos estáticos.
-
Retorno:
-
String com a URL de arquivos estáticos.
-
-
Exemplo:
console.log("URL de arquivos estáticos:", customPageContext.url.getStaticFileUrl());
Idioma Atual
currentLanguage.get()
Retorna o idioma atual do sistema.
-
Retorno:
-
String com o código do idioma (ex:
'pt-BR','en-US').
-
-
Exemplo:
console.log("Idioma atual:", customPageContext.currentLanguage.get());
currentLanguage.isEnglish()
Verifica se o idioma atual é inglês.
-
Retorno:
-
truese for inglês. -
falsecaso contrário.
-
-
Exemplo:
if (customPageContext.currentLanguage.isEnglish()) { console.log("Idioma atual é inglês."); }
currentLanguage.getIIF_TextFromCurrentLanguage(text_ptBR, text_ENG, text_ESP)
Retorna o texto correspondente ao idioma atual.
-
Parâmetros:
-
text_ptBR(String): Texto em português. -
text_ENG(String): Texto em inglês. -
text_ESP(String): Texto em espanhol.
-
-
Retorno:
-
String com o texto no idioma atual.
-
-
Exemplo:
const texto = customPageContext.currentLanguage.getIIF_TextFromCurrentLanguage("Olá", "Hello", "Hola"); console.log(texto); // Retorna "Olá" se o idioma for português.
Mensagens
O módulo customPageContext.msg fornece funções para exibir e ocultar mensagens de alerta, erro, sucesso e aviso no sistema. Abaixo estão as funcionalidades disponíveis.
Ocultar Mensagens
hide(forcarFechar)
Oculta todas as mensagens exibidas.
-
Parâmetros:
-
forcarFechar(Boolean): Força o fechamento das mensagens.
-
-
Exemplo:
customPageContext.msg.hide(true); // Oculta todas as mensagens, forçando o fechamento.
Exibir Mensagens
show(type, msg, title, options)
Exibe uma mensagem de alerta, erro, sucesso ou aviso.
-
Parâmetros:
-
type(String): Tipo da mensagem. Valores possíveis:-
'warning': Mensagem de aviso. -
'error': Mensagem de erro. -
'success': Mensagem de sucesso.
-
-
msg(String): Texto da mensagem. -
title(String): Título da mensagem. -
options(Object): Opções adicionais para personalização da mensagem.
-
-
Exemplo:
customPageContext.msg.show("success", "Operação realizada com sucesso!", "Sucesso", { timeout: 5000 });
warning(msg, title, options)
Exibe uma mensagem de aviso.
-
Parâmetros:
-
msg(String): Texto da mensagem. -
title(String): Título da mensagem. -
options(Object): Opções adicionais.
-
-
Exemplo:
customPageContext.msg.warning("Atenção: Este campo é obrigatório.", "Aviso");
error(msg, title)
Exibe uma mensagem de erro.
-
Parâmetros:
-
msg(String): Texto da mensagem. -
title(String): Título da mensagem.
-
-
Exemplo:
customPageContext.msg.error("Ocorreu um erro ao salvar o formulário.", "Erro");
success(msg, title, options)
Exibe uma mensagem de sucesso.
-
Parâmetros:
-
msg(String): Texto da mensagem. -
title(String): Título da mensagem. -
options(Object): Opções adicionais.
-
-
Exemplo:
customPageContext.msg.success("Formulário salvo com sucesso!", "Sucesso", { timeout: 3000 });
Funções Legadas de Mensagens
As funções abaixo são mantidas para compatibilidade com versões anteriores, mas é recomendado utilizar as funções acima (show, warning, error, success).
hideMsgs()
Oculta todas as mensagens exibidas.
-
Exemplo:
customPageContext.msg.hideMsgs();
showMsgWarning(msg, title, options)
Exibe uma mensagem de aviso (legado).
-
Parâmetros:
-
msg(String): Texto da mensagem. -
title(String): Título da mensagem. -
options(Object): Opções adicionais.
-
-
Exemplo:
customPageContext.msg.showMsgWarning("Atenção: Este campo é obrigatório.", "Aviso");
showMsgError(msg, title)
Exibe uma mensagem de erro (legado).
-
Parâmetros:
-
msg(String): Texto da mensagem. -
title(String): Título da mensagem.
-
-
Exemplo:
customPageContext.msg.showMsgError("Ocorreu um erro ao salvar o formulário.", "Erro");
showMsgSuccess(msg, title, options)
Exibe uma mensagem de sucesso (legado).
-
Parâmetros:
-
msg(String): Texto da mensagem. -
title(String): Título da mensagem. -
options(Object): Opções adicionais.
-
-
Exemplo:
customPageContext.msg.showMsgSuccess("Formulário salvo com sucesso!", "Sucesso", { timeout: 3000 });
Exemplos de Uso de Mensagem
Exibindo uma mensagem de sucesso:
customPageContext.msg.success("Dados salvos com sucesso!", "Sucesso", { timeout: 5000 });
Exibindo uma mensagem de erro:
customPageContext.msg.error("Erro ao processar a solicitação.", "Erro");
Ocultando todas as mensagens:
customPageContext.msg.hide(true);
Manipulação de Números
number.convertString_toNumber(strValueToConvert, qtdCasasDecimais)
Converte uma string formatada em número.
-
Parâmetros:
-
strValueToConvert(String): Valor em formato de string. -
qtdCasasDecimais(Number): Quantidade de casas decimais.
-
-
Retorno:
-
Número convertido.
-
-
Exemplo:
const numero = customPageContext.number.convertString_toNumber("1.000,50", 2); console.log(numero); // Retorna 1000.50
number.convertNumber_toStringFormatted(numberToConvert, qtdCasasDecimais)
Converte um número em uma string formatada de acordo com o idioma.
-
Parâmetros:
-
numberToConvert(Number): Número a ser convertido. -
qtdCasasDecimais(Number): Quantidade de casas decimais.
-
-
Retorno:
-
String formatada.
-
-
Exemplo:
const texto = customPageContext.number.convertNumber_toStringFormatted(1000.50, 2); console.log(texto); // Retorna "1.000,50" em português.
Manipulação de Datas
isCurrentMonthAndYear(data)
Verifica se a data fornecida pertence ao mês e ano atuais.
-
Parâmetros:
-
data(String): Data no formatoDD/MM/YYYY.
-
-
Retorno:
-
truese a data for do mês e ano atuais. -
falsecaso contrário.
-
-
Exceções:
-
Lança um
TypeErrorse a data estiver em um formato inválido.
-
-
Exemplo:
customPageContext.datetime.validation.isCurrentMonthAndYear("25/10/2023"); // Retorna true se outubro de 2023 for o mês e ano atuais.
compare(date1, compare, date2)
Compara duas datas com base no operador especificado.
-
Parâmetros:
-
date1(String): Primeira data no formatoDD/MM/YYYY. -
compare(String): Operador de comparação. Valores possíveis:-
'greater'ou'>' -
'greater-or-equal'ou'>=' -
'less'ou'<' -
'less-or-equal'ou'<=' -
'equal'ou'=='
-
-
date2(String): Segunda data no formatoDD/MM/YYYY.
-
-
Retorno:
-
trueoufalse, dependendo da comparação.
-
-
Exceções:
-
Lança um
TypeErrorse as datas estiverem em formato inválido ou se o operador de comparação não for reconhecido.
-
-
Exemplo:
customPageContext.datetime.validation.compare("25/10/2023", "greater", "20/10/2023"); // Retorna true.
compareDatetime(datetime1, compare, datetime2)
Compara duas datas e horários com base no operador especificado.
-
Parâmetros:
-
datetime1(String): Primeira data e horário no formatoDD/MM/YYYY HH:mm. -
compare(String): Operador de comparação. Valores possíveis:-
'greater'ou'>' -
'greater-or-equal'ou'>=' -
'less'ou'<' -
'less-or-equal'ou'<=' -
'equal'ou'=='
-
-
datetime2(String): Segunda data e horário no formatoDD/MM/YYYY HH:mm.
-
-
Retorno:
-
trueoufalse, dependendo da comparação.
-
-
Exceções:
-
Lança um
TypeErrorse os dados estiverem em formato inválido ou se o operador de comparação não for reconhecido.
-
-
Exemplo:
customPageContext.datetime.validation.compareDatetime("25/10/2023 14:30", "greater", "25/10/2023 12:00"); // Retorna true.
compareToday(compare, date2)
Compara a data atual com uma data fornecida.
-
Parâmetros:
-
compare(String): Operador de comparação. Valores possíveis:-
'greater'ou'>' -
'greater-or-equal'ou'>=' -
'less'ou'<' -
'less-or-equal'ou'<=' -
'equal'ou'=='
-
-
date2(String): Data no formatoDD/MM/YYYY.
-
-
Retorno:
-
trueoufalse, dependendo da comparação.
-
-
Exemplo:
customPageContext.datetime.validation.compareToday("less", "30/10/2023"); // Retorna true se a data atual for menor que 30/10/2023.
Adição de Tempo
day(data, days)
Adiciona dias a uma data.
-
Parâmetros:
-
data(String): Data no formatoDD/MM/YYYYouDD/MM/YYYY HH:mm. -
days(Number): Número de dias a serem adicionados.
-
-
Retorno:
-
Data resultante no mesmo formato da entrada.
-
-
Exemplo:
customPageContext.datetime.add.day("25/10/2023", 5); // Retorna "30/10/2023".
month(data, months)
Adiciona meses a uma data.
-
Parâmetros:
-
data(String): Data no formatoDD/MM/YYYYouDD/MM/YYYY HH:mm. -
months(Number): Número de meses a serem adicionados.
-
-
Retorno:
-
Data resultante no mesmo formato da entrada.
-
-
Exemplo:
customPageContext.datetime.add.month("25/10/2023", 2); // Retorna "25/12/2023".
year(data, years)
Adiciona anos a uma data.
-
Parâmetros:
-
data(String): Data no formatoDD/MM/YYYYouDD/MM/YYYY HH:mm. -
years(Number): Número de anos a serem adicionados.
-
-
Retorno:
-
Data resultante no mesmo
-
hour(data, hours)
Adiciona horas a uma data e horário.
-
Parâmetros:
-
data(String): Data e horário no formatoDD/MM/YYYY HH:mm. -
hours(Number): Número de horas a serem adicionadas.
-
-
Retorno:
-
Data e horário resultante no formato
DD/MM/YYYY HH:mm.
-
-
Exemplo:
customPageContext.datetime.add.hour("25/10/2023 14:30", 3); // Retorna "25/10/2023 17:30".
minute(data, minutes)
Adiciona minutos a uma data e horário.
-
Parâmetros:
-
data(String): Data e horário no formatoDD/MM/YYYY HH:mm. -
minutes(Number): Número de minutos a serem adicionados.
-
-
Retorno:
-
Data e horário resultante no formato
DD/MM/YYYY HH:mm.
-
-
Exemplo:
customPageContext.datetime.add.minute("25/10/2023 14:30", 15); // Retorna "25/10/2023 14:45".
Obtenção de Datas
getLastDayOfCurrentMonth()
Retorna o último dia do mês atual.
-
Retorno:
-
Data no formato
DD/MM/YYYY.
-
-
Exemplo:
customPageContext.datetime.getLastDayOfCurrentMonth(); // Retorna "31/10/2023" se outubro for o mês atual.
getLastDayOfMonth(data)
Retorna o último dia do mês da data fornecida.
-
Parâmetros:
-
data(String): Data no formatoDD/MM/YYYY.
-
-
Retorno:
-
Data no formato
DD/MM/YYYY.
-
-
Exemplo:
customPageContext.datetime.getLastDayOfMonth("25/10/2023"); // Retorna "31/10/2023".
Data e Horário Atuais
getDateNow()
Retorna a data e horário atuais.
-
Retorno:
-
Objeto
Daterepresentando a data e horário atuais.
-
-
Exemplo:
customPageContext.datetime.getDateNow(); // Retorna a data e horário atuais.
getFormattedDateTime()
Retorna a data e horário atuais formatados.
-
Retorno:
-
String no formato
DD/MM/YYYY HH:mm.
-
-
Exemplo:
customPageContext.datetime.getFormattedDateTime(); // Retorna "25/10/2023 14:30".
getFormattedDate()
Retorna a data atual formatada.
-
Retorno:
-
String no formato
DD/MM/YYYY.
-
-
Exemplo:
customPageContext.datetime.getFormattedDate(); // Retorna "25/10/2023".
[Custom Page] Como apresentar mensagens para o usuario
#CustomPage
Abaixo exemplos em javascript para apresentação de mensanges para o usuário
function alerta() {
alert('mensagem de alerta 1');
}
function confirma() {
if (confirm("confirma msm?")) {
alert('confirmado');
} else {
alert('nao confirmado');
}
}
//função para apresentar uma mensage de sucesso
function showSuccess() {
customPageContext.msg.success("msg", "msg title");
}
//função para apresentar uma mensage de atenção
function showWarning() {
customPageContext.msg.warning("msg", "msg title");
}
//função para apresentar uma mensage de erro
function showError() {
customPageContext.msg.error("msg", "msg title");
}
Abaixo um exemplo para forçar esconder uma mensagem
function hideMsgs() {
customPageContext.msg.hideMsgs();
}
[Custom Page] Como buscar a data atual
Em Javascript
function logdate() {
alert(GetDateNow())
}
Em C#
DateTime.Now.ToUserTimeZone()
[Custom Page] Como abrir outra página ou um lightbox / modal a partir do Custom Page
#CustomPage
Para abrir um lightbox usando Javascript:
function openLightBox(tamanho, titulo) {
customPageContext.openLightBox('about:blank', tamanho, titulo)
}
//Abrir lightbox tela cheia
openLightBox('fullscreen');
//Abrir lightbox tamanho grande
openLightBox('g');
//Abrir lightbox tamanho médio
openLightBox('m');
//Abrir lightbox tamanho pequeno
openLightBox('p');
Para redirecionar para outra página usando Javascript:
customPageContext.redirectTo(url);
[Custom Page] Buscar informações do banco de dados através (Query)
No Page<body> ou em um partial cshtml utilize o código C# abaixo para fazer uma query na tabela de usuários e lista-los
@{
var userNames = new List<string>();
var dt = await CustomPageContext.GetDataTableAsync("select coalesce(usu_nome,'') as name from tbl_usuario where deletado = false limit 5");
for(var i = 0; i < dt.Rows.Count; i++){
userNames.Add(dt.Rows[i]["name"].ToString());
}
}
@Html.Raw(string.Join("<br>", userNames))
[Global Code] Como declarar uma variável publica em todo o sistema
No C# do Global Code:
//usando a keyword PUBLIC + tipo + nome da varaiavel que quer criar
public string EssaEhUmaVariavelGlobal = "legal";
Nas demais classes C# ou cshtml do sistema que queiram consumir essa variavel:
string valorDaVariavel_EssaEhUmaVariavelGlobal = GlobalClass.EssaEhUmaVariavelGlobal;
[Custom Page] Como inserir, atualizar e deletar um registro em um determinado Form estando em um Custom Page
Para Inserir (Insert)
Insert usando C#
public class ExemploMinhaClasseCsharp{
public async Task<Guid> InserirRegistroAsync(string nome, string email){
//troque o valor da variavel estruturaformularioidASerCriadoOuAtualizado para o Id do Form que você quer inserir um registro
var estruturaformularioidASerCriadoOuAtualizado = Guid.Parse("0153b02c-d4d8-4747-9a69-45aafa113f81");
//preencher a collection valuesToSave com os valores para o form que quer salvar
var valuesToSave = new DataDictionary();
valuesToSave.Add("name", nome);
valuesToSave.Add("value1", email);
var createdId = await CustomPageContext.SaveEntityAsync(estruturaformularioidASerCriadoOuAtualizado, valuesToSave);
return createdId;
}
}
public ExemploMinhaClasseCsharp CreateInstanceExemploMinhaClasseCsharp(){
var obj = CreateInstance<ExemploMinhaClasseCsharp>();
return obj;
}
Agora você precisa chamar esse metodo dentro do seu page<body> ou no partial cshtml.
@{
var obj = CustomPageClass.CreateInstanceExemploMinhaClasseCsharp();
var idCriado = await obj.InserirRegistroAsync("joao", "joao@joao.com");
}
idCriado: @idCriado
Insert usando cshtml
@{
//troque o valor da variavel estruturaformularioidASerCriadoOuAtualizado para o Id do Form que você quer inserir um registro
var estruturaformularioidASerCriadoOuAtualizado = Guid.Parse("0153b02c-d4d8-4747-9a69-45aafa113f81");
//preencher a collection valuesToSave com os valores para o form que quer salvar
var valuesToSave = new DataDictionary();
valuesToSave.Add("name", nome);
valuesToSave.Add("value1", email);
var createdId = await CustomPageContext.SaveEntityAsync(estruturaformularioidASerCriadoOuAtualizado, valuesToSave);
}
Id Form Criado: @createdId
Para Atualizar (Update)
Update usando C#
public class ExemploMinhaClasseCsharp{
public async Task AtualizarRegistroAsync(Guid idRegistro, string nome, string email){
//troque o valor da variavel estruturaformularioidASerCriadoOuAtualizado para o Id do Estrutura do Formulario que você quer atualizar um registro
var estruturaformularioidASerCriadoOuAtualizado = Guid.Parse("0153b02c-d4d8-4747-9a69-45aafa113f81");
//preencher a collection valuesToSave com os valores para o form que quer salvar
var valuesToSave = new DataDictionary();
valuesToSave.Add("id", idRegistro);
valuesToSave.Add("name", nome);
valuesToSave.Add("value1", email);
await CustomPageContext.SaveEntityAsync(estruturaformularioidASerCriadoOuAtualizado, valuesToSave);
}
}
public ExemploMinhaClasseCsharp CreateInstanceExemploMinhaClasseCsharp(){
var obj = CreateInstance<ExemploMinhaClasseCsharp>();
return obj;
}
Agora você precisa chamar esse metodo dentro do seu page<body> ou no partial cshtml.
@{
var obj = CustomPageClass.CreateInstanceExemploMinhaClasseCsharp();
var idRegistro = CustomPageContext.GetParam("idRegistro");
await obj.AtualizarRegistroAsync(Guid.Parse(idRegistro), "joao", "joao@joao.com");
}
Form Atualizado
Uma das formas para Passar o Id do Registro que deve ser atualizado, você pode utilizar a função abaixo no javascript:
function loadPartialToUpdateRegister() {
var cshtmlPartialName = "[coloque aqui o nome do partial cshtml que vc fez as regras de atualizar]";
customPageContext.loadCsHtmlComponent(cshtmlPartialName,
{
placeholderId: 'result_cshtml', //parametro opcional, se o cshtml retornar algum html e vc quiser, vc pode colocar o retorno dentro de algum placeholder, div, etc..
extraData: {
idRegistro: $('#guidRegistro').val(), //supondo que vc tenha um campo (guidRegistro) na tela com o GUID preenchido ref ao id do registro que quer atualizar
},
onSuccess: function (result) {
customPageContext.msg.success("Atualização com sucesso", "Confirmação");
},
onError: function (error) {
customPageContext.msg.error("Atualização nao realizada", "Erro");
console.log('error', error)
}
}
)
}
Update usando cshtml
@{
var idRegistro = CustomPageContext.GetParam("idRegistro");
//troque o valor da variavel estruturaformularioidASerCriadoOuAtualizado para o Id do Estrutura do Formulario que você quer atualizar um registro
var estruturaformularioidASerCriadoOuAtualizado = Guid.Parse("0153b02c-d4d8-4747-9a69-45aafa113f81");
//preencher a collection valuesToSave com os valores para o form que quer salvar
var valuesToSave = new DataDictionary();
valuesToSave.Add("id", idRegistro);
valuesToSave.Add("name", nome);
valuesToSave.Add("value1", email);
await CustomPageContext.SaveEntityAsync(estruturaformularioidASerCriadoOuAtualizado, valuesToSave);
}
Form Atualizado
Uma das formas para Passar o Id do Registro que deve ser atualizado, você pode utilizar a função abaixo no javascript:
function loadPartialToUpdateRegister() {
var cshtmlPartialName = "[coloque aqui o nome do partial cshtml que vc fez as regras de atualizar]";
customPageContext.loadCsHtmlComponent(cshtmlPartialName,
{
placeholderId: 'result_cshtml', //parametro opcional, se o cshtml retornar algum html e vc quiser, vc pode colocar o retorno dentro de algum placeholder, div, etc..
extraData: {
idRegistro: $('#guidRegistro').val(), //supondo que vc tenha um campo (guidRegistro) na tela com o GUID preenchido ref ao id do registro que quer atualizar
},
onSuccess: function (result) {
customPageContext.msg.success("Atualização com sucesso", "Confirmação");
},
onError: function (error) {
customPageContext.msg.error("Atualização nao realizada", "Erro");
console.log('error', error)
}
}
)
}
Para Deletar (Delete)
Delete usando C#
public class ExemploMinhaClasseCsharp{
public async Task DeletarRegistroAsync(Guid idRegistro){
await CustomPageContext.DeleteAsync(idRegistro);
}
}
public ExemploMinhaClasseCsharp CreateInstanceExemploMinhaClasseCsharp(){
var obj = CreateInstance<ExemploMinhaClasseCsharp>();
return obj;
}
Agora você precisa chamar esse metodo dentro do seu page<body> ou no partial cshtml.
@{
var obj = CustomPageClass.CreateInstanceExemploMinhaClasseCsharp();
var idRegistro = CustomPageContext.GetParam("idRegistro");
await obj.DeletarRegistroAsync(Guid.Parse(idRegistro));
}
Form Deletado
Uma das formas para Passar o Id do Registro que deve ser atualizado, você pode utilizar a função abaixo no javascript:
function loadPartialToDeleteRegister() {
var cshtmlPartialName = "[coloque aqui o nome do partial cshtml que vc fez as regras de deletar]";
customPageContext.loadCsHtmlComponent(cshtmlPartialName,
{
placeholderId: 'result_cshtml', //parametro opcional, se o cshtml retornar algum html e vc quiser, vc pode colocar o retorno dentro de algum placeholder, div, etc..
extraData: {
idRegistro: $('#guidRegistro').val(), //supondo que vc tenha um campo (guidRegistro) na tela com o GUID preenchido ref ao id do registro que quer deletar
},
onSuccess: function (result) {
customPageContext.msg.success("Removido com sucesso", "Confirmação");
},
onError: function (error) {
customPageContext.msg.error("Remoção nao realizada", "Erro");
console.log('error', error)
}
}
)
}
Delete usando cshtml
@{
var idRegistro = CustomPageContext.GetParam("idRegistro");
await CustomPageContext.DeleteAsync(idRegistro);
}
Form Atualizado
Uma das formas para Passar o Id do Registro que deve ser atualizado, você pode utilizar a função abaixo no javascript:
function loadPartialToDeleteRegister() {
var cshtmlPartialName = "[coloque aqui o nome do partial cshtml que vc fez as regras de deletar]";
customPageContext.loadCsHtmlComponent(cshtmlPartialName,
{
placeholderId: 'result_cshtml', //parametro opcional, se o cshtml retornar algum html e vc quiser, vc pode colocar o retorno dentro de algum placeholder, div, etc..
extraData: {
idRegistro: $('#guidRegistro').val(), //supondo que vc tenha um campo (guidRegistro) na tela com o GUID preenchido ref ao id do registro que quer deletar
},
onSuccess: function (result) {
customPageContext.msg.success("Removido com sucesso", "Confirmação");
},
onError: function (error) {
customPageContext.msg.error("Remoção nao realizada", "Erro");
console.log('error', error)
}
}
)
}
[Custom Page] Como abrir outra página ou um lightbox / modal a partir do Custom Page
function openLightBox(tamanho, url) {
var __baseUrl = customPageContext.url.getBaseUrl();
url = __baseUrl + url;
customPageContext.openLightBox(url, tamanho)
}
//Abrir lightbox tela cheia
//Abrir um custom page
openLightBox('fullscreen', 'custompage/6d6d2752-5fcd-4303-aa1b-1ab9e32b38d3')
//Abrir lightbox tamanho grande
//Abrir um form de cadastro
openLightBox('g', 'fluxo/index/0153b02c-d4d8-4747-9a69-45aafa113f81/1f25c74f-a048-4d83-86eb-f31b9608b615')
//Abrir lightbox tamanho médio
//Abrir um list de um form
openLightBox('m', 'fluxo/list/0153b02c-d4d8-4747-9a69-45aafa113f81')
//Abrir lightbox tamanho pequeno
//abrir um board
openLightBox('p', '/b/YKYZ92/custom-code')
[Form] Quais são as funções nativas do AgilityFlow disponíveis no JavaScript para utilizar em um Formulário? formContext
O módulo formContext fornece uma série de funções utilitárias para manipulação de formulários, campos, datas, mensagens e outras funcionalidades no contexto de um formulário personalizado. Abaixo estão as funcionalidades disponíveis, organizadas por categoria.
Verificações de Contexto
parentFrame
Identifica e armazena a referência do iframe pai.
formContext.parentFrame
formContext.parentFrame.formContext.field.getValue("xxx")
isMobile()
Verifica se o dispositivo é móvel.
-
Retorno:
-
truese for um dispositivo móvel. -
falsecaso contrário.
-
-
Exemplo:
if (formContext.isMobile()) { console.log("Dispositivo móvel detectado."); }
isPublicPortal()
Verifica se o formulário está sendo exibido em um portal público.
-
Retorno:
-
truese for um portal público. -
falsecaso contrário.
-
-
Exemplo:
if (formContext.isPublicPortal()) { console.log("Formulário em portal público."); }
isPublicForm()
Verifica se o formulário é público (mesma lógica de isPublicPortal).
-
Retorno:
-
truese for um formulário público. -
falsecaso contrário.
-
-
Exemplo:
if (formContext.isPublicForm()) { console.log("Formulário público detectado."); }
Redirecionamento
redirectTo(url)
Redireciona para uma URL especificada.
-
Parâmetros:
-
url(String): URL para redirecionamento.
-
-
Exemplo:
formContext.redirectTo("https://www.exemplo.com");
Abrir Lightbox
openLightBox(link, tamanholightbox, titulo)
Abre uma lightbox com o conteúdo da URL especificada.
-
Parâmetros:
-
link(String): URL a ser carregada na lightbox. -
tamanholightbox(String): Tamanho da lightbox. Valores possíveis:'p','m','g','fullscreen','fullscreen-headerless'. -
titulo(String): Título da lightbox.
-
-
Exemplo:
formContext.openLightBox("https://www.exemplo.com", "m", "Título da Lightbox");
Carregamento de Arquivos JavaScript
addJavascriptFile(options)
Adiciona um arquivo JavaScript à página de forma assíncrona e executa um callback após o carregamento.
-
Parâmetros:
-
options(Object): Objeto com as propriedades:-
file_url(String): URL do arquivo JavaScript. -
callback_onload(Function): Função a ser executada após o carregamento do arquivo.
-
-
-
Exemplo:
formContext.addJavascriptFile({ file_url: "https://www.exemplo.com/script.js", callback_onload: function() { console.log("Script carregado!"); } });
Busca de CEP
buscaCEP.configurar(idCampoCep, idCamposPreenchiveis, callbacks)
Configura a busca de CEP para campos específicos.
-
Parâmetros:
-
idCampoCep(String): ID do campo de CEP. -
idCamposPreenchiveis(String): ID dos campos a serem preenchidos com os dados do CEP. -
callbacks(Object): Callbacks para eventos relacionados à busca de CEP.
-
-
Exemplo:
formContext.buscaCEP.configurar("cep", "endereco", { onSuccess: function(data) { console.log("CEP encontrado:", data); } });
Carregamento de Componentes CSHTML
loadCsHtmlComponent(componentName, options)
Carrega um componente CSHTML via AJAX.
-
Parâmetros:
-
componentName(String): Nome do componente. -
options(Object): Opções adicionais para o carregamento.
-
-
Exemplo:
function loadPartial() { var cshtmlPartialName = "[coloque aqui o nome do partial cshtml que vc fez as regras de atualizar]"; formContext.loadCsHtmlComponent(cshtmlPartialName, { placeholderId: 'result_cshtml', //parametro opcional, se o cshtml retornar algum html e vc quiser, vc pode colocar o retorno dentro de algum placeholder, div, etc.. extraData: { idRegistro: $('#guidRegistro').val(), nome: $('#nome').val(), email: $('#email').val() }, onSuccess: function (result) { formContext.msg.success("Executado com sucesso", "Confirmação"); }, onError: function (error) { formContext.msg.error("Execução não realizada", "Erro"); console.log('error', error) } } ) }
Manipulação de URLs
url.getBaseUrl()
Retorna a URL base do sistema.
-
Retorno:
-
String com a URL base.
-
-
Exemplo:
console.log("URL base:", formContext.url.getBaseUrl());
url.getStaticFileUrl()
Retorna a URL base para arquivos estáticos.
-
Retorno:
-
String com a URL de arquivos estáticos.
-
-
Exemplo:
console.log("URL de arquivos estáticos:", formContext.url.getStaticFileUrl());
Idioma Atual
currentLanguage.get()
Retorna o idioma atual do sistema.
-
Retorno:
-
String com o código do idioma (ex:
'pt-BR','en-US').
-
-
Exemplo:
console.log("Idioma atual:", formContext.currentLanguage.get());
currentLanguage.isEnglish()
Verifica se o idioma atual é inglês.
-
Retorno:
-
truese for inglês. -
falsecaso contrário.
-
-
Exemplo:
if (formContext.currentLanguage.isEnglish()) { console.log("Idioma atual é inglês."); }
currentLanguage.getIIF_TextFromCurrentLanguage(text_ptBR, text_ENG, text_ESP)
Retorna o texto correspondente ao idioma atual.
-
Parâmetros:
-
text_ptBR(String): Texto em português. -
text_ENG(String): Texto em inglês. -
text_ESP(String): Texto em espanhol.
-
-
Retorno:
-
String com o texto no idioma atual.
-
-
Exemplo:
const texto = formContext.currentLanguage.getIIF_TextFromCurrentLanguage("Olá", "Hello", "Hola"); console.log(texto); // Retorna "Olá" se o idioma for português.
Mensagens
O módulo formContext.msg fornece funções para exibir e ocultar mensagens de alerta, erro, sucesso e aviso no sistema. Abaixo estão as funcionalidades disponíveis.
Ocultar Mensagens
hide(forcarFechar)
Oculta todas as mensagens exibidas.
-
Parâmetros:
-
forcarFechar(Boolean): Força o fechamento das mensagens.
-
-
Exemplo:
formContext.msg.hide(true); // Oculta todas as mensagens, forçando o fechamento.
Exibir Mensagens
show(type, msg, title, options)
Exibe uma mensagem de alerta, erro, sucesso ou aviso.
-
Parâmetros:
-
type(String): Tipo da mensagem. Valores possíveis:-
'warning': Mensagem de aviso. -
'error': Mensagem de erro. -
'success': Mensagem de sucesso.
-
-
msg(String): Texto da mensagem. -
title(String): Título da mensagem. -
options(Object): Opções adicionais para personalização da mensagem.
-
-
Exemplo:
formContext.msg.show("success", "Operação realizada com sucesso!", "Sucesso", { timeout: 5000 });
warning(msg, title, options)
Exibe uma mensagem de aviso.
-
Parâmetros:
-
msg(String): Texto da mensagem. -
title(String): Título da mensagem. -
options(Object): Opções adicionais.
-
-
Exemplo:
formContext.msg.warning("Atenção: Este campo é obrigatório.", "Aviso");
error(msg, title)
Exibe uma mensagem de erro.
-
Parâmetros:
-
msg(String): Texto da mensagem. -
title(String): Título da mensagem.
-
-
Exemplo:
formContext.msg.error("Ocorreu um erro ao salvar o formulário.", "Erro");
success(msg, title, options)
Exibe uma mensagem de sucesso.
-
Parâmetros:
-
msg(String): Texto da mensagem. -
title(String): Título da mensagem. -
options(Object): Opções adicionais.
-
-
Exemplo:
formContext.msg.success("Formulário salvo com sucesso!", "Sucesso", { timeout: 3000 });
Funções Legadas de Mensagens
As funções abaixo são mantidas para compatibilidade com versões anteriores, mas é recomendado utilizar as funções acima (show, warning, error, success).
hideMsgs()
Oculta todas as mensagens exibidas.
-
Exemplo:
formContext.msg.hideMsgs();
showMsgWarning(msg, title, options)
Exibe uma mensagem de aviso (legado).
-
Parâmetros:
-
msg(String): Texto da mensagem. -
title(String): Título da mensagem. -
options(Object): Opções adicionais.
-
-
Exemplo:
formContext.msg.showMsgWarning("Atenção: Este campo é obrigatório.", "Aviso");
showMsgError(msg, title)
Exibe uma mensagem de erro (legado).
-
Parâmetros:
-
msg(String): Texto da mensagem. -
title(String): Título da mensagem.
-
-
Exemplo:
formContext.msg.showMsgError("Ocorreu um erro ao salvar o formulário.", "Erro");
showMsgSuccess(msg, title, options)
Exibe uma mensagem de sucesso (legado).
-
Parâmetros:
-
msg(String): Texto da mensagem. -
title(String): Título da mensagem. -
options(Object): Opções adicionais.
-
-
Exemplo:
formContext.msg.showMsgSuccess("Formulário salvo com sucesso!", "Sucesso", { timeout: 3000 });
Exemplos de Uso de Mensagem
Exibindo uma mensagem de sucesso:
formContext.msg.success("Dados salvos com sucesso!", "Sucesso", { timeout: 5000 });
Exibindo uma mensagem de erro:
formContext.msg.error("Erro ao processar a solicitação.", "Erro");
Ocultando todas as mensagens:
formContext.msg.hide(true);
Manipulação de Números
number.convertString_toNumber(strValueToConvert, qtdCasasDecimais)
Converte uma string formatada em número.
-
Parâmetros:
-
strValueToConvert(String): Valor em formato de string. -
qtdCasasDecimais(Number): Quantidade de casas decimais.
-
-
Retorno:
-
Número convertido.
-
-
Exemplo:
const numero = formContext.number.convertString_toNumber("1.000,50", 2); console.log(numero); // Retorna 1000.50
number.convertNumber_toStringFormatted(numberToConvert, qtdCasasDecimais)
Converte um número em uma string formatada de acordo com o idioma.
-
Parâmetros:
-
numberToConvert(Number): Número a ser convertido. -
qtdCasasDecimais(Number): Quantidade de casas decimais.
-
-
Retorno:
-
String formatada.
-
-
Exemplo:
const texto = formContext.number.convertNumber_toStringFormatted(1000.50, 2); console.log(texto); // Retorna "1.000,50" em português.
Manipulação de Datas
isCurrentMonthAndYear(data)
Verifica se a data fornecida pertence ao mês e ano atuais.
-
Parâmetros:
-
data(String): Data no formatoDD/MM/YYYY.
-
-
Retorno:
-
truese a data for do mês e ano atuais. -
falsecaso contrário.
-
-
Exceções:
-
Lança um
TypeErrorse a data estiver em um formato inválido.
-
-
Exemplo:
formContext.datetime.validation.isCurrentMonthAndYear("25/10/2023"); // Retorna true se outubro de 2023 for o mês e ano atuais.
compare(date1, compare, date2)
Compara duas datas com base no operador especificado.
-
Parâmetros:
-
date1(String): Primeira data no formatoDD/MM/YYYY. -
compare(String): Operador de comparação. Valores possíveis:-
'greater'ou'>' -
'greater-or-equal'ou'>=' -
'less'ou'<' -
'less-or-equal'ou'<=' -
'equal'ou'=='
-
-
date2(String): Segunda data no formatoDD/MM/YYYY.
-
-
Retorno:
-
trueoufalse, dependendo da comparação.
-
-
Exceções:
-
Lança um
TypeErrorse as datas estiverem em formato inválido ou se o operador de comparação não for reconhecido.
-
-
Exemplo:
formContext.datetime.validation.compare("25/10/2023", "greater", "20/10/2023"); // Retorna true.
compareDatetime(datetime1, compare, datetime2)
Compara duas datas e horários com base no operador especificado.
-
Parâmetros:
-
datetime1(String): Primeira data e horário no formatoDD/MM/YYYY HH:mm. -
compare(String): Operador de comparação. Valores possíveis:-
'greater'ou'>' -
'greater-or-equal'ou'>=' -
'less'ou'<' -
'less-or-equal'ou'<=' -
'equal'ou'=='
-
-
datetime2(String): Segunda data e horário no formatoDD/MM/YYYY HH:mm.
-
-
Retorno:
-
trueoufalse, dependendo da comparação.
-
-
Exceções:
-
Lança um
TypeErrorse os dados estiverem em formato inválido ou se o operador de comparação não for reconhecido.
-
-
Exemplo:
formContext.datetime.validation.compareDatetime("25/10/2023 14:30", "greater", "25/10/2023 12:00"); // Retorna true.
compareToday(compare, date2)
Compara a data atual com uma data fornecida.
-
Parâmetros:
-
compare(String): Operador de comparação. Valores possíveis:-
'greater'ou'>' -
'greater-or-equal'ou'>=' -
'less'ou'<' -
'less-or-equal'ou'<=' -
'equal'ou'=='
-
-
date2(String): Data no formatoDD/MM/YYYY.
-
-
Retorno:
-
trueoufalse, dependendo da comparação.
-
-
Exemplo:
formContext.datetime.validation.compareToday("less", "30/10/2023"); // Retorna true se a data atual for menor que 30/10/2023.
Adição de Tempo
day(data, days)
Adiciona dias a uma data.
-
Parâmetros:
-
data(String): Data no formatoDD/MM/YYYYouDD/MM/YYYY HH:mm. -
days(Number): Número de dias a serem adicionados.
-
-
Retorno:
-
Data resultante no mesmo formato da entrada.
-
-
Exemplo:
formContext.datetime.add.day("25/10/2023", 5); // Retorna "30/10/2023".
month(data, months)
Adiciona meses a uma data.
-
Parâmetros:
-
data(String): Data no formatoDD/MM/YYYYouDD/MM/YYYY HH:mm. -
months(Number): Número de meses a serem adicionados.
-
-
Retorno:
-
Data resultante no mesmo formato da entrada.
-
-
Exemplo:
formContext.datetime.add.month("25/10/2023", 2); // Retorna "25/12/2023".
year(data, years)
Adiciona anos a uma data.
-
Parâmetros:
-
data(String): Data no formatoDD/MM/YYYYouDD/MM/YYYY HH:mm. -
years(Number): Número de anos a serem adicionados.
-
-
Retorno:
-
Data resultante no mesmo
-
hour(data, hours)
Adiciona horas a uma data e horário.
-
Parâmetros:
-
data(String): Data e horário no formatoDD/MM/YYYY HH:mm. -
hours(Number): Número de horas a serem adicionadas.
-
-
Retorno:
-
Data e horário resultante no formato
DD/MM/YYYY HH:mm.
-
-
Exemplo:
formContext.datetime.add.hour("25/10/2023 14:30", 3); // Retorna "25/10/2023 17:30".
minute(data, minutes)
Adiciona minutos a uma data e horário.
-
Parâmetros:
-
data(String): Data e horário no formatoDD/MM/YYYY HH:mm. -
minutes(Number): Número de minutos a serem adicionados.
-
-
Retorno:
-
Data e horário resultante no formato
DD/MM/YYYY HH:mm.
-
-
Exemplo:
formContext.datetime.add.minute("25/10/2023 14:30", 15); // Retorna "25/10/2023 14:45".
Obtenção de Datas
getLastDayOfCurrentMonth()
Retorna o último dia do mês atual.
-
Retorno:
-
Data no formato
DD/MM/YYYY.
-
-
Exemplo:
formContext.datetime.getLastDayOfCurrentMonth(); // Retorna "31/10/2023" se outubro for o mês atual.
getLastDayOfMonth(data)
Retorna o último dia do mês da data fornecida.
-
Parâmetros:
-
data(String): Data no formatoDD/MM/YYYY.
-
-
Retorno:
-
Data no formato
DD/MM/YYYY.
-
-
Exemplo:
formContext.datetime.getLastDayOfMonth("25/10/2023"); // Retorna "31/10/2023".
Data e Horário Atuais
getDateNow()
Retorna a data e horário atuais.
-
Retorno:
-
Objeto
Daterepresentando a data e horário atuais.
-
-
Exemplo:
formContext.datetime.getDateNow(); // Retorna a data e horário atuais.
getFormattedDateTime()
Retorna a data e horário atuais formatados.
-
Retorno:
-
String no formato
DD/MM/YYYY HH:mm.
-
-
Exemplo:
formContext.datetime.getFormattedDateTime(); // Retorna "25/10/2023 14:30".
getFormattedDate()
Retorna a data atual formatada.
-
Retorno:
-
String no formato
DD/MM/YYYY.
-
-
Exemplo:
formContext.datetime.getFormattedDate(); // Retorna "25/10/2023".
Manipulação de Campos
O módulo formContext.field fornece funções para manipular campos em formulários, como verificar assinaturas, controlar campos obrigatórios, gerenciar selects, ocultar/exibir campos, habilitar/desabilitar campos e definir/obter valores. Abaixo estão as funcionalidades disponíveis.
Campo de Assinatura
signature.isDefined(campokey)
Verifica se uma assinatura foi preenchida em um campo específico.
-
Parâmetros:
-
campokey(String): ID do campo de assinatura.
-
-
Retorno:
-
truese a assinatura foi preenchida. -
falsecaso contrário.
-
-
Exemplo:
if (formContext.field.signature.isDefined("assinatura")) { console.log("Assinatura preenchida."); }
Campos Obrigatórios
required.ignoreRequired(campokey)
Ignora a validação de campo obrigatório para um campo específico.
-
Parâmetros:
-
campokey(String): ID do campo.
-
-
Exemplo:
formContext.field.required.ignoreRequired("campo1"); // Ignora a validação de campo obrigatório para "campo1".
required.unsetIgnoreRequired(campokey)
Remove a configuração de ignorar validação de campo obrigatório para um campo específico.
-
Parâmetros:
-
campokey(String): ID do campo.
-
-
Exemplo:
formContext.field.required.unsetIgnoreRequired("campo1"); // Remove a configuração de ignorar validação para "campo1".
Campos Select Personalizados
customSelect.setDefaultStyle(selector)
Aplica o estilo padrão do sistema a um select personalizado.
-
Parâmetros:
-
selector(String): Seletor do campo select.
-
-
Exemplo:
formContext.field.customSelect.setDefaultStyle("meuSelect"); // Aplica o estilo padrão ao select com ID "meuSelect".
Manipulação de Itens em Campos Select Personalizados
select.items.disable(campokey, valuesToDisable)
Desabilita itens específicos em um campo select.
-
Parâmetros:
-
campokey(String): ID do campo select. -
valuesToDisable(String ou Array): Valor(es) do(s) item(ns) a ser(em) desabilitado(s).
-
-
Exemplo:
formContext.field.select.items.disable("meuSelect", "valor1"); // Desabilita o item com valor "valor1". formContext.field.select.items.disable("meuSelect", ["valor1", "valor2"]); // Desabilita os itens com valores "valor1" e "valor2".
select.items.enable(campokey, valuesToDisable)
Habilita itens específicos em um campo select.
-
Parâmetros:
-
campokey(String): ID do campo select. -
valuesToDisable(String ou Array): Valor(es) do(s) item(ns) a ser(em) habilitado(s).
-
-
Exemplo:
formContext.field.select.items.enable("meuSelect", "valor1"); // Habilita o item com valor "valor1". formContext.field.select.items.enable("meuSelect", ["valor1", "valor2"]); // Habilita os itens com valores "valor1" e "valor2".
select.items.disableAll(campokey)
Desabilita todos os itens de um campo select.
-
Parâmetros:
-
campokey(String): ID do campo select.
-
-
Exemplo:
formContext.field.select.items.disableAll("meuSelect"); // Desabilita todos os itens do select.
select.items.enableAll(campokey)
Habilita todos os itens de um campo select.
-
Parâmetros:
-
campokey(String): ID do campo select.
-
-
Exemplo:
formContext.field.select.items.enableAll("meuSelect"); // Habilita todos os itens do select.
Visibilidade de Campos
hide(campokey)
Oculta um campo específico.
-
Parâmetros:
-
campokey(String ou Array): ID do campo ou lista de IDs.
-
-
Exemplo:
formContext.field.hide("campo1"); // Oculta o campo com ID "campo1". formContext.field.hide(["campo1", "campo2"]); // Oculta os campos com IDs "campo1" e "campo2".
show(campokey)
Exibe um campo específico.
-
Parâmetros:
-
campokey(String ou Array): ID do campo ou lista de IDs.
-
-
Exemplo:
formContext.field.show("campo1"); // Exibe o campo com ID "campo1". formContext.field.show(["campo1", "campo2"]); // Exibe os campos com IDs "campo1" e "campo2".
hideAll()
Oculta todos os campos do formulário.
-
Exemplo:
formContext.field.hideAll(); // Oculta todos os campos.
showAll()
Exibe todos os campos do formulário.
-
Exemplo:
formContext.field.showAll(); // Exibe todos os campos.
Habilitação/Desabilitação de Campos
disable(campokey)
Desabilita um campo específico.
-
Parâmetros:
-
campokey(String ou Array): ID do campo ou lista de IDs.
-
-
Exemplo:
formContext.field.disable("campo1"); // Desabilita o campo com ID "campo1". formContext.field.disable(["campo1", "campo2"]); // Desabilita os campos com IDs "campo1" e "campo2".
enable(campokey)
Habilita um campo específico.
-
Parâmetros:
-
campokey(String ou Array): ID do campo ou lista de IDs.
-
-
Exemplo:
formContext.field.enable("campo1"); // Habilita o campo com ID "campo1". formContext.field.enable(["campo1", "campo2"]); // Habilita os campos com IDs "campo1" e "campo2".
disableAll()
Desabilita todos os campos do formulário.
-
Exemplo:
formContext.field.disableAll(); // Desabilita todos os campos.
enableAll()
Habilita todos os campos do formulário.
-
Exemplo:
formContext.field.enableAll(); // Habilita todos os campos.
Definição e Obtenção de Valores de Campos
setValue(campoKey, value, options)
Define o valor de um campo.
-
Parâmetros:
-
campoKey(String): ID do campo. -
value(String): Valor a ser definido. -
options(Object): Opções adicionais.
-
-
Exemplo:
formContext.field.setValue("campo1", "Valor exemplo"); // Define o valor do campo "campo1".
getValue(campoKey)
Obtém o valor de um campo.
-
Parâmetros:
-
campoKey(String): ID do campo.
-
-
Retorno:
-
Valor do campo.
-
-
Exemplo:
const valor = formContext.field.getValue("campo1"); // Obtém o valor do campo "campo1".
getText(campoKey)
Obtém o texto exibido de um campo.
-
Parâmetros:
-
campoKey(String): ID do campo.
-
-
Retorno:
-
Texto do campo.
-
-
Exemplo:
const texto = formContext.field.getText("campo1"); // Obtém o texto do campo "campo1".
getInt(campoKey)
Obtém o valor de um campo como número inteiro.
-
Parâmetros:
-
campoKey(String): ID do campo.
-
-
Retorno:
-
Valor inteiro.
-
-
Exemplo:
const valorInteiro = formContext.field.getInt("campo1"); // Obtém o valor inteiro do campo "campo1".
getDecimal(campoKey)
Obtém o valor de um campo como número decimal.
-
Parâmetros:
-
campoKey(String): ID do campo.
-
-
Retorno:
-
Valor decimal.
-
-
Exemplo:
const valorDecimal = formContext.field.getDecimal("campo1"); // Obtém o valor decimal do campo "campo1".
getFloat(campoKey)
Obtém o valor de um campo como número de ponto flutuante.
-
Parâmetros:
-
campoKey(String): ID do campo.
-
-
Retorno:
-
Valor de ponto flutuante.
-
-
Exemplo:
const valorFloat = formContext.field.getFloat("campo1"); // Obtém o valor de ponto flutuante do campo "campo1".
getNumber(campoKey)
Obtém o valor de um campo como número (inteiro ou decimal, dependendo da máscara do campo).
-
Parâmetros:
-
campoKey(String): ID do campo.
-
-
Retorno:
-
Valor numérico.
-
-
Exemplo:
const valorNumerico = formContext.field.getNumber("campo1"); // Obtém o valor numérico do campo "campo1".
Manipulação do Formulário
O objeto formContext.form gerencia diversas funcionalidades relacionadas ao formulário, incluindo salvamento, rascunhos, ações e manipulação da toolbar.
Estrutura do Objeto formContext.form
-
formContext.form: Contém funcionalidades relacionadas ao formulário.-
save(): Salva o formulário. -
saveDraft(): Salva o formulário como rascunho. -
undoDraft(): Desfaz um rascunho. -
getFormActionOnSubmit(): Obtém o tipo de envio do formulário. -
invalidateForm(options): Inválida o submit do formulário. -
toolbar: Manipula a toolbar do formulário. -
disableNativeSuccessMsg(): Desabilita mensagens nativas de sucesso. -
forceToSetStateFormToChanged(): Força o status do formulário para "alterado". -
isNew(): Verifica se o formulário é novo. -
isDraft(): Verifica se o formulário é um rascunho. -
action: Define os tipos de ações possíveis no formulário.
-
Funções e Exemplos de Uso do formContext.form
save()
Salva o formulário.
formContext.form.save();
saveDraft()
Salva o formulário como rascunho.
formContext.form.saveDraft();
undoDraft()
Desfaz um rascunho.
formContext.form.undoDraft();
getFormActionOnSubmit()
Obtém o tipo de envio do formulário.
var action = formContext.form.getFormActionOnSubmit();
console.log(action);
invalidateForm(options)
Inválida o submit do formulário.
formContext.form.invalidateForm({ message: "Erro ao enviar!" });
toolbar.hide()
Esconde a toolbar.
formContext.form.toolbar.hide();
toolbar.show()
Exibe a toolbar.
formContext.form.toolbar.show();
toolbar.remove()
Remove a toolbar.
formContext.form.toolbar.remove();
disableNativeSuccessMsg()
Desabilita mensagens nativas de sucesso.
formContext.form.disableNativeSuccessMsg();
forceToSetStateFormToChanged()
Força o status do formulário para "alterado".
formContext.form.forceToSetStateFormToChanged();
isNew()
Verifica se o formulário é novo.
if (formContext.form.isNew()) {
console.log("Formulário novo");
}
isDraft()
Verifica se o formulário é um rascunho.
if (formContext.form.isDraft()) {
console.log("Formulário em rascunho");
}
Funções e Exemplos de Uso do formContext.form.action
action.isSave(formAction)
Verifica se a ação é de salvar.
if (formContext.form.action.isSave(1)) {
console.log("Ação de salvar detectada");
}
action.isSaveDraft(formAction)
Verifica se a ação é de salvar como rascunho.
if (formContext.form.action.isSaveDraft(2)) {
console.log("Ação de salvar rascunho");
}
action.isDiscardDraft(formAction)
Verifica se a ação é de descartar o rascunho.
if (formContext.form.action.isDiscardDraft(3)) {
console.log("Ação de descartar rascunho");
}
action.isApproveFromWorkflow(formAction)
Verifica se a ação é de aprovar no workflow.
if (formContext.form.action.isApproveFromWorkflow(4)) {
console.log("Ação de aprovação no workflow");
}
action.isRejectFromWorkflow(formAction)
Verifica se a ação é de rejeitar no workflow.
if (formContext.form.action.isRejectFromWorkflow(5)) {
console.log("Ação de rejeição no workflow");
}
action.isReturnFromWorkflow(formAction)
Verifica se a ação é de retorno no workflow.
if (formContext.form.action.isReturnFromWorkflow(6)) {
console.log("Ação de retorno no workflow");
}
action.isDelete(formAction)
Verifica se a ação é de deleção.
if (formContext.form.action.isDelete(7)) {
console.log("Ação de deleção detectada");
}
action.isSaveChildForm(formAction)
Verifica se a ação é de salvar um formulário filho.
if (formContext.form.action.isSaveChildForm(8)) {
console.log("Ação de salvar formulário filho");
}
action.isDeleteChildForm(formAction)
Verifica se a ação é de deletar um formulário filho.
if (formContext.form.action.isDeleteChildForm(9)) {
console.log("Ação de deletar formulário filho");
}
Manipulação do Formulário Filho (Child Form) formContext.childForm
datatable.refresh(tableid_relacaoFormularioPaiFilhoId)
Atualiza a tabela do formulário filho que está no formulário pai.
Exemplo de Uso:
formContext.childForm.datatable.refresh("tabela123");
datatable.totalRows(tableid_relacaoFormularioPaiFilhoId)
Retorna o número total de linhas da tabela do formulário filho.
Exemplo de Uso:
var total = formContext.childForm.datatable.totalRows("tabela123");
console.log("Total de linhas:", total);
datatable.getAllChildIds(tableid_relacaoFormularioPaiFilhoId)
Retorna todos os IDs dos formulários filhos presentes na tabela.
Exemplo de Uso:
var ids = formContext.childForm.datatable.getAllChildIds("tabela123");
console.log("IDs dos formulários filhos:", ids);
datatable.getAllChildIdsOrdered(tableid_relacaoFormularioPaiFilhoId)
Retorna todos os IDs dos formulários filhos respeitando a ordenação atual.
Exemplo de Uso:
var orderedIds = formContext.childForm.datatable.getAllChildIdsOrdered("tabela123");
console.log("IDs ordenados:", orderedIds);
datatable.getResultJson(tableid_relacaoFormularioPaiFilhoId)
Retorna um JSON com os resultados apresentados na tabela do formulário filho.
Exemplo de Uso:
var result = formContext.childForm.datatable.getResultJson("tabela123");
console.log("Resultados da tabela:", result);
datatable.setOrder(tableid_relacaoFormularioPaiFilhoId, items_sorted)
Reordena os itens da tabela filha conforme a lista ordenada de IDs.
Exemplo de Uso:
var sortedItems = [
{ formid: "123", draftid: "" },
{ formid: "456", draftid: "" },
{ formid: "789", draftid: "" }
];
formContext.childForm.datatable.setOrder("tabela123", sortedItems);
blockLinkEditOpening()
Bloqueia a abertura do link ao clicar na linha do grid.
Exemplo de Uso:
formContext.childForm.blockLinkEditOpening();
unlockLinkEditOpening()
Desbloqueia a abertura do link ao clicar na linha do grid.
Exemplo de Uso:
formContext.childForm.unlockLinkEditOpening();
Painéis formContext.panel
O módulo formContext.panel fornece funções para manipular painéis (grupo de informações), como exibir, ocultar e controlar o estado de colapso (aberto/fechado). Abaixo estão as funcionalidades disponíveis.
Exibir e Ocultar Painéis
hide(panelId)
Oculta um painel específico.
-
Parâmetros:
-
panelId(String): ID do painel a ser ocultado.
-
-
Exemplo:
formContext.panel.hide("painel1"); // Oculta o painel com ID "painel1".
show(panelId)
Exibe um painel específico.
-
Parâmetros:
-
panelId(String): ID do painel a ser exibido.
-
-
Exemplo:
formContext.panel.show("painel1"); // Exibe o painel com ID "painel1".
Expandir e Recolher Painéis
O módulo collapse permite controlar o estado de colapso (aberto/fechado) de um painel.
collapse.toggle(panelId)
Alterna o estado de colapso de um painel (abre se estiver fechado e fecha se estiver aberto).
-
Parâmetros:
-
panelId(String): ID do painel.
-
-
Exemplo:
formContext.panel.collapse.toggle("painel1"); // Alterna o estado de colapso do painel com ID "painel1".
collapse.isCollapsed(panelId)
Verifica se um painel está colapsado (fechado).
-
Parâmetros:
-
panelId(String): ID do painel.
-
-
Retorno:
-
truese o painel estiver colapsado. -
falsese o painel estiver expandido.
-
-
Exemplo:
const estaColapsado = formContext.panel.collapse.isCollapsed("painel1"); if (estaColapsado) { console.log("O painel está fechado."); } else { console.log("O painel está aberto."); }
collapse.close(panelId)
Fecha (colapsa) um painel.
-
Parâmetros:
-
panelId(String): ID do painel.
-
-
Exemplo:
formContext.panel.collapse.close("painel1"); // Fecha o painel com ID "painel1".
collapse.open(panelId)
Abre (expande) um painel.
-
Parâmetros:
-
panelId(String): ID do painel.
-
-
Exemplo:
formContext.panel.collapse.open("painel1"); // Abre o painel com ID "painel1".
Exemplos de Uso de funções de painéis
Ocultando e exibindo um painel:
formContext.panel.hide("painel1"); // Oculta o painel.
formContext.panel.show("painel1"); // Exibe o painel.
Alternando o estado de colapso de um painel:
formContext.panel.collapse.toggle("painel1"); // Alterna entre aberto e fechado.
Verificando se um painel está colapsado:
if (formContext.panel.collapse.isCollapsed("painel1")) {
console.log("O painel está fechado.");
} else {
console.log("O painel está aberto.");
}
Fechando e abrindo um painel:
formContext.panel.collapse.close("painel1"); // Fecha o painel.
formContext.panel.collapse.open("painel1"); // Abre o painel.
[Custom Page] Como Chamar um Método Global no Custom Page?
Em C#, utilize a classe GlobalClass, como no exemplo abaixo:
//pra chamar um metodo global por exemplo
await GlobalClass.ExecuteExampleAsync()
Como Obter Parâmetros da Query String com JavaScript
Introdução
A query string é a parte da URL que contém parâmetros, geralmente utilizados para passar informações entre páginas. No JavaScript, podemos extrair esses parâmetros utilizando a API URLSearchParams.
Exemplo de URL
Vamos considerar a seguinte URL:
http://seusubdominio.agilifytlow.io?o=valor
Neste caso, o parâmetro o possui o valor valor.
Código JavaScript
Podemos obter o valor do parâmetro o com o seguinte código:
// Captura os parâmetros da query string
const urlParams = new URLSearchParams(window.location.search);
// Obtém o valor do parâmetro 'o'
const oValue = urlParams.get('o');
// Exibe o valor no console
console.log(oValue);
Explicação do Código
-
window.location.searchretorna a parte da URL após o?, ou seja, a query string (?o=valor). -
new URLSearchParams(window.location.search)cria um objeto que permite manipular e acessar os parâmetros da query string. -
urlParams.get('o')obtém o valor do parâmetroo, retornando'valor'. -
console.log(oValue);exibe o valor capturado no console do navegador.
Aplicações Comuns
-
Captura de dados para preencher formulário
-
Personalização de conteúdo baseado em parâmetros da URL
-
Redirecionamentos e filtragens dinâmicas com base em parâmetros
Tratamento de Parâmetros Opcionais
Caso o parâmetro não esteja presente na URL, urlParams.get('o') retornará null. Para evitar erros, podemos adicionar um valor padrão, nesse caso, deixamos em branco usando o '':
const oValue = urlParams.get('o') || '';
console.log(oValue);
Conclusão
A API URLSearchParams fornece uma maneira simples e eficiente de manipular parâmetros da querystring em JavaScript. Isso permite maior flexibilidade no desenvolvimento de aplicações web dinâmicas.
Como escutar o evento javascript que ocorre antes de preencher uma tabela filha e depois de preencher
Evento before-data-load que ocorre antes de carragar os dados na tabela filha
//escutando o evento pós carregamento: before-data-load
//remover os botões de actions da table filha com id 3240ec20-313b-921e-c587-ea979a720690 por exemplo
$('#3240ec20-313b-921e-c587-ea979a720690').on('before-data-load', function (e) {
console.log("evento que ocorre antes de carregar a tabela, before-data-load);
});
Evento data-loaded que ocorre antes de carragar os dados na tabela filha
//escutando o evento pós carregamento: data-loaded
//remover os botões de actions da table filha com id 3240ec20-313b-921e-c587-ea979a720690 por exemplo
$('#3240ec20-313b-921e-c587-ea979a720690').on('data-loaded', function (e, result_json) {
console.log("evento que ocorre depois de carregar a tabela, data-loaded);
$('.grid-result .action-buttons').remove();
});
Como remover os botões de editar e remover de cada linha de uma tabela filha e também o botão de adicionar um novo registro filho
Para remover o botão de adicionar novo registro na tabela filha
Javascript: No form pai, coloque o código javacript abaixo, trocando o id do botão de adicionar da tabela filha que gostaria de remover
$(document).on("ready", function () {
//troca o id abaixo pelo id do botão que de adicionar form filho
$("#btn-formulario-relacionado-3240ec20-313b-921e-c587-ea979a720690").remove();
});
Css: esconda o botão visualmente
No exemplo abaixo forçamos via css que o botão nem seja apresentado, caso o script javascript nao rode à tempo
#btn-formulario-relacionado-3240ec20-313b-921e-c587-ea979a720690{
display: none;
}
Para Remover o editar e remover de cada linha da tabela filha:
Javascript: No form pai, coloque o código javacript abaixo, trocando o Id para o id da tabela filha que gostaria de remover os actions buttons
//remover os actions da table filha só por garantia
$('#trocar_aqui_para_o_guid_tabela_filha').on('data-loaded', function (e, result_json) {
$('.grid-result .action-buttons').remove();
});
Css: Deixe visualmente a coluna onde os actions buttons eram apresentados menores
No exemplo abaixo colocamos uma largura de 30px para qualquer tabela de formulário filho e também forçamos via css que os actions buttons nem seja apresentados, caso o script javascript nao rode à tempo
.grid-result .action-buttons {
display: none !important;
}
.grid-result colgroup col:first-child {
width: 30px !important;
}
Como validar se um e-mail está no formato válido?
Configurar o GlobalClass
Na GlobalClass, crie um arquivo C#, chamado EmailValidator ou algo similar
Coloque dentro do C# criado a seguinte classe
public class EmailValidator{
public bool IsValidEmail(string email)
{
if (string.IsNullOrWhiteSpace(email))
return false;
string pattern = @"^[^@\s]+@[^@\s]+\.[^@\s]+$";
return System.Text.RegularExpressions.Regex.IsMatch(email, pattern, System.Text.RegularExpressions.RegexOptions.IgnoreCase);
}
}
Configurar a regra no Formulário
Dentro do Businnes Rules de um formulário que você tenha um campo de e-mail que gostaria de validar, crie uma regra de negocio chamada Email Validator ou algo similar.
Para esse exemplo, estamos considerando que você tem um campo chamado "email" nesse formulário.
Arraste a business rules criada para ser executada no evento de "Salvar" do formulário.
Dentro da businesse rules, arraste um componente de Promograçao em C# e cole o seguinte código:
Esse código chama a utiliza a GlobalClass EmailValidator e o metodo criado IsValidEmail para validar se o e-mail é valido.
public async Task ExecuteAsync(){
var email = FormContext.GetValue("email");
var emailValidator = GlobalClass.CreateInstanceEmailValidator();
if(!emailValidator.IsValidEmail(email)){
FormContext.WarningMessage("Informe um e-mail válido");
}
}
Configuração de perfil de acesso para visualizar o Custom Menu. Quem poderá ver o item do menu?
⚠ Se o usuário não possuir permissão para a funcionalidade, o item de menu não será exibido para ele, mesmo que esteja configurado no Custom Menu.
Configurou o item no menu mas ele ainda nao aparece para um determinado usuário?
Esse artigo explica como resolver as regras de controle de acesso.
Como funciona o controle de acesso aos itens do menu?
Na tela de Custom Menu, você pode definir quais itens de menu estarão disponíveis para os usuários do sistema. No entanto, é importante entender que a simples adição de um item ao menu não garante que o usuário terá acesso a ele.
Como funciona o controle de acesso?
O sistema verifica se o usuário tem permissão para visualizar e acessar cada item do menu com base no Perfil de Acesso associado a ele. Isso significa que:
O que fazer para que um usuário veja um item no menu?
Para garantir que um usuário tenha acesso ao item de menu desejado, siga estes passos:
- Confirme o Perfil de Acesso do usuário logado: Identifique qual Perfil de Acesso está sendo usado pelo usuário que deve visualizar o menu.
-
Habilite a Funcionalidade: Acesse a configuração do Perfil de Acesso e conceda permissão à funcionalidade associada ao item de menu.
⚠ Se o usuário não possuir permissão para a funcionalidade, o item de menu não será exibido para ele, mesmo que esteja configurado no Custom Menu.
Caso tenha dúvidas, consulte a equipe responsável pela administração de perfis e permissões no sistema.
Como destacar informações importantes, como alertas, sucessos, erros no corpo de um Formulário? Adicione avisos coloridos no Formulário.
A imagem abaxio exemplifica 4 formas de colocar avisos coloridos:
Introdução
Este guia explica como adicionar avisos coloridos (amarelo, azul, verde e vermelho) em um formulário usando HTML e classes CSS. Os avisos são úteis para destacar informações importantes, como alertas, sucessos, erros e informações.
Passo a Passo
1. Na customização do Form, crie um componente cshtml
Crie um componente cshtml para definir os avisos coloridos. Você pode nomear o arquivo como AvisosColoridos.
2. Adicionar o Código dos Avisos
No componente cshtml AvisosColoridos, adicione o seguinte código:
<div class="alert alert-alt alert-warning" role="alert">
<i class="icon md-lamp icon-alert-warning"></i>
<div class="alert-text">
Essa versão de um aviso de warning
</div>
</div>
<div class="alert alert-alt alert-primary" role="alert">
<i class="icon md-lamp icon-alert-primary"></i>
<div class="alert-text">
Essa versão de um aviso de informação
</div>
</div>
<div class="alert alert-alt alert-success" role="alert">
<i class="icon md-lamp icon-alert-success"></i>
<div class="alert-text">
Essa versão de um aviso de sucesso
</div>
</div>
<div class="alert alert-alt alert-danger" role="alert">
<i class="icon md-lamp icon-alert-danger"></i>
<div class="alert-text">
Essa versão de um aviso de erro
</div>
</div>
3. Adicione o novo campo AvisosColoridos ao Form
4. Arraste o componente cshtml para dentro do form onde você gostaria que as msgs aparecessem.
5. Personalização
Você pode personalizar o texto e os ícones dos avisos conforme necessário. As css classes que mudam as cores de cada msg são (alert-warning, alert-primary, alert-success, alert-danger)
Conclusão
Seguindo esses passos, você pode facilmente adicionar avisos coloridos em seus formulários para melhorar a experiência do usuário e destacar informações importantes.
Como fazer a cópia completa de um registro de um formulário? Incluindo as tabelas filhas
Cópia Simples, sem considerar tabelas filhas
Em todos os formulários por padrão já existe uma opção de duplicar/copiar o registro, através do botão representado pelo icone: que fica na barra de botões do formulário:
Essa opção não copia os registos dos formulários filhos ou tabelas. Caso seja necessário, utilize a técnica demonstrada no tópico abaixo nesse mesmo artigo.
Cópia Completa, considerando tabelas filhas
Crie e configure o botão para copiar
- Entre no formulário que você deseja colocar o botão de "Copiar"
- Crie um botão chamado "Copiar", marque para que esse botão
- Marque para esse botão ser mostrado na barra de botões do formulario
- Marque para esse botão Não ser mostrado dentro do formulario
- Deixa o botão fora do layout do formulario, ele nao precisa ser arrastado para dentro do formularío, caso esteja, remova
- no clique do botão em javascript, confiure para chamar a função js: copiarRegistro()
No Visual Code Editor do Formulário
Adicione o Javascript abaixo
function copiarRegistro() {
//só deixa copiar caso nao seja um form novo
if (formContext.form.isNew())
{
pageMsg.formContext.msg.showMsgWarning("Salve o formulário antes de copiar", "Falha ao copiar")
return;
}
//chama o cshtml "CopiarRegistro" que fará a copia
formContext.loadAjax("CopiarRegistro", {
onSuccess: function (response) {
//em caso de sucesso, mostra a msg de sucesso e já redireciona o usuario para a proxima pagina
pageMsg.showMsgSuccess("Orçamento Duplicado", "Sucesso");
//em caso de sucesso, redireciona para a url que foi criado
//importante mudar aqui para o id da estrutura do formulario correto
window.parent.location = window.parent.base_url + "fluxo/index/74ad209b-ee6a-4ae3-9920-2caad2bc7451/" + response.trim() ;
},
onError: function (err) {
pageMsg.formContext.msg.showMsgWarning("Falha: " + err, "Falha ao copiar")
console.error("Erro ao carregar o registro:", err);
}
});
}
Crie um cshtml chamado CopiarRegistro
Cole o código cshtml / C# abaixo:
@{
/*
NESSE EXEMPLO, ESTOU COPIANDO O FORMULARIO ORÇAMENTO E OS ORÇAMENTO ITEM QUE É FILHO DE ORÇAMENTO
*/
//MUDAR AQUI PARA OS IDS DAS ESTRUTURA DOS FORMULARIOS
var idEstruturaFormularioOrcamento = Guid.Parse("74ad209b-ee6a-4ae3-9920-2caad2bc7451");
var idEstruturaFormularioItemOrcamento = Guid.Parse("0c114359-8cb1-4d42-85b4-9882417c386a");
//CRIAR O DICTIONARY COM OS DADOS DO FORM PAI, ORÇAMENTO
var values = new DataDictionary();
values.Add("numero",PageContext.GetValue("numero"));
values.Add("cliente",PageContext.GetValue("cliente"));
//SALVAR O ORÇAMENTO E RECUPERA O ID CRIADO
var orcamentoId = await PageContext.SaveEntityAsync(idEstruturaFormularioOrcamento, values);
var paramsQueryItemOrcamento = new List<NpgsqlParameter>();
paramsQueryItemOrcamento.Add(new NpgsqlParameter("@orcamento", new Guid(PageContext.FormId.ToString())));
//FAZ UMA QUERY PARA BUSCAR TODOS OS ITENS DO ORÇEMANTO ITEM
var sqlItemOrcamento = "select * from x_tbl_orcamento__item where deletado = false and idorcamento = @orcamento limit 100";
var dtItemOrcamento = await PageContext.GetDataTableAsync(sqlItemOrcamento, paramsQueryItemOrcamento.ToArray());
//CASO TENHA ITENS, FAZ UM LOOP PARA COPIAR TODOS E SALVAR
if (dtItemOrcamento != null && dtItemOrcamento.Rows.Count >= 1)
{
foreach (DataRow itemOrcamento in dtItemOrcamento.Rows)
{
//CRIAR O DICTIONARY COM OS DADOS DO FORM FILHO, ORÇAMENTO ITEM
var valuesItemOrcamento = new DataDictionary();
//AQUI COLOCAR O ID DO ORÇAMENTO QUE FAZ A LIGAÇÃO ENTRE O ORÇAMENTO (PAI) E ORÇAMENTO ITEM (FILHO)
valuesItemOrcamento.Add("idorcamento", orcamentoId);
valuesItemOrcamento.Add("detalhes_do_item",itemOrcamento["detalhes_do_item"].ToString());
valuesItemOrcamento.Add("nome_do_item",itemOrcamento["nome_do_item"].ToString());
//SALVAR O ORÇAMENTO ITEM
await PageContext.SaveEntityAsync(idEstruturaFormularioItemOrcamento, valuesItemOrcamento);
}
}
}
@orcamentoId
Nas configuraçoes de botões do formulário, marque para o botão padrão de "duplicar/copiar" não aparecer. Em algumas versões essa opção de nao aparecer pode não estar disponível, sendo assim, você pode usar o css abaixo na opção de CSS para deixar o botão invisível
#btnCopyForm{
display: none
}
Como consultar no banco de dados os campos de upload e acessar a imagem por URL?
Consulta de Dados de Upload no AgilityFlow
Contexto
Campos do tipo upload de arquivo não ficam armazenados diretamente na tabela principal dos dados do formulário. Eles são gravados separadamente na tabela tbl_storage, sendo necessários alguns identificadores para localizar os arquivos corretamente.
Como consultar os dados do upload
Utilize a consulta SQL abaixo para buscar as informações do arquivo enviado:
SELECT sto_id, sto_diretorio AS diretorio, sto_nome_original AS nome_original, sto_nome_virtual AS nome_virtual FROM tbl_storage
WHERE
fca_id = '<id do campo>' AND
frm_id = '<id do formulário>' AND
deletado = false
LIMIT 10
Descrição dos parâmetros
| Campo | Descrição |
|---|---|
fca_id |
ID do campo específico de upload (*** veja na imagem abaixo como pegar esse iD) |
frm_id |
ID do formulário preenchido (registro do formulário) |
deletado |
Define se o arquivo foi excluído logicamente. Use false para considerar apenas arquivos ativos. |
Como recuperar o fca_id do campo Upload?
Acesse o Inspect Element do campo e vá até o local onde o campo de Upload está localizado. Pegue o Id do campo Hidden, como na figura abaixo:
Exemplo prático
Com os seguintes valores:
fca_id = '66584118-b987-4560-bf0f-5fc3e884f849'-
frm_id = '33584118-b987-4560-bf0f-5fc3e884jdhr'
A consulta seria:
SELECT
sto_id,
sto_diretorio,
sto_nome_original,
sto_nome_virtual
FROM
tbl_storage
WHERE
fca_id = '66584118-b987-4560-bf0f-5fc3e884f849' AND
frm_id = '33584118-b987-4560-bf0f-5fc3e884jdhr' AND
deletado = false
LIMIT 10;
Como acessar a imagem via URL
Após consultar os dados na tabela tbl_storage, você poderá obter também o valor do campo sto_id. Com esse ID, é possível acessar a imagem diretamente pelo navegador ou por uma integração externa, utilizando a seguinte URL:
Exemplo:
Se o sto_id retornado na consulta for abc123, a URL para acessar a imagem será:
Essa URL pode ser usada para visualização, download ou incorporação da imagem em outros sistemas ou páginas.
Como chamar uma API externa a partir do agilityflow
Este exemplo mostra como fazer uma requisição HTTP POST para uma API externa no contexto do AgilityFlow.
Importante sobre CancellationToken
O método PostAsync deve sempre utilizar um CancellationToken para garantir que a requisição seja cancelável, evitando problemas em fluxos interrompidos ou expirados.
Para recuperar o CancellationToken, utilize o método adequado ao contexto em que o código está sendo executado. Alguns exemplos:
-
Em regras de negócio do formulário:
FormContext.GetCurrentCancellationToken() -
Em chamadas feitas dentro de uma API customizada:
ApiContext.GetCurrentCancellationToken() -
Em componentes Razor (.cshtml) do formulário:
PageContext.GetCurrentCancellationToken() -
E assim por diante, conforme o contexto (
GlobalContext,CustomPageContext,CardContext, etc.)
Basta utilizar o método
GetCurrentCancellationToken()do contexto atual.
Observação
-
Troque
<<URL_DA_API>>pela URL real da API que deseja acionar.
Como chamar a api em cada contexto?
No FormContext
Crie uma regra de negócio e dentro da regra de Programação em C#, utilize o código abaixo
public async Task ExecuteAsync()
{
var formId = FormContext.FormId.Value.ToString();
await CallExternalApiAsync(formId);
}
public async Task CallExternalApiAsync(string qualquerParametro)
{
if (string.IsNullOrWhiteSpace(qualquerParametro)) return;
var payload = new
{
parametroParaApi = qualquerParametro
};
using (var httpClient = new HttpClient())
{
var content = new StringContent(
JsonConvert.SerializeObject(payload),
Encoding.UTF8,
"application/json"
);
await httpClient.PostAsync("<<URL_DA_API>>", content, FormContext.GetCurrentCancellationToken());
}
}
Na ApiContext
Na programação em C#
public async Task RunAsync()
{
await CallExternalApiAsync("exemplo de parametro");
}
public async Task CallExternalApiAsync(string qualquerParametro)
{
if (string.IsNullOrWhiteSpace(qualquerParametro)) return;
var payload = new
{
parametroParaApi = qualquerParametro
};
using (var httpClient = new HttpClient())
{
var content = new StringContent(
JsonConvert.SerializeObject(payload),
Encoding.UTF8,
"application/json"
);
await httpClient.PostAsync("<<URL_DA_API>>", content, ApiContext.GetCurrentCancellationToken());
}
}
No PageContext dos componentes Cshtml do formulário
Na programação em C# razor dos componente
@{
string qualquerParametro = "";
if (!string.IsNullOrWhiteSpace(qualquerParametro)){
var payload = new
{
parametroParaApi = qualquerParametro
};
using (var httpClient = new HttpClient())
{
var content = new StringContent(
JsonConvert.SerializeObject(payload),
Encoding.UTF8,
"application/json"
);
await httpClient.PostAsync("<<URL_DA_API>>", content, PageContext.GetCurrentCancellationToken());
}
}
}
No GlobalContext
Na programação em C#
public async Task CallExternalApiAsync(string qualquerParametro)
{
if (string.IsNullOrWhiteSpace(requestId)) return;
var payload = new
{
parametroParaApi = qualquerParametro
};
using (var httpClient = new HttpClient())
{
var content = new StringContent(
JsonConvert.SerializeObject(payload),
Encoding.UTF8,
"application/json"
);
await httpClient.PostAsync("<<URL_DA_API>>", content, GlobalContext.GetCurrentCancellationToken());
}
}
No CustomPageContext
Na programação em C# do custom page context
public async Task CallExternalApiAsync(string qualquerParametro)
{
if (string.IsNullOrWhiteSpace(requestId)) return;
var payload = new
{
parametroParaApi = qualquerParametro
};
using (var httpClient = new HttpClient())
{
var content = new StringContent(
JsonConvert.SerializeObject(payload),
Encoding.UTF8,
"application/json"
);
await httpClient.PostAsync("<<URL_DA_API>>", content, CustomPageContext.GetCurrentCancellationToken());
}
}
Limitação ao usar campo do tipo Autocomplete com Numero Sequencial, "Identity" (bigint) na Descrição
No AgilityFlow, ao utilizar um campo do tipo Autocomplete e configurar a Descrição do item com o campo "Identity" de tipo bigint, pode ocorrer o seguinte erro:
Causa
O erro ocorre porque, internamente, na busca que é feita para apresentar as infos no Autocomplete é utilizado um operador de comparação do tipo ~~* (ilike), que é compatível apenas com campos text ou varchar. O tipo bigint não pode ser utilizado diretamente em uma operação ilike.
Solução
Para contornar esse comportamento, é necessário utilizar uma Query Customizável como origem dos dados do campo Autocomplete. Dessa forma, você pode fazer o cast adequado ou definir uma lógica personalizada para exibição e busca.
Exemplo de Ajuste
SELECT Id as Value, "CAMPO_DE_APRESENTACAO" as Name FROM TABELA
where deletado = false and
( @whereLikeCampoApresentacao IS NULL OR
"CAMPO_DE_APRESENTACAO" ilike '%' || @whereLikeCampoApresentacao || '%' )
Algumas regras importantes para a Query Customizada:
1 - O resultado final da query precisa ser os dados do formulário base que você definiu como campo de origem do autocomplete
2 - Na query, o campo de apresentação ainda precisa ser o mesmo do campo qe você definiu nas configurações do autocomplete
3 - Lembre-se de tratar os dados que já foram deletados, usando no where "...deletado = false.."
4 - A query deve retornar duas colunas com os seguintes alias: "Name" e "Value". O "Name" deve ser a mesma coluna definida no campo de apresentação (#) e o "Value", deve ser a coluna "id" do formulário definido como base de dados (Compras ). Exemplo:
SELECT Id as Value, "CAMPO_DE_APRESENTACAO" as Name FROM TABELA where deletado = false and ( @whereLikeCampoApresentacao IS NULL OR "CAMPO_DE_APRESENTACAO" ilike '%' || @whereLikeCampoApresentacao || '%' )
Abrindo Telas em Modo Standalone (sem menus, logo, etc.)
Em algumas situações, pode ser necessário abrir uma tela ou formulário do AgilityFlow de forma isolada, sem exibir os elementos padrões da interface, como:
Esse recurso é útil para integrações externas, form embutidos, visualizações em iframe, ou até mesmo para simplificar a interface em determinados contextos específicos.
Como ativar o modo standalone
Para isso, basta adicionar o parâmetro pagemode=standalone à URL desejada.
Exemplo:
Comportamento do modo standalone
Ao utilizar pagemode=standalone, os seguintes elementos da interface serão ocultados automaticamente:
Quando usar
Use o pagemode=standalone nos seguintes casos:
- Compartilhamento de links limpos, com foco apenas no conteúdo principal
-
Ambientes de exibição simplificada (como quiosques ou tablets)
Observações
-
A URL continua respeitando as permissões de acesso e autenticação do usuário.
-
O parâmetro pode ser combinado com outros parâmetros de URL normalmente.
Como desativar a paginação automática em Queries do AgilityFlow [disable(auto-pagination)]
Visão Geral
Por padrão, o AgilityFlow aplica paginação automática nas queries para garantir performance e evitar sobrecarga na aplicação. No entanto, desenvolvedores podem optar por desabilitar a paginação automática, desde que sigam rigorosamente algumas regras obrigatórias.
Essa configuração é usada em cenários específicos como:
-
Customização avançada de queries
-
Tabelas filhas (Master x Detail)
-
Queries para componentes como
AutoComplete,Listas dinâmicas,CustomDatatable, entre outros
Como desativar a paginação automática
Você deve adicionar a seguinte tag no início da query:
E também usar essas tags obrigatórias no corpo da query:
-
{{pagination-clause}}→ onde será injetado oOFFSET ... LIMIT ... -
{{orderby}}→ onde será injetado oORDER BY -
{{pagination-column}}→ onde será injetada a coluna auxiliar,0 as __result_count_totalpara compatibilidade com aggregate
Exemplo completo:
[disable(auto-pagination)]
SELECT
nome, email, created_at {{pagination-column}}
FROM
tbl_xxxxx
WHERE
deletado = false
{{orderby}}
{{pagination-clause}}
Regras obrigatórias para queries com paginação desativada
Se você optar por desativar a paginação, deve:
| Regra | Descrição |
|---|---|
✅ Incluir as tags {{pagination-clause}}, {{orderby}} e {{pagination-column} na query |
Elas serão substituídas automaticamente no runtime |
✅ Garantir que a query nunca retorne mais do que a configuração page size (qtd de registros esperado) |
O sistema lançará erro se exceder |
✅ Adicionar deletado = false em todas as tabelas utilizadas |
Obrigatório |
❌ Nunca usar ORDER BY, LIMIT, OFFSET diretamente na query sem [disable(auto-pagination)] |
Vai lançar erro |
❌ Não usar INSERT, UPDATE, DELETE |
Apenas SELECTs são permitidos |
Validações adicionais feitas pelo sistema
Mesmo com a paginação desativada, a query será validada quanto a:
-
Segurança (SQL Injection, funções perigosas)
-
Conformidade com naming (sem colunas com espaços, acentos ou nomes reservados como
data) -
Volume de dados (validação por
EXPLAIN) -
Tags obrigatórias ausentes
-
Uso de parâmetros esperados (ex:
@master_idem detail tables)
Como adicionar uma assinatura digital em um Report Print / template de Impressão / PDF
Em muitos cenários regulatórios ou operacionais, é necessário que um Report Print contenha uma assinatura do responsável, seja ela manual, digitalizada ou capturada via formulário.
Neste artigo, vamos mostrar como configurar um campo de assinatura e ajustá-lo visualmente no Report Print, de forma simples e flexível.
Visão geral da solução
A ideia é bem objetiva:
-
Criar um formulário com um campo do tipo Assinatura
-
Arrastar esse campo para dentro do Report Print
-
Ajustar o tamanho e o posicionamento da assinatura usando o Código-Fonte do editor
1. Criando o campo de Assinatura no formulário
No formulário que alimenta o Report Print:
-
Crie um novo campo
-
Selecione o tipo: Assinatura
-
Salve o formulário
Esse campo será responsável por armazenar a imagem da assinatura associada ao operador ou responsável.
Importante: o campo aparecerá disponível como variável para ser usado no Report Print.
2. Inserindo a assinatura no Report Print
Com o Report Print aberto no editor:
-
Arraste o campo Assinatura para o local desejado no documento
-
Ele aparecerá como um placeholder dinâmico (exemplo:
@Assinatura)
Neste momento, o layout ainda é básico, sem controle fino de tamanho ou alinhamento.
3. Acessando o modo Código-Fonte
Para personalizar o layout:
-
Clique no ícone Código-Fonte no menu do editor
-
O HTML completo do Report Print será exibido
É nesse ponto que conseguimos controlar exatamente como a assinatura será exibida.
4. Criando uma classe CSS para a assinatura
No início do código (ou em um local apropriado), adicione um bloco de estilo, exemplo:
<style type="text/css">.assina2{
width: 270px;
margin: auto;
margin-bottom: -30px;
}
</style>
-
width: 270px
Define um tamanho padrão para a assinatura, evitando que ela fique grande demais -
margin: auto
Centraliza a assinatura horizontalmente -
margin-bottom: -30px
Ajusta o espaçamento vertical, aproximando a assinatura do texto abaixo (nome, cargo, empresa etc.)
Esse valor pode (e deve) ser ajustado conforme o layout do seu documento.
5. Envolvendo o campo de assinatura com a classe CSS
Agora, localize no HTML o trecho onde o campo de assinatura aparece e envolva-o com uma div usando a classe criada:
No seu caso real, o campo aparece como um label com bindings internos, algo semelhante a:
<div class="assina2">
<span class="fontededados">
<label class="p-name" data-variablename="Assinatura"> Assinatura </label>
</span>
</div>
O importante é que todo o bloco da assinatura esteja dentro da div.assina2. como no exemplo abaixo
Como adicionar e atualizar itens em uma tabela de formulário filho
Como adicionar e atualizar itens em uma tabela de formulário filho
Este guia explica como inserir e atualizar registros em uma tabela de formulário filho a partir de um formulário pai, utilizando JavaScript + componente CsHtml (partial).
O exemplo usa dados fictícios apenas para demonstrar o funcionamento.
Visão geral da solução
O fluxo funciona assim:
-
Criamos um Formulário Filho (referenciando o pai).
-
Criamos um Formulário Pai e associamos o formulário filho como uma tabela.
-
No formulário pai, criamos um botão que chama um método JavaScript no onclick.
-
Esse método JavaScript carrega um componente CsHtml (partial).
-
Dentro do CsHtml, executamos um loop para inserir registros na tabela do formulário filho.
-
Após a execução, a tabela é atualizada automaticamente na tela.
1. Criar o Formulário Pai
Primeiro, crie um formulário pai contendo os campos que você julgar necessário.
-
Valor da Operação
-
Repsonsável pela operação
2. Criar o Formulário Filho
Em seguida, crie um formulário filho contendo os campos que serão inseridos na tabela.
Exemplo de campos:
-
Tipo de recebível
-
Cedente
-
Sacado
-
Quantidade de parcelas
-
Data de vencimento
-
Valor nominal
- id_pai (IMPORTANTE, aqui você cria o campo que vai associar o form pai e filho) ***
*** detalhes de como fazer a relação Pai e Filho podem ser encontrado em outros docs na Wiki do agilityflow
2. Associar o Formulário Pai ao Filho
No formulário pai:
-
Associe o formulário filho como uma tabela
-
Garanta que ele esteja configurado como tabela de formulário filho
Recupere o Id dessa tabela, no nosso exemplo é: "0e7f3b2f-dd68-a2d4-fe4e-b68e1c3957ef"
Usaremos mais abaixo, algo assim:
var tableid_recebivel = Guid.Parse("0e7f3b2f-dd68-a2d4-fe4e-b68e1c3957ef");
3. Criar o componente CsHtml (partial)
Agora criamos o componente CsHtml que será carregado pelo JavaScript, crie com o nome import_fake
Esse componente será responsável por:
- Inserir registros no formulário filho
-
Retornar o controle para o JavaScript
4. Lógica do CsHtml para inserir registros
Dentro do CsHtml, usamos C# para inserir os dados.
Neste exemplo:
-
Só inserimos se o formulário for novo
-
Ignoramos formulários em rascunho
-
Criamos 10 registros fictícios apenas para demonstração
Exemplo:
@{
//id da tabela
var tableid_recebivel = Guid.Parse("0e7f3b2f-dd68-a2d4-fe4e-b68e1c3957ef"); //table id DO FORMULÁRIO FILHO
//testa se é um form NOVO e se NÂO é RASCUNHO pois nesse exemplo quero inserir apenas para formulário NOVOS que não sejam RASCUNHOs
var isNovo = Model.Id.IsNullOrEmpty();
var isRascunho = !Model.RascunhoId.IsNullOrEmpty();
if(isNovo && !isRascunho){
for (var i = 0;i<10;i++){
var parcelas = Random.Shared.Next(1, 19);
//info do formulario filho
var campos_e_valores = new DataDictionary();
campos_e_valores["tipo_de_recebivel"] = "e253f97a-8315-4ed9-b5f8-9820f7152a60";
campos_e_valores["cedente"] = "335e3af4-f97d-4cf4-9b5c-faf5d14c726d";
campos_e_valores["sacado"] = "12a5c07d-d955-4dc2-85cf-55b20d889761";
campos_e_valores["qtd_de_parcelas"] = parcelas.ToString();
campos_e_valores["data_de_vencto"] = DateTime.Now.AddMonths(1).ToUserTimeZone().ToString();
campos_e_valores["valor_nominal"] = "35000";
//adiciona na tabela filha
//retorna o id do rascunho desse formlario filho, pois o ID final só será gerado ao Salvar o Formulario PAi
var formRascunhoId = await PageContext.AddChildFormAsync( tableid_recebivel, campos_e_valores);
}
}
}
5. Criar o botão no Formulário Pai
No formulário pai, crie um botão com um onclick chamando uma função JavaScript.
Exemplo:
Esse botão será responsável por iniciar o processo de inserção.
6. JavaScript do Formulário Pai
No JavaScript do formulário pai, carregamos o componente CsHtml usando loadCsHtmlComponent.
Esse componente cshtml executará a lógica de inserção e ao retornar faremos via Javacript o "refresh" da tabela para que os dados inseridos apareçam
Exemplo:
function import_fake() {
formContext.loadCsHtmlComponent("import_fake", {
onSuccess: function (result) {
// formContext.msg.success("Executado com sucesso", "Confirmação");
var tableid_recebivel = "0e7f3b2f-dd68-a2d4-fe4e-b68e1c3957ef"
formContext.childForm.datatable.refresh(tableid_recebivel);
}
});
}
Pontos importantes:
-
O
onSuccessé executado após o CsHtml terminar. -
O
datatable.refreshgarante que os novos registros apareçam na tela.
7. O que acontece internamente
-
Cada chamada de
AddChildFormAsynccria um registro no formulário filho -
O ID final do registro só será gerado quando o formulário pai for salvo
-
O retorno do método é o ID do rascunho, usado internamente pelo sistema
8. Atualizando os dados da tabela
Após o CsHtml finalizar:
-
O JavaScript executa
datatable.refresh -
A tabela do formulário filho é recarregada
-
Os registros recém-inseridos aparecem imediatamente na tela
Observações importantes
-
Este exemplo usa dados fictícios
- Sempre valide se o formulário não está em rascunho
-
Para atualizações, a lógica pode ser adaptada para:
-
Buscar registros existentes
-
Alterar valores
-
Inserir apenas registros que não existam
-
Se você precisar atualizar um registro basta seguir o código usando o PageContext.UpdateChildForm como no exemplo abaixo:
@{
//id da tabela
var tableid_relacaoFormularioPaiFilhoId = Guid.Parse("0dd874a9-9c39-4e4f-acc3-02015a60f6bb"); //table id DO FORMULÁRIO FILHO
//info do formulario filho
var campos_e_valores = new DataDictionary();
campos_e_valores["nome_filho"] = "Exemplo 01 - " + DateTime.Now;
campos_e_valores["valor_numerico"] = PageContext.FormatNumberToString_EnglishFormat(999999.99, 2);
//testa se é um form NOVO e se NÂO é RASCUNHO pois nesse exemplo quero inserir apenas para formulário NOVOS que não sejam RASCUNHOs
var isNovo = Model.Id.IsNullOrEmpty();
var isRascunho = !Model.RascunhoId.IsNullOrEmpty();
if(isNovo && !isRascunho){
//adiciona na tabela filha
//retorna o id do rascunho desse formlario filho, pois o ID final só será gerado ao Salvar o Formulario PAi
var formRascunhoId = PageContext.AddChildForm( tableid_relacaoFormularioPaiFilhoId, campos_e_valores);
//atualiza o item que acabamos de adicionar, apenas para demonstração
Guid? idFormularioFilho = null;
campos_e_valores["nome_filho"] = "Exemplo Atualizado 0123456789 - " + DateTime.Now;
PageContext.UpdateChildForm(
//se ainda não foi salvo pela primeira vez, o item só terá o Id do Rascunho
rascunhoId,
//se já foi salvo pela primeira vez, o item já terá o Id
//então passa aqui o id (nesse exemplo estamos passando null para atualizar apenas o
idFormularioFilho,
tableid_relacaoFormularioPaiFilhoId,
campos_e_valores);
}
}

























