Painel |
---|
borderColor | lightgrey |
---|
bgColor | #F0F0F0 |
---|
borderWidth | 2 |
---|
borderStyle | dashed |
---|
|
|
01. INTRODUÇÃO/OBJETIVO
Temos como objetivo implementar técnicas para facilitar a personalização de telas TOTVS - Linha Datasul de forma lowcode, apenas com cadastro de campos por parte do cliente.
02. VISÃO GERAL
A partir da release 12.1.31 são disponibilizados as técnicas e cadastros para implementar a personalização em telas HTML da linha Datasul.
Nesta técnica de personalização, o desenvolvedor deverá realizar o cadastro dos campos a serem personalizados e criar alguns componentes em PO-UI que utilizem os componentes: PO-DYNAMIC-FORM, PO-DYNAMIC-VIEW e PO-PAGE-DYNAMIC-TABLE (este último somente se for necessário). Deve-se também implementar endpoint em Progress, o qual será utilizado como fonte de dados para os campos personalizados.
03. PRÉ-REQUISITOS
Para utilização desta técnica será necessário possuir conhecimento de desenvolvimento com: APIs REST em Progress, Angular, TypeScript e PO-UI.
04. TÉCNICAS
A Técnica de personalização de telas HTML com PO-UI contempla os seguintes objetos:
Endpoint Progress do Framework
Retorna a lista de campos personalizados que devem ser previamente cadastrados na tela de Personalização em HTML.
Neste item, deverá ser utilizado o endpoint Progress /api/btb/v1/personalizationView/metadata/ + código_do_programa ,onde deve ser passado o Código do Programa Datasul que conterá a lista de campos personalizados.
Exemplo: Implementação de personalização para o programa pedido-execucao-monitor, deve-se utilizar o endpoint "/api/btb/v1/personalizationView/metadata/pedido-execucao-monitor":
Endpoint Progress que devem ser implementados na "área de negócio"
Deve retornar os dados que serão apresentados nos campos personalizados;
Utilitário facilitador no Progress
Foi implementado no Progress o utilitário - btb/personalizationUtil.p - com seu include btb/personalizationUtil.i, que deve ser utilizado para retornar à área de negócio a lista de campos personalizáveis de um determinado programa, cujo o intuito é facilitar a implementação para que seja enviado somente os valores dos campos personalizáveis.
Devido a característica do PO-UI dinâmico, caso seja enviado os dados de campos que não estão na lista de campos, o PO-UI irá apresentar o valor do campo com uma label com o mesmo nome do campo. Com a obtenção da lista de campos pode-se evitar o envio de informações que estão fora da lista de campos personalizados.
Todos os componentes dinâmicos do PO-UI realizam, no mínimo, duas requisições REST, uma para obter a lista de campos personalizáveis e outra para obter os dados a serem apresentados nesses campos.
Abaixo temos o papel de cada componente dinâmico que podemos utilizar:
PO-DYNAMIC-FORM
: Para a edição e criação de um novo registro personalizado;
PO-DYNAMIC-VIEW
: Para a visualização do registro personalizado.
Dica |
---|
|
Pode-se implementar também um componente PO-PAGE-DYNAMIC-TABLE , para a navegação dos registros e permitir a visualização e edição dos mesmos. |
Em nossa técnica, em todas as requisições REST, será enviado:
- Para buscar a lista de campos personalizados utilizando o endpoint Progress fornecido pelo framework, que é o /api/btb/v1/personalizationView/metadata/ + codigo_do_programa;
- O código do programa personalizado e também um id do registro corrente para obtenção dos valores, necessários para buscar os valores dos dados a serem apresentados.
05. EXEMPLO DE UTILIZAÇÃO
Cadastro Atributos de campos personalizados
A seguir são apresentados as telas necessárias para a realização do cadastro dos campos personalizados.
Ao localizar no menu o programa Campos personalizados (html.personalization-metadata
), é apresentada a tela em formato de lista que conterá todos os campos (metadados) cadastrados no produto Datasul. Para cadastrar um campo que será utilizado na personalização, basta clicar no botão +Adicionar.
Image Removed
A tela a seguir apresenta o cadastro do metadado relacionado a um campo que pode ser apresentado no programa como personalizado.
Image Removed
Para alguns tipos de campo, é possível informar uma lista de opções apresentadas em tela, para isso basta informar os dados (chave, valor).
Image Removed
Campo | Descrição | Obrigatório |
---|
Código Programa Datasul | Código do programa base que podem ser aplicadas as técnicas de personalização Nota |
---|
| É possível cadastrar os campos somente em programas que permitem a personalização |
| Sim |
Identificador Campo | Identificador único do campo (por programa), necessário para a geração da tela personalizada (código do campo) | Sim |
Nome Campo | Nome do campo que será apresentado na tela (label do campo) Caso o campo não seja informado, o nome do campo apresentado será o informado no identificador. | Não |
Tipo Campo | Tipo do campo cadastrado Caso o campo não seja informado, será considerado que o campo é do tipo Character . Tipos de campos permitidos: Tipo | Descrição |
---|
Checkbox | Valores lógicos, apresentado na interface como um componente de Switch. | Números | Valores numéricos, não sendo permitido a inserção de caracteres. | Data | Valores de datas, apresentado na interface como DatePicker . | Hora | Valor do horário, apresentado máscara 99:99 por padrão. | Character | Valores alfanuméricos. | Moeda | Valores monetários. | TextArea | Valores alfanuméricos, apresentado na interface em um box com 3 linhas. | Senha | Valores alfanuméricos, apresentados na interface como Password. | Radio Group | Lista de seleção apresentadas no formato de radio group , permitido no máximo 3 opções. | Checkbox Group | Lista de seleção múltipla apresentadas no formato de checkbox group , permitido no máximo 3 opções. | Select | Lista de seleção apresentadas no formato de select, é obrigatório cadastrar ao menos 4 opções. | Multiselect | Lista de seleção múltipla apresentadas no formato de select, é obrigatório cadastrar ao menos 4 opções. | Combobox | Lista de seleção apresentadas no formato de combobox , é obrigatório informar o atributo optionsService para resgatar os dados da lista. |
| Não |
Lista Opções | Informa a lista de opções a serem apresentadas em conjunto com o tipo do componente especificado. Informações |
---|
| Esta opção está disponível somente para os tipos Radio Group, Checkbox Group, Select e Multiselect, |
| Somente Leitura | Opção para que o campo seja apresentado como somente leitura (torna o campo readOnly) | Sim |
Habilita personalização | Opção para habilitar ou desabilitar a apresentação da personalização por campo (torna o campo visível) | Sim |
Com a configuração de atributos dos campos personalizados, é possível adicionar outras características tais como:
Ao renderizar os campos personalizados em tela, esses atributos serão inclusos no campo personalizado e enviados para tela.
Aviso |
---|
|
Os nomes dos atributos devem ser os mesmos que estão documentados nas propriedades do componente no PO-UI. Exemplo: Para personalizar um campo no formato CPF, criamos o campo COD_CPF e adicionamos um atributo do tipo mask que conterá o formato 999.999.999-99. O atributo mask corresponde a uma propriedade do componente PO-INPUT. |
Componentes em PO-UI
A seguir, são apresentados exemplos de códigos para a implementação com HTML e TypeScript:
Componente HTML (personalization-detail.component.html)
Expandir |
---|
title | > > > Clique para ver o código... |
---|
|
Bloco de código |
---|
language | powershell |
---|
theme | Confluence |
---|
firstline | 1 |
---|
linenumbers | true |
---|
| <po-loading-overlay
[hidden]="!showLoading">
</po-loading-overlay>
<po-page-detail
p-title="Detalhe do Idioma"
[p-breadcrumb]="breadcrumb"
(p-edit)="editClick()"
(p-back)="goBackClick()"> |
Bloco de código |
---|
language | xml |
---|
firstline | 10 |
---|
title | Trecho da personalização |
---|
linenumbers | true |
---|
| <!-- INICIO CODIGO PERSONALIZAVEL -->
<po-dynamic-view
[p-fields]="fields"
[p-value]="record">
</po-dynamic-view>
<!-- FINAL CODIGO PERSONALIZAVEL -->
|
Bloco de código |
---|
language | xml |
---|
firstline | 18 |
---|
linenumbers | true |
---|
| </po-page-detail |
|
Componente TypeScript (personalization-detail.component.ts)
Expandir |
---|
title | > > > Clique para ver o código... |
---|
|
Bloco de código |
---|
language | delphi |
---|
firstline | 1 |
---|
linenumbers | true |
---|
| import { Component, |
|
Após cadastrar o campo, o mesmo é apresentado na tela inicial onde é possível realizar filtros sobre seus resultados, bem como efetuar ações de edição de campos, inclusão de atributos e exclusão de campos.
Image Removed
Ao clicar na opção de editar, não será possível modificar o código do programa Datasul vinculado e também seu identificador. Os demais campos estão habilitados para edição.
Image Removed
Atributos de campos personalizados
Com a configuração de atributos dos campos personalizados, é possível adicionar outras características tais como:
Ao renderizar os campos personalizados em tela, esses atributos serão inclusos no campo personalizado e enviados para tela.
Aviso |
---|
|
Os nomes dos atributos devem ser os mesmos que estão documentados nas propriedades do componente no PO-UI. Exemplo: Para personalizar um campo no formato CPF, criamos o campo COD_CPF e adicionamos um atributo do tipo mask que conterá o formato 999.999.999-99. O atributo mask corresponde a uma propriedade do componente PO-INPUT. |
Componentes em PO-UI
A seguir, são apresentados exemplos de códigos para a implementação com HTML e TypeScript:
Componente HTML (personalization-detail.component.html)
Expandir |
---|
title | > > > Clique para ver o código... |
---|
|
Bloco de código |
---|
language | powershell |
---|
theme | Confluence |
---|
firstline | 1 |
---|
linenumbers | true |
---|
| <po-loading-overlay
[hidden]="!showLoading">
</po-loading-overlay>
<po-page-detail
p-title="Detalhe do Idioma"
[p-breadcrumb]="breadcrumb"
(p-edit)="editClick()"
(p-back)="goBackClick()"> |
Bloco de código |
---|
language | xml |
---|
firstline | 10 |
---|
title | Trecho da personalização |
---|
linenumbers | true |
---|
| <!-- INICIO CODIGO PERSONALIZAVEL -->
<po-dynamic-view
[p-fields]="fields"
[p-value]="record">
</po-dynamic-view>
<!-- FINAL CODIGO PERSONALIZAVEL -->
|
Bloco de código |
---|
language | xml |
---|
firstline | 18 |
---|
linenumbers | true |
---|
| </po-page-detail |
|
Componente TypeScript (personalization-detail.component.ts)
Expandir |
---|
title | > > > Clique para ver o código... |
---|
|
Bloco de código |
---|
language | delphi |
---|
firstline | 1 |
---|
linenumbers | true |
---|
| import { Component, OnInit } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
import { PoBreadcrumb, PoBreadcrumbItem } from '@po-ui/ng-components';
import { PersonalizationService } from '../personalization.service';
@Component({
selector: 'app-personalization-detail',
templateUrl: './personalization-detail.component.html',
styleUrls: ['./personalization-detail.component.css']
}) |
Bloco de código |
---|
language | js |
---|
firstline | 12 |
---|
title | Variáveis |
---|
linenumbers | true |
---|
| export class PersonalizationDetailComponent implements OnInit {
public static cProg = 'html.aplicativos-eai';
// definicao das variaveis utilizadas
public currentId: string;
public fields: Array<any> = [];
public record = {};
public showLoading = false;
public breadcrumb: PoBreadcrumb = { items: [] };
public breadcrumbItem: PoBreadcrumbItem; |
Bloco de código |
---|
language | js |
---|
firstline | 23 |
---|
title | Construtor |
---|
linenumbers | true |
---|
| // construtor com os servicos necessarios
constructor(
private service: PersonalizationService,
private activatedRoute: ActivatedRoute,
private route: Router
) { } |
Bloco de código |
---|
language | js |
---|
firstline | 29 |
---|
title | Leitura do componente |
---|
linenumbers | true |
---|
| // load do componente
public ngOnInit(): void {
this.activatedRoute.params.subscribe(pars => {
this.showLoading = true;
this.record = {};
// Carrega o registro pelo ID
// tslint:disable-next-line:no-string-literal
this.currentId = pars['id'];
//---BUSCA OS VALORES DOS CAMPOS PERSONALIZADOS DA AREA DE NEGOCIO ----
// busca os valores dos dados a serem apresentados
this.service.loadValuesById(this.currentId).subscribe(resp => {
Object.keys(resp).forEach((key) => this.record[key] = resp[key]);
// ---BUSCA OS CAMPOS PERSONALIZADOS DO PROGRAMA ----
// carrega a lista de campos personalizados somente apos receber os dados a serem apresentados
this.service.loadMetadata().subscribe(metadata => {
// tslint:disable-next-line:no-string-literal
this.fields = metadata['fields'];
this.showLoading = false;
});
});
});
this.setBreadcrumb();
}
private setBreadcrumb(): void {
this.breadcrumbItem = { label: 'Home', link: '/' };
this.breadcrumb.items = this.breadcrumb.items.concat(this.breadcrumbItem);
this.breadcrumbItem = { label: 'Listagem de Idiomas' , link: '/personalization' };
this.breadcrumb.items = this.breadcrumb.items.concat(this.breadcrumbItem);
this.breadcrumbItem = { label: 'Detalhe do Idioma' };
this.breadcrumb.items = this.breadcrumb.items.concat(this.breadcrumbItem);
}
} |
Bloco de código |
---|
language | js |
---|
firstline | 64 |
---|
title | Ação dos botões Editar e Voltar |
---|
linenumbers | true |
---|
| // Redireciona quando clicar no botao Edit
public editClick(): void {
this.route.navigate(['/personalization', 'edit', this.currentId]);
}
// Redireciona quando clicar no botao Voltar
public goBackClick(): void {
this.route.navigate(['/personalization']);
}
} |
|
Componente HTML (personalization-edit.component.html)
Expandir |
---|
title | > > > Clique para ver o código... |
---|
|
Bloco de código |
---|
language | powershell |
---|
theme | Confluence |
---|
firstline | 1 |
---|
linenumbers | true |
---|
| <po-loading-overlay
[hidden]="!showLoading">
</po-loading-overlay>
<po-page-edit
[p-title]="cTitle"
[p-breadcrumb]="breadcrumb"
[p-disable-submit]="formEdit.form.invalid"
(p-cancel)="cancelClick()"
(p-save)="saveClick()"> |
Bloco de código |
---|
language | xml |
---|
firstline | 11 |
---|
title | Trecho da personalização |
---|
linenumbers | true |
---|
| <!-- INICIO CODIGO PERSONALIZAVEL -->
<po-dynamic-form
#formEdit
p-auto-focus="string"
[p-fields]="fields"
[p-validate]="validationUrl"
[p-value]="record">
</po-dynamic-form>
<!-- FINAL CODIGO PERSONALIZAVEL -->
|
Bloco de código |
---|
language | xml |
---|
firstline | 22 |
---|
linenumbers | true |
---|
| </po-page-edit> |
|
Componente TypeScript (personalization-edit.component.ts)
Expandir |
---|
title | > > > Clique para ver o código... |
---|
|
Bloco de código |
---|
language | js |
---|
theme | Confluence |
---|
firstline | 1 |
---|
linenumbers | true |
---|
| import { Component, OnInit, ViewChild } from '@angular/core';
import { NgForm } from '@angular/forms';
import { ActivatedRoute, Router } from '@angular/router';
import { PoBreadcrumb, PoBreadcrumbItem, PoDialogService, PoNotificationService } from '@po-ui/ng-components';
import { PersonalizationService } from './../personalization.service';
@Component({
selector: 'app-personalization-edit',
templateUrl: './personalization-edit.component.html',
styleUrls: ['./personalization-edit.component.css']
}) |
Bloco de código |
---|
language | js |
---|
firstline | 13 |
---|
title | Variáveis |
---|
linenumbers | true |
---|
| export class PersonalizationEditComponent implements OnInit {
// Define as variaveis a serem utilizadas
public cTitle: string;
public currentId: string;
public record = {};
public fields: Array<any> = [];
public isUpdate = false;
public showLoading = false;
public validationUrl = this.service.getUrlAreaValidation();
public breadcrumb: PoBreadcrumb = { items: [] };
public breadcrumbItem: PoBreadcrumbItem;
// Obtem a referencia do componente HTML
@ViewChild('formEdit', { static: true })
formEdit: NgForm;
|
Bloco de código |
---|
language | js |
---|
firstline | 30 |
---|
title | Construtor |
---|
linenumbers | true |
---|
| // Construtor da classe com os servicos necessarios
constructor(
private service: PersonalizationService,
private activatedRoute: ActivatedRoute,
private route: Router,
private poDialog: PoDialogService,
private poNotification: PoNotificationService
) { }
|
Bloco de código |
---|
language | js |
---|
firstline | 38 |
---|
title | Leitura do componente |
---|
linenumbers | true |
---|
| // Load do componente
public ngOnInit(): void {
this.isUpdate = false;
this.showLoading = true;
// Carrega o registro pelo ID
this.activatedRoute.params.subscribe(pars => {
// tslint:disable-next-line:no-string-literal
this.currentId = pars['id'];
// Se nao tiver o ID definido sera um CREATE
if (this.currentId === undefined) {
this.isUpdate = false;
this.cTitle = 'Novo Idioma';
} else {
this.isUpdate = true;
this.cTitle = 'Edição do Idioma';
}
// Atualiza o breadcrumb de acordo com o tipo de edicao
this.setBreadcrumb();
// Se for uma alteracao, busca o registro a ser alterado
if (this.isUpdate) {
// ----- BUSCA OS VALORES DOS CAMPOS PERSONALIZADOS DA AREA DE NEGOCIO -----
this.service.loadValuesById(this.currentId).subscribe(resp => {
Object.keys(resp).forEach((key) => this.record[key] = resp[key]);
// ----- BUSCA OS CAMPOS PERSONALIZADOS DO PROGRAMA -----
// Em alteracao temos que receber o registro para depois buscar a lista de campos
this.getMetadata();
});
} else {
// Se for create, pega a lista de campos
this.getMetadata();
}
});
}
private setBreadcrumb(): void {
this.breadcrumbItem = { label: 'Home', action: this.beforeRedirect.bind(this) };
this.breadcrumb.items = this.breadcrumb.items.concat(this.breadcrumbItem);
this.breadcrumbItem = { label: 'Listagem de Idiomas', action: this.beforeRedirect.bind(this) };
this.breadcrumb.items = this.breadcrumb.items.concat(this.breadcrumbItem);
this.breadcrumbItem = { label: this.cTitle };
this.breadcrumb.items = this.breadcrumb.items.concat(this.breadcrumbItem);
}
// Retorna a lista de campos
private getMetadata() {
this.service.loadMetadata().subscribe(metadata => {
// tslint:disable-next-line:no-string-literal
this.fields = metadata['fields'];
this.showLoading = false;
});
}
// Redireciona via breadcrumb
private beforeRedirect(itemBreadcrumbLabel) {
if (this.formEdit.valid) {
this.route.navigate(['/']);
} else {
this.poDialog.confirm({
title: 'Cancelamento de edição',
message: 'Os dados ainda não foram gravados, confirma redirecinamento ?',
confirm: () => this.route.navigate(['/'])
});
}
}
|
Bloco de código |
---|
language | js |
---|
firstline | 107 |
---|
title | Gravação do registro |
---|
linenumbers | true |
---|
| // Grava o registro quando clicado no botao Salvar
public saveClick(): void {
this.showLoading = true;
if (this.isUpdate) {
// Altera um registro ja existente
this.service.update(this.currentId, this.record).subscribe(resp => {
this.poNotification.success('Dados atualizados com sucesso');
this.showLoading = false;
this.route.navigate(['/personalization']);
});
} else {
// Cria um registro novo
this.service.create(this.currentId, this.record).subscribe(resp => {
this.poNotification.success('Dados criados com sucesso');
this.showLoading = false;
this.route.navigate(['/personalization']);
});
}
}
// Cancela a edicao e redireciona ao clicar no botao Cancelar
public cancelClick(): void {
this.poDialog.confirm({
title: 'Confirmar cancelamento',
message: 'Voce deseja realmente cancelar a edição?',
confirm: () => this.route.navigate(['/personalization'])
});
}
} |
Bloco de código |
---|
language | js |
---|
firstline | 136 |
---|
title | Cancelamento da edição |
---|
linenumbers | true |
---|
| // Cancela a edicao e redireciona ao clicar no botao Cancelar
public cancelClick(): void {
this.poDialog.confirm({
title: 'Confirmar cancelamento',
message: 'Voce deseja realmente cancelar a edição?',
confirm: () => this.route.navigate(['/personalization'])
});
}
} |
|
Componente HTML (personalization-list.component.html)
Expandir |
---|
title | > > > Clique para ver o código... |
---|
|
Bloco de código |
---|
language | powershell |
---|
theme | Confluence |
---|
firstline | 1 |
---|
linenumbers | true |
---|
| <po-loading-overlay
[hidden]="!showLoading">
</po-loading-overlay> |
Bloco de código |
---|
language | xml |
---|
firstline | 4 |
---|
title | Trecho da personalização |
---|
linenumbers | true |
---|
| <!-- INICIO CODIGO PERSONALIZAVEL -->
<po-page-dynamic-table
p-auto-router
p-title="Listagem de Idiomas"
[p-actions]="actions"
[p-breadcrumb]="breadcrumb"
[p-fields]="fields"
[p-service-api]="serviceApi">
</po-page-dynamic-table>
<!-- FINAL CODIGO PERSONALIZAVEL -->
|
|
Componente TypeScript (personalization-list.component.ts)
Expandir |
---|
title | > > > Clique para ver o código... |
---|
|
Bloco de código |
---|
language | js |
---|
theme | Confluence |
---|
firstline | 1 |
---|
linenumbers | true |
---|
| import { Component, OnInit } from '@angular/core';
import { PoBreadcrumb, PoBreadcrumbItem } from '@po-ui/ng-components';
import { PoPageDynamicTableActions } from '@po-ui/ng-templates';
import { PersonalizationService } from './../personalization.service';
@Component({
selector: 'app-personalization-list',
templateUrl: './personalization-list.component.html',
styleUrls: ['./personalization-list.component.css']
}) |
Bloco de código |
---|
language | js |
---|
firstline | 12 |
---|
title | Variáveis |
---|
linenumbers | true |
---|
| export class PersonalizationListComponent implements OnInit {
// Definicao das variaveis utilizadas
public serviceApi: string;
public fields: Array<any> = [];
public showLoading = false;
public literals;
public readonly actions: PoPageDynamicTableActions = {
new: '/personalization/create',
detail: '/personalization/detail/:id',
edit: '/personalization/edit/:id',
remove: true
};
public breadcrumb: PoBreadcrumb = { items: [] };
public breadcrumbItem: PoBreadcrumbItem;
|
Bloco de código |
---|
language | js |
---|
firstline | 30 |
---|
title | Construtor |
---|
linenumbers | true |
---|
| // Construtor da classe
constructor(
private service: PersonalizationService
) { }
|
Bloco de código |
---|
language | js |
---|
firstline | 34 |
---|
title | Leitura do componente |
---|
linenumbers | true |
---|
| // Load do componente
public ngOnInit(): void {
this.fields = [];
this.serviceApi = this.service.getUrlArea();
this.showLoading = true;
// ------- BUSCA OS CAMPOS PERSONALIZADOS DO PROGRAMA --------
this.service.loadMetadata().subscribe(metadata => {
// tslint:disable-next-line:no-string-literal
this.fields = metadata['fields'];
this.showLoading = false;
});
this.setBreadcrumb();
}
private setBreadcrumb(): void {
this.breadcrumbItem = { label: 'Home', link: '/' };
this.breadcrumb.items = this.breadcrumb.items.concat(this.breadcrumbItem);
this.breadcrumbItem = { label: 'Listagem de Idiomas' };
this.breadcrumb.items = this.breadcrumb.items.concat(this.breadcrumbItem);
}
}
|
|
Endpoint em Progress para a área de negócio
A seguir, são apresentados exemplos de endpoint em Progress, que deverão ser implementados pela área de negócio para obtenção dos valores a serem apresentados nos campos personalizados.
Tela do componente HTML com o resultado da personalização
Tela de Listagem
Image Removed
Tela de Criação/Edição
Image Removed
Tela de Detalhe/Visualização
Image Removed
Dica |
---|
|
Os fontes de exemplo para a personalização também estão disponíveis em nosso GIT (fwk-totvs-jille) em LINKS ÚTEIS. |
Tela do componente HTML com o resultado da personalização
Tela de Listagem
Image Added
Tela de Criação/Edição
Image Added
Tela de Detalhe/Visualização
Image Added