Browse Source

Merge pull request #19740 from tiagovb/dev

Translate docs to pt-BR: "Exception-Handling.md", "/UI/AspNetCore/*" and "/Modules/*"
pull/19752/head
maliming 2 years ago
committed by GitHub
parent
commit
e41cb53ca4
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 3
      docs/pt-BR/AspNetCore/Auto-API-Controllers.md
  2. 3
      docs/pt-BR/AspNetCore/Bundling-Minification.md
  3. 3
      docs/pt-BR/AspNetCore/Client-Side-Package-Management.md
  4. 3
      docs/pt-BR/AspNetCore/Dynamic-CSharp-API-Clients.md
  5. 3
      docs/pt-BR/AspNetCore/Tag-Helpers/Dynamic-Forms.md
  6. 3
      docs/pt-BR/AspNetCore/Tag-Helpers/Index.md
  7. 3
      docs/pt-BR/AspNetCore/Theming.md
  8. 3
      docs/pt-BR/AspNetCore/Widgets.md
  9. 391
      docs/pt-BR/Audit-Logging.md
  10. 360
      docs/pt-BR/Authorization.md
  11. 159
      docs/pt-BR/Background-Jobs-Quartz.md
  12. 146
      docs/pt-BR/Background-Workers-Quartz.md
  13. 144
      docs/pt-BR/Background-Workers.md
  14. 343
      docs/pt-BR/Exception-Handling.md
  15. 80
      docs/pt-BR/Modules/Account.md
  16. 60
      docs/pt-BR/Modules/Audit-Logging.md
  17. 55
      docs/pt-BR/Modules/Background-Jobs.md
  18. 135
      docs/pt-BR/Modules/Cms-Kit/Blogging.md
  19. 144
      docs/pt-BR/Modules/Cms-Kit/Comments.md
  20. 137
      docs/pt-BR/Modules/Cms-Kit/Dynamic-Widget.md
  21. 72
      docs/pt-BR/Modules/Cms-Kit/Global-Resources.md
  22. 143
      docs/pt-BR/Modules/Cms-Kit/Index.md
  23. 90
      docs/pt-BR/Modules/Cms-Kit/Menus.md
  24. 33
      docs/pt-BR/Modules/Cms-Kit/Pages.md
  25. 111
      docs/pt-BR/Modules/Cms-Kit/Ratings.md
  26. 126
      docs/pt-BR/Modules/Cms-Kit/Reactions.md
  27. 165
      docs/pt-BR/Modules/Cms-Kit/Tags.md
  28. 577
      docs/pt-BR/Modules/Database-Tables.md
  29. 675
      docs/pt-BR/Modules/Docs.md
  30. 105
      docs/pt-BR/Modules/Feature-Management.md
  31. 321
      docs/pt-BR/Modules/Identity.md
  32. 175
      docs/pt-BR/Modules/IdentityServer.md
  33. 32
      docs/pt-BR/Modules/Index.md
  34. 514
      docs/pt-BR/Modules/OpenIddict.md
  35. 109
      docs/pt-BR/Modules/Permission-Management.md
  36. 313
      docs/pt-BR/Modules/Setting-Management.md
  37. 134
      docs/pt-BR/Modules/Tenant-Management.md
  38. 87
      docs/pt-BR/Modules/Virtual-File-Explorer.md
  39. 74
      docs/pt-BR/UI/AspNetCore/AutoComplete-Select.md
  40. 96
      docs/pt-BR/UI/AspNetCore/Basic-Theme.md
  41. 45
      docs/pt-BR/UI/AspNetCore/Branding.md
  42. 479
      docs/pt-BR/UI/AspNetCore/Bundling-Minification.md
  43. 115
      docs/pt-BR/UI/AspNetCore/Client-Side-Package-Management.md
  44. 477
      docs/pt-BR/UI/AspNetCore/Customization-User-Interface.md
  45. 161
      docs/pt-BR/UI/AspNetCore/Data-Table-Column-Extensions.md
  46. 298
      docs/pt-BR/UI/AspNetCore/Data-Tables.md
  47. 97
      docs/pt-BR/UI/AspNetCore/Dynamic-JavaScript-Proxies.md
  48. 108
      docs/pt-BR/UI/AspNetCore/Entity-Action-Extensions.md
  49. 227
      docs/pt-BR/UI/AspNetCore/Forms-Validation.md
  50. 150
      docs/pt-BR/UI/AspNetCore/JavaScript-API/Ajax.md
  51. 23
      docs/pt-BR/UI/AspNetCore/JavaScript-API/Auth.md
  52. 56
      docs/pt-BR/UI/AspNetCore/JavaScript-API/Block-Busy.md
  53. 49
      docs/pt-BR/UI/AspNetCore/JavaScript-API/CurrentUser.md
  54. 116
      docs/pt-BR/UI/AspNetCore/JavaScript-API/DOM.md
  55. 87
      docs/pt-BR/UI/AspNetCore/JavaScript-API/Events.md
  56. 29
      docs/pt-BR/UI/AspNetCore/JavaScript-API/Features.md
  57. 24
      docs/pt-BR/UI/AspNetCore/JavaScript-API/GlobalFeatures.md
  58. 20
      docs/pt-BR/UI/AspNetCore/JavaScript-API/Index.md
  59. 146
      docs/pt-BR/UI/AspNetCore/JavaScript-API/Localization.md
  60. 49
      docs/pt-BR/UI/AspNetCore/JavaScript-API/Logging.md
  61. 127
      docs/pt-BR/UI/AspNetCore/JavaScript-API/Message.md
  62. 45
      docs/pt-BR/UI/AspNetCore/JavaScript-API/Notify.md
  63. 39
      docs/pt-BR/UI/AspNetCore/JavaScript-API/ResourceLoader.md
  64. 32
      docs/pt-BR/UI/AspNetCore/JavaScript-API/Settings.md
  65. 105
      docs/pt-BR/UI/AspNetCore/Layout-Hooks.md
  66. 412
      docs/pt-BR/UI/AspNetCore/Modals.md
  67. 288
      docs/pt-BR/UI/AspNetCore/Navigation-Menu.md
  68. 160
      docs/pt-BR/UI/AspNetCore/Overall.md
  69. 84
      docs/pt-BR/UI/AspNetCore/Page-Alerts.md
  70. 62
      docs/pt-BR/UI/AspNetCore/Page-Header.md
  71. 162
      docs/pt-BR/UI/AspNetCore/Page-Toolbar-Extensions.md
  72. 99
      docs/pt-BR/UI/AspNetCore/Security-Headers.md
  73. 157
      docs/pt-BR/UI/AspNetCore/Static-JavaScript-Proxies.md
  74. 82
      docs/pt-BR/UI/AspNetCore/Tag-Helpers/Alerts.md
  75. 37
      docs/pt-BR/UI/AspNetCore/Tag-Helpers/Badges.md
  76. 18
      docs/pt-BR/UI/AspNetCore/Tag-Helpers/Blockquote.md
  77. 126
      docs/pt-BR/UI/AspNetCore/Tag-Helpers/Borders.md
  78. 25
      docs/pt-BR/UI/AspNetCore/Tag-Helpers/Breadcrumbs.md
  79. 37
      docs/pt-BR/UI/AspNetCore/Tag-Helpers/Button-groups.md
  80. 98
      docs/pt-BR/UI/AspNetCore/Tag-Helpers/Buttons.md
  81. 188
      docs/pt-BR/UI/AspNetCore/Tag-Helpers/Cards.md
  82. 71
      docs/pt-BR/UI/AspNetCore/Tag-Helpers/Carousel.md
  83. 92
      docs/pt-BR/UI/AspNetCore/Tag-Helpers/Collapse.md
  84. 93
      docs/pt-BR/UI/AspNetCore/Tag-Helpers/Dropdowns.md
  85. 281
      docs/pt-BR/UI/AspNetCore/Tag-Helpers/Dynamic-Forms.md
  86. 14
      docs/pt-BR/UI/AspNetCore/Tag-Helpers/Figure.md
  87. 435
      docs/pt-BR/UI/AspNetCore/Tag-Helpers/Form-elements.md
  88. 273
      docs/pt-BR/UI/AspNetCore/Tag-Helpers/Grids.md
  89. 45
      docs/pt-BR/UI/AspNetCore/Tag-Helpers/Index.md
  90. 76
      docs/pt-BR/UI/AspNetCore/Tag-Helpers/List-Groups.md
  91. 88
      docs/pt-BR/UI/AspNetCore/Tag-Helpers/Modals.md
  92. 114
      docs/pt-BR/UI/AspNetCore/Tag-Helpers/Navs.md
  93. 57
      docs/pt-BR/UI/AspNetCore/Tag-Helpers/Paginator.md
  94. 40
      docs/pt-BR/UI/AspNetCore/Tag-Helpers/Popovers.md
  95. 68
      docs/pt-BR/UI/AspNetCore/Tag-Helpers/Progress-Bars.md
  96. 61
      docs/pt-BR/UI/AspNetCore/Tag-Helpers/Tables.md
  97. 91
      docs/pt-BR/UI/AspNetCore/Tag-Helpers/Tabs.md
  98. 35
      docs/pt-BR/UI/AspNetCore/Tag-Helpers/Tooltips.md
  99. 207
      docs/pt-BR/UI/AspNetCore/Testing.md
  100. 442
      docs/pt-BR/UI/AspNetCore/Theming.md

3
docs/pt-BR/AspNetCore/Auto-API-Controllers.md

@ -0,0 +1,3 @@
Este documento foi movido.
[Clique para navegar até o documento Auto API Controllers](../API/Auto-API-Controllers.md)

3
docs/pt-BR/AspNetCore/Bundling-Minification.md

@ -0,0 +1,3 @@
Este documento foi movido.
[Clique para navegar até o documento de Bundling & Minification do ASP.NET Core MVC](../UI/AspNetCore/Bundling-Minification.md)

3
docs/pt-BR/AspNetCore/Client-Side-Package-Management.md

@ -0,0 +1,3 @@
Este documento foi movido.
[Clique para navegar até o documento de Gerenciamento de Pacotes do Lado do Cliente do ASP.NET Core MVC](../UI/AspNetCore/Client-Side-Package-Management.md)

3
docs/pt-BR/AspNetCore/Dynamic-CSharp-API-Clients.md

@ -0,0 +1,3 @@
Este documento foi movido.
[Clique para navegar até o documento Dynamic C# API Clients](../API/Dynamic-CSharp-API-Clients.md)

3
docs/pt-BR/AspNetCore/Tag-Helpers/Dynamic-Forms.md

@ -0,0 +1,3 @@
Este documento foi movido.
[Clique para navegar até o documento de Formulários Dinâmicos](../../UI/AspNetCore/Tag-Helpers/Dynamic-Forms.md)

3
docs/pt-BR/AspNetCore/Tag-Helpers/Index.md

@ -0,0 +1,3 @@
Este documento foi movido.
[Clique para navegar até o documento ABP Tag Helpers](../../UI/AspNetCore/Tag-Helpers/Index.md)

3
docs/pt-BR/AspNetCore/Theming.md

@ -0,0 +1,3 @@
Este documento foi movido.
[Clique para navegar até o documento de Temas](../UI/AspNetCore/Theming.md)

3
docs/pt-BR/AspNetCore/Widgets.md

@ -0,0 +1,3 @@
Este documento foi movido.
[Clique para navegar até o documento Widgets](../UI/AspNetCore/Widgets.md)

391
docs/pt-BR/Audit-Logging.md

@ -1,3 +1,390 @@
# Audit Logging
# Registro de Auditoria
Façam
[Wikipedia](https://en.wikipedia.org/wiki/Audit_trail): "*Um rastro de auditoria (também chamado de **log de auditoria**) é um registro cronológico relevante para a segurança, conjunto de registros e/ou destino e origem de registros que fornecem evidências documentais da sequência de atividades que afetaram a qualquer momento uma operação, procedimento ou evento específico*".
O ABP Framework fornece um **sistema de registro de auditoria extensível** que automatiza o registro de auditoria por **convenção** e fornece **pontos de configuração** para controlar o nível dos logs de auditoria.
Um **objeto de log de auditoria** (consulte a seção Objeto de Log de Auditoria abaixo) é tipicamente criado e salvo por solicitação da web. Ele inclui;
* Detalhes da **solicitação e resposta** (como URL, método Http, informações do navegador, código de status HTTP... etc.).
* **Ações realizadas** (ações do controlador e chamadas de métodos de serviço de aplicação com seus parâmetros).
* **Mudanças de entidade** ocorridas na solicitação da web.
* Informações de **exceção** (se houve um erro durante a execução da solicitação).
* **Duração da solicitação** (para medir o desempenho da aplicação).
> Os [modelos de inicialização](Startup-Templates/Index.md) são configurados para o sistema de registro de auditoria, o que é adequado para a maioria das aplicações. Use este documento para um controle detalhado sobre o sistema de log de auditoria.
### Suporte do Provedor de Banco de Dados
* Totalmente suportado pelo provedor [Entity Framework Core](Entity-Framework-Core.md).
* O log de alterações de entidade não é suportado pelo provedor [MongoDB](MongoDB.md). Outros recursos funcionam conforme o esperado.
## UseAuditing()
O middleware `UseAuditing()` deve ser adicionado ao pipeline de solicitações do ASP.NET Core para criar e salvar os logs de auditoria. Se você criou suas aplicações usando [os modelos de inicialização](Startup-Templates/Index.md), ele já está adicionado.
## AbpAuditingOptions
`AbpAuditingOptions` é o principal [objeto de opções](Options.md) para configurar o sistema de log de auditoria. Você pode configurá-lo no método `ConfigureServices` do seu [módulo](Module-Development-Basics.md):
````csharp
Configure<AbpAuditingOptions>(options =>
{
options.IsEnabled = false; //Desativa o sistema de auditoria
});
````
Aqui, uma lista das opções que você pode configurar:
* `IsEnabled` (padrão: `true`): Uma chave raiz para habilitar ou desabilitar o sistema de auditoria. Outras opções não são usadas se esse valor for `false`.
* `HideErrors` (padrão: `true`): O sistema de log de auditoria oculta e escreve [logs](Logging.md) regulares se ocorrer algum erro ao salvar os objetos de log de auditoria. Se salvar os logs de auditoria for crítico para o seu sistema, defina isso como `false` para lançar uma exceção em caso de ocultação de erros.
* `IsEnabledForAnonymousUsers` (padrão: `true`): Se você deseja escrever logs de auditoria apenas para os usuários autenticados, defina isso como `false`. Se você salvar logs de auditoria para usuários anônimos, verá `null` para os valores de `UserId` desses usuários.
* `AlwaysLogOnException` (padrão: `true`): Se definido como verdadeiro, sempre salva o log de auditoria em caso de exceção/erro sem verificar outras opções (exceto `IsEnabled`, que desativa completamente o registro de auditoria).
* `IsEnabledForIntegrationService` (padrão: `false`): O Registro de Auditoria é desativado para [serviços de integração](Integration-Services.md) por padrão. Defina essa propriedade como `true` para habilitá-la.
* `IsEnabledForGetRequests` (padrão: `false`): As solicitações HTTP GET normalmente não devem fazer nenhuma alteração no banco de dados e o sistema de log de auditoria não salva objetos de log de auditoria para solicitações GET. Defina isso como `true` para habilitá-lo também para as solicitações GET.
* `DisableLogActionInfo` (padrão: `false`): Se definido como verdadeiro, não registrará mais `AuditLogActionInfo`.
* `ApplicationName`: Se várias aplicações estiverem salvando logs de auditoria em um único banco de dados, defina essa propriedade com o nome da sua aplicação, para que você possa distinguir os logs de diferentes aplicações. Se você não definir, ele será definido a partir do valor `IApplicationInfoAccessor.ApplicationName`, que é o nome da assembly de entrada por padrão.
* `IgnoredTypes`: Uma lista de `Type`s a serem ignorados para o registro de auditoria. Se for um tipo de entidade, as alterações para esse tipo de entidades não serão salvas. Esta lista também é usada ao serializar os parâmetros de ação.
* `EntityHistorySelectors`: Uma lista de seletores usados para determinar se um tipo de entidade é selecionado para salvar a alteração da entidade. Consulte a seção abaixo para detalhes.
* `SaveEntityHistoryWhenNavigationChanges` (padrão: `true`): Se definido como verdadeiro, salvará as alterações da entidade no log de auditoria quando houver alterações em propriedades de navegação.
* `Contributors`: Uma lista de implementações de `AuditLogContributor`. Um contribuidor é uma forma de estender o sistema de log de auditoria. Consulte a seção "Contribuidores de Log de Auditoria" abaixo.
* `AlwaysLogSelectors`: Uma lista de seletores para salvar os logs de auditoria para os critérios correspondentes.
### Seletores de Histórico de Entidade
Salvar todas as alterações de todas as suas entidades exigiria muito espaço no banco de dados. Por esse motivo, **o sistema de log de auditoria não salva nenhuma alteração para as entidades a menos que você configure explicitamente**.
Para salvar todas as alterações de todas as entidades, simplesmente use o método de extensão `AddAllEntities()`.
````csharp
Configure<AbpAuditingOptions>(options =>
{
options.EntityHistorySelectors.AddAllEntities();
});
````
`options.EntityHistorySelectors` na verdade é uma lista de predicados de tipo. Você pode escrever uma expressão lambda para definir seu filtro.
O seletor de exemplo abaixo faz o mesmo do método de extensão `AddAllEntities()` definido acima:
````csharp
Configure<AbpAuditingOptions>(options =>
{
options.EntityHistorySelectors.Add(
new NamedTypeSelector(
"MeuSeletorNome",
type =>
{
if (typeof(IEntity).IsAssignableFrom(type))
{
return true;
}
else
{
return false;
}
}
)
);
});
````
A condição `typeof(IEntity).IsAssignableFrom(type)` será `true` para qualquer classe que implemente a interface `IEntity` (tecnicamente, todas as entidades em sua aplicação). Você pode verificar condicionalmente e retornar `true` ou `false` com base em sua preferência.
`options.EntityHistorySelectors` é uma forma flexível e dinâmica de selecionar as entidades para o registro de auditoria. Outra forma é usar os atributos `Audited` e `DisableAuditing` por entidade.
## AbpAspNetCoreAuditingOptions
`AbpAspNetCoreAuditingOptions` é o [objeto de opções](Options.md) para configurar o registro de auditoria na camada ASP.NET Core. Você pode configurá-lo no método `ConfigureServices` do seu [módulo](Module-Development-Basics.md):
````csharp
Configure<AbpAspNetCoreAuditingOptions>(options =>
{
options.IgnoredUrls.Add("/produtos");
});
````
`IgnoredUrls` é a única opção. É uma lista de prefixos de URLs ignorados. No exemplo anterior, todas as URLs que começam com `/produtos` serão ignoradas para o registro de auditoria.
## Habilitando/Desabilitando o Registro de Auditoria para Serviços
### Habilitar/Desabilitar para Controladores e Ações
Todas as ações do controlador são registradas por padrão (consulte `IsEnabledForGetRequests` acima para solicitações GET).
Você pode usar o `[DisableAuditing]` para desativá-lo para um tipo de controlador específico:
````csharp
[DisableAuditing]
public class HomeController : AbpController
{
//...
}
````
Use `[DisableAuditing]` para qualquer ação para controlá-la no nível da ação:
````csharp
public class HomeController : AbpController
{
[DisableAuditing]
public async Task<ActionResult> Home()
{
//...
}
public async Task<ActionResult> OutraAcaoRegistrada()
{
//...
}
}
````
### Habilitar/Desabilitar para Serviços de Aplicação e Métodos
As chamadas de métodos de [serviço de aplicação](Application-Services.md) também são incluídas no log de auditoria por padrão. Você pode usar o `[DisableAuditing]` no nível do serviço ou do método.
#### Habilitar/Desabilitar para Outros Serviços
O registro de auditoria de ação pode ser habilitado para qualquer tipo de classe (registrado e resolvido da [injeção de dependência](Dependency-Injection.md)) enquanto é habilitado apenas para os controladores e os serviços de aplicação por padrão.
Use `[Audited]` e `[DisableAuditing]` para qualquer classe ou método que precisa ser registrado no log de auditoria. Além disso, sua classe pode (direta ou implicitamente) implementar a interface `IAuditingEnabled` para habilitar o registro de auditoria para essa classe por padrão.
### Habilitar/Desabilitar para Entidades e Propriedades
Uma entidade é ignorada no registro de alteração de entidade nos seguintes casos;
* Se você adicionar um tipo de entidade às `AbpAuditingOptions.IgnoredTypes` (como explicado anteriormente), ele é completamente ignorado no sistema de registro de auditoria.
* Se o objeto não for uma [entidade](Entities.md) (não implementa `IEntity` diretamente ou implicitamente - Todas as entidades implementam essa interface por padrão).
* Se o tipo de entidade não for público.
Caso contrário, você pode usar `Audited` para habilitar o registro de alteração de entidade para uma entidade:
````csharp
[Audited]
public class MinhaEntidade : Entity<Guid>
{
//...
}
````
Ou desativá-lo para uma entidade:
````csharp
[DisableAuditing]
public class MinhaEntidade : Entity<Guid>
{
//...
}
````
Desativar o registro de auditoria pode ser necessário apenas se a entidade estiver sendo selecionada pelos `AbpAuditingOptions.EntityHistorySelectors` que foram explicados anteriormente.
Você pode desativar o registro de auditoria apenas para algumas propriedades de suas entidades para um controle detalhado sobre o registro de auditoria:
````csharp
[Audited]
public class MeuUsuario : Entity<Guid>
{
public string Nome { get; set; }
public string Email { get; set; }
[DisableAuditing] //Ignora a Senha no registro de auditoria
public string Senha { get; set; }
}
````
O sistema de log de auditoria salvará as alterações para a entidade `MeuUsuario` enquanto ignora a propriedade `Senha`, que pode ser perigosa de salvar por motivos de segurança.
Em alguns casos, você pode querer salvar apenas algumas propriedades de suas entidades e ignorar todas as outras. Escrever `[DisableAuditing]` para todas as outras propriedades seria tedioso. Em tais casos, use `[Audited]` apenas para as propriedades desejadas e marque a entidade com o atributo `[DisableAuditing]`:
````csharp
[DisableAuditing]
public class MeuUsuario : Entity<Guid>
{
[Audited] //Apenas registra a alteração do Nome
public string Nome { get; set; }
public string Email { get; set; }
public string Senha { get; set; }
}
````
## IAuditingStore
`IAuditingStore` é uma interface usada para salvar os objetos de log de auditoria (explicados abaixo) pelo Framework ABP. Se você precisa salvar os objetos de log de auditoria em um armazenamento de dados personalizado, pode implementar o `IAuditingStore` em sua própria aplicação e substituir usando o [sistema de injeção de dependência](Dependency-Injection.md).
`SimpleLogAuditingStore` é usado se nenhum armazenamento de auditoria estiver registrado. Ele simplesmente escreve o objeto de auditoria no sistema padrão de [logging](Logging.md).
[O Módulo de Registro de Auditoria](Modules/Audit-Logging.md) foi configurado nos [modelos de inicialização](Startup-Templates/Index.md) para salvar objetos de log de auditoria em um banco de dados (ele suporta vários provedores de banco de dados). Portanto, na maioria das vezes, você não precisa se preocupar com como o `IAuditingStore` foi implementado e usado.
## Objeto de Log de Auditoria
Um **objeto de log de auditoria** é criado para cada **solicitação web** por padrão. Um objeto de log de auditoria pode ser representado pelo seguinte diagrama de relação:
![**auditlog-object-diagram**](images/auditlog-object-diagram.png)
* **AuditLogInfo**: O objeto raiz com as seguintes propriedades:
* `ApplicationName`: Quando você salva logs de auditoria de diferentes aplicações no mesmo banco de dados, essa propriedade é usada para distinguir os logs das aplicações.
* `UserId`: Id do usuário atual, se o usuário estiver logado.
* `UserName`: Nome do usuário atual, se o usuário estiver logado (esse valor está aqui para não depender do módulo/sistema de identidade para pesquisa).
* `TenantId`: Id do locatário atual, para uma aplicação multi-locatário.
* `TenantName`: Nome do locatário atual, para uma aplicação multi-locatário.
* `ExecutionTime`: O momento em que este objeto de log de auditoria foi criado.
* `ExecutionDuration`: Duração total da execução da solicitação, em milissegundos. Isso pode ser usado para observar o desempenho da aplicação.
* `ClientId`: Id do cliente atual, se o cliente estiver autenticado. Um cliente é geralmente uma aplicação de terceiros que usa o sistema por meio de uma API HTTP.
* `ClientName`: Nome do cliente atual, se disponível.
* `ClientIpAddress`: Endereço IP do cliente/dispositivo do usuário.
* `CorrelationId`: Id de [Correlação Atual](CorrelationId.md). O Id de correlação é usado para relacionar os logs de auditoria escritos por diferentes aplicações (ou microsserviços) em uma única operação lógica.
* `BrowserInfo`: Informações do nome/versão do navegador do usuário atual, se disponível.
* `HttpMethod`: Método HTTP da solicitação atual (GET, POST, PUT, DELETE... etc.).
* `HttpStatusCode`: Código de status da resposta HTTP para esta solicitação.
* `Url`: URL da solicitação.
* **AuditLogActionInfo**: Um log de auditoria de ação é tipicamente uma ação de controlador ou uma chamada de método de [serviço de aplicação](Application-Services.md) durante a solicitação web. Um log de ação pode conter várias ações. Um objeto de ação tem as seguintes propriedades:
* `ServiceName`: Nome do controlador/serviço executado.
* `MethodName`: Nome do método executado do controlador/serviço.
* `Parameters`: Um texto formatado em JSON representando os parâmetros passados para o método.
* `ExecutionTime`: O momento em que este método foi executado.
* `ExecutionDuration`: Duração da execução do método, em milissegundos. Isso pode ser usado para observar o desempenho do método.
* **EntityChangeInfo**: Representa uma alteração de uma entidade nesta solicitação web. Um log de auditoria pode conter zero ou mais alterações de entidade. Uma alteração de entidade tem as seguintes propriedades:
* `ChangeTime`: O momento em que a entidade foi alterada.
* `ChangeType`: Um enum com os seguintes campos: `Criado` (0), `Atualizado` (1) e `Excluído` (2).
* `EntityId`: Id da entidade que foi alterada.
* `EntityTenantId`: Id do locatário a que esta entidade pertence.
* `EntityTypeFullName`: Nome do tipo (classe) da entidade com namespace completo (como *Acme.BookStore.Book* para a entidade Book).
* **EntityPropertyChangeInfo**: Representa uma alteração de uma propriedade de uma entidade. Uma informação de alteração de entidade (explicada acima) pode conter uma ou mais alterações de propriedade com as seguintes propriedades:
* `NewValue`: Novo valor da propriedade. É `null` se a entidade foi excluída.
* `OriginalValue`: Valor antigo/original antes da alteração. É `null` se a entidade foi recém-criada.
* `PropertyName`: O nome da propriedade na classe da entidade.
* `PropertyTypeFullName`: Nome do tipo (classe) da propriedade com namespace completo.
* **Exception**: Um objeto de log de auditoria pode conter zero ou mais exceções. Dessa forma, você pode obter um relatório das solicitações com falha.
* **Comment**: Um valor de string arbitrário para adicionar mensagens personalizadas à entrada de log de auditoria. Um objeto de log de auditoria pode conter zero ou mais comentários.
Além das propriedades padrão explicadas acima, os objetos `AuditLogInfo`, `AuditLogActionInfo` e `EntityChangeInfo` implementam a interface `IHasExtraProperties`, para que você possa adicionar propriedades personalizadas a esses objetos.
## Contribuidores de Log de Auditoria
Você pode estender o sistema de auditoria criando uma classe derivada da classe `AuditLogContributor`, que define os métodos `PreContribute` e `PostContribute`.
O único contribuidor pré-construído é a classe `AspNetCoreAuditLogContributor`, que define as propriedades relacionadas a uma solicitação HTTP.
Um contribuidor pode definir propriedades e coleções da classe `AuditLogInfo` para adicionar mais informações.
Exemplo:
````csharp
public class MyAuditLogContributor : AuditLogContributor
{
public override void PreContribute(AuditLogContributionContext context)
{
var currentUser = context.ServiceProvider.GetRequiredService<ICurrentUser>();
context.AuditInfo.SetProperty(
"MyCustomClaimValue",
currentUser.FindClaimValue("MyCustomClaim")
);
}
public override void PostContribute(AuditLogContributionContext context)
{
context.AuditInfo.Comments.Add("Algum comentário...");
}
}
````
* `context.ServiceProvider` pode ser usado para resolver serviços da [injeção de dependência](Dependency-Injection.md).
* `context.AuditInfo` pode ser usado para acessar o objeto de log de auditoria atual para manipulá-lo.
Após criar um contribuidor, você deve adicioná-lo à lista `AbpAuditingOptions.Contributors`:
````csharp
Configure<AbpAuditingOptions>(options =>
{
options.Contributors.Add(new MyAuditLogContributor());
});
````
## IAuditLogScope & IAuditingManager
Esta seção explica os serviços `IAuditLogScope` e `IAuditingManager` para casos de uso avançados.
Um **escopo de log de auditoria** é um [escopo ambiente](Ambient-Context-Pattern.md) que **constrói** e **salva** um objeto de log de auditoria (explicado anteriormente). Por padrão, um escopo de log de auditoria é criado para uma solicitação web pelo Middleware de Log de Auditoria (veja a seção `UseAuditing()` acima).
### Acesso ao Escopo Atual de Log de Auditoria
Os contribuidores de log de auditoria, explicados acima, são uma maneira global de manipular o objeto de log de auditoria. É bom se você puder obter um valor de um serviço.
Se você precisar manipular o objeto de log de auditoria em um ponto arbitrário de sua aplicação, pode acessar o escopo de log de auditoria atual e obter o objeto de log de auditoria atual (independente de como o escopo é gerenciado). Exemplo:
````csharp
public class MeuServico : ITransientDependency
{
private readonly IAuditingManager _auditingManager;
public MeuServico(IAuditingManager auditingManager)
{
_auditingManager = auditingManager;
}
public async Task FazerIssoAsync()
{
var escopoAtualDeLogDeAuditoria = _auditingManager.Current;
if (escopoAtualDeLogDeAuditoria != null)
{
escopoAtualDeLogDeAuditoria.Log.Comments.Add(
"Executou o método MeuServico.FazerIssoAsync :)"
);
escopoAtualDeLogDeAuditoria.Log.SetProperty("MinhaPropriedadePersonalizada", 42);
}
}
}
````
Sempre verifique se `_auditingManager.Current` é nulo ou não, porque é controlado em um escopo externo e você não pode saber se um escopo de log de auditoria foi criado antes de chamar seu método.
### Criar Manualmente um Escopo de Log de Auditoria
Raramente você precisa criar manualmente um escopo de log de auditoria, mas se precisar, pode criar um escopo de log de auditoria usando o `IAuditingManager` como no exemplo a seguir:
````csharp
public class MeuServico : ITransientDependency
{
private readonly IAuditingManager _auditingManager;
public MeuServico(IAuditingManager auditingManager)
{
_auditingManager = auditingManager;
}
public async Task FazerIssoAsync()
{
using (var escopoDeAuditoria = _auditingManager.BeginScope())
{
try
{
//Chame outros serviços...
}
catch (Exception ex)
{
//Adicione exceções
_auditingManager.Current.Log.Exceptions.Add(ex);
throw;
}
finally
{
//Sempre salve o log
await escopoDeAuditoria.SaveAsync();
}
}
}
}
````
Você pode chamar outros serviços, que podem chamar outros, que podem alterar entidades e assim por diante. Todas essas interações são salvas como um único objeto de log de auditoria no bloco finally.
## O Módulo de Registro de Auditoria
O Módulo de Registro de Auditoria basicamente implementa o `IAuditingStore` para salvar os objetos de log de auditoria em um banco de dados. Ele suporta vários provedores de banco de dados. Este módulo é adicionado aos modelos de inicialização por padrão.
Consulte o documento [Módulo de Registro de Auditoria](Modules/Audit-Logging.md) para mais informações.

360
docs/pt-BR/Authorization.md

@ -1,3 +1,359 @@
## Authorization
# Autorização
Façam
A autorização é usada para verificar se um usuário tem permissão para realizar operações específicas na aplicação.
O ABP estende a [Autorização do ASP.NET Core](https://docs.microsoft.com/pt-br/aspnet/core/security/authorization/introduction) adicionando **permissões** como [políticas](https://docs.microsoft.com/pt-br/aspnet/core/security/authorization/policies) automáticas e permitindo que o sistema de autorização seja utilizado nos **[serviços de aplicação](Application-Services.md)** também.
Portanto, todos os recursos de autorização do ASP.NET Core e a documentação são válidos em uma aplicação baseada no ABP. Este documento se concentra nos recursos adicionados ao sistema de autorização do ASP.NET Core.
## Atributo Authorize
O ASP.NET Core define o atributo [**Authorize**](https://docs.microsoft.com/pt-br/aspnet/core/security/authorization/simple) que pode ser usado para uma ação, um controlador ou uma página. O ABP permite que você use o mesmo atributo para um [serviço de aplicação](Application-Services.md).
Exemplo:
```csharp
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Volo.Abp.Application.Services;
namespace Acme.BookStore
{
[Authorize]
public class AuthorAppService : ApplicationService, IAuthorAppService
{
public Task<List<AuthorDto>> GetListAsync()
{
...
}
[AllowAnonymous]
public Task<AuthorDto> GetAsync(Guid id)
{
...
}
[Authorize("BookStore_Author_Create")]
public Task CreateAsync(CreateAuthorDto input)
{
...
}
}
}
```
- O atributo `Authorize` obriga o usuário a fazer login na aplicação para usar os métodos do `AuthorAppService`. Portanto, o método `GetListAsync` está disponível apenas para usuários autenticados.
- `AllowAnonymous` suprime a autenticação. Portanto, o método `GetAsync` está disponível para todos, incluindo usuários não autorizados.
- `[Authorize("BookStore_Author_Create")]` define uma política (consulte [autorização baseada em políticas](https://docs.microsoft.com/pt-br/aspnet/core/security/authorization/policies)) que é verificada para autorizar o usuário atual.
"BookStore_Author_Create" é um nome de política arbitrário. Se você declarar um atributo como esse, o sistema de autorização do ASP.NET Core espera que uma política seja definida anteriormente.
Você pode, é claro, implementar suas próprias políticas conforme descrito na documentação do ASP.NET Core. Mas para condições simples de verdadeiro/falso, como se uma política foi concedida a um usuário ou não, o ABP define o sistema de permissões, que será explicado na próxima seção.
## Sistema de Permissões
Uma permissão é uma política simples que é concedida ou proibida para um usuário, função ou cliente específico.
### Definindo Permissões
Para definir permissões, crie uma classe que herde de `PermissionDefinitionProvider`, conforme mostrado abaixo:
```csharp
using Volo.Abp.Authorization.Permissions;
namespace Acme.BookStore.Permissions
{
public class BookStorePermissionDefinitionProvider : PermissionDefinitionProvider
{
public override void Define(IPermissionDefinitionContext context)
{
var myGroup = context.AddGroup("BookStore");
myGroup.AddPermission("BookStore_Author_Create");
}
}
}
```
> O ABP descobre automaticamente essa classe. Nenhuma configuração adicional é necessária!
> Normalmente, você define essa classe dentro do projeto `Application.Contracts` da sua [aplicação](Startup-Templates/Application.md). O modelo de inicialização já vem com uma classe vazia chamada *YourProjectNamePermissionDefinitionProvider* com a qual você pode começar.
No método `Define`, você precisa adicionar um **grupo de permissões** ou obter um grupo existente e adicionar **permissões** a esse grupo.
Quando você define uma permissão, ela se torna utilizável no sistema de autorização do ASP.NET Core como um nome de **política**. Ela também se torna visível na interface do usuário. Veja o diálogo de permissões para uma função:
![authorization-new-permission-ui](images/authorization-new-permission-ui.png)
- O grupo "BookStore" é mostrado como uma nova guia no lado esquerdo.
- "BookStore_Author_Create" no lado direito é o nome da permissão. Você pode concedê-la ou proibi-la para a função.
Quando você salva o diálogo, ele é salvo no banco de dados e usado no sistema de autorização.
> A tela acima está disponível quando você instalou o módulo de identidade, que é usado principalmente para gerenciamento de usuários e funções. Os modelos de inicialização já vêm com o módulo de identidade pré-instalado.
#### Localizando o Nome da Permissão
"BookStore_Author_Create" não é um bom nome de permissão para a interface do usuário. Felizmente, os métodos `AddPermission` e `AddGroup` podem receber um `LocalizableString` como segundo parâmetro:
```csharp
var myGroup = context.AddGroup(
"BookStore",
LocalizableString.Create<BookStoreResource>("BookStore")
);
myGroup.AddPermission(
"BookStore_Author_Create",
LocalizableString.Create<BookStoreResource>("Permission:BookStore_Author_Create")
);
```
Em seguida, você pode definir os textos para as chaves "BookStore" e "Permission:BookStore_Author_Create" no arquivo de localização:
```json
"BookStore": "Livraria",
"Permission:BookStore_Author_Create": "Criar um novo autor"
```
> Para mais informações, consulte a [documentação de localização](Localization.md) sobre o sistema de localização.
A interface do usuário localizada será como mostrado abaixo:
![authorization-new-permission-ui-localized](images/authorization-new-permission-ui-localized.png)
#### Multi-Tenancy
O ABP suporta [multi-tenancy](Multi-Tenancy.md) como um recurso de primeira classe. Você pode definir a opção de lado de multi-tenancy ao definir uma nova permissão. Ela pode ter um dos três valores definidos abaixo:
- **Host**: A permissão está disponível apenas para o lado do host.
- **Tenant**: A permissão está disponível apenas para o lado do tenant.
- **Ambos** (padrão): A permissão está disponível tanto para o lado do tenant quanto para o lado do host.
> Se sua aplicação não é multi-tenant, você pode ignorar essa opção.
Para definir a opção de lado de multi-tenancy, passe para o terceiro parâmetro do método `AddPermission`:
```csharp
myGroup.AddPermission(
"BookStore_Author_Create",
LocalizableString.Create<BookStoreResource>("Permission:BookStore_Author_Create"),
multiTenancySide: MultiTenancySides.Tenant //defina o lado de multi-tenancy!
);
```
#### Habilitar/Desabilitar Permissões
Uma permissão está habilitada por padrão. É possível desabilitar uma permissão. Uma permissão desabilitada será proibida para todos. Você ainda pode verificar a permissão, mas ela sempre retornará proibida.
Exemplo de definição:
````csharp
myGroup.AddPermission("Author_Management", isEnabled: false);
````
Normalmente, você não precisa definir uma permissão desabilitada (a menos que queira desabilitar temporariamente um recurso da sua aplicação). No entanto, você pode querer desabilitar uma permissão definida em um módulo dependente. Dessa forma, você pode desabilitar a funcionalidade relacionada à aplicação. Consulte a seção "*Alterando as Definições de Permissão de um Módulo Dependente*" abaixo para um exemplo de uso.
> Observação: Verificar uma permissão não definida lançará uma exceção, enquanto verificar uma permissão desabilitada simplesmente retornará proibida (falso).
#### Permissões Filhas
Uma permissão pode ter permissões filhas. Isso é especialmente útil quando você deseja criar uma árvore de permissões hierárquica, onde uma permissão pode ter permissões secundárias adicionais que estão disponíveis apenas se a permissão pai for concedida.
Exemplo de definição:
```csharp
var authorManagement = myGroup.AddPermission("Author_Management");
authorManagement.AddChild("Author_Management_Create_Books");
authorManagement.AddChild("Author_Management_Edit_Books");
authorManagement.AddChild("Author_Management_Delete_Books");
```
O resultado na interface do usuário é mostrado abaixo (provavelmente você desejará localizar as permissões para sua aplicação):
![authorization-new-permission-ui-hierarcy](images/authorization-new-permission-ui-hierarcy.png)
Para o código de exemplo, é assumido que uma função/usuário com a permissão "Author_Management" concedida pode ter permissões adicionais. Em seguida, um serviço de aplicação típico que verifica permissões pode ser definido como mostrado abaixo:
```csharp
[Authorize("Author_Management")]
public class AuthorAppService : ApplicationService, IAuthorAppService
{
public Task<List<AuthorDto>> GetListAsync()
{
...
}
public Task<AuthorDto> GetAsync(Guid id)
{
...
}
[Authorize("Author_Management_Create_Books")]
public Task CreateAsync(CreateAuthorDto input)
{
...
}
[Authorize("Author_Management_Edit_Books")]
public Task UpdateAsync(CreateAuthorDto input)
{
...
}
[Authorize("Author_Management_Delete_Books")]
public Task DeleteAsync(CreateAuthorDto input)
{
...
}
}
```
- `GetListAsync` e `GetAsync` estarão disponíveis para usuários se a permissão `Author_Management` for concedida.
- Outros métodos requerem permissões adicionais.
### Substituindo uma Permissão por uma Política Personalizada
Se você definir e registrar uma política no sistema de autorização do ASP.NET Core com o mesmo nome de uma permissão, sua política substituirá a permissão existente. Isso é uma maneira poderosa de estender a autorização para um módulo pré-construído que você está usando em sua aplicação.
Consulte o documento [autorização baseada em políticas](https://docs.microsoft.com/pt-br/aspnet/core/security/authorization/policies) para aprender como definir uma política personalizada.
### Alterando as Definições de Permissão de um Módulo Dependente
Uma classe derivada de `PermissionDefinitionProvider` (assim como o exemplo acima) também pode obter definições de permissão existentes (definidas pelos [módulos](Module-Development-Basics.md) dependentes) e alterar suas definições.
Exemplo:
````csharp
context
.GetPermissionOrNull(IdentityPermissions.Roles.Delete)
.IsEnabled = false;
````
Quando você escreve esse código dentro do seu provedor de definição de permissão, ele encontra a permissão de "exclusão de função" do [Módulo de Identidade](Modules/Identity.md) e desabilita a permissão, para que ninguém possa excluir uma função na aplicação.
> Dica: É melhor verificar o valor retornado pelo método `GetPermissionOrNull`, pois ele pode retornar nulo se a permissão fornecida não foi definida.
### Provedores de Valor de Permissão
O sistema de verificação de permissões é extensível. Qualquer classe derivada de `PermissionValueProvider` (ou que implemente `IPermissionValueProvider`) pode contribuir para a verificação de permissões. Existem três provedores de valor predefinidos:
- `UserPermissionValueProvider` verifica se o usuário atual tem a permissão concedida. Ele obtém o ID do usuário das reivindicações atuais. O nome da reivindicação do usuário é definido pela propriedade estática `AbpClaimTypes.UserId`.
- `RolePermissionValueProvider` verifica se algum dos papéis do usuário atual tem a permissão concedida. Ele obtém os nomes dos papéis das reivindicações atuais. O nome das reivindicações de papéis é definido pela propriedade estática `AbpClaimTypes.Role`.
- `ClientPermissionValueProvider` verifica se o cliente atual tem a permissão concedida. Isso é especialmente útil em uma interação máquina a máquina, onde não há usuário atual. Ele obtém o ID do cliente das reivindicações atuais. O nome da reivindicação do cliente é definido pela propriedade estática `AbpClaimTypes.ClientId`.
Você pode estender o sistema de verificação de permissões definindo seu próprio provedor de valor de permissão.
Exemplo:
```csharp
public class SystemAdminPermissionValueProvider : PermissionValueProvider
{
public SystemAdminPermissionValueProvider(IPermissionStore permissionStore)
: base(permissionStore)
{
}
public override string Name => "SystemAdmin";
public async override Task<PermissionGrantResult>
CheckAsync(PermissionValueCheckContext context)
{
if (context.Principal?.FindFirst("User_Type")?.Value == "SystemAdmin")
{
return PermissionGrantResult.Granted;
}
return PermissionGrantResult.Undefined;
}
}
```
Esse provedor permite que todas as permissões sejam concedidas a um usuário com uma reivindicação `User_Type` que tenha o valor `SystemAdmin`. É comum usar as reivindicações atuais e o `IPermissionStore` em um provedor de valor de permissão.
Um provedor de valor de permissão deve retornar um dos seguintes valores do método `CheckAsync`:
- `PermissionGrantResult.Granted` é retornado para conceder a permissão ao usuário. Se qualquer um dos provedores retornar `Granted`, o resultado será `Granted`, se nenhum outro provedor retornar `Prohibited`.
- `PermissionGrantResult.Prohibited` é retornado para proibir a permissão ao usuário. Se qualquer um dos provedores retornar `Prohibited`, o resultado será sempre `Prohibited`. Não importa o que os outros provedores retornem.
- `PermissionGrantResult.Undefined` é retornado se esse provedor de valor de permissão não puder decidir sobre o valor da permissão. Retorne isso para permitir que outros provedores verifiquem a permissão.
Uma vez que um provedor é definido, ele deve ser adicionado às `AbpPermissionOptions`, como mostrado abaixo:
```csharp
Configure<AbpPermissionOptions>(options =>
{
options.ValueProviders.Add<SystemAdminPermissionValueProvider>();
});
```
### Armazenamento de Permissões
`IPermissionStore` é a única interface que precisa ser implementada para ler o valor das permissões de uma fonte de persistência, geralmente um sistema de banco de dados. O módulo de gerenciamento de permissões a implementa e é pré-instalado no modelo de inicialização da aplicação. Consulte a [documentação do módulo de gerenciamento de permissões](Modules/Permission-Management.md) para obter mais informações.
### AlwaysAllowAuthorizationService
`AlwaysAllowAuthorizationService` é uma classe usada para ignorar o serviço de autorização. Geralmente é usado em testes de integração, onde você pode querer desabilitar o sistema de autorização.
Use o método de extensão `IServiceCollection.AddAlwaysAllowAuthorization()` para registrar o `AlwaysAllowAuthorizationService` no sistema de [injeção de dependência](Dependency-Injection.md):
```csharp
public override void ConfigureServices(ServiceConfigurationContext context)
{
context.Services.AddAlwaysAllowAuthorization();
}
```
Isso já é feito para testes de integração do modelo de inicialização.
### Fábrica de Claims Principal
As reivindicações são elementos importantes da autenticação e autorização. O ABP usa o serviço `IAbpClaimsPrincipalFactory` para criar reivindicações na autenticação. Esse serviço foi projetado para ser extensível. Se você precisar adicionar suas próprias reivindicações ao ticket de autenticação, poderá implementar `IAbpClaimsPrincipalContributor` em sua aplicação.
**Exemplo: Adicionar uma reivindicação `SocialSecurityNumber` e obtê-la:**
```csharp
public class SocialSecurityNumberClaimsPrincipalContributor : IAbpClaimsPrincipalContributor, ITransientDependency
{
public async Task ContributeAsync(AbpClaimsPrincipalContributorContext context)
{
var identity = context.ClaimsPrincipal.Identities.FirstOrDefault();
var userId = identity?.FindUserId();
if (userId.HasValue)
{
var userService = context.ServiceProvider.GetRequiredService<IUserService>(); //Seu serviço personalizado
var socialSecurityNumber = await userService.GetSocialSecurityNumberAsync(userId.Value);
if (socialSecurityNumber != null)
{
identity.AddClaim(new Claim("SocialSecurityNumber", socialSecurityNumber));
}
}
}
}
public static class CurrentUserExtensions
{
public static string GetSocialSecurityNumber(this ICurrentUser currentUser)
{
return currentUser.FindClaimValue("SocialSecurityNumber");
}
}
```
> Se você estiver usando o Identity Server, adicione suas reivindicações a `RequestedClaims` de `AbpClaimsServiceOptions`.
```csharp
Configure<AbpClaimsServiceOptions>(options =>
{
options.RequestedClaims.AddRange(new[]{ "SocialSecurityNumber" });
});
```
## Veja também
* [Módulo de Gerenciamento de Permissões](Modules/Permission-Management.md)
* [API de Autenticação JavaScript do ASP.NET Core MVC / Razor Pages](UI/AspNetCore/JavaScript-API/Auth.md)
* [Gerenciamento de Permissões na Interface do Usuário Angular](UI/Angular/Permission-Management.md)
* [Tutorial em vídeo](https://abp.io/video-courses/essentials/authorization)</source>

159
docs/pt-BR/Background-Jobs-Quartz.md

@ -0,0 +1,159 @@
# Gerenciador de Tarefas em Segundo Plano Quartz
[Quartz](https://www.quartz-scheduler.net/) é um avançado gerenciador de tarefas em segundo plano. Você pode integrar o Quartz com o ABP Framework para usá-lo em vez do [gerenciador de tarefas em segundo plano padrão](Background-Jobs.md). Dessa forma, você pode usar a mesma API de tarefas em segundo plano para o Quartz e seu código será independente do Quartz. Se preferir, você também pode usar diretamente a API do Quartz.
> Consulte o [documento de tarefas em segundo plano](Background-Jobs.md) para aprender como usar o sistema de tarefas em segundo plano. Este documento mostra apenas como instalar e configurar a integração com o Quartz.
## Instalação
É sugerido usar o [ABP CLI](CLI.md) para instalar este pacote.
### Usando o ABP CLI
Abra uma janela de linha de comando na pasta do projeto (arquivo .csproj) e digite o seguinte comando:
````bash
abp add-package Volo.Abp.BackgroundJobs.Quartz
````
> Se você ainda não o fez, primeiro precisa instalar o [ABP CLI](CLI.md). Para outras opções de instalação, consulte [a página de descrição do pacote](https://abp.io/package-detail/Volo.Abp.BackgroundJobs.Quartz).
### Instalação Manual
Se você deseja instalar manualmente:
1. Adicione o pacote NuGet [Volo.Abp.BackgroundJobs.Quartz](https://www.nuget.org/packages/Volo.Abp.BackgroundJobs.Quartz) ao seu projeto:
````
Install-Package Volo.Abp.BackgroundJobs.Quartz
````
2. Adicione o `AbpBackgroundJobsQuartzModule` à lista de dependências do seu módulo:
````csharp
[DependsOn(
//...outras dependências
typeof(AbpBackgroundJobsQuartzModule) //Adicione a nova dependência do módulo
)]
public class SeuModulo : AbpModule
{
}
````
## Configuração
O Quartz é uma biblioteca muito configurável e o framework ABP fornece `AbpQuartzOptions` para isso. Você pode usar o método `PreConfigure` na classe do seu módulo para pré-configurar essa opção. O ABP a usará ao inicializar o módulo Quartz. Por exemplo:
````csharp
[DependsOn(
//...outras dependências
typeof(AbpBackgroundJobsQuartzModule) //Adicione a nova dependência do módulo
)]
public class SeuModulo : AbpModule
{
public override void PreConfigureServices(ServiceConfigurationContext context)
{
var configuration = context.Services.GetConfiguration();
PreConfigure<AbpQuartzOptions>(options =>
{
options.Properties = new NameValueCollection
{
["quartz.jobStore.dataSource"] = "BackgroundJobsDemoApp",
["quartz.jobStore.type"] = "Quartz.Impl.AdoJobStore.JobStoreTX, Quartz",
["quartz.jobStore.tablePrefix"] = "QRTZ_",
["quartz.serializer.type"] = "json",
["quartz.dataSource.BackgroundJobsDemoApp.connectionString"] = configuration.GetConnectionString("Quartz"),
["quartz.dataSource.BackgroundJobsDemoApp.provider"] = "SqlServer",
["quartz.jobStore.driverDelegateType"] = "Quartz.Impl.AdoJobStore.SqlServerDelegate, Quartz",
};
});
}
}
````
A partir da versão 3.1 do ABP, adicionamos o `Configurator` ao `AbpQuartzOptions` para configurar o Quartz. Por exemplo:
````csharp
[DependsOn(
//...outras dependências
typeof(AbpBackgroundJobsQuartzModule) //Adicione a nova dependência do módulo
)]
public class SeuModulo : AbpModule
{
public override void PreConfigureServices(ServiceConfigurationContext context)
{
var configuration = context.Services.GetConfiguration();
PreConfigure<AbpQuartzOptions>(options =>
{
options.Configurator = configure =>
{
configure.UsePersistentStore(storeOptions =>
{
storeOptions.UseProperties = true;
storeOptions.UseJsonSerializer();
storeOptions.UseSqlServer(configuration.GetConnectionString("Quartz"));
storeOptions.UseClustering(c =>
{
c.CheckinMisfireThreshold = TimeSpan.FromSeconds(20);
c.CheckinInterval = TimeSpan.FromSeconds(10);
});
});
};
});
}
}
````
> Você pode escolher a maneira que preferir para configurar o Quartz.
O Quartz armazena informações de tarefas e agendamento **em memória por padrão**. No exemplo, usamos a pré-configuração do [padrão de opções](Options.md) para alterá-lo para o banco de dados. Para mais configurações do Quartz, consulte a [documentação do Quartz](https://www.quartz-scheduler.net/).
## Tratamento de Exceções
### Estratégia de tratamento de exceções padrão
Quando ocorre uma exceção na tarefa em segundo plano, o ABP fornece a **estratégia de tratamento padrão** que tenta novamente a cada 3 segundos, até 3 vezes. Você pode alterar a contagem de tentativas e o intervalo de tentativa por meio das opções `AbpBackgroundJobQuartzOptions`:
```csharp
[DependsOn(
//...outras dependências
typeof(AbpBackgroundJobsQuartzModule) //Adicione a nova dependência do módulo
)]
public class SeuModulo : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
Configure<AbpBackgroundJobQuartzOptions>(options =>
{
options.RetryCount = 1;
options.RetryIntervalMillisecond = 1000;
});
}
}
```
### Personalizar a estratégia de tratamento de exceções
Você pode personalizar a estratégia de tratamento de exceções por meio das opções `AbpBackgroundJobQuartzOptions`:
```csharp
[DependsOn(
//...outras dependências
typeof(AbpBackgroundJobsQuartzModule) //Adicione a nova dependência do módulo
)]
public class SeuModulo : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
Configure<AbpBackgroundJobQuartzOptions>(options =>
{
options.RetryStrategy = async (retryIndex, executionContext, exception) =>
{
// personalizar o tratamento de exceções
};
});
}
}
```</source>

146
docs/pt-BR/Background-Workers-Quartz.md

@ -0,0 +1,146 @@
# Gerenciador de Trabalhadores em Segundo Plano Quartz
[Quartz](https://www.quartz-scheduler.net/) é um avançado gerenciador de trabalhadores em segundo plano. Você pode integrar o Quartz com o ABP Framework para usá-lo em vez do [gerenciador de trabalhadores em segundo plano padrão](Background-Workers.md). O ABP simplesmente integra o Quartz.
## Instalação
É sugerido usar o [ABP CLI](CLI.md) para instalar este pacote.
### Usando o ABP CLI
Abra uma janela de linha de comando na pasta do projeto (arquivo .csproj) e digite o seguinte comando:
````bash
abp add-package Volo.Abp.BackgroundWorkers.Quartz
````
### Instalação Manual
Se você deseja instalar manualmente:
1. Adicione o pacote NuGet [Volo.Abp.BackgroundWorkers.Quartz](https://www.nuget.org/packages/Volo.Abp.BackgroundWorkers.Quartz) ao seu projeto:
````
Install-Package Volo.Abp.BackgroundWorkers.Quartz
````
2. Adicione o módulo `AbpBackgroundWorkersQuartzModule` à lista de dependências do seu módulo:
````csharp
[DependsOn(
//...outras dependências
typeof(AbpBackgroundWorkersQuartzModule) //Adicione a nova dependência do módulo
)]
public class SeuModulo : AbpModule
{
}
````
> A integração do trabalhador em segundo plano do Quartz fornece o adaptador `QuartzPeriodicBackgroundWorkerAdapter` para adaptar as classes derivadas `PeriodicBackgroundWorkerBase` e `AsyncPeriodicBackgroundWorkerBase`. Portanto, você ainda pode seguir o [documento de trabalhadores em segundo plano](Background-Workers.md) para definir o trabalhador em segundo plano.
## Configuração
Veja [Configuração](Background-Jobs-Quartz#Configuração).
## Criar um Trabalhador em Segundo Plano
Um trabalho em segundo plano é uma classe que deriva da classe base `QuartzBackgroundWorkerBase`. Por exemplo, uma classe de trabalhador simples é mostrada abaixo:
```` csharp
public class MeuTrabalhadorDeLog : QuartzBackgroundWorkerBase
{
public MeuTrabalhadorDeLog()
{
JobDetail = JobBuilder.Create<MeuTrabalhadorDeLog>().WithIdentity(nameof(MeuTrabalhadorDeLog)).Build();
Trigger = TriggerBuilder.Create().WithIdentity(nameof(MeuTrabalhadorDeLog)).StartNow().Build();
}
public override Task Execute(IJobExecutionContext context)
{
Logger.LogInformation("Executando MeuTrabalhadorDeLog..!");
return Task.CompletedTask;
}
}
````
Nós simplesmente implementamos o método Execute para escrever um log. O trabalhador em segundo plano é um **singleton por padrão**. Se desejar, você também pode implementar uma [interface de dependência](Dependency-Injection#Interfaces-de-Dependência) para registrá-lo com outro ciclo de vida.
> Dica: Adicionar identidade aos trabalhadores em segundo plano é uma boa prática, pois o Quartz distingue trabalhos diferentes com base na identidade.
## Adicionar ao BackgroundWorkerManager
Os trabalhadores em segundo plano padrão são **adicionados automaticamente** ao BackgroundWorkerManager quando a aplicação é **inicializada**. Você pode definir o valor da propriedade `AutoRegister` como `false`, se desejar adicioná-lo manualmente:
```` csharp
public class MeuTrabalhadorDeLog : QuartzBackgroundWorkerBase
{
public MeuTrabalhadorDeLog()
{
AutoRegister = false;
JobDetail = JobBuilder.Create<MeuTrabalhadorDeLog>().WithIdentity(nameof(MeuTrabalhadorDeLog)).Build();
Trigger = TriggerBuilder.Create().WithIdentity(nameof(MeuTrabalhadorDeLog)).StartNow().Build();
}
public override Task Execute(IJobExecutionContext context)
{
Logger.LogInformation("Executando MeuTrabalhadorDeLog..!");
return Task.CompletedTask;
}
}
````
Se você deseja desabilitar globalmente a adição automática de trabalhadores, você pode desabilitá-la globalmente através das opções `AbpBackgroundWorkerQuartzOptions`:
```csharp
[DependsOn(
//...outras dependências
typeof(AbpBackgroundWorkersQuartzModule) //Adicione a nova dependência do módulo
)]
public class SeuModulo : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
Configure<AbpBackgroundWorkerQuartzOptions>(options =>
{
options.IsAutoRegisterEnabled = false;
});
}
}
```
## Tópicos Avançados
### Personalizar o ScheduleJob
Suponha que você tenha um trabalhador que é executado a cada 10 minutos, mas devido a um servidor indisponível por 30 minutos, 3 execuções são perdidas. Você deseja executar todas as execuções perdidas quando o servidor estiver disponível novamente. Você deve definir seu trabalhador em segundo plano da seguinte forma:
```csharp
public class MeuTrabalhadorDeLog : QuartzBackgroundWorkerBase
{
public MeuTrabalhadorDeLog()
{
JobDetail = JobBuilder.Create<MeuTrabalhadorDeLog>().WithIdentity(nameof(MeuTrabalhadorDeLog)).Build();
Trigger = TriggerBuilder.Create().WithIdentity(nameof(MeuTrabalhadorDeLog)).WithSimpleSchedule(s=>s.WithIntervalInMinutes(1).RepeatForever().WithMisfireHandlingInstructionIgnoreMisfires()).Build();
ScheduleJob = async scheduler =>
{
if (!await scheduler.CheckExists(JobDetail.Key))
{
await scheduler.ScheduleJob(JobDetail, Trigger);
}
};
}
public override Task Execute(IJobExecutionContext context)
{
Logger.LogInformation("Executando MeuTrabalhadorDeLog..!");
return Task.CompletedTask;
}
}
```
No exemplo, definimos o intervalo de execução do trabalhador como 10 minutos e definimos `WithMisfireHandlingInstructionIgnoreMisfires`. Personalizamos o `ScheduleJob` e adicionamos o trabalhador ao Quartz somente quando o trabalhador em segundo plano não existe.
### Mais
Consulte a [documentação](https://www.quartz-scheduler.net/documentation/index.html) do Quartz para obter mais informações.

144
docs/pt-BR/Background-Workers.md

@ -0,0 +1,144 @@
# Background Workers
## Introdução
Background workers são threads independentes simples na aplicação que são executadas em segundo plano. Geralmente, eles são executados periodicamente para realizar algumas tarefas. Exemplos:
* Um background worker pode ser executado periodicamente para **excluir logs antigos**.
* Um background worker pode ser executado periodicamente para **identificar usuários inativos** e **enviar e-mails** para fazer com que os usuários retornem à sua aplicação.
## Criando um Background Worker
Um background worker deve implementar diretamente ou indiretamente a interface `IBackgroundWorker`.
> Um background worker é inerentemente [singleton](Dependency-Injection.md). Portanto, apenas uma única instância da sua classe de worker é instanciada e executada.
### BackgroundWorkerBase
`BackgroundWorkerBase` é uma maneira fácil de criar um background worker.
````csharp
public class MyWorker : BackgroundWorkerBase
{
public override Task StartAsync(CancellationToken cancellationToken = default)
{
//...
}
public override Task StopAsync(CancellationToken cancellationToken = default)
{
//...
}
}
````
Inicie o seu worker no método `StartAsync` (que é chamado quando a aplicação é iniciada) e pare no método `StopAsync` (que é chamado quando a aplicação é encerrada).
> Você pode implementar diretamente a interface `IBackgroundWorker`, mas `BackgroundWorkerBase` fornece algumas propriedades úteis, como `Logger`.
### AsyncPeriodicBackgroundWorkerBase
Vamos supor que queremos tornar um usuário inativo se ele não tiver feito login na aplicação nos últimos 30 dias. A classe `AsyncPeriodicBackgroundWorkerBase` simplifica a criação de workers periódicos, então vamos usá-la no exemplo abaixo:
````csharp
public class PassiveUserCheckerWorker : AsyncPeriodicBackgroundWorkerBase
{
public PassiveUserCheckerWorker(
AbpAsyncTimer timer,
IServiceScopeFactory serviceScopeFactory
) : base(
timer,
serviceScopeFactory)
{
Timer.Period = 600000; //10 minutos
}
protected async override Task DoWorkAsync(
PeriodicBackgroundWorkerContext workerContext)
{
Logger.LogInformation("Iniciando: Definindo status de usuários inativos...");
//Resolver dependências
var userRepository = workerContext
.ServiceProvider
.GetRequiredService<IUserRepository>();
//Realizar o trabalho
await userRepository.UpdateInactiveUserStatusesAsync();
Logger.LogInformation("Concluído: Definindo status de usuários inativos...");
}
}
````
* `AsyncPeriodicBackgroundWorkerBase` usa o objeto `AbpAsyncTimer` (um timer thread-safe) para determinar **o período**. Podemos definir a propriedade `Period` no construtor.
* É necessário implementar o método `DoWorkAsync` para **executar** o trabalho periódico.
* É uma boa prática **resolver as dependências** a partir do `PeriodicBackgroundWorkerContext` em vez de usar injeção de dependência no construtor. Isso ocorre porque `AsyncPeriodicBackgroundWorkerBase` usa um `IServiceScope` que é **descartado** quando o trabalho é concluído.
* `AsyncPeriodicBackgroundWorkerBase` **captura e registra exceções** lançadas pelo método `DoWorkAsync`.
## Registrando o Background Worker
Após criar a classe do background worker, você deve adicioná-la ao `IBackgroundWorkerManager`. O local mais comum é o método `OnApplicationInitializationAsync` da sua classe de módulo:
````csharp
[DependsOn(typeof(AbpBackgroundWorkersModule))]
public class MyModule : AbpModule
{
public override async Task OnApplicationInitializationAsync(
ApplicationInitializationContext context)
{
await context.AddBackgroundWorkerAsync<PassiveUserCheckerWorker>();
}
}
````
`context.AddBackgroundWorkerAsync(...)` é um método de extensão que simplifica a expressão abaixo:
````csharp
await context.ServiceProvider
.GetRequiredService<IBackgroundWorkerManager>()
.AddAsync(
context
.ServiceProvider
.GetRequiredService<PassiveUserCheckerWorker>()
);
````
Dessa forma, ele resolve o background worker fornecido e o adiciona ao `IBackgroundWorkerManager`.
Embora geralmente adicionemos workers no método `OnApplicationInitializationAsync`, não há restrições quanto a isso. Você pode injetar o `IBackgroundWorkerManager` em qualquer lugar e adicionar workers em tempo de execução. O gerenciador de background workers irá parar e liberar todos os workers registrados quando a aplicação for encerrada.
## Opções
A classe `AbpBackgroundWorkerOptions` é usada para [definir opções](Options.md) para os background workers. Atualmente, há apenas uma opção:
* `IsEnabled` (padrão: true): Usado para **habilitar/desabilitar** o sistema de background workers para a sua aplicação.
> Consulte o documento [Options](Options.md) para aprender como definir opções.
## Mantendo a Aplicação Sempre em Execução
Os background workers só funcionam se a sua aplicação estiver em execução. Se você hospedar a execução do job em segundo plano na sua aplicação web (esse é o comportamento padrão), você deve garantir que a sua aplicação web esteja configurada para sempre estar em execução. Caso contrário, os jobs em segundo plano só funcionarão enquanto a sua aplicação estiver em uso.
## Executando em um Cluster
Tenha cuidado se você executar várias instâncias da sua aplicação simultaneamente em um ambiente de cluster. Nesse caso, cada aplicação executa o mesmo worker, o que pode criar conflitos se os workers estiverem executando em recursos compartilhados (processando os mesmos dados, por exemplo).
Se isso for um problema para os seus workers, você tem as seguintes opções:
* Implemente os seus background workers de forma que eles funcionem em um ambiente de cluster sem problemas. Usar o [lock distribuído](Distributed-Locking.md) para garantir o controle de concorrência é uma forma de fazer isso. Um background worker em uma instância da aplicação pode manipular um lock distribuído, então os workers em outras instâncias da aplicação aguardarão pelo lock. Dessa forma, apenas um worker realiza o trabalho real, enquanto os outros esperam ociosos. Se você implementar isso, os seus workers serão executados com segurança, independentemente de como a aplicação estiver implantada.
* Pare os background workers (defina `AbpBackgroundWorkerOptions.IsEnabled` como `false`) em todas as instâncias da aplicação, exceto em uma delas, para que apenas a instância única execute os workers.
* Pare os background workers (defina `AbpBackgroundWorkerOptions.IsEnabled` como `false`) em todas as instâncias da aplicação e crie uma aplicação dedicada (talvez uma aplicação console executando em seu próprio contêiner ou um serviço do Windows em execução em segundo plano) para executar todas as tarefas em segundo plano. Essa pode ser uma boa opção se os seus background workers consumirem muitos recursos do sistema (CPU, RAM ou Disco), para que você possa implantar essa aplicação de background em um servidor dedicado e suas tarefas em segundo plano não afetem o desempenho da sua aplicação.
## Integrações
O sistema de background workers é extensível e você pode alterar o gerenciador de background workers padrão com a sua própria implementação ou com uma das integrações pré-construídas.
Veja as alternativas de gerenciador de workers pré-construídas:
* [Quartz Background Worker Manager](Background-Workers-Quartz.md)
* [Hangfire Background Worker Manager](Background-Workers-Hangfire.md)
## Veja Também
* [Background Jobs](Background-Jobs.md)

343
docs/pt-BR/Exception-Handling.md

@ -0,0 +1,343 @@
# Tratamento de Exceções
O ABP fornece uma infraestrutura integrada e oferece um modelo padrão para lidar com exceções.
* **Lida automaticamente com todas as exceções** e envia uma **mensagem de erro formatada padrão** para o cliente em uma solicitação de API/AJAX.
* Oculta automaticamente os **erros internos de infraestrutura** e retorna uma mensagem de erro padrão.
* Fornece uma maneira fácil e configurável de **localizar** mensagens de exceção.
* Mapeia automaticamente exceções padrão para **códigos de status HTTP** e fornece uma opção configurável para mapear exceções personalizadas.
## Tratamento Automático de Exceções
O `AbpExceptionFilter` lida com uma exceção se **qualquer uma das seguintes condições** forem atendidas:
* A exceção é lançada por uma **ação do controlador** que retorna um **resultado de objeto** (não um resultado de visualização).
* A solicitação é uma solicitação AJAX (o valor do cabeçalho HTTP `X-Requested-With` é `XMLHttpRequest`).
* O cliente aceita explicitamente o tipo de conteúdo `application/json` (por meio do cabeçalho HTTP `accept`).
Se a exceção for tratada, ela é automaticamente **registrada** e uma **mensagem JSON formatada** é retornada ao cliente.
### Formato da Mensagem de Erro
A mensagem de erro é uma instância da classe `RemoteServiceErrorResponse`. O JSON de erro mais simples tem uma propriedade **message** conforme mostrado abaixo:
````json
{
"error": {
"message": "Este tópico está bloqueado e não é possível adicionar uma nova mensagem"
}
}
````
Existem **campos opcionais** que podem ser preenchidos com base na exceção que ocorreu.
##### Código de Erro
O **código de erro** é um valor de string opcional e único para a exceção. A exceção lançada deve implementar a interface `IHasErrorCode` para preencher este campo. Exemplo de valor JSON:
````json
{
"error": {
"code": "App:010042",
"message": "Este tópico está bloqueado e não é possível adicionar uma nova mensagem"
}
}
````
O código de erro também pode ser usado para localizar a exceção e personalizar o código de status HTTP (consulte as seções relacionadas abaixo).
##### Detalhes do Erro
Os **detalhes do erro** são um campo opcional da mensagem de erro JSON. A exceção lançada deve implementar a interface `IHasErrorDetails` para preencher este campo. Exemplo de valor JSON:
```json
{
"error": {
"code": "App:010042",
"message": "Este tópico está bloqueado e não é possível adicionar uma nova mensagem",
"details": "Informações mais detalhadas sobre o erro..."
}
}
```
##### Erros de Validação
**validationErrors** é um campo padrão que é preenchido se a exceção lançada implementar a interface `IHasValidationErrors`.
````json
{
"error": {
"code": "App:010046",
"message": "Sua solicitação não é válida, corrija e tente novamente!",
"validationErrors": [{
"message": "O nome de usuário deve ter no mínimo 3 caracteres.",
"members": ["userName"]
},
{
"message": "A senha é obrigatória",
"members": ["password"]
}]
}
}
````
`AbpValidationException` implementa a interface `IHasValidationErrors` e é automaticamente lançada pelo framework quando a entrada de uma solicitação não é válida. Portanto, geralmente você não precisa lidar com erros de validação, a menos que tenha lógica de validação altamente personalizada.
### Registro
As exceções capturadas são automaticamente registradas.
#### Nível de Registro
As exceções são registradas com o nível `Error` por padrão. O nível de log pode ser determinado pela exceção se ela implementar a interface `IHasLogLevel`. Exemplo:
````C#
public class MinhaExcecao : Exception, IHasLogLevel
{
public LogLevel LogLevel { get; set; } = LogLevel.Warning;
//...
}
````
#### Exceções de Registro Próprio
Alguns tipos de exceção podem precisar escrever logs adicionais. Eles podem implementar a interface `IExceptionWithSelfLogging` se necessário. Exemplo:
````C#
public class MinhaExcecao : Exception, IExceptionWithSelfLogging
{
public void Log(ILogger logger)
{
//...log informações adicionais
}
}
````
> Os métodos de extensão `ILogger.LogException` são usados para escrever logs de exceção. Você pode usar o mesmo método de extensão quando necessário.
## Exceções de Negócios
A maioria de suas próprias exceções será exceções de negócios. A interface `IBusinessException` é usada para marcar uma exceção como uma exceção de negócios.
`BusinessException` implementa a interface `IBusinessException` além das interfaces `IHasErrorCode`, `IHasErrorDetails` e `IHasLogLevel`. O nível de log padrão é `Warning`.
Normalmente, você tem um código de erro relacionado a uma exceção de negócios específica. Por exemplo:
````C#
throw new BusinessException(QaErrorCodes.CanNotVoteYourOwnAnswer);
````
`QaErrorCodes.CanNotVoteYourOwnAnswer` é apenas uma `const string`. O seguinte formato de código de erro é recomendado:
````
<namespace-do-código>:<código-de-erro>
````
**namespace-do-código** é um **valor único** específico para o seu módulo/aplicação. Exemplo:
````
Volo.Qa:010002
````
`Volo.Qa` é o namespace do código aqui. O namespace do código será então usado ao **localizar** mensagens de exceção.
* Você pode **lançar diretamente** uma `BusinessException` ou **derivar** seus próprios tipos de exceção dela quando necessário.
* Todas as propriedades são opcionais para a classe `BusinessException`. Mas geralmente você define a propriedade `ErrorCode` ou `Message`.
## Localização de Exceções
Um problema ao lançar exceções é como localizar mensagens de erro ao enviá-las para o cliente. O ABP oferece dois modelos e suas variantes.
### Exceção Amigável ao Usuário
Se uma exceção implementa a interface `IUserFriendlyException`, então o ABP não altera suas propriedades `Message` e `Details` e a envia diretamente para o cliente.
A classe `UserFriendlyException` é a implementação integrada da interface `IUserFriendlyException`. Exemplo de uso:
````C#
throw new UserFriendlyException(
"O nome de usuário deve ser único!"
);
````
Dessa forma, **não há necessidade de localização**. Se você deseja localizar a mensagem, pode injetar e usar o **localizador de strings padrão** (consulte o [documento de localização](Localization.md)). Exemplo:
````C#
throw new UserFriendlyException(_stringLocalizer["UserNameShouldBeUniqueMessage"]);
````
Em seguida, defina no **recurso de localização** para cada idioma. Exemplo:
````json
{
"culture": "pt",
"texts": {
"UserNameShouldBeUniqueMessage": "O nome de usuário deve ser único!"
}
}
````
O localizador de strings já suporta **mensagens parametrizadas**. Por exemplo:
````C#
throw new UserFriendlyException(_stringLocalizer["UserNameShouldBeUniqueMessage", "john"]);
````
Em seguida, o texto de localização pode ser:
````json
"UserNameShouldBeUniqueMessage": "O nome de usuário deve ser único! '{0}' já está em uso!"
````
* A interface `IUserFriendlyException` é derivada da `IBusinessException` e a classe `UserFriendlyException` é derivada da classe `BusinessException`.
### Usando Códigos de Erro
`UserFriendlyException` é bom, mas tem alguns problemas em usos avançados:
* Requer que você **injete o localizador de strings** em todos os lugares e sempre o use ao lançar exceções.
* No entanto, em alguns casos, pode **não ser possível** injetar o localizador de strings (em um contexto estático ou em um método de entidade).
Em vez de localizar a mensagem ao lançar a exceção, você pode separar o processo usando **códigos de erro**.
Primeiro, defina o mapeamento do **namespace-do-código** para o **recurso de localização** na configuração do módulo:
````C#
services.Configure<AbpExceptionLocalizationOptions>(options =>
{
options.MapCodeNamespace("Volo.Qa", typeof(QaResource));
});
````
Então, qualquer uma das exceções com o namespace `Volo.Qa` será localizada usando seu recurso de localização fornecido. O recurso de localização deve sempre ter uma entrada com a chave do código de erro. Exemplo:
````json
{
"culture": "pt",
"texts": {
"Volo.Qa:010002": "Você não pode votar em sua própria resposta!"
}
}
````
Então uma exceção de negócios pode ser lançada com o código de erro:
````C#
throw new BusinessException(QaDomainErrorCodes.CanNotVoteYourOwnAnswer);
````
* Lançar qualquer exceção que implemente a interface `IHasErrorCode` se comporta da mesma maneira. Portanto, a abordagem de localização de código de erro não é exclusiva para a classe `BusinessException`.
* Não é necessário definir uma string localizada para uma mensagem de erro. Se não estiver definido, o ABP envia a mensagem de erro padrão para o cliente. Ele não usa a propriedade `Message` da exceção! se você deseja isso, use a `UserFriendlyException` (ou use um tipo de exceção que implemente a interface `IUserFriendlyException`).
#### Usando Parâmetros de Mensagem
Se você tiver uma mensagem de erro parametrizada, poderá defini-la com a propriedade `Data` da exceção. Por exemplo:
````C#
throw new BusinessException("App:010046")
{
Data =
{
{"UserName", "john"}
}
};
````
Felizmente, há uma maneira mais simples de codificar isso:
````C#
throw new BusinessException("App:010046")
.WithData("UserName", "john");
````
Em seguida, o texto localizado pode conter o parâmetro `UserName`:
````json
{
"culture": "pt",
"texts": {
"App:010046": "O nome de usuário deve ser único. '{UserName}' já está em uso!"
}
}
````
* `WithData` pode ser encadeado com mais de um parâmetro (como `.WithData(...).WithData(...)`).
## Mapeamento de Códigos de Status HTTP
O ABP tenta determinar automaticamente o código de status HTTP mais adequado para tipos comuns de exceção seguindo estas regras:
* Para a `AbpAuthorizationException`:
* Retorna `401` (não autorizado) se o usuário não estiver logado.
* Retorna `403` (proibido) se o usuário estiver logado.
* Retorna `400` (requisição inválida) para a `AbpValidationException`.
* Retorna `404` (não encontrado) para a `EntityNotFoundException`.
* Retorna `403` (proibido) para a `IBusinessException` (e `IUserFriendlyException` já que estende a `IBusinessException`).
* Retorna `501` (não implementado) para a `NotImplementedException`.
* Retorna `500` (erro interno do servidor) para outras exceções (que são assumidas como exceções de infraestrutura).
O `IHttpExceptionStatusCodeFinder` é usado para determinar automaticamente o código de status HTTP. A implementação padrão é a classe `DefaultHttpExceptionStatusCodeFinder`. Pode ser substituída ou estendida conforme necessário.
### Mapeamentos Personalizados
A determinação automática do código de status HTTP pode ser substituída por mapeamentos personalizados. Por exemplo:
````C#
services.Configure<AbpExceptionHttpStatusCodeOptions>(options =>
{
options.Map("Volo.Qa:010002", HttpStatusCode.Conflict);
});
````
## Inscrevendo-se nas Exceções
É possível ser informado quando o Framework ABP **manipula uma exceção**. Ele registra automaticamente todas as exceções no [logger padrão](Logging.md), mas você pode querer fazer mais.
Nesse caso, crie uma classe derivada da classe `ExceptionSubscriber` em sua aplicação:
````csharp
public class MeuAssinanteDeExcecao : ExceptionSubscriber
{
public async override Task HandleAsync(ExceptionNotificationContext context)
{
//TODO...
}
}
````
O objeto `context` contém informações necessárias sobre a exceção ocorrida.
> Você pode ter vários assinantes, cada um recebe uma cópia da exceção. As exceções lançadas pelo seu assinante são ignoradas (mas ainda registradas).
## Exceções Integradas
Alguns tipos de exceção são automaticamente lançados pelo framework:
- `AbpAuthorizationException` é lançada se o usuário atual não tiver permissão para realizar a operação solicitada. Consulte [autorização](Authorization.md) para mais informações.
- `AbpValidationException` é lançada se a entrada da solicitação atual não for válida. Consulte [validação](Validation.md) para mais informações.
- `EntityNotFoundException` é lançada se a entidade solicitada não estiver disponível. Isso é lançado principalmente por [repositórios](Repositories.md).
Você também pode lançar esses tipos de exceção em seu código (embora raramente seja necessário).
## AbpExceptionHandlingOptions
`AbpExceptionHandlingOptions` é o principal [objeto de opções](Options.md) para configurar o sistema de tratamento de exceções. Você pode configurá-lo no método `ConfigureServices` do seu [módulo](Module-Development-Basics.md):
````csharp
Configure<AbpExceptionHandlingOptions>(options =>
{
options.SendExceptionsDetailsToClients = true;
options.SendStackTraceToClients = false;
});
````
Aqui está uma lista das opções que você pode configurar:
* `SendExceptionsDetailsToClients` (padrão: `false`): Você pode habilitar ou desabilitar o envio de detalhes da exceção para o cliente.
* `SendStackTraceToClients` (padrão: `true`): Você pode habilitar ou desabilitar o envio da pilha de chamadas da exceção para o cliente. Se você deseja enviar a pilha de chamadas para o cliente, deve definir tanto as opções `SendStackTraceToClients` quanto `SendExceptionsDetailsToClients` como `true`, caso contrário, a pilha de chamadas não será enviada para o cliente.
## Veja Também
* [Tutorial em vídeo](https://abp.io/video-courses/essentials/exception-handling)

80
docs/pt-BR/Modules/Account.md

@ -0,0 +1,80 @@
# Módulo de Conta
O módulo de conta implementa recursos básicos de autenticação, como **login**, **registro**, **recuperação de senha** e **gerenciamento de conta**.
Este módulo é baseado na biblioteca de identidade da Microsoft e no módulo de identidade. Ele possui integração com o IdentityServer (com base no módulo IdentityServer) e com o OpenIddict (com base no módulo OpenIddict) para fornecer autenticação avançada, controle de acesso e outros recursos avançados de autenticação.
## Como instalar
Este módulo já vem pré-instalado (como pacotes NuGet/NPM). Você pode continuar a usá-lo como pacote e obter atualizações facilmente, ou pode incluir seu código-fonte em sua solução (consulte o comando `get-source` da CLI) para desenvolver seu próprio módulo personalizado.
### O código-fonte
O código-fonte deste módulo pode ser acessado [aqui](https://github.com/abpframework/abp/tree/dev/modules/account). O código-fonte está licenciado sob a licença MIT, portanto, você pode usá-lo e personalizá-lo livremente.
## Interface do usuário
Esta seção apresenta as principais páginas fornecidas por este módulo.
### Login
A página `/Account/Login` fornece a funcionalidade de login.
![account-module-login](../images/account-module-login.png)
Os botões de login social/externo ficam visíveis se você configurá-los. Consulte a seção *Logins Sociais/Externos* abaixo. Os links de registro e recuperação de senha redirecionam para as páginas explicadas nas próximas seções.
### Registro
A página `/Account/Register` fornece a funcionalidade de registro de novo usuário.
![account-module-register](../images/account-module-register.png)
### Recuperação de senha e redefinição de senha
A página `/Account/ForgotPassword` fornece uma maneira de enviar um link de redefinição de senha para o endereço de e-mail do usuário. O usuário então clica no link e define uma nova senha.
![account-module-forgot-password](../images/account-module-forgot-password.png)
### Gerenciamento de conta
A página `/Account/Manage` é usada para alterar a senha e as informações pessoais do usuário.
![account-module-manage-account](../images/account-module-manage-account.png)
## Integração com o OpenIddict
O pacote [Volo.Abp.Account.Web.OpenIddict](https://www.nuget.org/packages/Volo.Abp.Account.Web.OpenIddict) fornece integração com o OpenIddict. Este pacote já vem instalado com o modelo de inicialização do aplicativo. Consulte a documentação do módulo OpenIddict.
## Integração com o IdentityServer
O pacote [Volo.Abp.Account.Web.IdentityServer](https://www.nuget.org/packages/Volo.Abp.Account.Web.IdentityServer) fornece integração com o IdentityServer. Este pacote já vem instalado com o modelo de inicialização do aplicativo. Consulte a documentação do módulo IdentityServer.
## Logins Sociais/Externos
O módulo de conta já está configurado para lidar com logins sociais ou externos prontamente. Você pode seguir a documentação do ASP.NET Core para adicionar um provedor de login social/externo à sua aplicação.
### Exemplo: Autenticação do Facebook
Siga o documento de integração do Facebook do ASP.NET Core para oferecer suporte ao login do Facebook em sua aplicação.
#### Adicionar o pacote NuGet
Adicione o pacote [Microsoft.AspNetCore.Authentication.Facebook](https://www.nuget.org/packages/Microsoft.AspNetCore.Authentication.Facebook) ao seu projeto. Com base na sua arquitetura, isso pode ser feito no projeto `.Web`, `.IdentityServer` (para configuração em camadas) ou `.Host`.
#### Configurar o provedor
Use o método de extensão `.AddFacebook(...)` no método `ConfigureServices` do seu [módulo](../Module-Development-Basics.md) para configurar o cliente:
````csharp
context.Services.AddAuthentication()
.AddFacebook(facebook =>
{
facebook.AppId = "...";
facebook.AppSecret = "...";
facebook.Scope.Add("email");
facebook.Scope.Add("public_profile");
});
````
> Seria uma prática melhor usar o `appsettings.json` ou o sistema de segredos do usuário do ASP.NET Core para armazenar suas credenciais, em vez de um valor codificado como esse. Siga o documento da Microsoft para aprender a usar os segredos do usuário.

60
docs/pt-BR/Modules/Audit-Logging.md

@ -0,0 +1,60 @@
# Módulo de Registro de Auditoria
O Módulo de Registro de Auditoria basicamente implementa o `IAuditingStore` para salvar os objetos de registro de auditoria em um banco de dados.
> Este documento abrange apenas o módulo de registro de auditoria que persiste os registros de auditoria em um banco de dados. Consulte o documento [registro de auditoria](../Audit-Logging.md) para obter mais informações sobre o sistema de registro de auditoria.
## Como Instalar
Este módulo vem pré-instalado (como pacotes NuGet/NPM). Você pode continuar a usá-lo como pacote e obter atualizações facilmente, ou pode incluir seu código-fonte em sua solução (consulte o comando `get-source` [CLI](../CLI.md)) para desenvolver seu módulo personalizado.
### O Código Fonte
O código fonte deste módulo pode ser acessado [aqui](https://github.com/abpframework/abp/tree/dev/modules/audit-logging). O código fonte é licenciado com [MIT](https://choosealicense.com/licenses/mit/), então você pode usá-lo e personalizá-lo livremente.
## Internos
### Camada de Domínio
#### Agregados
- `AuditLog` (raiz do agregado): Representa um registro de log de auditoria no sistema.
- `EntityChange` (coleção): Entidades alteradas do registro de auditoria.
- `AuditLogAction` (coleção): Ações executadas do registro de auditoria.
#### Repositórios
Os seguintes repositórios personalizados são definidos para este módulo:
- `IAuditLogRepository`
### Provedores de Banco de Dados
#### Comum
##### Prefixo da tabela / coleção e esquema
Todas as tabelas/coleções usam o prefixo `Abp` por padrão. Defina propriedades estáticas na classe `AbpAuditLoggingDbProperties` se você precisar alterar o prefixo da tabela ou definir um nome de esquema (se suportado pelo seu provedor de banco de dados).
##### String de conexão
Este módulo usa `AbpAuditLogging` como nome da string de conexão. Se você não definir uma string de conexão com esse nome, ela será usada a string de conexão `Default`. Consulte a documentação sobre [strings de conexão](https://docs.abp.io/en/abp/latest/Connection-Strings) para obter mais detalhes.
#### Entity Framework Core
##### Tabelas
- **AbpAuditLogs**
- AbpAuditLogActions
- AbpEntityChanges
- AbpEntityPropertyChanges
#### MongoDB
##### Coleções
- **AbpAuditLogs**
## Veja Também
* [Sistema de registro de auditoria](../Audit-Logging.md)

55
docs/pt-BR/Modules/Background-Jobs.md

@ -0,0 +1,55 @@
# Módulo de Tarefas em Segundo Plano
O módulo de Tarefas em Segundo Plano implementa a interface `IBackgroundJobStore` e torna possível usar o gerenciador de tarefas em segundo plano padrão do ABP Framework. Se você não deseja usar este módulo, então você deve implementar a interface `IBackgroundJobStore` por conta própria.
> Este documento aborda apenas o módulo de tarefas em segundo plano que persiste as tarefas em segundo plano em um banco de dados. Consulte o documento [tarefas em segundo plano](../Background-Jobs.md) para obter mais informações sobre o sistema de tarefas em segundo plano.
## Como Instalar
Este módulo vem pré-instalado (como pacotes NuGet/NPM). Você pode continuar a usá-lo como pacote e obter atualizações facilmente, ou pode incluir seu código-fonte em sua solução (consulte o comando `get-source` [CLI](../CLI.md)) para desenvolver seu próprio módulo personalizado.
### O Código Fonte
O código-fonte deste módulo pode ser acessado [aqui](https://github.com/abpframework/abp/tree/dev/modules/background-jobs). O código-fonte é licenciado com [MIT](https://choosealicense.com/licenses/mit/), então você pode usá-lo e personalizá-lo livremente.
## Internos
### Camada de Domínio
#### Agregados
- `BackgroundJobRecord` (raiz do agregado): Representa um registro de tarefa em segundo plano.
#### Repositórios
Os seguintes repositórios personalizados são definidos para este módulo:
- `IBackgroundJobRepository`
### Provedores de Banco de Dados
#### Comum
##### Prefixo da tabela / coleção e esquema
Todas as tabelas/coleções usam o prefixo `Abp` por padrão. Defina propriedades estáticas na classe `BackgroundJobsDbProperties` se você precisar alterar o prefixo da tabela ou definir um nome de esquema (se suportado pelo seu provedor de banco de dados).
##### String de conexão
Este módulo usa `AbpBackgroundJobs` como nome da string de conexão. Se você não definir uma string de conexão com esse nome, ela será usada a string de conexão `Default`. Consulte a documentação sobre [strings de conexão](https://docs.abp.io/en/abp/latest/Connection-Strings) para obter mais detalhes.
#### Entity Framework Core
##### Tabelas
- **AbpBackgroundJobs**
#### MongoDB
##### Coleções
- **AbpBackgroundJobs**
## Veja Também
* [Sistema de tarefas em segundo plano](../Background-Jobs.md)

135
docs/pt-BR/Modules/Cms-Kit/Blogging.md

@ -0,0 +1,135 @@
# Kit CMS: Blogging
A funcionalidade de blogging fornece a interface necessária para gerenciar e renderizar blogs e postagens de blog.
## Habilitando a funcionalidade de blogging
Por padrão, as funcionalidades do Kit CMS estão desabilitadas. Portanto, você precisa habilitar as funcionalidades que deseja antes de começar a usá-lo. Você pode usar o sistema de [Global Feature](../../Global-Features.md) para habilitar/desabilitar as funcionalidades do Kit CMS durante o desenvolvimento. Alternativamente, você pode usar o [Sistema de Funcionalidades](https://docs.abp.io/en/abp/latest/Features) do ABP Framework para desabilitar uma funcionalidade do Kit CMS em tempo de execução.
> Verifique a seção "Como instalar" da documentação do módulo Kit CMS (Index.md#how-to-install) para saber como habilitar/desabilitar as funcionalidades do Kit CMS durante o desenvolvimento.
## Interface do usuário
### Itens do menu
Os seguintes itens de menu são adicionados pela funcionalidade de blogging à aplicação de administração:
* **Blogs**: Página de gerenciamento de blogs.
* **Postagens de blog**: Página de gerenciamento de postagens de blog.
## Páginas
### Blogs
A página de blogs é usada para criar e gerenciar blogs no seu sistema.
![página-de-blogs](../../images/cmskit-module-blogs-page.png)
Uma captura de tela do modal de criação de novo blog:
![edição-de-blogs](../../images/cmskit-module-blogs-edit.png)
**Slug** é a parte da URL do blog. Para este exemplo, a URL raiz do blog se torna `seu-domínio.com/blogs/blog-técnico/`.
- Você pode alterar o slug padrão usando a constante `CmsBlogsWebConsts.BlogRoutePrefix`. Por exemplo, se você definir como `foo`, a URL raiz do blog se torna `seu-domínio.com/foo/blog-técnico/`.
```csharp
public override void PreConfigureServices(ServiceConfigurationContext context)
{
CmsBlogsWebConsts.BlogsRoutePrefix = "foo";
}
```
#### Funcionalidades do blog
A funcionalidade de blog usa algumas das outras funcionalidades do Kit CMS. Você pode habilitar ou desabilitar as funcionalidades clicando na ação de funcionalidades para um blog.
![ação-de-funcionalidades-de-blogs](../../images/cmskit-module-blogs-feature-action.png)
Você pode selecionar/deselecionar as funcionalidades desejadas para as postagens de blog.
![diálogo-de-funcionalidades](../../images/cmskit-module-features-dialog-2.png)
##### Barra de navegação rápida na postagem de blog
Se você habilitar "Barra de navegação rápida nas postagens de blog", será habilitado o índice de rolagem conforme mostrado abaixo.
![índice-de-rolagem](../../images/cmskit-module-features-scroll-index.png)
### Gerenciamento de postagens de blog
Ao criar blogs, você pode gerenciar as postagens de blog nesta página.
![página-de-postagens-de-blog](../../images/cmskit-module-blog-posts-page.png)
Você pode criar e editar uma postagem de blog existente nesta página. Se você habilitar funcionalidades específicas, como tags, poderá definir tags para a postagem de blog nesta página.
![edição-de-postagem-de-blog](../../images/cmskit-module-blog-post-edit.png)
## Internos
### Camada de domínio
#### Agregados
Este módulo segue o guia de [Melhores Práticas e Convenções de Entidades](https://docs.abp.io/en/abp/latest/Best-Practices/Entities).
- `Blog` _(raiz do agregado)_: Apresenta blogs da aplicação.
- `BlogPost` _(raiz do agregado)_: Apresenta postagens de blog nos blogs.
- `BlogFeature` _(raiz do agregado)_: Apresenta o estado de habilitação/desabilitação das funcionalidades do blog, como reações, avaliações, comentários, etc.
#### Repositórios
Este módulo segue o guia de [Melhores Práticas e Convenções de Repositórios](https://docs.abp.io/en/abp/latest/Best-Practices/Repositories). Os seguintes repositórios são definidos para esta funcionalidade:
- `IBlogRepository`
- `IBlogPostRepository`
- `IBlogFeatureRepository`
#### Serviços de domínio
Este módulo segue o guia de [Melhores Práticas e Convenções de Serviços de Domínio](https://docs.abp.io/en/abp/latest/Best-Practices/Domain-Services).
- `BlogManager`
- `BlogPostManager`
- `BlogFeatureManager`
### Camada de aplicação
#### Serviços de aplicação
##### Comum
- `BlogFeatureAppService` _(implementa `IBlogFeatureAppService`)_
##### Administração
- `BlogAdminAppService` _(implementa `IBlogAdminAppService`)_
- `BlogFeatureAdminAppService` _(implementa `IBlogFeatureAdminAppService`)_
- `BlogPostAdminAppService` _(implementa `IBlogPostAdminAppService`)_
##### Público
- `BlogPostPublicAppService` _(implementa `IBlogPostPublicAppService`)_
### Provedores de banco de dados
#### Entity Framework Core
##### Tabelas
- CmsBlogs
- CmsBlogPosts
- CmsBlogFeatures
#### MongoDB
##### Coleções
- CmsBlogs
- CmsBlogPosts
- CmsBlogFeatures
## Extensões de entidade
Verifique a seção "Extensões de Entidade" da documentação do módulo Kit CMS (Index.md#entity-extensions) para saber como estender as entidades da funcionalidade de Blogging do módulo Kit CMS.

144
docs/pt-BR/Modules/Cms-Kit/Comments.md

@ -0,0 +1,144 @@
# Kit CMS: Comentários
O Kit CMS fornece um sistema de **comentários** para adicionar a funcionalidade de comentários a qualquer tipo de recurso, como postagens de blog, produtos, etc.
## Habilitando a funcionalidade de comentários
Por padrão, as funcionalidades do Kit CMS estão desabilitadas. Portanto, você precisa habilitar as funcionalidades desejadas antes de começar a usá-lo. Você pode usar o sistema de [Funcionalidades Globais](../../Global-Features.md) para habilitar/desabilitar as funcionalidades do Kit CMS durante o desenvolvimento. Alternativamente, você pode usar o [Sistema de Funcionalidades](https://docs.abp.io/pt-BR/abp/latest/Features) do ABP Framework para desabilitar uma funcionalidade do Kit CMS em tempo de execução.
> Verifique a seção ["Como instalar" da documentação do módulo Kit CMS](Index.md#como-instalar) para saber como habilitar/desabilitar as funcionalidades do Kit CMS durante o desenvolvimento.
## Opções
O sistema de comentários fornece um mecanismo para agrupar definições de comentários por tipos de entidade. Por exemplo, se você deseja usar o sistema de comentários para postagens de blog e produtos, você precisa definir dois tipos de entidade chamados `BlogPosts` e `Product` e adicionar comentários sob esses tipos de entidade.
`CmsKitCommentOptions` pode ser configurado na camada de domínio, no método `ConfigureServices` do seu [módulo](https://docs.abp.io/pt-BR/abp/latest/Module-Development-Basics). Exemplo:
```csharp
Configure<CmsKitCommentOptions>(options =>
{
options.EntityTypes.Add(new CommentEntityTypeDefinition("Product"));
options.IsRecaptchaEnabled = true; //false por padrão
options.AllowedExternalUrls = new Dictionary<string, List<string>>
{
{
"Product",
new List<string>
{
"https://abp.io/"
}
}
};
});
```
> Se você estiver usando a [Funcionalidade de Blog](Blogging.md), o ABP Framework define automaticamente um tipo de entidade para a funcionalidade de blog. Você pode facilmente substituir ou remover os tipos de entidade predefinidos no método `Configure` como mostrado acima.
Propriedades de `CmsKitCommentOptions`:
- `EntityTypes`: Lista de tipos de entidade (`CmsKitCommentOptions`) definidos no sistema de comentários.
- `IsRecaptchaEnabled`: Esta flag habilita ou desabilita o reCaptcha para o sistema de comentários. Você pode defini-la como **true** se quiser usar o reCaptcha em seu sistema de comentários.
- `AllowedExternalUrls`: Indica as URLs externas permitidas por tipos de entidade, que podem ser incluídas em um comentário. Se for especificado para um determinado tipo de entidade, apenas as URLs externas especificadas serão permitidas nos comentários.
Propriedades de `CommentEntityTypeDefinition`:
- `EntityType`: Nome do tipo de entidade.
## O Widget de Comentários
O sistema de comentários fornece um [widget](../../UI/AspNetCore/Widgets.md) de comentários para permitir que os usuários enviem comentários para recursos em sites públicos. Você pode simplesmente colocar o widget em uma página como abaixo.
```csharp
@await Component.InvokeAsync(typeof(CommentingViewComponent), new
{
entityType = "Product",
entityId = "...",
isReadOnly = false,
referralLinks = new [] {"nofollow"}
})
```
`entityType` foi explicado na seção anterior. `entityId` deve ser o id único do produto, neste exemplo. Se você tiver uma entidade Produto, você pode usar seu Id aqui. `referralLinks` é um parâmetro opcional. Você pode usar este parâmetro para adicionar valores (como "nofollow", "noreferrer" ou qualquer outro valor) aos atributos [rel](https://developer.mozilla.org/pt-BR/docs/Web/HTML/Attributes/rel) dos links.
## Interface do Usuário
### Itens de Menu
Os seguintes itens de menu são adicionados pela funcionalidade de comentários à aplicação de administração:
* **Comentários**: Abre a página de gerenciamento de comentários.
### Páginas
#### Gerenciamento de Comentários
Você pode visualizar e gerenciar comentários nesta página.
![comment-page](../../images/cmskit-module-comment-page.png)
Você também pode visualizar e gerenciar respostas nesta página.
![comments-detail](../../images/cmskit-module-comments-detail.png)
## Internos
### Camada de Domínio
#### Agregados
Este módulo segue o guia de [Melhores Práticas e Convenções de Entidades](https://docs.abp.io/pt-BR/abp/latest/Best-Practices/Entities).
##### Comentário
Um comentário representa um comentário escrito por um usuário.
- `Comment` (raiz do agregado): Representa um comentário escrito no sistema.
#### Repositórios
Este módulo segue o guia de [Melhores Práticas e Convenções de Repositórios](https://docs.abp.io/pt-BR/abp/latest/Best-Practices/Repositories).
Os seguintes repositórios personalizados são definidos para esta funcionalidade:
- `ICommentRepository`
#### Serviços de Domínio
Este módulo segue o guia de [Melhores Práticas e Convenções de Serviços de Domínio](https://docs.abp.io/pt-BR/abp/latest/Best-Practices/Domain-Services).
##### Gerenciador de Comentários
`CommentManager` é usado para realizar algumas operações para a raiz do agregado `Comment`.
### Camada de Aplicação
#### Serviços de Aplicação
- `CommentAdminAppService` (implementa `ICommentAdminAppService`): Implementa os casos de uso do sistema de gerenciamento de comentários, como listar ou remover comentários, etc.
- `CommentPublicAppService` (implementa `ICommentPublicAppService`): Implementa os casos de uso do sistema de gerenciamento de comentários em sites públicos, como listar comentários, adicionar comentários, etc.
### Provedores de Banco de Dados
#### Comum
##### Prefixo de tabela / coleção e esquema
Todas as tabelas/coleções usam o prefixo `Cms` por padrão. Defina propriedades estáticas na classe `CmsKitDbProperties` se você precisar alterar o prefixo da tabela ou definir um nome de esquema (se suportado pelo seu provedor de banco de dados).
##### String de conexão
Este módulo usa `CmsKit` como nome da string de conexão. Se você não definir uma string de conexão com esse nome, ela será usada a string de conexão `Default`.
Consulte a documentação de [strings de conexão](https://docs.abp.io/pt-BR/abp/latest/Connection-Strings) para obter detalhes.
#### Entity Framework Core
##### Tabelas
- CmsComments
#### MongoDB
##### Coleções
- **CmsComments**

137
docs/pt-BR/Modules/Cms-Kit/Dynamic-Widget.md

@ -0,0 +1,137 @@
# Widget Dinâmico
O kit CMS fornece um [widget](https://docs.abp.io/en/abp/latest/UI/AspNetCore/Widgets) dinâmico usado para renderizar os componentes previamente desenvolvidos pelo software no conteúdo das páginas e postagens de blog. Isso significa que você pode usar conteúdo dinâmico em conteúdo estático. Vamos mencionar como você pode fazer isso. Você tem duas opções para definir o widget no sistema: escrevendo e usando a interface do usuário.
### Adicionando o widget
Primeiramente, mostraremos como usar o sistema de widgets escrevendo manualmente no conteúdo das páginas e postagens de blog.
Vamos definir o componente de visualização
```csharp
[Widget]
[ViewComponent(Name = "CmsToday")]
public class TodayViewComponent : AbpViewComponent
{
public IViewComponentResult Invoke()
{
return View("~/ViewComponents/Today.cshtml",
new TodayViewComponent());
}
}
```
```html
@model Volo.CmsKit.ViewComponents.TodayViewComponent
<p>Bem-vindo ao componente de hoje</p>
<p>@DateTime.Now.ToString()</p>
```
Agora é hora de configurar no arquivo YourModule.cs
```csharp
Configure<CmsKitContentWidgetOptions>(options =>
{
options.AddWidget("Today","CmsToday");
});
```
Agora você está pronto para adicionar seu widget escrevendo.
[Widget Type="Today"]
Após concluir as etapas acima, você pode ver a saída à direita da captura de tela abaixo.
![cmskit-without-parameter.png](../../images/cmskit-without-parameter.png)
### Adicionando usando a interface do usuário
Agora mencionaremos a segunda opção, usando a interface do usuário.
Uma vez que escrever essas definições pode resultar em alguns erros, adicionamos um novo recurso para usar o sistema de widgets facilmente. À direita do editor, você verá o botão `W` personalizado para adicionar um widget dinâmico, como na imagem abaixo. Não se esqueça, por favor, que este é o modo de design e você precisa visualizar sua página no modo de visualização após salvar. Além disso, a guia `Preview` no editor estará pronta para verificar sua saída facilmente para configurações de widget nos recursos seguintes.
![cms-kit-page-editor](../../images/cms-kit-page-editor.png)
### Adicionando usando a interface do usuário com parâmetros
Vamos melhorar o exemplo acima adicionando um novo parâmetro chamado formato. Com esse recurso, podemos usar o sistema de widgets com muitos cenários diferentes, mas sem prolongar o documento. Além disso, esses exemplos podem ser expandidos com injeção de dependência e obtenção de valores do banco de dados, mas usaremos um exemplo básico. Vamos adicionar o parâmetro de formato para personalizar a data.
```csharp
[Widget]
[ViewComponent(Name = "CmsToday")]
public class TodayViewComponent : AbpViewComponent
{
public string Format { get; set; }
public IViewComponentResult Invoke(string format)
{
return View("~/ViewComponents/Today.cshtml",
new TodayViewComponent() { Format = format });
}
}
```
```html
@model Volo.CmsKit.ViewComponents.TodayViewComponent
<p>Bem-vindo ao componente de hoje</p>
<p>@DateTime.Now.ToString(Format)</p>
```
Vamos definir o componente de formato.
```csharp
[Widget]
[ViewComponent(Name = "Format")]
public class FormatViewComponent : AbpViewComponent
{
public IViewComponentResult Invoke()
{
return View("~/ViewComponents/Format.cshtml",
new FormatViewModel());
}
}
public class FormatViewModel
{
[DisplayName("Formate sua data no componente")]
public string Format { get; set; }
}
```
> Nota importante: Para obter as propriedades corretamente, você deve definir a propriedade `name` na página razor ou pode usar o componente ABP. O ABP lida com isso automaticamente.
```html
@using Volo.CmsKit.ViewComponents
@model FormatViewModel
<div>
<abp-input asp-for="Format" />
</div>
```
```csharp
Configure<CmsKitContentWidgetOptions>(options =>
{
options.AddWidget("Today", "CmsToday", "Format");
});
```
![cmskit-module-editor-parameter](../../images/cmskit-module-editor-parameter.png)
Nesta imagem, após escolher seu widget (em outro caso, ele muda automaticamente de acordo com sua configuração, o meu é `Today`. Seu nome de parâmetro é `parameterWidgetName` e seu valor é `Format`) você verá o próximo widget. Insira valores de entrada ou escolha-os e clique em `Add`. Você verá a saída sublinhada no editor. À direita da imagem, você também pode ver sua saída pré-visualizada.
Você pode editar essa saída manualmente se fizer algum código errado para isso (valor incorreto ou erro de digitação), você não verá o widget, mesmo assim, sua página será visualizada com sucesso.
## Opções
Para configurar o widget, você deve definir o código abaixo no arquivo YourModule.cs
```csharp
Configure<CmsKitContentWidgetOptions>(options =>
{
options.AddWidget(widgetType: "Today", widgetName: "CmsToday", parameterWidgetName: "Format");
});
```
Vamos analisar esses parâmetros em detalhes
* `widgetType` é usado para o usuário final e nomes mais legíveis. A palavra em negrito a seguir representa o widgetType.
[Widget Type="**Today**" Format="yyyy-dd-mm HH:mm:ss"].
* `widgetName` é usado para o nome do seu widget usado no código para o nome do `ViewComponent`.
* `parameterWidgetName` é usado no lado do componente do editor para ver no modal `Add Widget`.
Após escolher o tipo de widget na lista suspensa (agora apenas definido `Format`) e renderizar este widget automaticamente. É necessário apenas para ver a interface do usuário uma vez usando parâmetros.

72
docs/pt-BR/Modules/Cms-Kit/Global-Resources.md

@ -0,0 +1,72 @@
# CMS Kit: Recursos Globais
O sistema de Recursos Globais do CMS Kit permite adicionar estilos e scripts globais dinamicamente.
## Habilitando o Recurso de Recursos Globais
Por padrão, os recursos do CMS Kit estão desabilitados. Portanto, você precisa habilitar os recursos que deseja antes de começar a usá-lo. Você pode usar o sistema de [Recursos Globais](../../Global-Features.md) para habilitar/desabilitar os recursos do CMS Kit durante o desenvolvimento. Alternativamente, você pode usar o [Sistema de Recursos](https://docs.abp.io/en/abp/latest/Features) do ABP Framework para desabilitar um recurso do CMS Kit em tempo de execução.
> Verifique a seção "Como Instalar" da documentação do Módulo CMS Kit para saber como habilitar/desabilitar os recursos do CMS Kit durante o desenvolvimento.
## A Interface do Usuário
### Itens do Menu
O módulo CMS Kit adiciona os seguintes itens ao menu principal, sob o item de menu *Recursos Globais*:
* **Recursos Globais**: Página de gerenciamento de recursos globais.
A classe `CmsKitAdminMenus` possui as constantes para os nomes dos itens do menu.
### Página de Recursos Globais
A página de Recursos Globais é usada para gerenciar estilos e scripts globais no sistema.
![cms-kit-global-resources-page](../../images/cmskit-module-global-resources-page.png)
# Internos
## Camada de Domínio
#### Agregados
Este módulo segue o guia de [Melhores Práticas e Convenções de Entidades](https://docs.abp.io/en/abp/latest/Best-Practices/Entities).
- `GlobalResource` (raiz do agregado): Armazena um recurso.
#### Repositórios
Este módulo segue o guia de [Melhores Práticas e Convenções de Repositórios](https://docs.abp.io/en/abp/latest/Best-Practices/Repositories).
Os seguintes repositórios personalizados são definidos para este recurso:
- `IGlobalResourceRepository`
#### Serviços de Domínio
Este módulo segue o guia de [Melhores Práticas e Convenções de Serviços de Domínio](https://docs.abp.io/en/abp/latest/Best-Practices/Domain-Services).
##### Gerenciador de Recursos Globais
`GlobalResourceManager` é usado para realizar operações para a raiz do agregado `GlobalResource`.
### Camada de Aplicação
#### Serviços de Aplicação
- `GlobalResourceAdminAppService` (implementa `IGlobalResourceAdminAppService`): Implementa as operações de gerenciamento do sistema de recursos globais.
- `GlobalResourcePublicAppService` (implementa `IGlobalResourcePublicAppService`): Implementa os casos de uso públicos do sistema de recursos globais.
#### Banco de Dados
#### Entity Framework Core
##### Tabelas
- CmsGlobalResources
#### MongoDB
##### Coleções
- CmsGlobalResources

143
docs/pt-BR/Modules/Cms-Kit/Index.md

@ -0,0 +1,143 @@
# Módulo CMS Kit
Este módulo fornece recursos de CMS (Sistema de Gerenciamento de Conteúdo) para sua aplicação. Ele fornece **blocos de construção principais** e **sub-sistemas** totalmente funcionais para criar seu próprio site com recursos de CMS habilitados, ou usar os blocos de construção em seus sites com qualquer finalidade.
> **Este módulo está atualmente disponível apenas para a interface MVC / Razor Pages**. Embora não haja um pacote oficial do Blazor, ele também pode funcionar em uma interface Blazor Server, pois uma interface Blazor Server é na verdade um aplicativo híbrido que é executado em um aplicativo ASP.NET Core MVC / Razor Pages.
Os seguintes recursos estão atualmente disponíveis:
* Fornece um sistema de gerenciamento de [**páginas**](Pages.md) para gerenciar páginas dinâmicas com URLs dinâmicos.
* Fornece um sistema de [**blog**](Blogging.md) para criar e publicar postagens de blog com suporte a vários blogs.
* Fornece um sistema de [**marcação**](Tags.md) para marcar qualquer tipo de recurso, como uma postagem de blog.
* Fornece um sistema de [**comentários**](Comments.md) para adicionar recursos de comentários a qualquer tipo de recurso, como postagem de blog ou uma página de avaliação de produto.
* Fornece um sistema de [**reações**](Reactions.md) para adicionar recursos de reações (emojis) a qualquer tipo de recurso, como uma postagem de blog ou um comentário.
* Fornece um sistema de [**classificação**](Ratings.md) para adicionar recursos de classificação a qualquer tipo de recurso.
* Fornece um sistema de [**menu**](Menus.md) para gerenciar menus públicos dinamicamente.
* Fornece um sistema de [**recursos globais**](Global-Resources.md) para adicionar estilos e scripts globais dinamicamente.
* Fornece um sistema de [**widget dinâmico**](Dynamic-Widget.md) para criar widgets dinâmicos para páginas e postagens de blog.
> Você pode clicar nos links de recursos acima para entender e aprender como usá-los.
Todos os recursos podem ser usados individualmente. Se você desabilitar um recurso, ele desaparecerá completamente de sua aplicação, inclusive das tabelas do banco de dados, com a ajuda do sistema [Recursos Globais](../../Global-Features.md).
## Pré-requisitos
- Este módulo depende do módulo [BlobStoring](../../Blob-Storing.md) para armazenar conteúdo de mídia.
> Certifique-se de que o módulo `BlobStoring` esteja instalado e que pelo menos um provedor esteja configurado corretamente. Para obter mais informações, consulte a [documentação](../../Blob-Storing.md).
- O CMS Kit usa o [cache distribuído](../../Caching.md) para responder mais rapidamente.
> É altamente recomendado usar um cache distribuído, como o [Redis](../../Redis-Cache.md), para garantir a consistência dos dados em implantações distribuídas/clusterizadas.
## Como instalar
O [ABP CLI](../../CLI.md) permite instalar um módulo em uma solução usando o comando `add-module`. Você pode instalar o módulo CMS Kit em um terminal de linha de comando com o seguinte comando:
```bash
abp add-module Volo.CmsKit --skip-db-migrations
```
> Por padrão, o Cms-Kit está desabilitado pelo `GlobalFeature`. Por causa disso, a migração inicial estará vazia. Portanto, você pode pular a migração adicionando `--skip-db-migrations` ao comando de instalação se estiver usando o Entity Framework Core. Após habilitar o recurso global Cms-Kit, adicione uma nova migração.
Após o processo de instalação, abra a classe `GlobalFeatureConfigurator` no projeto `Domain.Shared` de sua solução e coloque o seguinte código no método `Configure` para habilitar todos os recursos no módulo CMS Kit.
```csharp
GlobalFeatureManager.Instance.Modules.CmsKit(cmsKit =>
{
cmsKit.EnableAll();
});
```
Em vez de habilitar todos, você pode preferir habilitar os recursos um por um. O exemplo a seguir habilita apenas os recursos de [marcadores](Tags.md) e [comentários](Comments.md):
````csharp
GlobalFeatureManager.Instance.Modules.CmsKit(cmsKit =>
{
cmsKit.Tags.Enable();
cmsKit.Comments.Enable();
});
````
> Se você estiver usando o Entity Framework Core, não se esqueça de adicionar uma nova migração e atualizar seu banco de dados.
## Os Pacotes
Este módulo segue o [guia de melhores práticas para desenvolvimento de módulos](https://docs.abp.io/en/abp/latest/Best-Practices/Index) e consiste em vários pacotes NuGet e NPM. Consulte o guia se você quiser entender os pacotes e as relações entre eles.
Os pacotes do CMS kit são projetados para vários cenários de uso. Se você verificar os [pacotes do CMS kit](https://www.nuget.org/packages?q=Volo.CmsKit), verá que alguns pacotes têm sufixos `Admin` e `Public`. A razão é que o módulo possui duas camadas de aplicação, considerando que eles podem ser usados em diferentes tipos de aplicativos. Essas camadas de aplicação usam uma única camada de domínio:
- Os pacotes `Volo.CmsKit.Admin.*` contêm as funcionalidades necessárias para aplicativos de administração (back office).
- Os pacotes `Volo.CmsKit.Public.*` contêm as funcionalidades usadas em sites públicos onde os usuários leem postagens de blog ou deixam comentários.
- Os pacotes `Volo.CmsKit.*` (sem sufixo Admin/Public) são chamados de pacotes unificados. Os pacotes unificados são atalhos para adicionar pacotes Admin e Public (da camada relacionada) separadamente. Se você tiver um único aplicativo para administração e site público, você pode usar esses pacotes.
## Internos
### Prefixo de tabela / coleção e esquema
Todas as tabelas/coleções usam o prefixo `Cms` por padrão. Defina propriedades estáticas na classe `CmsKitDbProperties` se você precisar alterar o prefixo da tabela ou definir um nome de esquema (se suportado pelo provedor de banco de dados).
### String de conexão
Este módulo usa `CmsKit` como nome da string de conexão. Se você não definir uma string de conexão com esse nome, ela será substituída pela string de conexão `Default`.
Consulte a documentação sobre [strings de conexão](https://docs.abp.io/en/abp/latest/Connection-Strings) para obter mais detalhes.
## Extensões de Entidade
O sistema de extensão de entidade do módulo (https://docs.abp.io/en/abp/latest/Module-Entity-Extensions) é um sistema de extensão **de alto nível** que permite **definir novas propriedades** para entidades existentes dos módulos dependentes. Ele automaticamente **adiciona propriedades à entidade**, **banco de dados**, **API HTTP** e **interface do usuário** em um único ponto.
Para estender as entidades do módulo CMS Kit, abra a classe `YourProjectNameModuleExtensionConfigurator` dentro do projeto `DomainShared` e altere o método `ConfigureExtraProperties` conforme mostrado abaixo.
```csharp
public static void ConfigureExtraProperties()
{
OneTimeRunner.Run(() =>
{
ObjectExtensionManager.Instance.Modules()
.ConfigureCmsKit(cmsKit =>
{
cmsKit.ConfigureBlog(plan => // estende a entidade Blog
{
plan.AddOrUpdateProperty<string>( //tipo de propriedade: string
"BlogDescription", //nome da propriedade
property => {
//regras de validação
property.Attributes.Add(new RequiredAttribute()); //adiciona o atributo obrigatório à propriedade definida
//...outras configurações para esta propriedade
}
);
});
cmsKit.ConfigureBlogPost(blogPost => // estende a entidade BlogPost
{
blogPost.AddOrUpdateProperty<string>( //tipo de propriedade: string
"BlogPostDescription", //nome da propriedade
property => {
//regras de validação
property.Attributes.Add(new RequiredAttribute()); //adiciona o atributo obrigatório à propriedade definida
property.Attributes.Add(
new StringLengthAttribute(MyConsts.MaximumDescriptionLength) {
MinimumLength = MyConsts.MinimumDescriptionLength
}
);
//...outras configurações para esta propriedade
}
);
});
});
});
}
```
* O método `ConfigureCmsKit(...)` é usado para configurar as entidades do módulo CMS Kit.
* `cmsKit.ConfigureBlog(...)` é usado para configurar a entidade **Blog** do módulo CMS Kit. Você pode adicionar ou atualizar suas propriedades extras na entidade **Blog**.
* `cmsKit.ConfigureBlogPost(...)` é usado para configurar a entidade **BlogPost** do módulo CMS Kit. Você pode adicionar ou atualizar suas propriedades extras na entidade **BlogPost**.
* Você também pode definir algumas regras de validação para a propriedade que você definiu. No exemplo acima, foram adicionados `RequiredAttribute` e `StringLengthAttribute` para a propriedade chamada **"BlogPostDescription"**.
* Quando você define a nova propriedade, ela será automaticamente adicionada à **Entidade**, **API HTTP** e **UI** para você.
* Depois de definir uma propriedade, ela aparece nos formulários de criação e atualização da entidade relacionada.
* As novas propriedades também aparecem na tabela de dados da página relacionada.

90
docs/pt-BR/Modules/Cms-Kit/Menus.md

@ -0,0 +1,90 @@
# CMS Kit: Menus
O sistema de menus do CMS Kit permite gerenciar menus públicos de forma dinâmica.
## Habilitando o recurso de menu
Por padrão, os recursos do CMS Kit estão desabilitados. Portanto, é necessário habilitar os recursos desejados antes de começar a usá-lo. Você pode usar o sistema de [Recursos Globais](../../Global-Features.md) para habilitar/desabilitar os recursos do CMS Kit durante o desenvolvimento. Alternativamente, você pode usar o [Sistema de Recursos](https://docs.abp.io/en/abp/latest/Features) do ABP Framework para desabilitar um recurso do CMS Kit em tempo de execução.
> Verifique a seção "Como instalar" da documentação do módulo CMS Kit (Index.md#how-to-install) para saber como habilitar/desabilitar os recursos do CMS Kit durante o desenvolvimento.
## A interface do usuário
### Itens de menu
O módulo CMS Kit adiciona os seguintes itens ao menu principal, sob o item de menu *CMS*:
* **Menus**: Página de gerenciamento de menus.
A classe `CmsKitAdminMenus` possui as constantes para os nomes dos itens de menu.
### Menus
#### Gerenciamento de menus
A página de menus é usada para gerenciar menus públicos dinâmicos no sistema.
![cms-kit-menus-page](../../images/cmskit-module-menus-page.png)
Os itens de menu criados serão visíveis no lado público do site, como mostrado abaixo:
![cms-kit-public-menus](../../images//cmskit-module-menus-public.png)
## Internos
### Camada de domínio
#### Agregados
Este módulo segue o guia de [Melhores Práticas e Convenções de Entidades](https://docs.abp.io/en/abp/latest/Best-Practices/Entities).
- `MenuItem` (raiz do agregado): Um item de menu representa um único nó na árvore de menus.
#### Repositórios
Este módulo segue o guia de [Melhores Práticas e Convenções de Repositórios](https://docs.abp.io/en/abp/latest/Best-Practices/Repositories).
Os seguintes repositórios personalizados são definidos para este recurso:
- `IMenuItemRepository`
#### Serviços de domínio
Este módulo segue o guia de [Melhores Práticas e Convenções de Serviços de Domínio](https://docs.abp.io/en/abp/latest/Best-Practices/Domain-Services).
##### Gerenciador de itens de menu
`MenuItemManager` é usado para realizar algumas operações para a raiz do agregado `MenuItemManager`.
### Camada de aplicação
#### Serviços de aplicação
- `MenuItemAdminAppService` (implementa `IMenuItemAdminAppService`): Implementa as operações de gerenciamento do sistema de menus.
- `MenuItemPublicAppService` (implementa `IMenuItemPublicAppService`): Implementa os casos de uso públicos do sistema de menus.
### Provedores de banco de dados
#### Comum
##### Prefixo de tabela / coleção e esquema
Todas as tabelas/coleções usam o prefixo `Cms` por padrão. Defina propriedades estáticas na classe `CmsKitDbProperties` se você precisar alterar o prefixo da tabela ou definir um nome de esquema (se suportado pelo seu provedor de banco de dados).
##### String de conexão
Este módulo usa `CmsKit` como nome da string de conexão. Se você não definir uma string de conexão com esse nome, ela será substituída pela string de conexão `Default`.
Consulte a documentação sobre [strings de conexão](https://docs.abp.io/en/abp/latest/Connection-Strings) para obter mais detalhes.
#### Entity Framework Core
##### Tabelas
- CmsMenuItems
#### MongoDB
##### Coleções
- CmsMenuItems

33
docs/pt-BR/Modules/Cms-Kit/Pages.md

@ -0,0 +1,33 @@
# Kit CMS: Páginas
O sistema de páginas do Kit CMS permite que você crie páginas dinâmicas especificando URLs, que é a funcionalidade fundamental de um CMS.
## Habilitando a Funcionalidade de Páginas
Por padrão, as funcionalidades do Kit CMS estão desabilitadas. Portanto, você precisa habilitar as funcionalidades que deseja antes de começar a usá-lo. Você pode usar o sistema de [Funcionalidades Globais](../../Global-Features.md) para habilitar/desabilitar as funcionalidades do Kit CMS durante o desenvolvimento. Alternativamente, você pode usar o [Sistema de Funcionalidades](https://docs.abp.io/en/abp/latest/Features) do ABP Framework para desabilitar uma funcionalidade do Kit CMS em tempo de execução.
> Verifique a seção "Como Instalar" da documentação do Módulo Kit CMS (Index.md#how-to-install) para saber como habilitar/desabilitar as funcionalidades do Kit CMS durante o desenvolvimento.
## A Interface do Usuário
### Itens do Menu
O módulo Kit CMS adiciona os seguintes itens ao menu principal, sob o item de menu *CMS*:
* **Páginas**: Página de gerenciamento de páginas.
A classe `CmsKitAdminMenus` possui as constantes para os nomes dos itens do menu.
### Páginas
#### Gerenciamento de Páginas
A página **Páginas** é usada para gerenciar páginas dinâmicas no sistema. Você pode criar/editar páginas com rotas e conteúdos dinâmicos nesta página:
![pages-edit](../../images/cmskit-module-pages-edit.png)
Depois de criar páginas, você pode definir uma delas como página inicial. Então, sempre que alguém navegar para a página inicial do seu aplicativo, eles verão o conteúdo dinâmico da página que você definiu nesta página.
![pages-page](../../images/cmskit-module-pages-page.png)
Além disso, quando você cria uma página, você pode acessá-la através da URL `/{slug}`.

111
docs/pt-BR/Modules/Cms-Kit/Ratings.md

@ -0,0 +1,111 @@
# Sistema de Avaliação
O kit CMS fornece um sistema de **avaliação** para adicionar recursos de avaliação a qualquer tipo de recurso, como postagens de blog, comentários, etc. Aqui está como o componente de avaliação se parece em uma página de exemplo:
![avaliações](../../images/cmskit-module-ratings.png)
## Habilitando o Recurso de Avaliação
Por padrão, os recursos do CMS Kit estão desabilitados. Portanto, você precisa habilitar os recursos que deseja antes de começar a usá-lo. Você pode usar o sistema de [Recurso Global](../../Global-Features.md) para habilitar/desabilitar os recursos do CMS Kit durante o desenvolvimento. Alternativamente, você pode usar o [Sistema de Recursos](https://docs.abp.io/en/abp/latest/Features) do ABP Framework para desabilitar um recurso do CMS Kit em tempo de execução.
> Verifique a seção ["Como Instalar" da documentação do Módulo CMS Kit](Index.md#how-to-install) para ver como habilitar/desabilitar os recursos do CMS Kit durante o desenvolvimento.
## Opções
O sistema de avaliação fornece um mecanismo para agrupar avaliações por tipos de entidade. Por exemplo, se você deseja usar o sistema de avaliação para produtos, você precisa definir um tipo de entidade chamado `Produto` e, em seguida, adicionar avaliações sob o tipo de entidade definido.
`CmsKitRatingOptions` pode ser configurado na camada de domínio, no método `ConfigureServices` do seu [módulo](https://docs.abp.io/en/abp/latest/Module-Development-Basics). Exemplo:
```csharp
Configure<CmsKitRatingOptions>(options =>
{
options.EntityTypes.Add(new RatingEntityTypeDefinition("Produto"));
});
```
> Se você estiver usando o [Recurso de Blog](Blogging.md), o framework ABP define automaticamente um tipo de entidade para o recurso de blog. Você pode facilmente substituir ou remover os tipos de entidade predefinidos no método `Configure` como mostrado acima.
Propriedades de `CmsKitRatingOptions`:
- `EntityTypes`: Lista de tipos de entidade definidos (`RatingEntityTypeDefinition`) no sistema de avaliação.
Propriedades de `RatingEntityTypeDefinition`:
- `EntityType`: Nome do tipo de entidade.
## O Widget de Avaliação
O sistema de avaliação fornece um widget de avaliação para permitir que os usuários enviem avaliações para recursos em sites públicos. Você pode simplesmente colocar o widget em uma página como abaixo.
```csharp
@await Component.InvokeAsync(typeof(RatingViewComponent), new
{
entityType = "Produto",
entityId = "entityId",
isReadOnly = false
})
```
`entityType` foi explicado na seção anterior. `entityId` deve ser o id único do produto, neste exemplo. Se você tiver uma entidade Produto, você pode usar seu Id aqui.
# Internos
## Camada de Domínio
#### Agregados
Este módulo segue o guia de [Melhores Práticas e Convenções de Entidades](https://docs.abp.io/en/abp/latest/Best-Practices/Entities).
##### Avaliação
Uma avaliação representa uma avaliação dada por um usuário.
- `Avaliação` (raiz do agregado): Representa uma avaliação dada no sistema.
#### Repositórios
Este módulo segue o guia de [Melhores Práticas e Convenções de Repositórios](https://docs.abp.io/en/abp/latest/Best-Practices/Repositories).
Os seguintes repositórios personalizados são definidos para este recurso:
- `IRatingRepository`
#### Serviços de Domínio
Este módulo segue o guia de [Melhores Práticas e Convenções de Serviços de Domínio](https://docs.abp.io/en/abp/latest/Best-Practices/Domain-Services).
##### Gerenciador de Reações
`RatingManager` é usado para realizar algumas operações para a raiz do agregado `Avaliação`.
### Camada de Aplicação
#### Serviços de Aplicação
- `RatingPublicAppService` (implementa `IRatingPublicAppService`): Implementa os casos de uso do sistema de avaliação.
### Provedores de Banco de Dados
#### Comum
##### Prefixo da tabela / coleção e esquema
Todas as tabelas/coleções usam o prefixo `Cms` por padrão. Defina propriedades estáticas na classe `CmsKitDbProperties` se você precisar alterar o prefixo da tabela ou definir um nome de esquema (se suportado pelo seu provedor de banco de dados).
##### String de conexão
Este módulo usa `CmsKit` como nome da string de conexão. Se você não definir uma string de conexão com esse nome, ela será usada a string de conexão `Default`.
Consulte a documentação de [strings de conexão](https://docs.abp.io/en/abp/latest/Connection-Strings) para obter detalhes.
#### Entity Framework Core
##### Tabelas
- CmsRatings
#### MongoDB
##### Coleções
- **CmsRatings**

126
docs/pt-BR/Modules/Cms-Kit/Reactions.md

@ -0,0 +1,126 @@
# Sistema de Reações
O kit CMS fornece um sistema de **reações** para adicionar recursos de reações a qualquer tipo de recurso, como postagens de blog ou comentários.
O componente de reação permite que os usuários reajam ao seu conteúdo por meio de ícones/emojis pré-definidos. Aqui está como o componente de reações pode parecer:
![reactions](../../images/cmskit-module-reactions.png)
Você também pode personalizar os ícones de reação mostrados no componente de reação.
## Habilitando o Recurso de Reação
Por padrão, os recursos do CMS Kit estão desabilitados. Portanto, você precisa habilitar os recursos que deseja antes de começar a usá-lo. Você pode usar o sistema de [Recurso Global](../../Global-Features.md) para habilitar/desabilitar recursos do CMS Kit durante o desenvolvimento. Alternativamente, você pode usar o [Sistema de Recursos](https://docs.abp.io/en/abp/latest/Features) do ABP Framework para desabilitar um recurso do CMS Kit em tempo de execução.
> Verifique a seção ["Como Instalar" da documentação do Módulo CMS Kit](Index.md#how-to-install) para ver como habilitar/desabilitar recursos do CMS Kit durante o desenvolvimento.
## Opções
O sistema de reação fornece um mecanismo para agrupar reações por tipos de entidade. Por exemplo, se você deseja usar o sistema de reação para produtos, você precisa definir um tipo de entidade chamado `Produto` e, em seguida, adicionar reações sob o tipo de entidade definido.
`CmsKitReactionOptions` pode ser configurado na camada de domínio, no método `ConfigureServices` do seu [módulo](https://docs.abp.io/en/abp/latest/Module-Development-Basics). Exemplo:
```csharp
Configure<CmsKitReactionOptions>(options =>
{
options.EntityTypes.Add(
new ReactionEntityTypeDefinition(
"Produto",
reactions: new[]
{
new ReactionDefinition(StandardReactions.Smile),
new ReactionDefinition(StandardReactions.ThumbsUp),
new ReactionDefinition(StandardReactions.ThumbsDown),
new ReactionDefinition(StandardReactions.Confused),
new ReactionDefinition(StandardReactions.Eyes),
new ReactionDefinition(StandardReactions.Heart)
}));
});
```
> Se você estiver usando os recursos [Comentário](Comments.md) ou [Blogging](Blogging.md), o framework ABP define reações predefinidas para esses recursos automaticamente.
Propriedades de `CmsKitReactionOptions`:
- `EntityTypes`: Lista de tipos de entidade definidos (`CmsKitReactionOptions`) no sistema de reação.
Propriedades de `ReactionEntityTypeDefinition`:
- `EntityType`: Nome do tipo de entidade.
- `Reactions`: Lista de reações definidas (`ReactionDefinition`) no tipo de entidade.
## O Widget de Reações
O sistema de reação fornece um widget de reação para permitir que os usuários enviem reações para recursos. Você pode colocar o widget em uma página da seguinte forma:
```csharp
@await Component.InvokeAsync(typeof(ReactionSelectionViewComponent), new
{
entityType = "Produto",
entityId = "..."
})
```
`entityType` foi explicado na seção anterior. `entityId` deve ser o id único do produto, neste exemplo. Se você tiver uma entidade Produto, pode usar seu Id aqui.
# Internos
## Camada de Domínio
#### Agregados
Este módulo segue o guia de [Melhores Práticas e Convenções de Entidades](https://docs.abp.io/en/abp/latest/Best-Practices/Entities).
##### UserReaction
Uma reação do usuário representa uma reação específica de um usuário.
- `UserReaction` (raiz do agregado): Representa uma reação específica no sistema.
#### Repositórios
Este módulo segue o guia de [Melhores Práticas e Convenções de Repositórios](https://docs.abp.io/en/abp/latest/Best-Practices/Repositories).
Os seguintes repositórios personalizados são definidos para este recurso:
- `IUserReactionRepository`
#### Serviços de Domínio
Este módulo segue o guia de [Melhores Práticas e Convenções de Serviços de Domínio](https://docs.abp.io/en/abp/latest/Best-Practices/Domain-Services).
##### Reaction Manager
`ReactionManager` é usado para realizar algumas operações para a raiz do agregado `UserReaction`.
### Camada de Aplicação
#### Serviços de Aplicação
- `ReactionPublicAppService` (implementa `IReactionPublicAppService`): Implementa os casos de uso do sistema de reação.
### Provedores de Banco de Dados
#### Comum
##### Prefixo da tabela/collection e esquema
Todas as tabelas/collections usam o prefixo `Cms` por padrão. Defina propriedades estáticas na classe `CmsKitDbProperties` se você precisar alterar o prefixo da tabela ou definir um nome de esquema (se suportado pelo seu provedor de banco de dados).
##### String de conexão
Este módulo usa `CmsKit` como nome da string de conexão. Se você não definir uma string de conexão com esse nome, ela será usada a string de conexão `Default`.
Consulte a documentação de [strings de conexão](https://docs.abp.io/en/abp/latest/Connection-Strings) para obter detalhes.
#### Entity Framework Core
##### Tabelas
- CmsUserReactions
#### MongoDB
##### Coleções
- **CmsUserReactions**

165
docs/pt-BR/Modules/Cms-Kit/Tags.md

@ -0,0 +1,165 @@
# Gerenciamento de Tags
O CMS Kit fornece um sistema de **tag** para marcar qualquer tipo de recurso, como uma postagem de blog.
## Habilitando o recurso de Gerenciamento de Tags
Por padrão, os recursos do CMS Kit estão desabilitados. Portanto, você precisa habilitar os recursos que deseja antes de começar a usá-lo. Você pode usar o sistema de [Recursos Globais](../../Global-Features.md) para habilitar/desabilitar os recursos do CMS Kit durante o desenvolvimento. Alternativamente, você pode usar o [Sistema de Recursos](https://docs.abp.io/en/abp/latest/Features) do ABP Framework para desabilitar um recurso do CMS Kit em tempo de execução.
> Verifique a seção ["Como instalar" da documentação do Módulo CMS Kit](Index.md#how-to-install) para saber como habilitar/desabilitar os recursos do CMS Kit durante o desenvolvimento.
## Opções
O sistema de tags fornece um mecanismo para agrupar tags por tipos de entidade. Por exemplo, se você deseja usar o sistema de tags para postagens de blog e produtos, você precisa definir dois tipos de entidade chamados `BlogPosts` e `Product` e adicionar tags sob esses tipos de entidade.
`CmsKitTagOptions` pode ser configurado na camada de domínio, no método `ConfigureServices` da sua classe [módulo](https://docs.abp.io/en/abp/latest/Module-Development-Basics).
**Exemplo: Adicionando suporte a tags para produtos**
```csharp
Configure<CmsKitTagOptions>(options =>
{
options.EntityTypes.Add(new TagEntityTypeDefiniton("Product"));
});
```
> Se você estiver usando o [Recurso de Blogging](Blogging.md), o framework ABP define automaticamente um tipo de entidade para o recurso de blog.
Propriedades de `CmsKitTagOptions`:
- `EntityTypes`: Lista de tipos de entidade definidos (`TagEntityTypeDefiniton`) no sistema de tags.
Propriedades de `TagEntityTypeDefiniton`:
- `EntityType`: Nome do tipo de entidade.
- `DisplayName`: O nome de exibição do tipo de entidade. Você pode usar um nome de exibição amigável para mostrar a definição do tipo de entidade no site de administração.
- `CreatePolicies`: Lista de nomes de políticas/permissões que permitem aos usuários criar tags sob o tipo de entidade.
- `UpdatePolicies`: Lista de nomes de políticas/permissões que permitem aos usuários atualizar tags sob o tipo de entidade.
- `DeletePolicies`: Lista de nomes de políticas/permissões que permitem aos usuários excluir tags sob o tipo de entidade.
## O Widget de Tag
O sistema de tags fornece um widget de tag [widget](../../UI/AspNetCore/Widgets.md) para exibir as tags associadas a um recurso que foi configurado para tags. Você pode simplesmente colocar o widget em uma página como a abaixo:
```csharp
@await Component.InvokeAsync(typeof(TagViewComponent), new
{
entityType = "Product",
entityId = "...",
urlFormat = "/products?tagId={TagId}&tagName={TagName}"
})
```
`entityType` foi explicado na seção anterior. Neste exemplo, o `entityId` deve ser o id único do produto. Se você tiver uma entidade `Product`, você pode usar seu Id aqui. `urlFormat` é o formato de string do URL que será gerado para cada tag. Você pode usar os espaços reservados `{TagId}` e `{TagName}` para preencher o URL. Por exemplo, o formato de URL acima preencherá URLs como `/products?tagId=1&tagName=tag1`.
## O Widget de Tags Populares
O sistema de tags fornece um widget de tags populares [widget](../../UI/AspNetCore/Widgets.md) para exibir tags populares de um recurso que foi configurado para tags. Você pode simplesmente colocar o widget em uma página como abaixo:
```csharp
@await Component.InvokeAsync(typeof(PopularTagsViewComponent), new
{
entityType = "Product",
urlFormat = "/products?tagId={TagId}&tagName={TagName}",
maxCount = 10
})
```
`entityType` foi explicado na seção anterior. `urlFormat` foi explicado na seção anterior. `maxCount` é o número máximo de tags a serem exibidas.
## Interface do Usuário
### Itens de Menu
Os seguintes itens de menu são adicionados pelo recurso de tags à aplicação de administração:
* **Tags**: Abre a página de gerenciamento de tags.
### Páginas
#### Gerenciamento de Tags
Esta página pode ser usada para criar, editar e excluir tags para os tipos de entidade.
![tags-page](../../images/cmskit-module-tags-page.png)
Você pode criar ou editar uma tag existente nesta página.
![tag-edit](../../images/cmskit-module-tag-edit.png)
## Internos
### Camada de Domínio
#### Agregados
Este módulo segue o guia de [Melhores Práticas e Convenções de Entidades](https://docs.abp.io/en/abp/latest/Best-Practices/Entities).
##### Tag
Uma tag representa uma tag sob o tipo de entidade.
- `Tag` (raiz do agregado): Representa uma tag no sistema.
##### EntityTag
Uma entidade tag representa uma conexão entre a tag e a entidade marcada.
- `EntityTag`(entidade): Representa uma conexão entre a tag e a entidade marcada.
#### Repositórios
Este módulo segue o guia de [Melhores Práticas e Convenções de Repositórios](https://docs.abp.io/en/abp/latest/Best-Practices/Repositories).
Os seguintes repositórios personalizados são definidos para este recurso:
- `ITagRepository`
- `IEntityTagRepository`
#### Serviços de Domínio
Este módulo segue o guia de [Melhores Práticas e Convenções de Serviços de Domínio](https://docs.abp.io/en/abp/latest/Best-Practices/Domain-Services).
##### Gerenciador de Tags
`TagManager` realiza algumas operações para a raiz do agregado `Tag`.
##### Gerenciador de Entidade Tag
`EntityTagManager` realiza algumas operações para a entidade `EntityTag`.
### Camada de Aplicação
#### Serviços de Aplicação
- `TagAdminAppService` (implementa `ITagAdminAppService`).
- `EntityTagAdminAppService` (implementa `IEntityTagAdminAppService`).
- `TagAppService` (implementa `ITagAppService`).
### Provedores de Banco de Dados
#### Comum
##### Prefixo de Tabela / Coleção e esquema
Todas as tabelas/coleções usam o prefixo `Cms` por padrão. Defina propriedades estáticas na classe `CmsKitDbProperties` se você precisar alterar o prefixo da tabela ou definir um nome de esquema (se suportado pelo seu provedor de banco de dados).
##### String de conexão
Este módulo usa `CmsKit` como nome da string de conexão. Se você não definir uma string de conexão com esse nome, ela será usada a string de conexão `Default`.
Consulte a documentação de [strings de conexão](https://docs.abp.io/en/abp/latest/Connection-Strings) para obter detalhes.
#### Entity Framework Core
##### Tabelas
- CmsTags
- CmsEntityTags
#### MongoDB
##### Coleções
- **CmsTags**
- **CmsEntityTags**

577
docs/pt-BR/Modules/Database-Tables.md

@ -0,0 +1,577 @@
# Tabelas do Banco de Dados
Esta documentação descreve todas as tabelas do banco de dados e seus propósitos. Você pode ler esta documentação para obter conhecimento geral das tabelas do banco de dados que vêm de cada módulo.
## [Módulo de Registro de Auditoria](Audit-Logging.md)
### AbpAuditLogs
Esta tabela armazena informações sobre os registros de auditoria no aplicativo. Cada registro representa um log de auditoria e rastreia as ações realizadas no aplicativo.
### AbpAuditLogActions
Esta tabela armazena informações sobre as ações realizadas no aplicativo, que são registradas para fins de auditoria.
#### Chaves Estrangeiras
| Tabela | Coluna | Descrição |
| --- | --- | --- |
| [AbpAuditLogs](#abpauditlogs) | Id | Vincula cada ação a um log de auditoria específico. |
### AbpEntityChanges
Esta tabela armazena informações sobre as alterações de entidade no aplicativo, que são registradas para fins de auditoria.
#### Chaves Estrangeiras
| Tabela | Coluna | Descrição |
| --- | --- | --- |
| [AbpAuditLogs](#abpauditlogs) | Id | Vincula cada alteração de entidade a um log de auditoria específico. |
### AbpEntityPropertyChanges
Esta tabela armazena informações sobre as alterações de propriedade em entidades no aplicativo, que são registradas para fins de auditoria.
#### Chaves Estrangeiras
| Tabela | Coluna | Descrição |
| --- | --- | --- |
| [AbpEntityChanges](#abpentitychanges) | Id | Vincula cada alteração de propriedade a uma alteração de entidade específica. |
## [Módulo de Tarefas em Segundo Plano](Background-Jobs.md)
### AbpBackgroundJobs
Esta tabela armazena informações sobre as tarefas em segundo plano no aplicativo e facilita seu gerenciamento e rastreamento eficientes. Cada entrada na tabela contém detalhes de uma tarefa em segundo plano, incluindo o nome da tarefa, argumentos, contagem de tentativas, próxima tentativa, última tentativa, status abandonado e prioridade.
## [Módulo de Gerenciamento de Inquilinos](Tenant-Management.md)
### AbpTenants
Esta tabela armazena informações sobre os inquilinos. Cada registro representa um inquilino e contém informações sobre o inquilino, como nome e outros detalhes.
### AbpTenantConnectionStrings
Esta tabela armazena informações sobre as strings de conexão do banco de dados do inquilino. Quando você define uma string de conexão para um inquilino, um novo registro será adicionado a esta tabela. Você pode consultar este banco de dados para obter strings de conexão por inquilinos.
#### Chaves Estrangeiras
| Tabela | Coluna | Descrição |
| --- | --- | --- |
| [AbpTenants](#abptenants) | Id | A coluna `Id` na tabela `AbpTenants` é usada para associar a string de conexão do inquilino ao inquilino correspondente. |
## Módulo de Blogging
### BlgUsers
Esta tabela armazena informações sobre os usuários do blog. Quando um novo usuário de identidade é criado, um novo registro será adicionado a esta tabela.
### BlgBlogs
Esta tabela serve para armazenar informações do blog e separar semanticamente as postagens de cada blog.
### BlgPosts
Esta tabela armazena informações sobre as postagens do blog. Você pode consultar esta tabela para obter postagens de blog por blogs.
#### Chaves Estrangeiras
| Tabela | Coluna | Descrição |
| --- | --- | --- |
| [BlgBlogs](#blgblogs) | Id | Para associar a postagem do blog ao blog correspondente. |
### BlgComments
Esta tabela armazena informações sobre os comentários feitos nas postagens do blog. Você pode consultar esta tabela para obter comentários por postagens.
#### Chaves Estrangeiras
| Tabela | Coluna | Descrição |
| --- | --- | --- |
| [BlgPosts](#blgposts) | Id | Vincula o comentário à postagem do blog correspondente. |
| [BlgComments](#blgcomments) | Id | Vincula o comentário ao comentário pai. |
### BlgTags
Esta tabela armazena informações sobre as tags. Quando uma nova tag é usada, um novo registro será adicionado a esta tabela. Você pode consultar esta tabela para obter tags por blogs.
### BlgPostTags
Esta tabela é usada para associar tags a postagens de blog, a fim de categorizar e organizar o conteúdo. Você pode consultar esta tabela para obter tags de postagens por postagens.
#### Chaves Estrangeiras
| Tabela | Coluna | Descrição |
| --- | --- | --- |
| [BlgTags](#blgtags) | Id | Vincula a tag da postagem à tag correspondente. |
| [BlgPosts](#blgposts) | Id | Vincula a tag da postagem à postagem do blog correspondente. |
## [Módulo CMS Kit](Cms-Kit/Index.md)
### CmsUsers
Esta tabela armazena informações sobre os usuários do módulo CMS Kit. Quando um novo usuário de identidade é criado, um novo registro será adicionado a esta tabela.
### CmsBlogs
Esta tabela serve para armazenar informações do blog e separar semanticamente as postagens de cada blog.
### CmsBlogPosts
Esta tabela armazena informações sobre as postagens do blog. Você pode consultar esta tabela para obter postagens de blog por blogs.
#### Chaves Estrangeiras
| Tabela | Coluna | Descrição |
| --- | --- | --- |
| [CmsUsers](#cmsusers) | Id | Vincula a postagem do blog ao autor correspondente. |
### CmsBlogFeatures
Esta tabela armazena informações sobre os recursos do blog. Você pode consultar esta tabela para obter recursos do blog por blogs.
### CmsComments
Esta tabela é utilizada pelo sistema de comentários do CMS Kit para armazenar comentários feitos nas postagens do blog. Você pode consultar esta tabela para obter comentários por postagens.
### CmsTags
Esta tabela armazena informações sobre as tags. Quando uma nova tag é usada, um novo registro será adicionado a esta tabela. Você pode consultar esta tabela para obter tags por blogs.
### CmsEntityTags
Esta tabela é utilizada pelo sistema de gerenciamento de tags para armazenar tags e sua relação com várias entidades, permitindo assim a categorização e organização eficiente do conteúdo. Você pode consultar esta tabela para obter tags de entidades por entidades.
### CmsGlobalResources
Esta tabela é uma tabela de banco de dados para o sistema de recursos globais do CMS Kit, permitindo a adição dinâmica de estilos e scripts globais.
### CmsMediaDescriptors
Esta tabela é utilizada pelo módulo CMS Kit para gerenciar arquivos de mídia usando o módulo [BlobStoring](../Blob-Storing.md).
### CmsMenuItems
Esta tabela é usada pelo sistema de menu do CMS Kit para gerenciar e armazenar informações sobre menus públicos dinâmicos, incluindo detalhes como nomes de exibição de itens de menu, URLs e relacionamentos hierárquicos.
### CmsPages
Esta tabela é utilizada pelo sistema de páginas do CMS Kit para armazenar páginas dinâmicas dentro do aplicativo, incluindo informações como URLs de página, títulos e conteúdo.
### CmsRatings
Esta tabela é utilizada pelo sistema de classificação do CMS Kit para armazenar classificações feitas em postagens de blog. Você pode consultar esta tabela para obter classificações por postagens.
### CmsUserReactions
Esta tabela é utilizada pelo sistema de reações do CMS Kit para armazenar reações feitas em postagens de blog. Você pode consultar esta tabela para obter reações por postagens.
## [Módulo de Documentação](Docs.md)
### DocsProjects
Esta tabela armazena informações do projeto para categorizar documentos de acordo com diferentes projetos.
### DocsDocuments
Esta tabela recupera o documento se ele não for encontrado no cache. A documentação está sendo atualizada quando o conteúdo é recuperado do banco de dados.
### DocsDocumentContributors
Esta tabela armazena informações sobre os contribuidores dos documentos. Você pode consultar esta tabela para obter contribuidores de documentos por documentos.
#### Chaves Estrangeiras
| Tabela | Coluna | Descrição |
| --- | --- | --- |
| [DocsDocuments](#docsdocuments) | Id | Vincula o contribuidor do documento ao documento correspondente. |
## [Módulo de Gerenciamento de Recursos](Feature-Management.md)
### AbpFeatureGroups
Esta tabela armazena informações sobre os grupos de recursos no aplicativo. Por exemplo, você pode agrupar todos os recursos na tabela [`AbpFeatures`](#abpfeatures) relacionados ao módulo `Identity` sob o grupo `Identity`.
### AbpFeatures
Esta tabela armazena informações sobre os recursos no aplicativo. Você pode usar a coluna `Name` para vincular cada recurso com seu valor de recurso correspondente na tabela [`AbpFeatureValues`](#abpfeaturevalues), para que você possa gerenciar e organizar facilmente os recursos.
### AbpFeatureValues
Esta tabela armazena os valores dos recursos para diferentes provedores. Você pode usar a coluna `Name` para vincular cada valor de recurso com seu recurso correspondente na tabela [`AbpFeatures`](#abpfeatures), para que você possa gerenciar e organizar facilmente os recursos.
## [Módulo de Identidade](Identity.md)
### AbpUsers
Esta tabela armazena informações sobre os usuários de identidade no aplicativo.
### AbpRoles
Esta tabela armazena informações sobre os papéis no aplicativo. Os papéis são usados para gerenciar e controlar o acesso a diferentes partes do aplicativo, atribuindo permissões e reivindicações aos papéis e, em seguida, atribuindo esses papéis aos usuários. Esta tabela é importante para gerenciar e organizar os papéis no aplicativo e para definir os direitos de acesso dos usuários.
### AbpClaimTypes
Esta tabela armazena informações sobre os tipos de reivindicação usados no aplicativo. Você pode usar as colunas `Name` e `Regex` para filtrar os tipos de reivindicação por nome e padrão regex, respectivamente, para que você possa gerenciar e rastrear facilmente os tipos de reivindicação no aplicativo.
### AbpLinkUsers
Esta tabela é útil para vincular várias contas de usuário em diferentes inquilinos ou aplicativos a um único usuário, permitindo que eles alternem facilmente entre suas contas.
### AbpUserClaims
Esta tabela pode gerenciar o controle de acesso baseado em usuário, permitindo atribuir reivindicações aos usuários, que descrevem os direitos de acesso do usuário individual.
#### Chaves Estrangeiras
| Tabela | Coluna | Descrição |
| --- | --- | --- |
| [AbpUsers](#abpusers) | Id | Vincula a reivindicação do usuário ao usuário correspondente. |
### AbpUserLogins
Esta tabela pode armazenar informações sobre os logins externos do usuário, como login com Facebook, Google, etc., e também pode ser usada para rastrear o histórico de login dos usuários.
#### Chaves Estrangeiras
| Tabela | Coluna | Descrição |
| --- | --- | --- |
| [AbpUsers](#abpusers) | Id | Vincula o login do usuário ao usuário correspondente. |
### AbpUserRoles
Esta tabela pode gerenciar o controle de acesso baseado em usuário, permitindo atribuir papéis aos usuários, que descrevem os direitos de acesso do usuário individual.
#### Chaves Estrangeiras
| Tabela | Coluna | Descrição |
| --- | --- | --- |
| [AbpUsers](#abpusers) | Id | Vincula o papel do usuário ao usuário correspondente. |
| [AbpRoles](#abproles) | Id | Vincula o papel do usuário ao papel correspondente. |
### AbpUserTokens
Esta tabela pode armazenar informações sobre tokens de atualização, tokens de acesso e outros tokens usados no aplicativo. Também pode ser usado para invalidar ou revogar tokens de usuário.
#### Chaves Estrangeiras
| Tabela | Coluna | Descrição |
| --- | --- | --- |
| [AbpUsers](#abpusers) | Id | Vincula o token do usuário ao usuário correspondente. |
### AbpOrganizationUnits
Esta tabela é útil para criar e gerenciar uma estrutura hierárquica da organização, permitindo agrupar usuários e atribuir papéis com base na estrutura da organização. Você pode usar as colunas `Code` e `ParentId` para filtrar as unidades organizacionais por código e ID do pai, respectivamente, para que você possa gerenciar e rastrear facilmente as unidades organizacionais no aplicativo.
#### Chaves Estrangeiras
| Tabela | Coluna | Descrição |
| --- | --- | --- |
| [AbpOrganizationUnits](#abporganizationunits) | ParentId | Vincula a unidade organizacional à sua unidade organizacional pai. |
### AbpOrganizationUnitRoles
Esta tabela é útil para gerenciar o controle de acesso baseado em função no nível das unidades organizacionais, permitindo atribuir diferentes papéis a diferentes partes da estrutura da organização. Você pode usar as colunas `OrganizationUnitId` e `RoleId` para filtrar os papéis por ID da unidade organizacional e ID do papel, respectivamente, para que você possa gerenciar e rastrear facilmente os papéis atribuídos às unidades organizacionais no aplicativo.
#### Chaves Estrangeiras
| Tabela | Coluna | Descrição |
| --- | --- | --- |
| [AbpOrganizationUnits](#abporganizationunits) | Id | Vincula o papel da unidade organizacional à unidade organizacional correspondente. |
| [AbpRoles](#abproles) | Id | Vincula o papel da unidade organizacional ao papel correspondente. |
### AbpUserOrganizationUnits
Esta tabela armazena informações sobre as unidades organizacionais atribuídas aos usuários no aplicativo. Esta tabela pode gerenciar relacionamentos entre usuário e unidade organizacional e agrupar usuários com base na estrutura da organização.
#### Chaves Estrangeiras
| Tabela | Coluna | Descrição |
| --- | --- | --- |
| [AbpUsers](#abpusers) | Id | Vincula a unidade organizacional do usuário ao usuário correspondente. |
| [AbpOrganizationUnits](#abporganizationunits) | Id | Vincula a unidade organizacional do usuário à unidade organizacional correspondente. |
### AbpRoleClaims
Esta tabela é útil para gerenciar o controle de acesso baseado em função, permitindo atribuir reivindicações aos papéis, que descrevem os direitos de acesso dos usuários que pertencem a esse papel.
#### Chaves Estrangeiras
| Tabela | Coluna | Descrição |
| --- | --- | --- |
| [AbpRoles](#abproles) | Id | Vincula a reivindicação do papel ao papel correspondente. |
### AbpSecurityLogs
Esta tabela registra operações e alterações importantes relacionadas às contas de usuário, permitindo que os usuários salvem os logs de segurança para referência futura.
## [Gerenciamento de Permissões](Permission-Management.md)
### AbpPermissionGroups
Esta tabela é importante para gerenciar e organizar as permissões no aplicativo, agrupando-as em categorias lógicas.
### AbpPermissions
Esta tabela é importante para gerenciar e controlar o acesso a diferentes partes do aplicativo e para definir as permissões granulares que compõem as permissões ou papéis maiores.
### AbpPermissionGrants
A tabela armazena e gerencia as permissões no aplicativo e mantém o controle das permissões concedidas, para quem e quando. Colunas como `Name`, `ProviderName`, `ProviderKey`, `TenantId` podem ser usadas para filtrar as permissões concedidas por nome, nome do provedor, chave do provedor e ID do inquilino, respectivamente, para que você possa gerenciar e rastrear facilmente as permissões concedidas no aplicativo.
## [Gerenciamento de Configurações](Setting-Management.md)
### AbpSettings
Esta tabela armazena pares de chave-valor de configurações para o aplicativo e permite a configuração dinâmica do aplicativo sem a necessidade de recompilação.
## [OpenIddict](OpenIddict.md)
### OpenIddictApplications
Esta tabela pode armazenar informações sobre as aplicações OpenID Connect, incluindo o ID do cliente, segredo do cliente, URI de redirecionamento e outras informações relevantes. Também pode ser usado para autenticar e autorizar clientes usando o protocolo OpenID Connect.
### OpenIddictAuthorizations
Esta tabela armazena os dados de autorização do OpenID Connect no aplicativo. Também pode ser usado para gerenciar e validar as concessões de autorização emitidas para clientes e usuários.
#### Chaves Estrangeiras
| Tabela | Coluna | Descrição |
| --- | --- | --- |
| [OpenIddictApplications](#openiddictapplications) | Id | Vincula a autorização à aplicação correspondente. |
### OpenIddictTokens
Esta tabela pode armazenar informações sobre os tokens OpenID Connect, incluindo o payload do token, expiração, tipo e outras informações relevantes. Também pode ser usado para gerenciar e validar os tokens emitidos para clientes e usuários, como tokens de acesso e tokens de atualização, e controlar o acesso a recursos protegidos.
#### Chaves Estrangeiras
| Tabela | Coluna | Descrição |
| --- | --- | --- |
| [OpenIddictApplications](#openiddictapplications) | Id | Vincula o token à aplicação correspondente. |
| [OpenIddictAuthorizations](#openiddictauthorizations) | Id | Vincula o token à autorização correspondente. |
### OpenIddictScopes
Esta tabela pode armazenar informações sobre os escopos OpenID Connect, incluindo o nome e a descrição do escopo. Também pode ser usado para definir as permissões ou direitos de acesso associados aos escopos, que são então usados para controlar o acesso a recursos protegidos.
## [IdentityServer](IdentityServer.md)
### IdentityServerApiResources
Esta tabela pode armazenar informações sobre os recursos da API, incluindo o nome do recurso, nome de exibição, descrição e outras informações relevantes. Também pode ser usado para definir os escopos, reivindicações e propriedades associadas aos recursos da API, que são então usados para controlar o acesso a recursos protegidos.
### IdentityServerIdentityResources
Esta tabela pode armazenar informações sobre os recursos de identidade, incluindo o nome, nome de exibição, descrição e status habilitado.
### IdentityServerClients
Esta tabela pode armazenar informações sobre os clientes, incluindo o ID do cliente, nome do cliente, URI do cliente e outras informações relevantes. Também pode ser usado para definir os escopos, reivindicações e propriedades associadas aos clientes, que são então usados para controlar o acesso a recursos protegidos.
### IdentityServerApiScopes
Esta tabela pode armazenar informações sobre os escopos da API, incluindo o nome do escopo, nome de exibição, descrição e outras informações relevantes. Também pode ser usado para definir as reivindicações e propriedades associadas aos escopos da API, que são então usados para controlar o acesso a recursos protegidos.
### IdentityServerApiResourceClaims
Esta tabela pode armazenar informações sobre as reivindicações de um recurso da API, incluindo o tipo de reivindicação e o ID do recurso da API.
#### Chaves Estrangeiras
| Tabela | Coluna | Descrição |
| --- | --- | --- |
| [IdentityServerApiResources](#identityserverapiresources) | Id | Vincula a reivindicação ao recurso da API correspondente. |
### IdentityServerIdentityResourceClaims
Esta tabela pode armazenar informações sobre as reivindicações de um recurso de identidade, incluindo o tipo de reivindicação e o ID do recurso de identidade.
#### Chaves Estrangeiras
| Tabela | Coluna | Descrição |
| --- | --- | --- |
| [IdentityServerIdentityResources](#identityserveridentityresources) | Id | Vincula a reivindicação ao recurso de identidade correspondente. |
### IdentityServerClientClaims
Esta tabela pode armazenar informações sobre as reivindicações de um cliente, incluindo o tipo de reivindicação, valor da reivindicação e ID do cliente.
#### Chaves Estrangeiras
| Tabela | Coluna | Descrição |
| --- | --- | --- |
| [IdentityServerClients](#identityserverclients) | Id | Vincula a reivindicação ao cliente correspondente. |
### IdentityServerApiScopeClaims
Esta tabela pode armazenar informações sobre as reivindicações de um escopo da API, incluindo o tipo de reivindicação e o ID do escopo da API.
#### Chaves Estrangeiras
| Tabela | Coluna | Descrição |
| --- | --- | --- |
| [IdentityServerApiScopes](#identityserverapiscopes) | Id | Vincula a reivindicação ao escopo da API correspondente. |
### IdentityServerApiResourceProperties
Esta tabela pode armazenar informações sobre propriedades, incluindo a chave da propriedade e o valor, e o recurso da API associado. Essas propriedades podem armazenar metadados adicionais ou informações de configuração relacionadas aos recursos da API.
#### Chaves Estrangeiras
| Tabela | Coluna | Descrição |
| --- | --- | --- |
| [IdentityServerApiResources](#identityserverapiresources) | Id | Vincula a propriedade ao recurso da API correspondente. |
### IdentityServerIdentityResourceProperties
Esta tabela pode armazenar informações sobre propriedades, incluindo a chave da propriedade e o valor, e o recurso de identidade associado. Essas propriedades podem armazenar metadados adicionais ou informações de configuração relacionadas aos recursos de identidade.
#### Chaves Estrangeiras
| Tabela | Coluna | Descrição |
| --- | --- | --- |
| [IdentityServerIdentityResources](#identityserveridentityresources) | Id | Vincula a propriedade ao recurso de identidade correspondente. |
### IdentityServerClientProperties
Esta tabela pode armazenar informações sobre as propriedades de um cliente, incluindo a chave, valor e ID do cliente. Essas propriedades podem armazenar metadados adicionais ou informações de configuração relacionadas aos clientes.
#### Chaves Estrangeiras
| Tabela | Coluna | Descrição |
| --- | --- | --- |
| [IdentityServerClients](#identityserverclients) | Id | Vincula a propriedade ao cliente correspondente. |
### IdentityServerApiScopeProperties
Esta tabela pode armazenar informações sobre as propriedades de um escopo da API, incluindo a chave, valor e ID do escopo da API. Essas propriedades podem armazenar metadados adicionais ou informações de configuração relacionadas aos escopos da API.
#### Chaves Estrangeiras
| Tabela | Coluna | Descrição |
| --- | --- | --- |
| [IdentityServerApiScopes](#identityserverapiscopes) | Id | Vincula a propriedade ao escopo da API correspondente. |
### IdentityServerApiResourceScopes
Esta tabela pode armazenar informações sobre os escopos de um recurso da API, incluindo o nome do escopo e o ID do recurso da API.
#### Chaves Estrangeiras
| Tabela | Coluna | Descrição |
| --- | --- | --- |
| [IdentityServerApiResources](#identityserverapiresources) | Id | Vincula o escopo ao recurso da API correspondente. |
### IdentityServerClientScopes
Esta tabela pode armazenar informações sobre os escopos de um cliente, incluindo o escopo e o ID do cliente.
#### Chaves Estrangeiras
| Tabela | Coluna | Descrição |
| --- | --- | --- |
| [IdentityServerClients](#identityserverclients) | Id | Vincula o escopo ao cliente correspondente. |
### IdentityServerApiResourceSecrets
Esta tabela pode armazenar informações sobre os segredos de um recurso da API, incluindo o valor do segredo, data de expiração e ID do recurso da API.
#### Chaves Estrangeiras
| Tabela | Coluna | Descrição |
| --- | --- | --- |
| [IdentityServerApiResources](#identityserverapiresources) | Id | Vincula o segredo ao recurso da API correspondente. |
### IdentityServerClientSecrets
Esta tabela pode armazenar informações sobre os segredos de um cliente, incluindo o valor do segredo, data de expiração e ID do cliente.
#### Chaves Estrangeiras
| Tabela | Coluna | Descrição |
| --- | --- | --- |
| [IdentityServerClients](#identityserverclients) | Id | Vincula o segredo ao cliente correspondente. |
### IdentityServerClientCorsOrigins
Esta tabela pode armazenar informações sobre as origens CORS de um cliente, incluindo a origem e o ID do cliente. Também pode ser usado para gerenciar e validar as origens CORS de um cliente.
#### Chaves Estrangeiras
| Tabela | Coluna | Descrição |
| --- | --- | --- |
| [IdentityServerClients](#identityserverclients) | Id | Vincula a origem CORS ao cliente correspondente. |
### IdentityServerClientGrantTypes
Esta tabela pode armazenar informações sobre os tipos de concessão de um cliente, incluindo o tipo de concessão e o ID do cliente.
#### Chaves Estrangeiras
| Tabela | Coluna | Descrição |
| --- | --- | --- |
| [IdentityServerClients](#identityserverclients) | Id | Vincula o tipo de concessão ao cliente correspondente. |
### IdentityServerClientIdPRestrictions
Esta tabela pode armazenar informações sobre as restrições do provedor de identidade de um cliente, incluindo o provedor de identidade e o ID do cliente.
#### Chaves Estrangeiras
| Tabela | Coluna | Descrição |
| --- | --- | --- |
| [IdentityServerClients](#identityserverclients) | Id | Vincula a restrição do provedor de identidade ao cliente correspondente. |
### IdentityServerClientPostLogoutRedirectUris
Esta tabela pode armazenar informações sobre os URIs de redirecionamento pós logout de um cliente, incluindo o URI de redirecionamento pós logout e o ID do cliente.
#### Chaves Estrangeiras
| Tabela | Coluna | Descrição |
| --- | --- | --- |
| [IdentityServerClients](#identityserverclients) | Id | Vincula o URI de redirecionamento pós logout ao cliente correspondente. |
### IdentityServerClientRedirectUris
Esta tabela pode armazenar informações sobre os URIs de redirecionamento de um cliente, incluindo o URI de redirecionamento e o ID do cliente.
#### Chaves Estrangeiras
| Tabela | Coluna | Descrição |
| --- | --- | --- |
| [IdentityServerClients](#identityserverclients) | Id | Vincula o URI de redirecionamento ao cliente correspondente. |
### IdentityServerDeviceFlowCodes
Esta tabela pode armazenar informações sobre os códigos de fluxo de dispositivo, incluindo o código do usuário, código do dispositivo, ID do assunto, ID do cliente, data de criação, expiração, dados e ID da sessão.
### IdentityServerPersistedGrants
Esta tabela pode armazenar informações sobre as concessões persistidas, incluindo a chave, tipo, ID do assunto, ID do cliente, data de criação, expiração e dados.
## Outros
### AbpBlobContainers
Esta tabela é importante para fornecer uma melhor experiência do usuário, permitindo que o aplicativo suporte vários contêineres e forneça recursos específicos de BLOB.
### AbpBlobs
Esta tabela armazena os dados binários de BLOBs (objetos binários grandes) no aplicativo. Cada BLOB está relacionado a um contêiner na tabela [AbpBlobContainers](#abpblobcontainers), onde o nome do contêiner, ID do inquilino e outras propriedades do contêiner podem ser encontrados.
#### Chaves Estrangeiras
| Tabela | Coluna | Descrição |
| --- | --- | --- |
| [AbpBlobContainers](#abpblobcontainers) | Id | Vincula o BLOB ao contêiner correspondente. |
### AbpLocalizationResources
Esta tabela armazena os recursos de localização para o aplicativo. Esta tabela é importante para fornecer uma melhor experiência do usuário, permitindo que o aplicativo suporte vários recursos e forneça texto localizado e outros recursos específicos de localização.
### AbpLocalizationTexts
A tabela contém o nome do recurso, nome da cultura e um valor codificado em JSON que contém o par chave-valor do texto de localização. Ele permite o armazenamento e gerenciamento eficiente de textos de localização e permite a atualização fácil ou adição de novas traduções para recursos e culturas específicas.

675
docs/pt-BR/Modules/Docs.md

@ -0,0 +1,675 @@
# Módulo de Documentação
## O que é o Módulo de Documentação?
O módulo de documentação é um módulo de aplicação para o framework ABP. Ele simplifica a documentação de software. Este módulo é gratuito e de código aberto.
### Integração
Atualmente, o módulo de documentação permite que você armazene sua documentação tanto no GitHub quanto no sistema de arquivos.
### Hospedagem
O módulo de documentação é um módulo de aplicação e não oferece nenhuma solução de hospedagem. Você pode hospedar sua documentação localmente ou na nuvem.
### Versionamento
Quando você usa o GitHub para armazenar sua documentação, o módulo de documentação suporta o versionamento. Se você tiver várias versões para sua documentação, haverá uma caixa de seleção na interface do usuário para alternar entre as versões. Se você escolher o sistema de arquivos para armazenar sua documentação, ele não suportará várias versões.
[Os documentos](https://docs.abp.io/) para o framework ABP também estão usando este módulo.
> O módulo de documentação segue as melhores práticas de arquitetura de módulos.
## Instalação
Este documento aborda o provedor `Entity Framework Core`, mas você também pode selecionar o `MongoDB` como seu provedor de banco de dados.
### 1- Criando uma aplicação
Se você não tiver um projeto ABP existente, você pode gerar um comando CLI a partir da página de início do site abp.io e executá-lo ou executar o comando abaixo:
```bash
abp new Acme.MyProject
```
### 2- Executando a aplicação vazia
Após baixar o projeto, extraia o arquivo ZIP e abra `Acme.MyProject.sln`. Você verá que a solução consiste nos projetos `Application`, `Application.Contracts`, `DbMigrator`, `Domain`, `Domain.Shared`, `EntityFrameworkCore`, `HttpApi`, `HttpApi.Client` e `Web`. Clique com o botão direito no projeto `Acme.MyProject.Web` e selecione **Definir como Projeto de Inicialização**.
![Criar um novo projeto](../images/docs-module_solution-explorer.png)
A string de conexão do banco de dados está localizada em `appsettings.json` do seu projeto `Acme.MyProject.Web`. Se você tiver uma configuração de banco de dados diferente, altere a string de conexão.
```json
{
"ConnectionStrings": {
"Default": "Server=(LocalDb)\\MSSQLLocalDB;Database=MyProject;Trusted_Connection=True"
}
}
```
Execute o projeto `Acme.MyProject.DbMigrator`, ele será responsável por aplicar a migração do banco de dados e os dados iniciais. O banco de dados `MyProject` será criado em seu servidor de banco de dados.
Agora um projeto ABP vazio foi criado! Agora você pode executar seu projeto e ver o site vazio.
Para fazer login no seu site, digite `admin` como nome de usuário e `1q2w3E*` como senha.
### 3- Instalação do Módulo
Os pacotes do módulo de documentação estão hospedados no NuGet. Existem 4 pacotes que precisam ser instalados em sua aplicação. Cada pacote deve ser instalado no projeto relevante.
#### 3.1- Usando o ABP CLI
É recomendado usar o ABP CLI para instalar o módulo. Abra a janela do CMD no diretório do arquivo de solução (`.sln`) e execute o seguinte comando:
```bash
abp add-module Volo.Docs
```
#### 3.2- Instalação manual
Ou você também pode instalar manualmente o pacote NuGet em cada projeto:
* Instale o pacote NuGet [Volo.Docs.Domain](https://www.nuget.org/packages/Volo.Docs.Domain/) no projeto `Acme.MyProject.Domain`.
```bash
Install-Package Volo.Docs.Domain
```
* Instale o pacote NuGet [Volo.Docs.EntityFrameworkCore](https://www.nuget.org/packages/Volo.Docs.EntityFrameworkCore/) no projeto `Acme.MyProject.EntityFrameworkCore`.
```bash
Install-Package Volo.Docs.EntityFrameworkCore
```
* Instale o pacote NuGet [Volo.Docs.Application](https://www.nuget.org/packages/Volo.Docs.Application/) no projeto `Acme.MyProject.Application`.
```bash
Install-Package Volo.Docs.Application
```
* Instale o pacote NuGet [Volo.Docs.Web](https://www.nuget.org/packages/Volo.Docs.Domain/) no projeto `Acme.MyProject.Web`.
```bash
Install-Package Volo.Docs.Web
```
##### 3.2.1- Adicionando Dependências de Módulo
Um módulo ABP deve declarar o atributo `[DependsOn]` se tiver uma dependência de outro módulo. Cada módulo deve ser adicionado no atributo `[DependsOn]` do projeto relevante.
* Abra `MyProjectDomainModule.cs` e adicione `typeof(DocsDomainModule)` como mostrado abaixo;
```csharp
[DependsOn(
typeof(DocsDomainModule),
typeof(AbpIdentityDomainModule),
typeof(AbpAuditingModule),
typeof(BackgroundJobsDomainModule),
typeof(AbpAuditLoggingDomainModule)
)]
public class MyProjectDomainModule : AbpModule
{
//...
}
```
* Abra `MyProjectEntityFrameworkCoreModule.cs` e adicione `typeof(DocsEntityFrameworkCoreModule)` como mostrado abaixo;
```csharp
[DependsOn(
typeof(DocsEntityFrameworkCoreModule),
typeof(MyProjectDomainModule),
typeof(AbpIdentityEntityFrameworkCoreModule),
typeof(AbpPermissionManagementEntityFrameworkCoreModule),
typeof(AbpSettingManagementEntityFrameworkCoreModule),
typeof(AbpEntityFrameworkCoreSqlServerModule),
typeof(BackgroundJobsEntityFrameworkCoreModule),
typeof(AbpAuditLoggingEntityFrameworkCoreModule)
)]
public class MyProjectEntityFrameworkCoreModule : AbpModule
{
//...
}
```
* Abra `MyProjectApplicationModule.cs` e adicione `typeof(DocsApplicationModule)` como mostrado abaixo;
```csharp
[DependsOn(
typeof(DocsApplicationModule),
typeof(MyProjectDomainModule),
typeof(AbpIdentityApplicationModule))]
public class MyProjectApplicationModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
Configure<AbpPermissionOptions>(options =>
{
options.DefinitionProviders.Add<MyProjectPermissionDefinitionProvider>();
});
Configure<AbpAutoMapperOptions>(options =>
{
options.AddProfile<MyProjectApplicationAutoMapperProfile>();
});
}
}
```
* Abra `MyProjectWebModule.cs` e adicione `typeof(DocsWebModule)` como mostrado abaixo;
```csharp
[DependsOn(
typeof(DocsWebModule),
typeof(MyProjectApplicationModule),
typeof(MyProjectEntityFrameworkCoreModule),
typeof(AbpAutofacModule),
typeof(AbpIdentityWebModule),
typeof(AbpAccountWebModule),
typeof(AbpAspNetCoreMvcUiBasicThemeModule)
)]
public class MyProjectWebModule : AbpModule
{
//...
}
```
##### 3.2.2- Adicionando Pacote NPM
Abra `package.json` e adicione `@abp/docs": "^5.0.0` como mostrado abaixo:
```json
{
"version": "1.0.0",
"name": "my-app",
"private": true,
"dependencies": {
"@abp/aspnetcore.mvc.ui.theme.basic": "^5.0.0",
"@abp/docs": "^5.0.0"
}
}
```
Em seguida, abra o terminal de linha de comando na pasta do projeto `Acme.MyProject.Web` e execute o seguinte comando:
````bash
abp install-libs
````
### 4- Integração com o Banco de Dados
#### 4.1- Integração com o Entity Framework
Se você escolher o Entity Framework como seu provedor de banco de dados, precisará configurar o módulo de documentação. Para fazer isso;
- Abra `MyProjectMigrationsDbContext.cs` e adicione `builder.ConfigureDocs()` ao `OnModelCreating()`.
```csharp
public class MyProjectMigrationsDbContext : AbpDbContext<MyProjectMigrationsDbContext>
{
public MyProjectMigrationsDbContext(DbContextOptions<MyProjectMigrationsDbContext> options)
: base(options)
{
}
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
/* Inclua módulos no contexto de migração do banco de dados */
builder.ConfigurePermissionManagement();
builder.ConfigureSettingManagement();
builder.ConfigureBackgroundJobs();
builder.ConfigureAuditLogging();
builder.ConfigureIdentity();
builder.ConfigureIdentityServer();
builder.ConfigureFeatureManagement();
builder.ConfigureTenantManagement();
builder.ConfigureDocs(); //Adicione esta linha para configurar o módulo de documentação
/* Configure personalizações para entidades dos módulos incluídos */
builder.Entity<IdentityUser>(b =>
{
b.ConfigureCustomUserProperties();
});
/* Configure suas próprias tabelas/entidades dentro do método ConfigureMyProject */
builder.ConfigureMyProject();
}
}
```
* Abra o `Console do Gerenciador de Pacotes` no `Visual Studio` e escolha `Acme.MyProject.EntityFrameworkCore` como projeto padrão. Em seguida, escreva o comando abaixo para adicionar a migração para o módulo de documentação.
```csharp
add-migration Added_Docs_Module
```
Quando o comando for executado com sucesso, você verá um novo arquivo de migração chamado `20181221111621_Added_Docs_Module` na pasta `Acme.MyProject.EntityFrameworkCore\Migrations`.
Agora, atualize o banco de dados para as alterações do módulo de documentação. Para fazer isso, execute o código abaixo no `Console do Gerenciador de Pacotes` no `Visual Studio`. Certifique-se de que `Acme.MyProject.EntityFrameworkCore` ainda é o projeto padrão.
```csharp
update-database
```
Por fim, você pode verificar seu banco de dados para ver as tabelas recém-criadas. Por exemplo, você pode ver a tabela `DocsProjects` adicionada ao seu banco de dados.
### 5- Vinculando o Módulo de Documentação
A rota padrão para o módulo de documentação é;
```txt
/Documents
```
Para adicionar o link do módulo de documentação ao menu de sua aplicação;
* Abra `MyProjectMenuContributor.cs` e adicione a linha abaixo ao método `ConfigureMainMenuAsync()`.
```csharp
context.Menu.Items.Add(new ApplicationMenuItem("MyProject.Docs", l["Menu:Docs"], "/Documents"));
```
A aparência final de **MyProjectMenuContributor.cs**
```csharp
private async Task ConfigureMainMenuAsync(MenuConfigurationContext context)
{
var l = context.ServiceProvider.GetRequiredService<IStringLocalizer<MyProjectResource>>();
context.Menu.Items.Insert(0, new ApplicationMenuItem("MyProject.Home", l["Menu:Home"], "/"));
context.Menu.Items.Add(new ApplicationMenuItem("MyProject.Docs", l["Menu:Docs"], "/Documents"));
}
```
A palavra-chave `Menu:Docs` é uma chave de localização. Para localizar o texto do menu, abra `Localization\MyProject\en.json` no projeto `Acme.MyProject.Domain`. E adicione a linha abaixo
```json
"Menu:Docs": "Documentos"
```
A aparência final de **en.json**
```json
{
"culture": "en",
"texts": {
"Menu:Home": "Início",
"Welcome": "Bem-vindo",
"LongWelcomeMessage": "Bem-vindo à aplicação. Este é um projeto inicial baseado no framework ABP. Para obter mais informações, visite abp.io.",
"Menu:Docs": "Documentos"
}
}
```
O novo item de menu para o Módulo de Documentação foi adicionado ao menu. Execute sua aplicação web e acesse a URL `http://localhost:YOUR_PORT_NUMBER/documents`.
Você verá um aviso que diz;
```txt
Ainda não há projetos!
```
Como ainda não adicionamos nenhum projeto, este aviso é normal.
### 6- Adicionando um Novo Projeto de Documentação
Abra `DocsProjects` em seu banco de dados e insira um novo registro com as seguintes informações de campo;
* **Name**: O nome de exibição do nome do documento que será mostrado na página da web.
* **ShortName**: Um nome curto e amigável para URL que será usado na URL de seus documentos.
* **Format**: O formato do documento (para Markdown: `md`, para HTML: `html`)
* **DefaultDocumentName**: O documento para a página inicial.
* **NavigationDocumentName**: O documento a ser usado para o menu de navegação (Índice).
* **MinimumVersion**: A versão mínima para mostrar os documentos. As versões abaixo não serão listadas.
* **DocumentStoreType**: A fonte dos documentos (para GitHub:`GitHub`, para sistema de arquivos`FileSystem`)
* **ExtraProperties**: Um JSON serializado que armazena configurações especiais para o `DocumentStoreType` selecionado.
* **MainWebsiteUrl**: A URL para quando o usuário clicar no logotipo da página do módulo de documentação. Você pode simplesmente definir como `/` para vincular ao endereço raiz do seu site.
* **LatestVersionBranchName**: Esta é uma configuração para o GitHub. É o nome do branch que será usado para recuperar os documentos. Você pode definir como `master`.
#### Exemplo de Registro de Projeto para "GitHub"
Você pode usar a documentação do [ABP Framework](https://github.com/abpframework/abp/) no GitHub para configurar seu repositório de documentos do GitHub.
- Name: `ABP framework (GitHub)`
- ShortName: `abp`
- Format: `md`
- DefaultDocumentName: `Index`
- NavigationDocumentName: `docs-nav.json`
- MinimumVersion: `<NULL>` (sem versão mínima)
- DocumentStoreType: `GitHub`
- ExtraProperties:
```json
{"GitHubRootUrl":"https://github.com/abpframework/abp/tree/{version}/docs","GitHubAccessToken":"***","GitHubUserAgent":""}
```
Observe que `GitHubAccessToken` está mascarado com `***`. É um token privado que você deve obter do GitHub. Consulte https://help.github.com/articles/creating-a-personal-access-token-for-the-command-line/
- MainWebsiteUrl: `/`
- LatestVersionBranchName: `dev`
Para bancos de dados `SQL`, você pode usar o comando `T-SQL` abaixo para inserir o exemplo especificado em sua tabela `DocsProjects`:
```mssql
INSERT [dbo].[DocsProjects] ([Id], [Name], [ShortName], [Format], [DefaultDocumentName], [NavigationDocumentName], [MinimumVersion], [DocumentStoreType], [ExtraProperties], [MainWebsiteUrl], [LatestVersionBranchName], [ParametersDocumentName], [ConcurrencyStamp]) VALUES (N'12f21123-e08e-4f15-bedb-ae0b2d939659', N'ABP framework (FileSystem)', N'abp', N'md', N'Index', N'docs-nav.json', NULL, N'FileSystem', N'{"Path":"C:\\Github\\abp\\docs"}', N'/', NULL, N'', N'12f21123e08e4f15bedbae0b2d939659')
```
Esteja ciente de que `GitHubAccessToken` está mascarado. É um token privado e você deve obter seu próprio token e substituir a string `***`.
Agora você pode executar a aplicação e navegar até `/Documents`.
#### Exemplo de Registro de Projeto para "FileSystem"
Você pode usar a documentação do [ABP Framework](https://github.com/abpframework/abp/) no GitHub para configurar seu repositório de documentos do GitHub.
- Name: `ABP framework (FileSystem)`
- ShortName: `abp`
- Format: `md`
- DefaultDocumentName: `Index`
- NavigationDocumentName: `docs-nav.json`
- MinimumVersion: `<NULL>` (sem versão mínima)
- DocumentStoreType: `FileSystem`
- ExtraProperties:
```json
{"Path":"C:\\Github\\abp\\docs"}
```
Observe que `Path` deve ser substituído pelo diretório de documentos local. Você pode obter a documentação do ABP Framework em https://github.com/abpframework/abp/tree/master/docs e copiar para o diretório `C:\\Github\\abp\\docs` para que funcione.
- MainWebsiteUrl: `/`
- LatestVersionBranchName: `<NULL>`
Para bancos de dados `SQL`, você pode usar o comando `T-SQL` abaixo para inserir o exemplo especificado em sua tabela `DocsProjects`:
```mssql
INSERT [dbo].[DocsProjects] ([Id], [Name], [ShortName], [Format], [DefaultDocumentName], [NavigationDocumentName], [MinimumVersion], [DocumentStoreType], [ExtraProperties], [MainWebsiteUrl], [LatestVersionBranchName], [ParametersDocumentName]) VALUES (N'12f21123-e08e-4f15-bedb-ae0b2d939659', N'ABP framework (FileSystem)', N'abp', N'md', N'Index', N'docs-nav.json', NULL, N'FileSystem', N'{"Path":"C:\\Github\\abp\\docs"}', N'/', NULL, N'')
```
Adicione um dos projetos de exemplo acima e execute a aplicação. No menu, você verá o link `Documentos`, clique no link do menu para abrir a página de documentos.
Até agora, criamos um novo aplicativo a partir do site abp.io e o preparamos para o módulo de documentação.
### 7- Criando um Novo Documento
No exemplo de registros de projeto, você vê que o `Format` é especificado como `md`, que se refere ao [Mark Down](https://en.wikipedia.org/wiki/Markdown). Você pode ver o guia de referência do mark down seguindo o link abaixo;
https://github.com/adam-p/markdown-here/wiki/Markdown-Cheatsheet
O módulo de documentação do ABP pode renderizar mark down para HTML.
Agora vamos dar uma olhada em um exemplo de documento em formato mark down.
~~~markdown
# Este é um cabeçalho
Bem-vindo ao Módulo de Documentação.
## Este é um subcabeçalho
[Este é um link](https://abp.io)
![Esta é uma imagem](https://abp.io/assets/my-image.png)
## Este é um bloco de código
```csharp
public class Person
{
public string Name { get; set; }
public string Address { get; set; }
}
```
~~~
Como exemplo, você pode ver a documentação do ABP Framework:
[https://github.com/abpframework/abp/blob/master/docs/en/](https://github.com/abpframework/abp/blob/master/docs/en/)
#### Recurso de seções condicionais (Usando Scriban)
O módulo de documentação usa o [Scriban](https://github.com/lunet-io/scriban/tree/master/doc) para mostrar ou ocultar algumas partes de um documento de forma condicional. Para usar esse recurso, você deve criar um arquivo JSON como **documento de parâmetros** para cada idioma. Ele conterá todas as chaves-valores, bem como seus nomes de exibição.
Por exemplo, [en/docs-params.json](https://github.com/abpio/abp-commercial-docs/blob/master/en/docs-params.json):
```json
{
"parameters": [{
"name": "UI",
"displayName": "UI",
"values": {
"MVC": "MVC / Razor Pages",
"NG": "Angular"
}
},
{
"name": "DB",
"displayName": "Database",
"values": {
"EF": "Entity Framework Core",
"Mongo": "MongoDB"
}
},
{
"name": "Tiered",
"displayName": "Tiered",
"values": {
"No": "Not Tiered",
"Yes": "Tiered"
}
}]
}
```
Como nem todos os documentos de seus projetos podem ter seções ou precisar de todos esses parâmetros, você deve declarar quais desses parâmetros serão usados para dividir o documento, como um bloco JSON em qualquer lugar do documento.
Por exemplo [Getting-Started.md](https://github.com/abpio/abp-commercial-docs/blob/master/en/getting-started.md):
```
.....
​```json
//[doc-params]
{
"UI": ["MVC","NG"],
"DB": ["EF", "Mongo"],
"Tiered": ["Yes", "No"]
}
​```
........
```
Esta seção será excluída automaticamente durante a renderização. E, é claro, essas chaves de valores devem corresponder às do **documento de parâmetros**.
![Interface](../images/docs-section-ui.png)
Agora você pode usar a sintaxe do **Scriban** para criar seções em seu documento.
Por exemplo:
````
{{ if UI == "NG" }}
* O argumento `-u` especifica o framework de IU, `angular` neste caso.
{{ end }}
{{ if DB == "Mongo" }}
* O argumento `-d` especifica o provedor de banco de dados, `mongodb` neste caso.
{{ end }}
{{ if Tiered == "Yes" }}
* O argumento `--tiered` é usado para criar uma solução em camadas em que o servidor de autenticação, as camadas de IU e API são fisicamente separadas.
{{ end }}
````
Você também pode usar variáveis em um texto, adicionando o sufixo **_Value** à sua chave:
```txt
Este documento pressupõe que você prefere usar **{{ UI_Value }}** como o framework de IU e **{{ DB_Value }}** como o provedor de banco de dados.
```
Além disso, as chaves **Document_Language_Code** e **Document_Version** são predefinidas se você quiser obter o código do idioma ou a versão do documento atual (isso pode ser útil para criar links que redirecionam para outro sistema de documentação em outro domínio).
------
**AVISO IMPORTANTE**: O Scriban usa "{{" e "}}" para a sintaxe. Portanto, você deve usar blocos de escape se for usá-los em seu documento (um documento Angular, por exemplo). Consulte a [documentação do Scriban](https://github.com/lunet-io/scriban/blob/master/doc/language.md#13-escape-block) para obter mais informações.
### 8- Criando o Documento de Navegação
O documento de navegação é o menu principal da página de documentos. Ele está localizado no lado esquerdo da página. É um arquivo `JSON`. Dê uma olhada no exemplo de documento de navegação abaixo para entender a estrutura.
```json
{
"items":[
{
"text":"Item de Menu de Exemplo - 1",
"items":[
{
"text":"Item de Menu de Exemplo - 1.1",
"items":[
{
"text":"Item de Menu de Exemplo - 1.1.1",
"path":"SampleMenuItem_1_1_1.md"
}
]
},
{
"text":"Item de Menu de Exemplo - 1.2",
"items":[
{
"text":"Item de Menu de Exemplo - 1.2.1",
"path":"SampleMenuItem_1_2_1.md"
},
{
"text":"Item de Menu de Exemplo - 1.2.2",
"path":"SampleMenuItem_1_2_2.md"
}
]
}
]
},
{
"text":"Item de Menu de Exemplo - 2",
"items":[
{
"text":"Item de Menu de Exemplo - 2.1",
"items":[
{
"text":"Item de Menu de Exemplo - 2.1.1",
"path":"SampleMenuItem_2_1_1.md"
}
]
}
]
}
]
}
```
O exemplo acima de arquivo `JSON` renderiza o menu de navegação abaixo como `HTML`.
![Menu de navegação](../images/docs-module_download-sample-navigation-menu.png)
Finalmente, um novo Módulo de Documentação é adicionado ao seu projeto, que é alimentado pelo GitHub.
## Pesquisa de Texto Completo (Elastic Search)
O módulo de documentação suporta pesquisa de texto completo usando o Elastic Search. Ele não está habilitado por padrão. Você pode configurar `DocsElasticSearchOptions` para habilitá-lo.
```csharp
Configure<DocsElasticSearchOptions>(options =>
{
options.Enable = true;
options.IndexName = "your_index_name"; //o nome do índice padrão é abp_documents
});
```
O `Índice` é criado automaticamente após o início da aplicação se o `Índice` não existir.
`DefaultElasticClientProvider` é responsável por criar `IElasticClient`. Por padrão, ele lê a `Url` do Elastic Search da `IConfiguration`.
Se o seu `IElasticClient` precisar de configurações adicionais, use a substituição do serviço `IElasticClientProvider` e substitua-o no sistema de [injeção de dependência](../Dependency-Injection.md).
```json
{
"ElasticSearch": {
"Url": "http://localhost:9200"
}
}
```
## Destacando Linhas
Você pode aplicar destaque a linhas de código específicas ou a um intervalo de linhas sequenciais.
Veja os exemplos a seguir:
```
```C# {3, 5}
public class Book : Entity<Guid>
{
public string Name { get; set; }
public string Surname { get; set; }
}
```
```
```
```C# {2-4}
public class Book : Entity<Guid>
{
public string Name { get; set; }
public string Surname { get; set; }
}
```
```
```
```C# {1, 2-4}
public class Book : Entity<Guid>
{
public string Name { get; set; }
public string Surname { get; set; }
}
```
```
---
## Próximo
O Módulo de Documentação também está disponível como um aplicativo independente. Confira [VoloDocs](../Apps/VoloDocs).

105
docs/pt-BR/Modules/Feature-Management.md

@ -0,0 +1,105 @@
# Módulo de Gerenciamento de Recursos
O módulo de Gerenciamento de Recursos implementa a interface `IFeatureManagementStore` definida pelo [Sistema de Recursos](../Features.md).
> Este documento aborda apenas o módulo de gerenciamento de recursos que persiste os valores dos recursos em um banco de dados. Consulte o documento [recursos](../Features.md) para obter mais informações sobre o sistema de recursos.
## Como Instalar
Este módulo vem pré-instalado (como pacotes NuGet/NPM). Você pode continuar a usá-lo como pacote e obter atualizações facilmente, ou pode incluir seu código-fonte em sua solução (consulte o comando `get-source` [CLI](../CLI.md)) para desenvolver seu próprio módulo personalizado.
### O Código Fonte
O código-fonte deste módulo pode ser acessado [aqui](https://github.com/abpframework/abp/tree/dev/modules/feature-management). O código-fonte é licenciado com [MIT](https://choosealicense.com/licenses/mit/), portanto, você pode usá-lo e personalizá-lo livremente.
## Interface do Usuário
### Diálogo de Gerenciamento de Recursos
O módulo de gerenciamento de recursos fornece um diálogo reutilizável para gerenciar recursos relacionados a um objeto. Por exemplo, o [Módulo de Gerenciamento de Inquilinos](Tenant-Management.md) o utiliza para gerenciar os recursos dos inquilinos na página de Gerenciamento de Inquilinos.
![features-module-opening](../images/features-module-opening.png)
Quando você clica em *Ações* -> *Recursos* para um inquilino, o diálogo de gerenciamento de recursos é aberto. Uma captura de tela de exemplo deste diálogo com dois recursos definidos:
![features-modal](../images/features-modal.png)
Neste diálogo, você pode habilitar, desabilitar ou definir valores para os recursos de um inquilino.
## IFeatureManager
`IFeatureManager` é o serviço principal fornecido por este módulo. Ele é usado para ler e alterar os valores de configuração para os inquilinos em um aplicativo multi-inquilino. `IFeatureManager` é normalmente usado pelo *Diálogo de Gerenciamento de Recursos*. No entanto, você pode injetá-lo se precisar definir um valor de recurso.
> Se você apenas deseja ler os valores dos recursos, use o `IFeatureChecker` conforme explicado no documento [Recursos](../Features.md).
**Exemplo: Obter/definir o valor de um recurso para um inquilino**
````csharp
using System;
using System.Threading.Tasks;
using Volo.Abp.DependencyInjection;
using Volo.Abp.FeatureManagement;
namespace Demo
{
public class MyService : ITransientDependency
{
private readonly IFeatureManager _featureManager;
public MyService(IFeatureManager featureManager)
{
_featureManager = featureManager;
}
public async Task SetFeatureDemoAsync(Guid tenantId, string value)
{
await _featureManager
.SetForTenantAsync(tenantId, "Recurso1", value);
var currentValue = await _featureManager
.GetOrNullForTenantAsync("Recurso1", tenantId);
}
}
}
````
## Provedores de Gerenciamento de Recursos
O Módulo de Gerenciamento de Recursos é extensível, assim como o [sistema de recursos](../Features.md). Você pode estendê-lo definindo provedores de gerenciamento de recursos. Existem 3 provedores de gerenciamento de recursos pré-construídos registrados na seguinte ordem:
* `DefaultValueFeatureManagementProvider`: Obtém o valor do valor padrão da definição do recurso. Ele não pode definir o valor padrão, pois os valores padrão são codificados na definição do recurso.
* `EditionFeatureManagementProvider`: Obtém ou define os valores dos recursos para uma edição. A edição é um grupo de recursos atribuídos a inquilinos. O sistema de edição não foi implementado pelo módulo de Gerenciamento de Inquilinos. Você pode implementá-lo por conta própria ou adquirir o [Módulo SaaS](https://commercial.abp.io/modules/Volo.Saas) do ABP Commercial, que o implementa e também fornece mais recursos SaaS, como assinatura e pagamento.
* `TenantFeatureManagementProvider`: Obtém ou define os valores dos recursos para inquilinos.
`IFeatureManager` usa esses provedores nos métodos de obtenção/definição. Normalmente, cada provedor de gerenciamento de recursos define métodos de extensão no serviço `IFeatureManager` (como `SetForTenantAsync` definido pelo provedor de gerenciamento de recursos de inquilinos).
Se você deseja criar seu próprio provedor, implemente a interface `IFeatureManagementProvider` ou herde da classe base `FeatureManagementProvider`:
````csharp
public class CustomFeatureProvider : FeatureManagementProvider
{
public override string Name => "Custom";
public CustomFeatureProvider(IFeatureManagementStore store)
: base(store)
{
}
}
````
A classe base `FeatureManagementProvider` faz a implementação padrão (usando o `IFeatureManagementStore`) para você. Você pode substituir os métodos base conforme necessário. Todo provedor deve ter um nome exclusivo, que é `Custom` neste exemplo (mantenha-o curto, pois ele é salvo no banco de dados para cada registro de valor de recurso).
Depois de criar sua classe de provedor, você deve registrá-la usando a classe de opções `FeatureManagementOptions` [options class](../Options.md):
````csharp
Configure<FeatureManagementOptions>(options =>
{
options.Providers.Add<CustomFeatureProvider>();
});
````
A ordem dos provedores é importante. Os provedores são executados na ordem inversa. Isso significa que o `CustomFeatureProvider` é executado primeiro neste exemplo. Você pode inserir seu provedor em qualquer ordem na lista `Providers`.
## Veja também
* [Recursos](../Features.md)

321
docs/pt-BR/Modules/Identity.md

@ -0,0 +1,321 @@
# Módulo de Gerenciamento de Identidade
O módulo de identidade é usado para gerenciar funções, usuários e suas permissões, com base na biblioteca de identidade da Microsoft.
## Como instalar
Este módulo já vem pré-instalado (como pacotes NuGet/NPM). Você pode continuar a usá-lo como pacote e obter atualizações facilmente, ou pode incluir seu código-fonte em sua solução (consulte o comando `get-source` [CLI](../CLI.md)) para desenvolver seu próprio módulo personalizado.
### O Código-fonte
O código-fonte deste módulo pode ser acessado [aqui](https://github.com/abpframework/abp/tree/dev/modules/identity). O código-fonte é licenciado com [MIT](https://choosealicense.com/licenses/mit/), então você pode usá-lo e personalizá-lo livremente.
## Interface do Usuário
Este módulo fornece opções de interface do usuário [Blazor](../UI/Blazor/Overall.md), [Angular](../UI/Angular/Quick-Start.md) e [MVC / Razor Pages](../UI/AspNetCore/Overall.md).
### Itens do Menu
Este módulo adiciona um item de menu *Gerenciamento de Identidade* no menu *Administração*:
![identity-module-menu](../images/identity-module-menu.png)
Os itens do menu e as páginas relacionadas são autorizados. Isso significa que o usuário atual deve ter as permissões relacionadas para torná-los visíveis. A função `admin` (e os usuários com essa função - como o usuário `admin`) já possui essas permissões. Se você deseja habilitar permissões para outras funções/usuários, abra a caixa de diálogo *Permissões* na página *Funções* ou *Usuários* e marque as permissões conforme mostrado abaixo:
![identity-module-permissions](../images/identity-module-permissions.png)
Consulte o documento de [Autorização](../Authorization.md) para entender o sistema de permissões.
### Páginas
Esta seção apresenta as principais páginas fornecidas por este módulo.
#### Usuários
Esta página é usada para ver a lista de usuários. Você pode criar/editar e excluir usuários, atribuir usuários a funções.
![identity-module-users](../images/identity-module-users.png)
Um usuário pode ter zero ou mais funções. Os usuários herdam permissões de suas funções. Além disso, você pode atribuir permissões diretamente aos usuários (clicando no botão *Ações*, em seguida, selecionando *Permissões*).
#### Funções
As funções são usadas para agrupar permissões e atribuí-las aos usuários.
![identity-module-roles](../images/identity-module-roles.png)
Além do nome da função, existem duas propriedades de uma função:
* `Padrão`: Se uma função for marcada como "padrão", essa função será atribuída aos novos usuários por padrão quando eles se registrarem na aplicação (usando o [Módulo de Conta](Account.md)).
* `Público`: Uma função pública de um usuário pode ser vista por outros usuários na aplicação. Essa funcionalidade não tem uso no módulo de identidade, mas é fornecida como uma funcionalidade que você pode querer usar em sua própria aplicação.
## Outras Funcionalidades
Esta seção abrange algumas outras funcionalidades fornecidas por este módulo que não possuem páginas de interface do usuário.
### Unidades Organizacionais
As unidades organizacionais (OU) podem ser usadas para agrupar usuários e entidades de forma hierárquica.
#### Entidade Unidade Organizacional
Uma OU é representada pela entidade **UnidadeOrganizacional**. As propriedades fundamentais desta entidade são:
- **TenantId**: Id do locatário desta OU. Pode ser nulo para OUs do host.
- **ParentId**: Id da OU pai. Pode ser nulo se esta for uma OU raiz.
- **Código**: Um código de string hierárquico que é único para um locatário.
- **DisplayName**: Nome exibido da OU.
#### Árvore de Organização
Como uma OU pode ter um pai, todas as OUs de um locatário estão em uma estrutura de **árvore**. Existem algumas regras para esta árvore:
- Pode haver mais de uma raiz (onde o `ParentId` é `null`).
- Há um limite para a contagem de filhos de primeiro nível de uma OU (por causa do comprimento fixo da unidade de código OU explicado abaixo).
#### Código da OU
O código da OU é gerado automaticamente e mantido pelo serviço `GerenciadorUnidadeOrganizacional`. É uma string que se parece com isso:
"**00001.00042.00005**"
Este código pode ser usado para consultar facilmente o banco de dados para todos os filhos de uma OU (recursivamente). Existem algumas regras para este código (aplicadas automaticamente quando você usa o `GerenciadorUnidadeOrganizacional`):
- É **único** para um [locatário](../Multi-Tenancy.md).
- Todos os filhos da mesma OU têm códigos que **começam com o código da OU pai**.
- É de **comprimento fixo** e baseado no nível da OU na árvore, conforme mostrado no exemplo.
- Embora o código da OU seja único, ele pode ser **alterado** se você mover a OU relacionada.
Observe que você deve referenciar uma OU pelo Id, não pelo Código, porque o Código pode ser alterado posteriormente.
#### Gerenciador de Unidade Organizacional
A classe `GerenciadorUnidadeOrganizacional` pode ser [injetada](../Dependency-Injection.md) e usada para gerenciar OUs. Casos de uso comuns são:
- Criar, atualizar ou excluir uma OU
- Mover uma OU na árvore de OUs.
- Obter informações sobre a árvore de OUs e seus itens.
### Log de Segurança de Identidade
O sistema de log de segurança registra algumas operações ou alterações importantes em sua conta (como *login* e *alteração de senha*). Você também pode salvar o log de segurança, se necessário.
Você pode injetar e usar `GerenciadorLogSegurancaIdentidade` ou `IGerenciadorLogSeguranca` para gravar logs de segurança. Ele criará um objeto de log por padrão e preencherá alguns valores comuns, como `CreationTime`, `ClientIpAddress`, `BrowserInfo`, `usuário/locatário atual`, etc. Claro, você pode substituí-los.
```cs
await GerenciadorLogSegurancaIdentidade.SalvarAsync(new ContextoLogSegurancaIdentidade()
{
Identidade = "IdentityServer",
Ação = "AlterarSenha"
});
```
Configure `OpcoesLogSegurancaAbp` para fornecer o nome do aplicativo (no caso de você ter várias aplicações e desejar distinguir as aplicações nos logs) para o log ou desativar esse recurso.
```cs
Configure<OpcoesLogSegurancaAbp>(opcoes =>
{
opcoes.NomeAplicativo = "AbpSecurityTest";
});
```
## Opções
`OpcoesIdentidade` é a classe de [opções](../Options.md) padrão fornecida pela biblioteca de [identidade](https://docs.microsoft.com/en-us/aspnet/core/security/authentication/identity) da Microsoft. Portanto, você pode definir essas opções no método `ConfigureServices` da sua classe de [módulo](../Module-Development-Basics.md).
**Exemplo: Definir o comprimento mínimo necessário das senhas**
````csharp
Configure<OpcoesIdentidade>(opcoes =>
{
opcoes.Senha.ComprimentoMinimo = 5;
});
````
O ABP leva essas opções um passo adiante e permite que você as altere em tempo de execução usando o [sistema de configurações](../Settings.md). Você pode [injetar](../Dependency-Injection.md) `IGerenciadorConfiguracao` e usar um dos métodos `Set...` para alterar os valores das opções para um usuário, um locatário ou globalmente para todos os usuários.
**Exemplo: Alterar o comprimento mínimo necessário das senhas para o locatário atual**
````csharp
public class MeuServico : IDependencyTransient
{
private readonly IGerenciadorConfiguracao _gerenciadorConfiguracao;
public MeuServico(IGerenciadorConfiguracao gerenciadorConfiguracao)
{
_gerenciadorConfiguracao = gerenciadorConfiguracao;
}
public async Task AlterarComprimentoMinSenha(int comprimentoMin)
{
await _gerenciadorConfiguracao.DefinirParaLocatarioAtualAsync(
NomesConfiguracaoIdentidade.Senha.ComprimentoMinimo,
comprimentoMin.ToString()
);
}
}
````
A classe `NomesConfiguracaoIdentidade` (no namespace `Volo.Abp.Identity.Settings`) define constantes para os nomes das configurações.
## Eventos Distribuídos
Este módulo define os seguintes ETOs (Event Transfer Objects) para permitir que você se inscreva em alterações nas entidades do módulo;
* `UserEto` é publicado em alterações feitas em uma entidade `IdentityUser`.
* `IdentityRoleEto` é publicado em alterações feitas em uma entidade `IdentityRole`.
* `IdentityClaimTypeEto` é publicado em alterações feitas em uma entidade `IdentityClaimType`.
* `OrganizationUnitEto` é publicado em alterações feitas em uma entidade `OrganizationUnit`.
**Exemplo: Ser notificado quando um novo usuário for criado**
````csharp
public class MeuManipulador :
IManipuladorEventoDistribuido<EntityCreatedEto<UserEto>>,
IDependencyTransient
{
public async Task ManipularEventoAsync(EntityCreatedEto<UserEto> evento)
{
UserEto user = evento.Entity;
// TODO: ...
}
}
````
`UserEto` e `IdentityRoleEto` são configurados para publicar automaticamente os eventos. Você deve configurar você mesmo para os outros. Consulte o documento de [Distributed Event Bus](../Distributed-Event-Bus.md) para aprender detalhes dos eventos pré-definidos.
> A inscrição nos eventos distribuídos é especialmente útil para cenários distribuídos (como arquitetura de microsserviços). Se você está construindo uma aplicação monolítica ou ouvindo eventos no mesmo processo que executa o Módulo de Identidade, então a inscrição nos [eventos locais](../Local-Event-Bus.md) pode ser mais eficiente e fácil.
## Internos
Esta seção abrange alguns detalhes internos do módulo que você não precisa muito, mas pode precisar usar em alguns casos.
### Camada de Domínio
#### Agregados
##### Usuário
Um usuário é geralmente uma pessoa que faz login e usa a aplicação.
* `IdentityUser` (raiz do agregado): Representa um usuário no sistema.
* `IdentityUserRole` (coleção): Funções do usuário.
* `IdentityUserClaim` (coleção): Reivindicações personalizadas do usuário.
* `IdentityUserLogin` (coleção): Logins externos do usuário.
* `IdentityUserToken` (coleção): Tokens do usuário (usados pelos serviços de identidade da Microsoft).
##### Função
Uma função é tipicamente um grupo de permissões para atribuir aos usuários.
* `IdentityRole` (raiz do agregado): Representa uma função no sistema.
* `IdentityRoleClaim` (coleção): Reivindicações personalizadas da função.
##### Tipo de Reivindicação
Um tipo de reivindicação é uma definição de uma reivindicação personalizada que pode ser atribuída a outras entidades (como funções e usuários) no sistema.
* `IdentityClaimType` (raiz do agregado): Representa uma definição de tipo de reivindicação. Ele contém algumas propriedades (por exemplo, Obrigatório, Regex, Descrição, ValueType) para definir o tipo de reivindicação e as regras de validação.
##### Log de Segurança de Identidade
Um objeto `IdentitySecurityLog` representa uma operação relacionada à autenticação (como *login*) no sistema.
* `IdentitySecurityLog` (raiz do agregado): Representa um log de segurança no sistema.
##### Unidade Organizacional
Uma unidade organizacional é uma entidade em uma estrutura hierárquica.
* ```OrganizationUnit``` (raiz do agregado): Representa uma unidade organizacional no sistema.
* ```Roles``` (coleção): Funções da unidade organizacional.
#### Repositórios
Os seguintes repositórios personalizados são definidos para este módulo:
* `IIdentityUserRepository`
* `IIdentityRoleRepository`
* `IIdentityClaimTypeRepository`
* ```IIdentitySecurityLogRepository```
* ```IOrganizationUnitRepository```
#### Serviços de Domínio
##### Gerenciador de Usuário
`IdentityUserManager` é usado para gerenciar usuários, suas funções, reivindicações, senhas, e-mails, etc. Ele é derivado da classe `UserManager<T>` da Microsoft Identity, onde `T` é `IdentityUser`.
##### Gerenciador de Função
`IdentityRoleManager` é usado para gerenciar funções e suas reivindicações. Ele é derivado da classe `RoleManager<T>` da Microsoft Identity, onde `T` é `IdentityRole`.
##### Gerenciador de Tipo de Reivindicação
`IdenityClaimTypeManager` é usado para realizar algumas operações para a raiz do agregado `IdentityClaimType`.
##### Gerenciador de Unidade Organizacional
```OrganizationUnitManager``` é usado para realizar algumas operações para a raiz do agregado ```OrganizationUnit```.
##### Gerenciador de Log de Segurança
```IdentitySecurityLogManager``` é usado para salvar logs de segurança.
### Camada de Aplicação
#### Serviços de Aplicação
* `IdentityUserAppService` (implementa `IIdentityUserAppService`): Implementa os casos de uso da interface do usuário de gerenciamento de usuários.
* `IdentityRoleAppService` (implementa `IIdentityRoleAppService`): Implementa os casos de uso da interface do usuário de gerenciamento de funções.
* `IdentityClaimTypeAppService` (implementa `IIdentityClaimTypeAppService`): Implementa os casos de uso da interface do usuário de gerenciamento de tipos de reivindicação.
* `IdentitySettingsAppService` (implementa `IIdentitySettingsAppService`): Usado para obter e atualizar configurações para o módulo de identidade.
* `IdentityUserLookupAppService` (implementa `IIdentityUserLookupAppService`): Usado para obter informações de um usuário por `id` ou `userName`. É destinado a ser usado internamente pelo framework ABP.
* `ProfileAppService` (implementa `IProfileAppService`): Usado para alterar o perfil de um usuário e a senha.
* ```IdentitySecurityLogAppService``` (implementa ```IIdentitySecurityLogAppService```): Implementa os casos de uso da interface do usuário de logs de segurança.
* ```OrganizationUnitAppService``` (implementa ```OrganizationUnitAppService```): Implementa os casos de uso da interface do usuário de gerenciamento de unidades organizacionais.
### Provedores de Banco de Dados
Este módulo fornece opções de [Entity Framework Core](../Entity-Framework-Core.md) e [MongoDB](../MongoDB.md) para o banco de dados.
#### Entity Framework Core
O pacote NuGet [Volo.Abp.Identity.EntityFrameworkCore](https://www.nuget.org/packages/Volo.Abp.Identity.EntityFrameworkCore) implementa a integração do EF Core.
##### Tabelas do Banco de Dados
* **AbpRoles**
* AbpRoleClaims
* **AbpUsers**
* AbpUserClaims
* AbpUserLogins
* AbpUserRoles
* AbpUserTokens
* **AbpClaimTypes**
* **AbpOrganizationUnits**
* AbpOrganizationUnitRoles
* AbpUserOrganizationUnits
* **AbpSecurityLogs**
#### MongoDB
O pacote NuGet [Volo.Abp.Identity.MongoDB](https://www.nuget.org/packages/Volo.Abp.Identity.MongoDB) implementa a integração do MongoDB.
##### Coleções do Banco de Dados
* **AbpRoles**
* **AbpUsers**
* **AbpClaimTypes**
* **AbpOrganizationUnits**
* **AbpSecurityLogs**
#### Propriedades Comuns do Banco de Dados
Você pode definir as seguintes propriedades da classe `AbpIdentityDbProperties` para alterar as opções do banco de dados:
* `DbTablePrefix` (`Abp` por padrão) é o prefixo para os nomes das tabelas/coleções.
* `DbSchema` (`null` por padrão) é o esquema do banco de dados.
* `ConnectionStringName` (`AbpIdentity` por padrão) é o nome da [string de conexão](../Connection-Strings.md) para este módulo.
Essas são propriedades estáticas. Se você quiser definir, faça isso no início de sua aplicação (normalmente, em `Program.cs`).

175
docs/pt-BR/Modules/IdentityServer.md

@ -0,0 +1,175 @@
# Módulo IdentityServer
O módulo IdentityServer fornece uma integração completa com o framework [IdentityServer4](https://github.com/IdentityServer/IdentityServer4) (IDS), que oferece recursos avançados de autenticação, como logon único e controle de acesso a API. Este módulo persiste clientes, recursos e outros objetos relacionados ao IDS no banco de dados. **Este módulo foi substituído pelo** [módulo OpenIddict](https://docs.abp.io/en/abp/latest/Modules/OpenIddict) após o ABP v6.0 nos modelos de inicialização.
> Observação: Você não pode usar os módulos IdentityServer e OpenIddict juntos. Eles são bibliotecas separadas de provedor OpenID para a mesma função.
## Como instalar
Você não precisa deste módulo quando estiver usando o módulo OpenIddict. No entanto, se você deseja continuar usando o IdentityServer4 para suas aplicações, você pode instalar este módulo e remover o módulo OpenIddict. Você pode continuar a usá-lo como pacote e obter atualizações facilmente, ou pode incluir seu código-fonte em sua solução (consulte o comando `get-source` [CLI](../CLI.md)) para desenvolver seu módulo personalizado.
### O código-fonte
O código-fonte deste módulo pode ser acessado [aqui](https://github.com/abpframework/abp/tree/dev/modules/identityserver). O código-fonte é licenciado com [MIT](https://choosealicense.com/licenses/mit/), então você pode usá-lo e personalizá-lo livremente.
## Interface do usuário
Este módulo implementa a lógica de domínio e as integrações com o banco de dados, mas não fornece nenhuma interface do usuário. A interface de gerenciamento é útil se você precisar adicionar clientes e recursos dinamicamente. Nesse caso, você pode construir a interface de gerenciamento por conta própria ou considerar a compra do [ABP Commercial](https://commercial.abp.io/), que fornece a interface de gerenciamento para este módulo.
## Relações com outros módulos
Este módulo é baseado no [módulo Identity](Identity.md) e possui um [pacote de integração](https://www.nuget.org/packages/Volo.Abp.Account.Web.IdentityServer) com o [módulo Account](Account.md).
## Opções
### AbpIdentityServerBuilderOptions
`AbpIdentityServerBuilderOptions` pode ser configurado no método `PreConfigureServices` do seu [módulo](https://docs.abp.io/en/abp/latest/Module-Development-Basics) do Identity Server. Exemplo:
````csharp
public override void PreConfigureServices(ServiceConfigurationContext context)
{
PreConfigure<AbpIdentityServerBuilderOptions>(builder =>
{
// Defina as opções aqui...
});
}
````
Propriedades de `AbpIdentityServerBuilderOptions`:
* `UpdateJwtSecurityTokenHandlerDefaultInboundClaimTypeMap` (padrão: true): Atualiza `JwtSecurityTokenHandler.DefaultInboundClaimTypeMap` para ser compatível com as reivindicações do Identity Server.
* `UpdateAbpClaimTypes` (padrão: true): Atualiza `AbpClaimTypes` para ser compatível com as reivindicações do Identity Server.
* `IntegrateToAspNetIdentity` (padrão: true): Integra ao ASP.NET Identity.
* `AddDeveloperSigningCredential` (padrão: true): Defina como false para suprimir a chamada AddDeveloperSigningCredential() no IIdentityServerBuilder.
`IIdentityServerBuilder` pode ser configurado no método `PreConfigureServices` do seu [módulo](https://docs.abp.io/en/abp/latest/Module-Development-Basics) do Identity Server. Exemplo:
````csharp
public override void PreConfigureServices(ServiceConfigurationContext context)
{
PreConfigure<IIdentityServerBuilder>(builder =>
{
builder.AddSigningCredential(...);
});
}
````
## Internos
### Camada de Domínio
#### Agregados
##### ApiResource
Os recursos da API são necessários para permitir que os clientes solicitem tokens de acesso.
* `ApiResource` (raiz do agregado): Representa um recurso da API no sistema.
* `ApiSecret` (coleção): segredos do recurso da API.
* `ApiScope` (coleção): escopos do recurso da API.
* `ApiResourceClaim` (coleção): reivindicações do recurso da API.
##### Client
Os clientes representam aplicativos que podem solicitar tokens do seu Identity Server.
* `Client` (raiz do agregado): Representa um aplicativo cliente do Identity Server.
* `ClientScope` (coleção): Escopos do cliente.
* `ClientSecret` (coleção): Segredos do cliente.
* `ClientGrantType` (coleção): Tipos de concessão do cliente.
* `ClientCorsOrigin` (coleção): Origens CORS do cliente.
* `ClientRedirectUri` (coleção): URIs de redirecionamento do cliente.
* `ClientPostLogoutRedirectUri` (coleção): URIs de redirecionamento de logout do cliente.
* `ClientIdPRestriction` (coleção): Restrições de provedor do cliente.
* `ClientClaim` (coleção): Reivindicações do cliente.
* `ClientProperty` (coleção): Propriedades personalizadas do cliente.
##### PersistedGrant
Persisted Grants armazena AuthorizationCodes, RefreshTokens e UserConsent.
* `PersistedGrant` (raiz do agregado): Representa um PersistedGrant para o servidor de identidade.
##### IdentityResource
Os recursos de identidade são dados como ID do usuário, nome ou endereço de e-mail de um usuário.
* `IdentityResource` (raiz do agregado): Representa um recurso de identidade do Identity Server.
* `IdentityClaim` (coleção): Reivindicações do recurso de identidade.
#### Repositórios
Os seguintes repositórios personalizados são definidos para este módulo:
* `IApiResourceRepository`
* `IClientRepository`
* `IPersistentGrantRepository`
* `IIdentityResourceRepository`
#### Serviços de Domínio
Este módulo não contém nenhum serviço de domínio, mas substitui os serviços abaixo;
* `AbpProfileService` (Usado quando `AbpIdentityServerBuilderOptions.IntegrateToAspNetIdentity` é true)
* `AbpClaimsService`
* `AbpCorsPolicyService`
### Configurações
Este módulo não define nenhuma configuração.
### Camada de Aplicação
#### Serviços de Aplicação
* `ApiResourceAppService` (implementa `IApiResourceAppService`): Implementa os casos de uso da interface de gerenciamento de recursos da API.
* `IdentityServerClaimTypeAppService` (implementa `IIdentityServerClaimTypeAppService`): Usado para obter a lista de reivindicações.
* `ApiResourceAppService` (implementa `IApiResourceAppService`): Implementa os casos de uso da interface de gerenciamento de recursos da API.
* `IdentityResourceAppService` (implementa `IIdentityResourceAppService`): Implementa os casos de uso da interface de gerenciamento de recursos de identidade.
### Provedores de Banco de Dados
#### Comum
##### Prefixo de Tabela/Collection e Esquema
Todas as tabelas/collections usam o prefixo `IdentityServer` por padrão. Defina as propriedades estáticas na classe `AbpIdentityServerDbProperties` se você precisar alterar o prefixo da tabela ou definir um nome de esquema (se suportado pelo seu provedor de banco de dados).
##### String de Conexão
Este módulo usa `AbpIdentityServer` como nome da string de conexão. Se você não definir uma string de conexão com esse nome, ela será usada a string de conexão `Default`.
Consulte a documentação sobre [strings de conexão](https://docs.abp.io/en/abp/latest/Connection-Strings) para obter mais detalhes.
#### Entity Framework Core
##### Tabelas
* **IdentityServerApiResources**
* IdentityServerApiSecrets
* IdentityServerApiScopes
* IdentityServerApiScopeClaims
* IdentityServerApiClaims
* **IdentityServerClients**
* IdentityServerClientScopes
* IdentityServerClientSecrets
* IdentityServerClientGrantTypes
* IdentityServerClientCorsOrigins
* IdentityServerClientRedirectUris
* IdentityServerClientPostLogoutRedirectUris
* IdentityServerClientIdPRestrictions
* IdentityServerClientClaims
* IdentityServerClientProperties
* **IdentityServerPersistedGrants**
* **IdentityServerIdentityResources**
* IdentityServerIdentityClaims
#### MongoDB
##### Coleções
* **IdentityServerApiResources**
* **IdentityServerClients**
* **IdentityServerPersistedGrants**
* **IdentityServerIdentityResources**

32
docs/pt-BR/Modules/Index.md

@ -0,0 +1,32 @@
# Módulos de Aplicação
ABP é um **framework de aplicação modular** que consiste em dezenas de **pacotes NuGet & NPM**. Ele também fornece uma infraestrutura completa para construir seus próprios módulos de aplicação, que podem ter entidades, serviços, integração de banco de dados, APIs, componentes de interface do usuário, entre outros.
Existem **dois tipos de módulos**. Eles não têm nenhuma diferença estrutural, mas são categorizados por funcionalidade e propósito:
* [**Módulos do framework**](https://github.com/abpframework/abp/tree/dev/framework/src): Estes são **módulos principais do framework** como cache, envio de e-mails, temas, segurança, serialização, validação, integração com o EF Core, integração com o MongoDB... etc. Eles não possuem funcionalidades de aplicação/negócio, mas facilitam o desenvolvimento diário fornecendo infraestrutura comum, integração e abstrações.
* [**Módulos de aplicação**](https://github.com/abpframework/abp/tree/dev/modules): Esses módulos implementam funcionalidades específicas de aplicação/negócio, como blogs, gerenciamento de documentos, gerenciamento de identidade, gerenciamento de locatários... etc. Eles geralmente possuem suas próprias entidades, serviços, APIs e componentes de interface do usuário.
## Módulos de Aplicação de Código Aberto
Existem alguns módulos de aplicação **gratuitos e de código aberto** desenvolvidos e mantidos como parte do ABP Framework.
* [**Conta**](Account.md): Fornece uma interface de usuário para o gerenciamento de contas e permite que o usuário faça login/registo na aplicação.
* [**Registro de Auditoria**](Audit-Logging.md): Persiste registros de auditoria em um banco de dados.
* [**Trabalhos em Segundo Plano**](Background-Jobs.md): Persiste trabalhos em segundo plano ao usar o gerenciador de trabalhos em segundo plano padrão.
* [**Kit CMS**](Cms-Kit/Index.md): Um conjunto de recursos reutilizáveis de *Sistema de Gerenciamento de Conteúdo*.
* [**Documentação**](Docs.md): Usado para criar um site de documentação técnica. A própria documentação do ABP já utiliza este módulo.
* [**Gerenciamento de Recursos**](Feature-Management.md): Usado para persistir e gerenciar os [recursos](../Features.md).
* **[Identidade](Identity.md)**: Gerencia unidades organizacionais, funções, usuários e suas permissões, com base na biblioteca Microsoft Identity.
* [**IdentityServer**](IdentityServer.md): Integra-se ao IdentityServer4.
* [**OpenIddict**](OpenIddict.md): Integra-se ao OpenIddict.
* [**Gerenciamento de Permissões**](Permission-Management.md): Usado para persistir permissões.
* **[Gerenciamento de Configurações](Setting-Management.md)**: Usado para persistir e gerenciar as [configurações](../Settings.md).
* [**Gerenciamento de Locatários**](Tenant-Management.md): Gerencia locatários para uma aplicação [multi-locatário](../Multi-Tenancy.md).
* [**Explorador de Arquivos Virtuais**](Virtual-File-Explorer.md): Fornece uma interface de usuário simples para visualizar arquivos em um [sistema de arquivos virtual](../Virtual-File-System.md).
Veja [o repositório do GitHub](https://github.com/abpframework/abp/tree/dev/modules) para o código-fonte de todos os módulos.
## Módulos de Aplicação Comerciais
A licença [ABP Commercial](https://commercial.abp.io/) fornece **módulos de aplicação pré-construídos adicionais** em cima do framework ABP. Veja a [lista de módulos](https://commercial.abp.io/modules) fornecida pelo ABP Commercial.

514
docs/pt-BR/Modules/OpenIddict.md

@ -0,0 +1,514 @@
## Módulo ABP OpenIddict
O módulo OpenIddict fornece uma integração com o [OpenIddict](https://github.com/openiddict/openiddict-core), que oferece recursos avançados de autenticação, como logon único, logoff único e controle de acesso à API. Este módulo persiste aplicativos, escopos e outros objetos relacionados ao OpenIddict no banco de dados.
## Como instalar
Este módulo já vem pré-instalado (como pacotes NuGet/NPM). Você pode continuar a usá-lo como um pacote e obter atualizações facilmente, ou pode incluir seu código-fonte em sua solução (consulte o comando `get-source` [CLI](../CLI.md)) para desenvolver seu próprio módulo personalizado.
### O código-fonte
O código-fonte deste módulo pode ser acessado [aqui](https://github.com/abpframework/abp/tree/dev/modules/openiddict). O código-fonte é licenciado pela [MIT](https://choosealicense.com/licenses/mit/), portanto, você pode usá-lo e personalizá-lo livremente.
## Interface do usuário
Este módulo implementa a lógica de domínio e as integrações com o banco de dados, mas não fornece nenhuma interface do usuário. A interface de gerenciamento é útil se você precisar adicionar aplicativos e escopos dinamicamente. Nesse caso, você pode construir a interface de gerenciamento por conta própria ou considerar a compra do [ABP Commercial](https://commercial.abp.io/), que fornece a interface de gerenciamento para este módulo.
## Relações com outros módulos
Este módulo é baseado no [Módulo de Identidade](Identity.md) e possui um [pacote de integração](https://www.nuget.org/packages/Volo.Abp.Account.Web.OpenIddict) com o [Módulo de Conta](Account.md).
## Opções
### OpenIddictBuilder
O `OpenIddictBuilder` pode ser configurado no método `PreConfigureServices` do seu [módulo](https://docs.abp.io/en/abp/latest/Module-Development-Basics) OpenIddict.
Exemplo:
```csharp
public override void PreConfigureServices(ServiceConfigurationContext context)
{
PreConfigure<OpenIddictBuilder>(builder =>
{
// Defina as opções aqui...
});
}
```
O `OpenIddictBuilder` contém vários métodos de extensão para configurar os serviços do OpenIddict:
- `AddServer()` registra os serviços do servidor de token OpenIddict no contêiner de DI. Contém as configurações do `OpenIddictServerBuilder`.
- `AddCore()` registra os serviços principais do OpenIddict no contêiner de DI. Contém as configurações do `OpenIddictCoreBuilder`.
- `AddValidation()` registra os serviços de validação de token OpenIddict no contêiner de DI. Contém as configurações do `OpenIddictValidationBuilder`.
### OpenIddictCoreBuilder
O `OpenIddictCoreBuilder` contém métodos de extensão para configurar os serviços principais do OpenIddict.
Exemplo:
```csharp
public override void PreConfigureServices(ServiceConfigurationContext context)
{
PreConfigure<OpenIddictCoreBuilder>(builder =>
{
// Defina as opções aqui...
});
}
```
Esses serviços contêm:
- Adição de `ApplicationStore`, `AuthorizationStore`, `ScopeStore`, `TokenStore`.
- Substituição de `ApplicationManager`, `AuthorizationManager`, `ScopeManager`, `TokenManager`.
- Substituição de `ApplicationStoreResolver`, `AuthorizationStoreResolver`, `ScopeStoreResolver`, `TokenStoreResolver`.
- Definição de `DefaultApplicationEntity`, `DefaultAuthorizationEntity`, `DefaultScopeEntity`, `DefaultTokenEntity`.
### OpenIddictServerBuilder
O `OpenIddictServerBuilder` contém métodos de extensão para configurar os serviços do servidor OpenIddict.
Exemplo:
```csharp
public override void PreConfigureServices(ServiceConfigurationContext context)
{
PreConfigure<OpenIddictServerBuilder>(builder =>
{
// Defina as opções aqui...
});
}
```
Esses serviços contêm:
- Registro de claims, escopos.
- Definição do URI `Issuer` que é usado como endereço base para os URIs de endpoint retornados pelo endpoint de descoberta.
- Adição de chaves de assinatura de desenvolvimento, chaves de criptografia/assinatura, credenciais e certificados.
- Adição/remoção de manipuladores de eventos.
- Habilitação/desabilitação de tipos de concessão.
- Definição de URIs de endpoint do servidor de autenticação.
### OpenIddictValidationBuilder
O `OpenIddictValidationBuilder` contém métodos de extensão para configurar os serviços de validação do OpenIddict.
Exemplo:
```csharp
public override void PreConfigureServices(ServiceConfigurationContext context)
{
PreConfigure<OpenIddictValidationBuilder>(builder =>
{
// Defina as opções aqui...
});
}
```
Esses serviços contêm:
- `AddAudiences()` para servidores de recursos.
- `SetIssuer()` define o URI usado para determinar a localização real do documento de configuração do OAuth 2.0/OpenID Connect ao usar a descoberta do provedor.
- `SetConfiguration()` para configurar `OpenIdConnectConfiguration`.
- `UseIntrospection()` para usar a introspecção em vez da validação local/direta.
- Adição de chave de criptografia, credenciais e certificados.
- Adição/remoção de manipuladores de eventos.
- `SetClientId()` para definir o identificador do cliente `client_id` ao se comunicar com o servidor de autorização remoto (por exemplo, para introspecção).
- `SetClientSecret()` para definir o identificador `client_secret` ao se comunicar com o servidor de autorização remoto (por exemplo, para introspecção).
- `EnableAuthorizationEntryValidation()` para habilitar a validação de autorização para garantir que o `access token` ainda seja válido fazendo uma chamada ao banco de dados para cada solicitação da API. *Observação:* Isso pode ter um impacto negativo no desempenho e só pode ser usado com um servidor de autorização baseado no OpenIddict.
- `EnableTokenEntryValidation()` para habilitar a validação de autorização para garantir que o `access token` ainda seja válido fazendo uma chamada ao banco de dados para cada solicitação da API. *Observação:* Isso pode ter um impacto negativo no desempenho e é necessário quando o servidor OpenIddict está configurado para usar tokens de referência.
- `UseLocalServer()` para registrar os serviços de integração de validação/servidor OpenIddict.
- `UseAspNetCore()` para registrar os serviços de validação do OpenIddict para o ASP.NET Core no contêiner de DI.
## Internos
### Camada de Domínio
#### Agregados
##### OpenIddictApplication
OpenIddictApplications representam os aplicativos que podem solicitar tokens do seu servidor OpenIddict.
- `OpenIddictApplications` (raiz do agregado): Representa um aplicativo OpenIddict.
- `ClientId` (string): O identificador do cliente associado ao aplicativo atual.
- `ClientSecret` (string): O segredo do cliente associado ao aplicativo atual. Pode ser criptografado ou hash para fins de segurança.
- `ConsentType` (string): O tipo de consentimento associado ao aplicativo atual.
- `DisplayName` (string): O nome de exibição associado ao aplicativo atual.
- `DisplayNames` (string): Os nomes de exibição localizados associados ao aplicativo atual serializados como um objeto JSON.
- `Permissions` (string): As permissões associadas ao aplicativo atual, serializadas como um array JSON.
- `PostLogoutRedirectUris` (string): As URLs de retorno de chamada de logoff associadas ao aplicativo atual, serializadas como um array JSON.
- `Properties` (string): As propriedades adicionais associadas ao aplicativo atual serializadas como um objeto JSON ou nulo.
- `RedirectUris` (string): As URLs de retorno de chamada associadas ao aplicativo atual, serializadas como um array JSON.
- `Requirements` (string): Os requisitos associados ao aplicativo atual.
- `Type` (string): O tipo de aplicativo associado ao aplicativo atual.
- `ClientUri` (string): URI para obter mais informações sobre o cliente.
- `LogoUri` (string): URI para o logotipo do cliente.
##### OpenIddictAuthorization
OpenIddictAuthorizations são usadas para manter os escopos permitidos e os tipos de fluxo de autorização.
- `OpenIddictAuthorization` (raiz do agregado): Representa uma autorização OpenIddict.
- `ApplicationId` (Guid?): O aplicativo associado à autorização atual.
- `Properties` (string): As propriedades adicionais associadas à autorização atual serializadas como um objeto JSON ou nulo.
- `Scopes` (string): Os escopos associados à autorização atual, serializados como um array JSON.
- `Status` (string): O status da autorização atual.
- `Subject` (string): O assunto associado à autorização atual.
- `Type` (string): O tipo da autorização atual.
##### OpenIddictScope
OpenIddictScopes são usados para manter os escopos dos recursos.
- `OpenIddictScope` (raiz do agregado): Representa um escopo OpenIddict.
- `Description` (string): A descrição pública associada ao escopo atual.
- `Descriptions` (string): As descrições públicas localizadas associadas ao escopo atual, serializadas como um objeto JSON.
- `DisplayName` (string): O nome de exibição associado ao escopo atual.
- `DisplayNames` (string): Os nomes de exibição localizados associados ao escopo atual serializados como um objeto JSON.
- `Name` (string): O nome único associado ao escopo atual.
- `Properties` (string): As propriedades adicionais associadas ao escopo atual serializadas como um objeto JSON ou nulo.
- `Resources` (string): Os recursos associados ao escopo atual, serializados como um array JSON.
##### OpenIddictToken
OpenIddictTokens são usados para persistir os tokens do aplicativo.
- `OpenIddictToken` (raiz do agregado): Representa um token OpenIddict.
- `ApplicationId` (Guid?): O aplicativo associado ao token atual.
- `AuthorizationId` (Guid?): A autorização associada ao token atual.
- `CreationDate` (DateTime?): A data de criação UTC do token atual.
- `ExpirationDate` (DateTime?): A data de expiração UTC do token atual.
- `Payload` (string): O payload do token atual, se aplicável. Usado apenas para tokens de referência e pode ser criptografado por motivos de segurança.
- `Properties` (string): As propriedades adicionais associadas ao token atual serializadas como um objeto JSON ou nulo.
- `RedemptionDate` (DateTime?): A data de resgate UTC do token atual.
- `Status` (string): O status da autorização atual.
- `ReferenceId` (string): O identificador de referência associado ao token atual, se aplicável. Usado apenas para tokens de referência e pode ser criptografado ou hash por motivos de segurança.
- `Status` (string): O status do token atual.
- `Subject` (string): O assunto associado ao token atual.
- `Type` (string): O tipo do token atual.
#### Armazenamentos
Este módulo implementa os armazenamentos do OpenIddict:
- `IAbpOpenIdApplicationStore`
- `IOpenIddictAuthorizationStore`
- `IOpenIddictScopeStore`
- `IOpenIddictTokenStore`
#### AbpOpenIddictStoreOptions
Você pode configurar o `PruneIsolationLevel/DeleteIsolationLevel` do `AbpOpenIddictStoreOptions` para definir o nível de isolamento para as operações de armazenamento, pois diferentes bancos de dados têm diferentes níveis de isolamento.
##### Repositórios
Os seguintes repositórios personalizados são definidos neste módulo:
- `IOpenIddictApplicationRepository`
- `IOpenIddictAuthorizationRepository`
- `IOpenIddictScopeRepository`
- `IOpenIddictTokenRepository`
##### Serviços de Domínio
Este módulo não contém nenhum serviço de domínio, mas substitui o serviço abaixo:
- `AbpApplicationManager` usado para popular/obter informações do `AbpApplicationDescriptor` que contém `ClientUri` e `LogoUri`.
### Provedores de Banco de Dados
#### Comum
##### Prefixo de Tabela/Collection e Esquema
Todas as tabelas/collections usam o prefixo `OpenIddict` por padrão. Defina as propriedades estáticas na classe `AbpOpenIddictDbProperties` se você precisar alterar o prefixo da tabela ou definir um nome de esquema (se suportado pelo seu provedor de banco de dados).
##### String de Conexão
Este módulo usa `AbpOpenIddict` como nome da string de conexão. Se você não definir uma string de conexão com esse nome, ela será usada a string de conexão `Default`.
Consulte a documentação sobre [strings de conexão](https://docs.abp.io/en/abp/latest/Connection-Strings) para obter detalhes.
#### Entity Framework Core
##### Tabelas
- **OpenIddictApplications**
- **OpenIddictAuthorizations**
- **OpenIddictScopes**
- **OpenIddictTokens**
#### MongoDB
##### Coleções
- **OpenIddictApplications**
- **OpenIddictAuthorizations**
- **OpenIddictScopes**
- **OpenIddictTokens**
## Módulo ASP.NET Core
Este módulo integra o ASP.NET Core, com controladores MVC embutidos para quatro protocolos. Ele usa o modo de passagem do OpenIddict [Pass-through mode](https://documentation.openiddict.com/guides/index.html#pass-through-mode).
```cs
AuthorizeController -> connect/authorize
TokenController -> connect/token
LogoutController -> connect/logout
UserInfoController -> connect/userinfo
```
> A implementação do **fluxo de dispositivo** será feita no módulo comercial.
#### AbpOpenIddictAspNetCoreOptions
`AbpOpenIddictAspNetCoreOptions` pode ser configurado no método `PreConfigureServices` do seu [módulo](https://docs.abp.io/en/abp/latest/Module-Development-Basics) OpenIddict.
Exemplo:
```csharp
PreConfigure<AbpOpenIddictAspNetCoreOptions>(options =>
{
// Defina as opções aqui...
});
```
Propriedades do `AbpOpenIddictAspNetCoreOptions`:
- `UpdateAbpClaimTypes(default: true)`: Atualiza `AbpClaimTypes` para ser compatível com as reivindicações do Openiddict.
- `AddDevelopmentEncryptionAndSigningCertificate(default: true)`: Registra (e gera, se necessário) um certificado de criptografia/assinatura de desenvolvimento específico do usuário. Este é um certificado usado para assinar e criptografar os tokens e apenas para **ambiente de desenvolvimento**. Você deve defini-lo como **false** para ambientes não de desenvolvimento.
> `AddDevelopmentEncryptionAndSigningCertificate` não pode ser usado em aplicativos implantados no IIS ou no Azure App Service: tentar usá-los no IIS ou no Azure App Service resultará em uma exceção lançada em tempo de execução (a menos que o pool de aplicativos esteja configurado para carregar um perfil de usuário). Para evitar isso, considere criar certificados autoassinados e armazená-los no repositório de certificados X.509 da(s) máquina(s) host. Consulte: https://documentation.openiddict.com/configuration/encryption-and-signing-credentials.html#registering-a-development-certificate
#### Removendo automaticamente Tokens/Autorizações Órfãs
A tarefa em segundo plano que remove automaticamente tokens/autorizações órfãs pode ser configurada por `TokenCleanupOptions`.
`TokenCleanupOptions` pode ser configurado no método `ConfigureServices` do seu [módulo](https://docs.abp.io/en/abp/latest/Module-Development-Basics) OpenIddict.
Exemplo:
```csharp
Configure<TokenCleanupOptions>(options =>
{
// Defina as opções aqui...
});
```
Propriedades do `TokenCleanupOptions`:
- `IsCleanupEnabled` (padrão: true): Habilita/desabilita a limpeza de token.
- `CleanupPeriod` (padrão: 3.600.000 ms): Define o período de limpeza.
- `DisableAuthorizationPruning`: Define um booleano indicando se a poda de autorizações deve ser desabilitada.
- `DisableTokenPruning`: Define um booleano indicando se a poda de tokens deve ser desabilitada.
- `MinimumAuthorizationLifespan` (padrão: 14 dias): Define a vida útil mínima que as autorizações devem ter para serem podadas. Não pode ser inferior a 10 minutos.
- `MinimumTokenLifespan` (padrão: 14 dias): Define a vida útil mínima que os tokens devem ter para serem podados. Não pode ser inferior a 10 minutos.
#### Atualizando Reivindicações em Access_token e Id_token
[Claims Principal Factory](https://docs.abp.io/en/abp/latest/Authorization#claims-principal-factory) pode ser usado para adicionar/remover reivindicações ao `ClaimsPrincipal`.
O serviço `AbpDefaultOpenIddictClaimsPrincipalHandler` adicionará tipos de reivindicações `Name`, `Email` e `Role` ao `access_token` e `id_token`, outras reivindicações são adicionadas apenas ao `access_token` por padrão e remove a reivindicação secreta `SecurityStampClaimType` do `Identity`.
Crie um serviço que herde de `IAbpOpenIddictClaimsPrincipalHandler` e adicione-o ao DI para controlar totalmente os destinos das reivindicações.
```cs
public class MyClaimDestinationsHandler : IAbpOpenIddictClaimsPrincipalHandler, ITransientDependency
{
public virtual Task HandleAsync(AbpOpenIddictClaimsPrincipalHandlerContext context)
{
foreach (var claim in context.Principal.Claims)
{
if (claim.Type == MyClaims.MyClaimsType)
{
claim.SetDestinations(OpenIddictConstants.Destinations.AccessToken, OpenIddictConstants.Destinations.IdentityToken);
}
if (claim.Type == MyClaims.MyClaimsType2)
{
claim.SetDestinations(OpenIddictConstants.Destinations.AccessToken);
}
}
return Task.CompletedTask;
}
}
Configure<AbpOpenIddictClaimsPrincipalOptions>(options =>
{
options.ClaimsPrincipalHandlers.Add<MyClaimDestinationsHandler>();
});
```
Para obter informações detalhadas, consulte: [OpenIddict claim destinations](https://documentation.openiddict.com/configuration/claim-destinations.html)
#### Desabilitar a Criptografia do AccessToken
O ABP desabilita a `criptografia do access token` por padrão para compatibilidade, mas pode ser habilitada manualmente, se necessário.
```cs
public override void PreConfigureServices(ServiceConfigurationContext context)
{
PreConfigure<OpenIddictServerBuilder>(builder =>
{
builder.Configure(options => options.DisableAccessTokenEncryption = false);
});
}
```
https://documentation.openiddict.com/configuration/token-formats.html#disabling-jwt-access-token-encryption
### Processo de Solicitação/Resposta
O `OpenIddict.Server.AspNetCore` adiciona um esquema de autenticação (`Name: OpenIddict.Server.AspNetCore, handler: OpenIddictServerAspNetCoreHandler`) e implementa a interface `IAuthenticationRequestHandler`.
Ele será executado primeiro no `AuthenticationMiddleware` e pode interromper o processamento da solicitação atual. Caso contrário, o `DefaultAuthenticateScheme` será chamado e continuará a executar o pipeline.
O `OpenIddictServerAspNetCoreHandler` chamará vários manipuladores embutidos (manipulando solicitações e respostas) e o manipulador processará de acordo com o contexto ou ignorará a lógica que não tem relação com ele.
Exemplo de uma solicitação de token:
```
POST /connect/token HTTP/1.1
Content-Type: application/x-www-form-urlencoded
grant_type=password&
client_id=AbpApp&
client_secret=1q2w3e*&
username=admin&
password=1q2w3E*&
scope=AbpAPI offline_access
```
Esta solicitação será processada por vários manipuladores. Eles confirmarão o tipo de endpoint da solicitação, verificarão `HTTP/HTTPS`, verificarão se os parâmetros da solicitação (`client, scope`, etc.) são válidos e existem no banco de dados, etc. Várias verificações de protocolo. E construir um objeto `OpenIddictRequest`, Se houver erros, o conteúdo da resposta pode ser definido e interromper diretamente a solicitação atual.
Se tudo estiver ok, a solicitação irá para nosso controlador de processamento (por exemplo, `TokenController`), podemos obter um `OpenIddictRequest` da solicitação HTTP neste momento. O restante será baseado neste objeto.
Verifique o `username` e `password` na solicitação. Se estiver correto, crie um objeto `ClaimsPrincipal` e retorne um `SignInResult`, que usa o nome do esquema de autenticação `OpenIddict.Validation.AspNetCore`, chamará o `OpenIddictServerAspNetCoreHandler` para processamento.
O `OpenIddictServerAspNetCoreHandler` fará algumas verificações para gerar json e substituir o conteúdo da resposta HTTP.
O `ForbidResult` `ChallengeResult` são todos os tipos de processamento acima.
Se você precisar personalizar o OpenIddict, será necessário substituir/excluir/adicionar novos manipuladores e fazer com que ele seja executado na ordem correta.
Consulte: https://documentation.openiddict.com/guides/index.html#events-model
### PKCE
https://documentation.openiddict.com/configuration/proof-key-for-code-exchange.html
### Definindo o Tempo de Vida dos Tokens
Atualize o método `PreConfigureServices` do arquivo AuthServerModule (ou HttpApiHostModule se você não tiver um servidor de autenticação separado) :
```csharp
PreConfigure<OpenIddictServerBuilder>(builder =>
{
builder.SetAuthorizationCodeLifetime(TimeSpan.FromMinutes(30));
builder.SetAccessTokenLifetime(TimeSpan.FromMinutes(30));
builder.SetIdentityTokenLifetime(TimeSpan.FromMinutes(30));
builder.SetRefreshTokenLifetime(TimeSpan.FromDays(14));
});
```
### Token de Atualização
Para usar o token de atualização, ele deve ser suportado pelo OpenIddictServer e o `refresh_token` deve ser solicitado pelo aplicativo.
> **Observação:** O aplicativo Angular já está configurado para usar o `refresh_token`.
#### Configurando o OpenIddictServer
Atualize o **OpenIddictDataSeedContributor**, adicione `OpenIddictConstants.GrantTypes.RefreshToken` aos tipos de concessão no método `CreateApplicationAsync`:
```csharp
await CreateApplicationAsync(
...
grantTypes: new List<string> //Fluxo híbrido
{
OpenIddictConstants.GrantTypes.AuthorizationCode,
OpenIddictConstants.GrantTypes.Implicit,
OpenIddictConstants.GrantTypes.RefreshToken,
},
...
```
> **Observação:** Você precisa recriar esse cliente se já tiver gerado o banco de dados.
#### Configurando o Aplicativo:
Você precisa solicitar o escopo **offline_access** para poder receber o `refresh_token`.
Nos aplicativos **Razor/MVC, Blazor-Server**, adicione `options.Scope.Add("offline_access");` às opções **OpenIdConnect**. Esses modelos de aplicativo usam autenticação por cookie por padrão e têm as opções de expiração do cookie definidas como:
```csharp
.AddCookie("Cookies", options =>
{
options.ExpireTimeSpan = TimeSpan.FromDays(365);
})
```
[Cookie ExpireTimeSpan ignorará a expiração do access_token](https://learn.microsoft.com/en-us/dotnet/api/Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationOptions.ExpireTimeSpan?view=aspnetcore-7.0&viewFallbackFrom=net-7.0) e o access_token expirado ainda será válido se for definido com um valor maior que o `refresh_token lifetime`. É recomendável manter o **Cookie ExpireTimeSpan** e o **Refresh Token lifetime** iguais, para que o novo token seja persistido no cookie.
Nos aplicativos **Blazor wasm**, adicione `options.ProviderOptions.DefaultScopes.Add("offline_access");` às opções **AddOidcAuthentication**.
Nos aplicativos **Angular**, adicione `offline_access` aos escopos **oAuthConfig** no arquivo *environment.ts*. (Os aplicativos Angular já têm essa configuração).
## Sobre a localização
Não localizamos nenhuma mensagem de erro no módulo OpenIddict, porque a especificação OAuth 2.0 restringe o conjunto de caracteres que você pode usar para os parâmetros de erro e error_description:
> A.7. "error" Syntax
> O elemento "error" é definido nas Seções 4.1.2.1, 4.2.2.1, 5.2, 7.2 e 8.5:
```
error = 1*NQSCHAR
```
> A.8. "error_description" Syntax
> O elemento "error_description" é definido nas Seções 4.1.2.1, 4.2.2.1, 5.2 e 7.2:
```
error-description = 1*NQSCHAR
NQSCHAR = %x20-21 / %x23-5B / %x5D-7E
```
## Projetos de demonstração
No diretório `app` do módulo, existem seis projetos (incluindo `angular`)
* `OpenIddict.Demo.Server`: Um aplicativo abp com módulos integrados (possui dois `clientes` e um `escopo`).
* `OpenIddict.Demo.API`: Aplicativo ASP NET Core API usando autenticação JwtBearer.
* `OpenIddict.Demo.Client.Mvc`: Aplicativo ASP NET Core MVC usando `OpenIdConnect` para autenticação.
* `OpenIddict.Demo.Client.Console`: Use `IdentityModel` para testar os vários endpoints do OpenIddict e chamar a API do `OpenIddict.Demo.API`.
* `OpenIddict.Demo.Client.BlazorWASM:` Aplicativo Blazor ASP NET Core usando `OidcAuthentication` para autenticação.
* `angular`: Um aplicativo angular que integra os módulos abp ng e usa oauth para autenticação.
#### Como executar?
Confirme a string de conexão do `appsettings.json` no projeto `OpenIddict.Demo.Server`. A execução do projeto criará automaticamente o banco de dados e inicializará os dados.
Após executar o projeto `OpenIddict.Demo.API`, você pode executar o restante dos projetos para testar.
## Guia de Migração
[Guia de Migração Passo a Passo do IdentityServer para o OpenIddict](../Migration-Guides/OpenIddict-Step-by-Step.md)

109
docs/pt-BR/Modules/Permission-Management.md

@ -0,0 +1,109 @@
# Módulo de Gerenciamento de Permissões
Este módulo implementa o `IPermissionStore` para armazenar e gerenciar valores de permissões em um banco de dados.
> Este documento aborda apenas o módulo de gerenciamento de permissões que persiste os valores de permissão em um banco de dados. Consulte o documento de [Autorização](../Authorization.md) para entender os sistemas de autorização e permissão.
## Como Instalar
Este módulo já vem pré-instalado (como pacotes NuGet/NPM). Você pode continuar a usá-lo como pacote e obter atualizações facilmente, ou pode incluir seu código-fonte em sua solução (consulte o comando `get-source` da [CLI](../CLI.md)) para desenvolver seu próprio módulo personalizado.
### O Código-fonte
O código-fonte deste módulo pode ser acessado [aqui](https://github.com/abpframework/abp/tree/dev/modules/permission-management). O código-fonte é licenciado com a licença [MIT](https://choosealicense.com/licenses/mit/), portanto, você pode usá-lo e personalizá-lo livremente.
## Interface do Usuário
### Diálogo de Gerenciamento de Permissões
O módulo de gerenciamento de permissões fornece um diálogo reutilizável para gerenciar permissões relacionadas a um objeto. Por exemplo, o [Módulo de Identidade](Identity.md) o utiliza para gerenciar as permissões de usuários e funções. A imagem a seguir mostra a página de Gerenciamento de Funções do Módulo de Identidade:
![permissions-module-open-dialog](../images/permissions-module-open-dialog.png)
Quando você clica em *Ações* -> *Permissões* para uma função, o diálogo de gerenciamento de permissões é aberto. Uma captura de tela de exemplo deste diálogo:
![permissions-module-dialog](../images/permissions-module-dialog.png)
Neste diálogo, você pode conceder permissões para a função selecionada. As abas no lado esquerdo representam os principais grupos de permissões e o lado direito contém as permissões definidas no grupo selecionado.
## IPermissionManager
`IPermissionManager` é o serviço principal fornecido por este módulo. Ele é usado para ler e alterar os valores de permissão. `IPermissionManager` é normalmente usado pelo *Diálogo de Gerenciamento de Permissões*. No entanto, você pode injetá-lo se precisar definir um valor de permissão.
> Se você apenas deseja ler/verificar os valores de permissão para o usuário atual, use o `IAuthorizationService` ou o atributo `[Authorize]`, conforme explicado no documento de [Autorização](../Authorization.md).
**Exemplo: Conceder permissões para funções e usuários usando o serviço `IPermissionManager`**
````csharp
public class MeuServico : ITransientDependency
{
private readonly IPermissionManager _permissionManager;
public MeuServico(IPermissionManager permissionManager)
{
_permissionManager = permissionManager;
}
public async Task ConcederPermissaoParaFuncaoDemoAsync(
string nomeFuncao, string permissao)
{
await _permissionManager
.SetForRoleAsync(nomeFuncao, permissao, true);
}
public async Task ConcederPermissaoParaUsuarioDemoAsync(
Guid idUsuario, string nomeFuncao, string permissao)
{
await _permissionManager
.SetForUserAsync(idUsuario, permissao, true);
}
}
````
## Provedores de Gerenciamento de Permissões
O Módulo de Gerenciamento de Permissões é extensível, assim como o [sistema de permissões](../Authorization.md). Você pode estendê-lo definindo provedores de gerenciamento de permissões.
O [Módulo de Identidade](Identity.md) define os seguintes provedores de gerenciamento de permissões:
* `UserPermissionManagementProvider`: Gerencia permissões baseadas em usuários.
* `RolePermissionManagementProvider`: Gerencia permissões baseadas em funções.
`IPermissionManager` usa esses provedores quando você obtém/define permissões. Você pode definir seu próprio provedor implementando o `IPermissionManagementProvider` ou herdando da classe base `PermissionManagementProvider`.
**Exemplo:**
````csharp
public class CustomPermissionManagementProvider : PermissionManagementProvider
{
public override string Name => "Custom";
public CustomPermissionManagementProvider(
IPermissionGrantRepository permissionGrantRepository,
IGuidGenerator guidGenerator,
ICurrentTenant currentTenant)
: base(
permissionGrantRepository,
guidGenerator,
currentTenant)
{
}
}
````
A classe base `PermissionManagementProvider` faz a implementação padrão (usando o `IPermissionGrantRepository`) para você. Você pode substituir os métodos base conforme necessário. Cada provedor deve ter um nome exclusivo, que é `Custom` neste exemplo (mantenha-o curto, pois ele é salvo no banco de dados para cada registro de valor de permissão).
Depois de criar sua classe de provedor, você deve registrá-la usando a classe de opções `PermissionManagementOptions` [options class](../Options.md):
````csharp
Configure<PermissionManagementOptions>(options =>
{
options.ManagementProviders.Add<CustomPermissionManagementProvider>();
});
````
A ordem dos provedores é importante. Os provedores são executados na ordem inversa. Isso significa que o `CustomPermissionManagementProvider` é executado primeiro neste exemplo. Você pode inserir seu provedor em qualquer ordem na lista `Providers`.
## Veja também
* [Autorização](../Authorization.md)

313
docs/pt-BR/Modules/Setting-Management.md

@ -0,0 +1,313 @@
# Módulo de Gerenciamento de Configurações
O Módulo de Gerenciamento de Configurações implementa a interface `ISettingStore` (consulte [o sistema de configurações](../Settings.md)) para armazenar os valores das configurações em um banco de dados e fornece a interface `ISettingManager` para gerenciar (alterar) os valores das configurações no banco de dados.
> O módulo de Gerenciamento de Configurações já está instalado e configurado nos [modelos de inicialização](../Startup-Templates/Index.md). Portanto, na maioria das vezes, você não precisa adicionar manualmente este módulo à sua aplicação.
## ISettingManager
`ISettingManager` é usado para obter e definir os valores das configurações. Exemplos:
````csharp
using System;
using System.Threading.Tasks;
using Volo.Abp.DependencyInjection;
using Volo.Abp.SettingManagement;
namespace Demo
{
public class MyService : ITransientDependency
{
private readonly ISettingManager _settingManager;
// Injeta o serviço ISettingManager
public MyService(ISettingManager settingManager)
{
_settingManager = settingManager;
}
public async Task FooAsync()
{
Guid user1Id = ...;
Guid tenant1Id = ...;
// Obtém/define um valor de configuração para o usuário atual ou para o usuário especificado
string layoutType1 =
await _settingManager.GetOrNullForCurrentUserAsync("App.UI.LayoutType");
string layoutType2 =
await _settingManager.GetOrNullForUserAsync("App.UI.LayoutType", user1Id);
await _settingManager.SetForCurrentUserAsync("App.UI.LayoutType", "LeftMenu");
await _settingManager.SetForUserAsync(user1Id, "App.UI.LayoutType", "LeftMenu");
// Obtém/define um valor de configuração para o locatário atual ou para o locatário especificado
string layoutType3 =
await _settingManager.GetOrNullForCurrentTenantAsync("App.UI.LayoutType");
string layoutType4 =
await _settingManager.GetOrNullForTenantAsync("App.UI.LayoutType", tenant1Id);
await _settingManager.SetForCurrentTenantAsync("App.UI.LayoutType", "LeftMenu");
await _settingManager.SetForTenantAsync(tenant1Id, "App.UI.LayoutType", "LeftMenu");
// Obtém/define um valor de configuração global e padrão
string layoutType5 =
await _settingManager.GetOrNullGlobalAsync("App.UI.LayoutType");
string layoutType6 =
await _settingManager.GetOrNullDefaultAsync("App.UI.LayoutType");
await _settingManager.SetGlobalAsync("App.UI.LayoutType", "TopMenu");
}
}
}
````
Portanto, você pode obter ou definir um valor de configuração para diferentes provedores de valores de configuração (Padrão, Global, Usuário, Locatário... etc).
> Use a interface `ISettingProvider` em vez da `ISettingManager` se você apenas precisa ler os valores das configurações, pois ela implementa o cache e suporta todos os cenários de implantação. Você pode usar a `ISettingManager` se estiver criando uma interface de gerenciamento de configurações.
### Cache de Configurações
Os valores das configurações são armazenados em cache usando o sistema de [cache distribuído](../Caching.md). Sempre use o `ISettingManager` para alterar os valores das configurações, pois ele gerencia o cache para você.
## Provedores de Gerenciamento de Configurações
O módulo de Gerenciamento de Configurações é extensível, assim como o [sistema de configurações](../Settings.md). Você pode estendê-lo definindo provedores de gerenciamento de configurações. Existem 5 provedores de gerenciamento de configurações pré-construídos registrados na seguinte ordem:
* `DefaultValueSettingManagementProvider`: Obtém o valor do valor padrão da definição da configuração. Ele não pode definir o valor padrão, pois os valores padrão são codificados na definição da configuração.
* `ConfigurationSettingManagementProvider`: Obtém o valor do serviço [IConfiguration](../Configuration.md). Ele não pode definir o valor de configuração, pois não é possível alterar os valores de configuração em tempo de execução.
* `GlobalSettingManagementProvider`: Obtém ou define o valor global (em todo o sistema) para uma configuração.
* `TenantSettingManagementProvider`: Obtém ou define o valor da configuração para um locatário.
* `UserSettingManagementProvider`: Obtém o valor da configuração para um usuário.
O `ISettingManager` usa os provedores de gerenciamento de configurações nos métodos de obtenção/definição. Normalmente, cada provedor de gerenciamento de configurações define métodos de extensão no serviço `ISettingManagement` (como `SetForUserAsync` definido pelo provedor de gerenciamento de configurações de usuário).
Se você deseja criar seu próprio provedor, implemente a interface `ISettingManagementProvider` ou herde da classe base `SettingManagementProvider`:
````csharp
public class CustomSettingProvider : SettingManagementProvider, ITransientDependency
{
public override string Name => "Custom";
public CustomSettingProvider(ISettingManagementStore store)
: base(store)
{
}
}
````
A classe base `SettingManagementProvider` faz a implementação padrão (usando o `ISettingManagementStore`) para você. Você pode substituir os métodos base conforme necessário. Todo provedor deve ter um nome exclusivo, que é `Custom` neste exemplo (mantenha-o curto, pois ele é salvo no banco de dados para cada registro de valor de configuração).
Depois de criar sua classe de provedor, você deve registrá-la usando a classe de opções `SettingManagementOptions` [options class](../Options.md):
````csharp
Configure<SettingManagementOptions>(options =>
{
options.Providers.Add<CustomSettingProvider>();
});
````
A ordem dos provedores é importante. Os provedores são executados na ordem inversa. Isso significa que o `CustomSettingProvider` é executado primeiro neste exemplo. Você pode inserir seu provedor em qualquer ordem na lista `Providers`.
## Veja também
* [Configurações](../Settings.md)
## Interface de Gerenciamento de Configurações
O módulo de Gerenciamento de Configurações fornece a interface de configuração de e-mail por padrão.
![Interface de Configuração de E-mail](../images/setting-management-email-ui.png)
> Você pode clicar no botão Enviar e-mail de teste para enviar um e-mail de teste e verificar suas configurações de e-mail.
Ele é extensível; você pode adicionar suas guias a esta página para as configurações de sua aplicação.
### Interface de Usuário MVC
#### Criar um Componente de Visualização de Configuração
Crie a pasta `MySettingGroup` dentro da pasta `Components`. Adicione um novo componente de visualização. Nomeie-o como `MySettingGroupViewComponent`:
![MySettingGroupViewComponent](../images/my-setting-group-view-component.png)
Abra o arquivo `MySettingGroupViewComponent.cs` e altere todo o conteúdo conforme mostrado abaixo:
```csharp
public class MySettingGroupViewComponent : AbpViewComponent
{
public virtual IViewComponentResult Invoke()
{
return View("~/Components/MySettingGroup/Default.cshtml");
}
}
```
> Você também pode usar o método `InvokeAsync`, neste exemplo, usamos o método `Invoke`.
#### Default.cshtml
Crie um arquivo `Default.cshtml` dentro da pasta `MySettingGroup`.
Abra o arquivo `Default.cshtml` e altere todo o conteúdo conforme mostrado abaixo:
```html
<div>
<p>Página do meu grupo de configurações</p>
</div>
```
#### BookStoreSettingPageContributor
Crie um arquivo `BookStoreSettingPageContributor.cs` dentro da pasta `Settings`:
![BookStoreSettingPageContributor](../images/my-setting-group-page-contributor.png)
O conteúdo do arquivo é mostrado abaixo:
```csharp
public class BookStoreSettingPageContributor : ISettingPageContributor
{
public Task ConfigureAsync(SettingPageCreationContext context)
{
context.Groups.Add(
new SettingPageGroup(
"Volo.Abp.MySettingGroup",
"MySettingGroup",
typeof(MySettingGroupViewComponent),
order : 1
)
);
return Task.CompletedTask;
}
public Task<bool> CheckPermissionsAsync(SettingPageCreationContext context)
{
// Você pode verificar as permissões aqui
return Task.FromResult(true);
}
}
```
Abra o arquivo `BookStoreWebModule.cs` e adicione o seguinte código:
```csharp
Configure<SettingManagementPageOptions>(options =>
{
options.Contributors.Add(new BookStoreSettingPageContributor());
});
```
#### Executar a Aplicação
Acesse a rota `/SettingManagement` para ver as alterações:
![Guia de Configurações Personalizadas](../images/my-setting-group-ui.png)
### Interface de Usuário Blazor
#### Criar um Componente Razor
Crie a pasta `MySettingGroup` dentro da pasta `Pages`. Adicione um novo componente Razor. Nomeie-o como `MySettingGroupComponent`:
![MySettingGroupComponent](../images/my-setting-group-component.png)
Abra o arquivo `MySettingGroupComponent.razor` e altere todo o conteúdo conforme mostrado abaixo:
```csharp
<Row>
<p>meu grupo de configurações</p>
</Row>
```
#### BookStoreSettingComponentContributor
Crie um arquivo `BookStoreSettingComponentContributor.cs` dentro da pasta `Settings`:
![BookStoreSettingComponentContributor](../images/my-setting-group-component-contributor.png)
O conteúdo do arquivo é mostrado abaixo:
```csharp
public class BookStoreSettingComponentContributor : ISettingComponentContributor
{
public Task ConfigureAsync(SettingComponentCreationContext context)
{
context.Groups.Add(
new SettingComponentGroup(
"Volo.Abp.MySettingGroup",
"MySettingGroup",
typeof(MySettingGroupComponent),
order : 1
)
);
return Task.CompletedTask;
}
public Task<bool> CheckPermissionsAsync(SettingComponentCreationContext context)
{
// Você pode verificar as permissões aqui
return Task.FromResult(true);
}
}
```
Abra o arquivo `BookStoreBlazorModule.cs` e adicione o seguinte código:
```csharp
Configure<SettingManagementComponentOptions>(options =>
{
options.Contributors.Add(new BookStoreSettingComponentContributor());
});
```
#### Executar a Aplicação
Acesse a rota `/setting-management` para ver as alterações:
![Guia de Configurações Personalizadas](../images/my-setting-group-blazor.png)
### Interface de Usuário Angular
#### Criar um Componente
Crie um componente com o seguinte comando:
```bash
yarn ng generate component my-settings
```
Abra o arquivo `app.component.ts` e modifique o arquivo conforme mostrado abaixo:
```js
import { Component } from '@angular/core';
import { SettingTabsService } from '@abp/ng.setting-management/config'; // importando SettingTabsService
import { MySettingsComponent } from './my-settings/my-settings.component'; // importando MySettingsComponent
@Component(/* metadados do componente */)
export class AppComponent {
constructor(private settingTabs: SettingTabsService) // injetando MySettingsComponent
{
// adicionado abaixo
settingTabs.add([
{
name: 'MySettings',
order: 1,
requiredPolicy: 'chave da política aqui',
component: MySettingsComponent,
},
]);
}
}
```
#### Executar a Aplicação
Acesse a rota `/setting-management` para ver as alterações:
![Guia de Configurações Personalizadas](../images/custom-settings.png)

134
docs/pt-BR/Modules/Tenant-Management.md

@ -0,0 +1,134 @@
# Módulo de Gerenciamento de Inquilinos
O [Multi-Tenancy](../Multi-Tenancy.md) é uma das principais características do ABP Framework. Ele fornece a infraestrutura fundamental para construir sua própria solução SaaS (Software-as-a-Service). O sistema de multi-tenancy do ABP abstrai onde seus inquilinos são armazenados, fornecendo a interface `ITenantStore`. Tudo que você precisa fazer é implementar essa interface.
**O módulo de gerenciamento de inquilinos é uma implementação da interface `ITenantStore`. Ele armazena inquilinos em um banco de dados. Ele também fornece uma interface de usuário para gerenciar seus inquilinos e suas [funcionalidades](../Features.md).**
> Por favor, **consulte a documentação do [Multi-Tenancy](../Multi-Tenancy.md)** para entender o sistema de multi-tenancy do ABP Framework. Este documento se concentra no módulo de gerenciamento de inquilinos.
### Sobre o Módulo SaaS Comercial do ABP
O [Módulo SaaS](https://commercial.abp.io/modules/Volo.Saas) é uma implementação alternativa deste módulo com mais funcionalidades e possibilidades. Ele é distribuído como parte da assinatura do [ABP Commercial](https://commercial.abp.io/).
## Como Instalar
Este módulo vem pré-instalado (como pacotes NuGet/NPM) quando você [cria uma nova solução](https://abp.io/get-started) com o ABP Framework. Você pode continuar a usá-lo como pacote e obter atualizações facilmente, ou pode incluir seu código-fonte em sua solução (consulte o comando `get-source` da [CLI](../CLI.md)) para desenvolver seu próprio módulo personalizado.
### O Código Fonte
O código-fonte deste módulo pode ser acessado [aqui](https://github.com/abpframework/abp/tree/dev/modules/tenant-management). O código-fonte é licenciado com [MIT](https://choosealicense.com/licenses/mit/), então você pode usá-lo e personalizá-lo livremente.
## Interface de Usuário
Este módulo adiciona o item de menu "*Administração -> Gerenciamento de Inquilinos -> Inquilinos*" ao menu principal do aplicativo, que abre a página mostrada abaixo:
![module-tenant-management-page](../images/module-tenant-management-page.png)
Nesta página, você vê todos os inquilinos. Você pode criar um novo inquilino conforme mostrado abaixo:
![module-tenant-management-new-tenant](../images/module-tenant-management-new-tenant.png)
Neste modal;
* **Nome**: O nome único do inquilino. Se você usar subdomínios para seus inquilinos (como https://algum-inquilino.seu-domínio.com), este será o nome do subdomínio.
* **Endereço de E-mail do Administrador**: Endereço de e-mail do usuário administrador para este inquilino.
* **Senha do Administrador**: A senha do usuário administrador para este inquilino.
Quando você clica no botão *Ações* próximo a um inquilino, você verá as ações que pode realizar:
![module-tenant-management-actions](../images/module-tenant-management-actions.png)
### Gerenciando as Funcionalidades do Inquilino
A ação Funcionalidades abre um modal para habilitar/desabilitar/configurar [funcionalidades](../Features.md) para o inquilino relacionado. Aqui, um exemplo de modal:
![features-modal](../images/features-modal.png)
### Gerenciando as Funcionalidades do Host
O botão *Gerenciar Funcionalidades do Host* é usado para configurar as funcionalidades do lado do host, se você usar as funcionalidades do seu aplicativo também no lado do host.
## Eventos Distribuídos
Este módulo define os seguintes ETOs (Event Transfer Objects) para permitir que você se inscreva em alterações nas entidades do módulo;
- `TenantEto` é publicado em alterações feitas em uma entidade `Tenant`.
**Exemplo: Receber uma notificação quando um novo inquilino for criado**
```cs
public class MeuManipulador :
IDistributedEventHandler<EntityCreatedEto<TenantEto>>,
ITransientDependency
{
public async Task HandleEventAsync(EntityCreatedEto<TenantEto> eventData)
{
TenantEto tenant = eventData.Entity;
// TODO: ...
}
}
```
`TenantEto` é configurado para publicar automaticamente os eventos. Você deve configurar-se para os outros. Consulte o documento [Distributed Event Bus](https://github.com/abpframework/abp/blob/rel-7.3/docs/en/Distributed-Event-Bus.md) para aprender detalhes dos eventos pré-definidos.
> A inscrição nos eventos distribuídos é especialmente útil para cenários distribuídos (como arquitetura de microsserviços). Se você estiver construindo um aplicativo monolítico ou ouvindo eventos no mesmo processo que executa o Módulo de Gerenciamento de Inquilinos, então a inscrição nos [eventos locais](https://github.com/abpframework/abp/blob/rel-7.3/docs/en/Local-Event-Bus.md) pode ser mais eficiente e fácil.
## Internos
Esta seção pode ser usada como referência se você quiser [personalizar](../Customizing-Application-Modules-Guide.md) este módulo sem alterar [seu código-fonte](https://github.com/abpframework/abp/tree/dev/modules/tenant-management).
### Camada de Domínio
#### Agregados
* `Tenant`
#### Repositórios
* `ITenantRepository`
#### Serviços de Domínio
* `TenantManager`
### Camada de Aplicação
#### Serviços de Aplicação
* `TenantAppService`
#### Permissões
- `AbpTenantManagement.Tenants`: Gerenciamento de inquilinos.
- `AbpTenantManagement.Tenants.Create`: Criar um novo inquilino.
- `AbpTenantManagement.Tenants.Update`: Editar um inquilino existente.
- `AbpTenantManagement.Tenants.Delete`: Excluir um inquilino existente.
- `AbpTenantManagement.Tenants.ManageFeatures`: Gerenciar as funcionalidades dos inquilinos.
### Integração com o Entity Framework Core
* `TenantManagementDbContext` (implementa `ITenantManagementDbContext`)
**Tabelas do Banco de Dados:**
* `AbpTenants`
* `AbpTenantConnectionStrings`
### Integração com o MongoDB
* `TenantManagementMongoDbContext` (implementa `ITenantManagementMongoDbContext`)
**Coleções do Banco de Dados:**
* `AbpTenants` (inclui também a string de conexão)
## Avisos
O ABP Framework permite usar a abordagem *banco de dados por inquilino*, que permite que um inquilino tenha um banco de dados dedicado. Este módulo possui a infraestrutura fundamental para tornar essa implementação possível (consulte seu código-fonte), no entanto, ele não implementa a camada de aplicação e as funcionalidades de interface do usuário para fornecê-lo como uma implementação pronta para uso. Você pode implementar esses recursos por conta própria ou considerar o uso do [Módulo SaaS Comercial do ABP](https://docs.abp.io/en/commercial/latest/modules/saas), que o implementa completamente e fornece muito mais recursos de negócios.
## Veja Também
* [Multi-Tenancy](../Multi-Tenancy.md)
* [Módulo SaaS Comercial do ABP](https://docs.abp.io/en/commercial/latest/modules/saas)

87
docs/pt-BR/Modules/Virtual-File-Explorer.md

@ -0,0 +1,87 @@
# Módulo de Explorador de Arquivos Virtual
## O que é o Módulo de Explorador de Arquivos Virtual?
O Módulo de Explorador de Arquivos Virtual fornece uma interface de usuário simples para visualizar todos os arquivos no [sistema de arquivos virtual](../Virtual-File-System.md).
> O Módulo de Explorador de Arquivos Virtual não está instalado nos [modelos de inicialização](../Startup-Templates/Index.md). Portanto, você precisa adicionar manualmente este módulo à sua aplicação.
### Instalação
#### 1- Usando o ABP CLI
Recomenda-se usar o [ABP CLI](../CLI.md) para instalar o módulo. Abra a janela do CMD no diretório do arquivo de solução (`.sln`) e execute o seguinte comando:
```
abp add-module Volo.VirtualFileExplorer
```
> Se você ainda não o fez, primeiro precisa instalar o [ABP CLI](../CLI.md). Para outras opções de instalação, consulte [a página de descrição do pacote](https://abp.io/package-detail/Volo.Abp.VirtualFileExplorer.Web).
#### 2- Instalação manual
Ou você também pode instalar manualmente o pacote nuget no projeto `Acme.MyProject.Web`:
* Instale o pacote nuget [Volo.Abp.VirtualFileExplorer.Web](https://www.nuget.org/packages/Volo.Abp.VirtualFileExplorer.Web/) no projeto `Acme.MyProject.Web`.
`Install-Package Volo.Abp.VirtualFileExplorer.Web`
##### 2.1- Adicionando Dependências do Módulo
* Abra `MyProjectWebModule.cs` e adicione `typeof(AbpVirtualFileExplorerWebModule)` como mostrado abaixo;
```csharp
[DependsOn(
typeof(AbpVirtualFileExplorerWebModule),
typeof(MyProjectApplicationModule),
typeof(MyProjectEntityFrameworkCoreModule),
typeof(AbpAutofacModule),
typeof(AbpIdentityWebModule),
typeof(AbpAccountWebModule),
typeof(AbpAspNetCoreMvcUiBasicThemeModule)
)]
public class MyProjectWebModule : AbpModule
{
//...
}
```
##### 2.2- Adicionando Pacote NPM
* Abra `package.json` e adicione `@abp/virtual-file-explorer": "^2.9.0` como mostrado abaixo:
```json
{
"version": "1.0.0",
"name": "my-app",
"private": true,
"dependencies": {
"@abp/aspnetcore.mvc.ui.theme.basic": "^2.9.0",
"@abp/virtual-file-explorer": "^2.9.0"
}
}
```
Em seguida, abra o terminal de linha de comando na pasta do projeto `Acme.MyProject.Web` e execute o seguinte comando:
````bash
abp install-libs
````
Isso é tudo, agora execute a aplicação e navegue até `/VirtualFileExplorer`. Você verá a página do explorador de arquivos virtual:
![Virtual-File-Explorer](../images/virtual-file-explorer.png)
### Opções
Você pode desativar o módulo de explorador de arquivos virtual através das opções `AbpVirtualFileExplorerOptions`:
```csharp
public override void PreConfigureServices(ServiceConfigurationContext context)
{
PreConfigure<AbpVirtualFileExplorerOptions>(options =>
{
options.IsEnabled = false;
});
}
```

74
docs/pt-BR/UI/AspNetCore/AutoComplete-Select.md

@ -0,0 +1,74 @@
# ASP.NET Core MVC / Razor Pages: Auto-Complete Select
Um componente de seleção simples às vezes não é útil com uma grande quantidade de dados. O ABP fornece uma implementação de seleção que funciona com paginação e pesquisa no lado do servidor usando o [Select2](https://select2.org/). Ele funciona bem com escolhas únicas ou múltiplas.
Uma captura de tela pode ser mostrada abaixo.
| Único | Múltiplo |
| --- | --- |
| ![autocomplete-select-example](../../images/abp-select2-single.png) |![autocomplete-select-example](../../images/abp-select2-multiple.png) |
## Começando
Esta é uma funcionalidade central e é usada pelo ABP Framework. Não há instalação personalizada ou pacotes adicionais necessários.
## Uso
Um uso simples é apresentado abaixo.
```html
<select asp-for="Book.AuthorId"
class="auto-complete-select"
data-autocomplete-api-url="/api/app/author"
data-autocomplete-display-property="name"
data-autocomplete-value-property="id"
data-autocomplete-items-property="items"
data-autocomplete-filter-param-name="filter"
data-autocomplete-allow-clear="true">
<!-- Você pode definir a(s) opção(ões) selecionada(s) aqui -->
<option selected value="@SelectedAuthor.Id">@SelectedAuthor.Name</option>
</select>
```
O select deve ter a classe `auto-complete-select` e os seguintes atributos:
- `data-autocomplete-api-url`: * URL do endpoint da API para obter os itens da seleção. Será enviado uma requisição **GET** para esta URL.
- `data-autocomplete-display-property`: * Nome da propriedade para exibição. _(Por exemplo: `name` ou `title`. Nome da propriedade da entidade/dto.)_.
- `data-autocomplete-value-property`: * Nome da propriedade identificadora. _(Por exemplo: `id`)_.
- `data-autocomplete-items-property`: * Nome da propriedade da coleção no objeto de resposta. _(Por exemplo: `items`)_
- `data-autocomplete-filter-param-name`: * Nome da propriedade de texto de filtro. _(Por exemplo: `filter`)_.
- `data-autocomplete-selected-item-name`: Texto para exibir como item selecionado.
- `data-autocomplete-parent-selector`: Expressão seletora jQuery para o DOM pai. _(Se estiver em um modal, é sugerido enviar o seletor do modal como este parâmetro)_.
- `data-autocomplete-allow-clear`: Se `true`, permitirá limpar o valor selecionado. Valor padrão: `false`.
- `data-autocomplete-placeholder`: Texto de espaço reservado para exibir quando nenhum valor estiver selecionado.
Além disso, o(s) valor(es) selecionado(s) deve(m) ser definido(s) com as tags `<option>` dentro do select, uma vez que a paginação é aplicada e as opções selecionadas podem não ter sido carregadas ainda.
### Escolhas Múltiplas
O AutoComplete Select suporta escolhas múltiplas. Se a tag select tiver o atributo `multiple`, permitirá escolher várias opções.
```html
<select asp-for="Book.TagIds"
class="auto-complete-select"
multiple="multiple"
data-autocomplete-api-url="/api/app/tags"
data-autocomplete-display-property="name"
data-autocomplete-value-property="id"
data-autocomplete-items-property="items"
data-autocomplete-filter-param-name="filter">
@foreach(var tag in SelectedTags)
{
<option selected value="@tag.Id">@tag.Name</option>
}
</select>
```
Será automaticamente vinculado a uma coleção do tipo de valor definido.
```csharp
public List<Guid> TagIds { get; set; }
```
## Avisos
Se o usuário autenticado não tiver permissão na URL fornecida, o usuário receberá um erro de autorização. Tenha cuidado ao projetar esse tipo de interface de usuário.
Você pode criar um endpoint/método específico, [não autorizado](../../Authorization.md), para obter a lista de itens, para que a página possa recuperar dados de pesquisa de uma entidade dependente sem dar permissão de leitura completa aos usuários.

96
docs/pt-BR/UI/AspNetCore/Basic-Theme.md

@ -0,0 +1,96 @@
# ASP.NET Core MVC / Razor Pages: O Tema Básico
O Tema Básico é uma implementação de tema para a interface do usuário do ASP.NET Core MVC / Razor Pages. É um tema minimalista que não adiciona nenhum estilo além do [Bootstrap](https://getbootstrap.com/) básico. Você pode usar o Tema Básico como o **tema base** e construir seu próprio tema ou estilo em cima dele. Veja a seção *Customização*.
O Tema Básico possui suporte para idiomas da direita para a esquerda (RTL).
> Se você está procurando um tema profissional e pronto para uso empresarial, você pode conferir o [Tema Lepton](https://commercial.abp.io/themes), que faz parte do [ABP Commercial](https://commercial.abp.io/).
> Veja o documento [Theming](Theming.md) para aprender sobre temas.
## Instalação
Se você precisa instalar manualmente este tema, siga os passos abaixo:
* Instale o pacote NuGet [Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic](https://www.nuget.org/packages/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic) em seu projeto web.
* Adicione `AbpAspNetCoreMvcUiBasicThemeModule` no atributo `[DependsOn(...)]` para a sua [classe de módulo](../../Module-Development-Basics.md) no projeto web.
* Instale o pacote NPM [@abp/aspnetcore.mvc.ui.theme.basic](https://www.npmjs.com/package/@abp/aspnetcore.mvc.ui.theme.basic) em seu projeto web (por exemplo, `npm install @abp/aspnetcore.mvc.ui.theme.basic` ou `yarn add @abp/aspnetcore.mvc.ui.theme.basic`).
* Execute o comando `abp install-libs` em um terminal de linha de comando na pasta do projeto web.
## Layouts
O Tema Básico implementa os layouts padrão. Todos os layouts implementam as seguintes partes:
* [Bundles](Bundling-Minification.md) globais
* [Alertas de página](Page-Alerts.md)
* [Hooks de layout](Layout-Hooks.md)
* Recursos de [widget](Widgets.md)
### O Layout da Aplicação
![basic-theme-application-layout](../../images/basic-theme-application-layout.png)
O Layout da Aplicação implementa as seguintes partes, além das partes comuns mencionadas acima:
* Marca
* [Menu](Navigation-Menu.md) principal
* [Toolbar](Toolbars.md) principal com seleção de idioma e menu do usuário
### O Layout da Conta
![basic-theme-account-layout](../../images/basic-theme-account-layout.png)
O Layout da Conta implementa as seguintes partes, além das partes comuns mencionadas acima:
* Marca
* [Menu](Navigation-Menu.md) principal
* [Toolbar](Toolbars.md) principal com seleção de idioma e menu do usuário
* Área de troca de inquilino
### Layout Vazio
O layout vazio é vazio, como o nome sugere. No entanto, ele implementa as partes comuns mencionadas acima.
## Customização
Você tem duas opções para personalizar este tema:
### Sobrescrevendo Estilos/Componentes
Nesta abordagem, você continua a usar o tema como pacotes NuGet e NPM e personaliza as partes que precisa. Existem várias maneiras de personalizá-lo;
#### Sobrescrever os Estilos
1. Crie um arquivo CSS na pasta `wwwroot` do seu projeto:
![example-global-styles](../../images/example-global-styles.png)
2. Adicione o arquivo de estilo ao bundle global, no método `ConfigureServices` da sua [classe de módulo](../../Module-Development-Basics.md):
````csharp
Configure<AbpBundlingOptions>(options =>
{
options.StyleBundles.Configure(BasicThemeBundles.Styles.Global, bundle =>
{
bundle.AddFiles("/styles/global-styles.css");
});
});
````
#### Sobrescrever os Componentes
Veja o [Guia de Customização da Interface do Usuário](Customization-User-Interface.md) para aprender como substituir componentes, personalizar e estender a interface do usuário.
### Copiar e Personalizar
Você pode executar o seguinte comando [ABP CLI](../../CLI.md) no diretório do projeto **Web** para copiar o código-fonte para a sua solução:
`abp add-module Volo.BasicTheme --with-source-code --add-to-solution-file`
----
Ou, você pode baixar o [código-fonte](https://github.com/abpframework/abp/tree/dev/modules/basic-theme/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic) do Tema Básico, copiar manualmente o conteúdo do projeto para a sua solução, reorganizar as dependências de pacote/módulo (veja a seção de Instalação acima para entender como ele foi instalado no projeto) e personalizar livremente o tema com base nos requisitos da sua aplicação.
## Veja também
* [Theming](Theming.md)

45
docs/pt-BR/UI/AspNetCore/Branding.md

@ -0,0 +1,45 @@
# ASP.NET Core MVC / Razor Pages: Branding
## IBrandingProvider
`IBrandingProvider` é uma interface simples que é usada para mostrar o nome e o logotipo da aplicação no layout.
A captura de tela abaixo mostra *MyProject* como o nome da aplicação:
![branding-nobrand](../../images/branding-nobrand.png)
Você pode implementar a interface `IBrandingProvider` ou herdar da classe `DefaultBrandingProvider` para definir o nome da aplicação:
````csharp
using Volo.Abp.Ui.Branding;
using Volo.Abp.DependencyInjection;
namespace MyProject.Web
{
[Dependency(ReplaceServices = true)]
public class MyProjectBrandingProvider : DefaultBrandingProvider
{
public override string AppName => "Book Store";
public override string LogoUrl => "/logo.png";
}
}
````
> Atualmente, definir o `AppName` só é aplicável ao [Tema Básico](../../Themes/Basic.md), não tem efeito nos outros [temas oficiais](../../Themes/Index.md).
O resultado será como mostrado abaixo:
![bookstore-added-logo](../../images/bookstore-added-logo.png)
`IBrandingProvider` possui as seguintes propriedades:
* `AppName`: O nome da aplicação.
* `LogoUrl`: Uma URL para mostrar o logotipo da aplicação.
* `LogoReverseUrl`: Uma URL para mostrar o logotipo da aplicação em um tema de cor reversa (escuro, por exemplo).
> **Dica**: `IBrandingProvider` é usado em cada atualização de página. Para uma aplicação multi-inquilino, você pode retornar um nome de aplicação específico do inquilino para personalizá-lo por inquilino.
## Sobrescrevendo a Área de Branding
Você pode consultar o [Guia de Customização de UI](Customization-User-Interface.md) para aprender como substituir a área de branding por um componente de visualização personalizado.

479
docs/pt-BR/UI/AspNetCore/Bundling-Minification.md

@ -0,0 +1,479 @@
# ASP.NET Core MVC Bundling & Minification
Existem várias maneiras de agrupar e minificar recursos do lado do cliente (arquivos JavaScript e CSS). As formas mais comuns são:
* Usando a extensão do Visual Studio [Bundler & Minifier](https://marketplace.visualstudio.com/items?itemName=MadsKristensen.BundlerMinifier) ou o [pacote NuGet](https://www.nuget.org/packages/BuildBundlerMinifier/).
* Usando os gerenciadores de tarefas [Gulp](https://gulpjs.com/)/[Grunt](https://gruntjs.com/) e seus plugins.
O ABP oferece uma maneira simples, dinâmica, poderosa, modular e integrada.
## Pacote Volo.Abp.AspNetCore.Mvc.UI.Bundling
> Este pacote já está instalado por padrão nos modelos de inicialização. Portanto, na maioria das vezes, você não precisa instalá-lo manualmente.
Se você não estiver usando um modelo de inicialização, pode usar o [ABP CLI](../../CLI.md) para instalá-lo em seu projeto. Execute o seguinte comando na pasta que contém o arquivo .csproj do seu projeto:
````
abp add-package Volo.Abp.AspNetCore.Mvc.UI.Bundling
````
> Se você ainda não o fez, primeiro precisa instalar o [ABP CLI](../../CLI.md). Para outras opções de instalação, consulte [a página de descrição do pacote](https://abp.io/package-detail/Volo.Abp.AspNetCore.Mvc.UI.Bundling).
## Tag Helpers de Agrupamento Razor
A maneira mais simples de criar um pacote é usar os tag helpers `abp-script-bundle` ou `abp-style-bundle`. Exemplo:
````html
<abp-style-bundle name="MyGlobalBundle">
<abp-style src="/libs/bootstrap/css/bootstrap.css" />
<abp-style src="/libs/font-awesome/css/font-awesome.css" />
<abp-style src="/libs/toastr/toastr.css" />
<abp-style src="/styles/my-global-style.css" />
</abp-style-bundle>
````
Este pacote define um pacote de estilo com um **nome único**: `MyGlobalBundle`. É muito fácil entender como usá-lo. Vamos ver como ele *funciona*:
* O ABP cria o pacote como **lazy** a partir dos arquivos fornecidos quando é **solicitado pela primeira vez**. Para as chamadas subsequentes, ele é retornado do **cache**. Isso significa que, se você adicionar condicionalmente os arquivos ao pacote, ele será executado apenas uma vez e quaisquer alterações na condição não afetarão o pacote para as próximas solicitações.
* O ABP adiciona os arquivos do pacote **individualmente** à página para o ambiente `development`. Ele agrupa e minifica automaticamente para outros ambientes (`staging`, `production`...). Consulte a seção *Modo de Agrupamento* para alterar esse comportamento.
* Os arquivos do pacote podem ser arquivos **físicos** ou [**virtuais/embutidos**](../../Virtual-File-System.md).
* O ABP adiciona automaticamente uma **string de consulta de versão** ao URL do arquivo do pacote para evitar que os navegadores armazenem em cache quando o pacote está sendo atualizado. (como ?_v=67872834243042 - gerado a partir da última data de alteração dos arquivos relacionados). A versão funciona mesmo se os arquivos do pacote forem adicionados individualmente à página (no ambiente de desenvolvimento).
### Importando os Tag Helpers de Agrupamento
> Isso já é importado por padrão nos modelos de inicialização. Portanto, na maioria das vezes, você não precisa adicioná-lo manualmente.
Para usar os tag helpers de pacote, você precisa adicioná-los ao seu arquivo `_ViewImports.cshtml` ou à sua página:
````
@addTagHelper *, Volo.Abp.AspNetCore.Mvc.UI.Bundling
````
### Pacotes sem nome
O nome é **opcional** para os tag helpers de pacote razor. Se você não definir um nome, ele será **calculado** automaticamente com base nos nomes dos arquivos do pacote usados (eles são **concatenados** e **hashados**). Exemplo:
````html
<abp-style-bundle>
<abp-style src="/libs/bootstrap/css/bootstrap.css" />
<abp-style src="/libs/font-awesome/css/font-awesome.css" />
<abp-style src="/libs/toastr/toastr.css" />
@if (ViewBag.IncludeCustomStyles != false)
{
<abp-style src="/styles/my-global-style.css" />
}
</abp-style-bundle>
````
Isso pode criar **dois pacotes diferentes** (um inclui o `my-global-style.css` e o outro não).
Vantagens de pacotes **sem nome**:
* É possível **adicionar itens condicionalmente** ao pacote. Mas isso pode levar a várias variações do pacote com base nas condições.
Vantagens de pacotes **com nome**:
* Outros **módulos podem contribuir** para o pacote pelo nome (consulte as seções abaixo).
### Arquivo Único
Se você precisa apenas adicionar um único arquivo à página, pode usar a tag `abp-script` ou `abp-style` sem envolvê-la na tag `abp-script-bundle` ou `abp-style-bundle`. Exemplo:
````xml
<abp-script src="/scripts/my-script.js" />
````
O nome do pacote será *scripts.my-scripts* para o exemplo acima ("/" é substituído por "."). Todos os recursos de agrupamento funcionam como esperado para pacotes de arquivo único também.
## Opções de Agrupamento
Se você precisa usar o mesmo pacote em **múltiplas páginas** ou deseja usar alguns recursos mais **poderosos**, você pode configurar pacotes **por código** em sua classe de [módulo](../../Module-Development-Basics.md).
### Criando um Novo Pacote
Exemplo de uso:
````C#
[DependsOn(typeof(AbpAspNetCoreMvcUiBundlingModule))]
public class MyWebModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
Configure<AbpBundlingOptions>(options =>
{
options
.ScriptBundles
.Add("MyGlobalBundle", bundle => {
bundle.AddFiles(
"/libs/jquery/jquery.js",
"/libs/bootstrap/js/bootstrap.js",
"/libs/toastr/toastr.min.js",
"/scripts/my-global-scripts.js"
);
});
});
}
}
````
> Você pode usar o mesmo nome (*MyGlobalBundle* aqui) para um pacote de script e estilo, pois eles são adicionados a coleções diferentes (`ScriptBundles` e `StyleBundles`).
Após definir um pacote desse tipo, ele pode ser incluído em uma página usando os mesmos tag helpers definidos acima. Exemplo:
````html
<abp-script-bundle name="MyGlobalBundle" />
````
Desta vez, nenhum arquivo é definido na definição do tag helper porque os arquivos do pacote são definidos pelo código.
### Configurando um Pacote Existente
O ABP também oferece suporte à [modularidade](../../Module-Development-Basics.md) para agrupamento. Um módulo pode modificar um pacote existente criado por um módulo dependente. Exemplo:
````C#
[DependsOn(typeof(MyWebModule))]
public class MyWebExtensionModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
Configure<AbpBundlingOptions>(options =>
{
options
.ScriptBundles
.Configure("MyGlobalBundle", bundle => {
bundle.AddFiles(
"/scripts/my-extension-script.js"
);
});
});
}
}
````
Você também pode usar o método `ConfigureAll` para configurar todos os pacotes existentes:
````C#
[DependsOn(typeof(MyWebModule))]
public class MyWebExtensionModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
Configure<AbpBundlingOptions>(options =>
{
options
.ScriptBundles
.ConfigureAll(bundle => {
bundle.AddFiles(
"/scripts/my-extension-script.js"
);
});
});
}
}
````
## Contribuidores de Pacotes
Adicionar arquivos a um pacote existente é útil. E se você precisar **substituir** um arquivo no pacote ou quiser adicionar arquivos **condicionalmente**? Definir um contribuidor de pacote fornece poder extra para esses casos.
Um exemplo de contribuidor de pacote que substitui o bootstrap.css por uma versão personalizada:
````C#
public class MyExtensionGlobalStyleContributor : BundleContributor
{
public override void ConfigureBundle(BundleConfigurationContext context)
{
context.Files.ReplaceOne(
"/libs/bootstrap/css/bootstrap.css",
"/styles/extensions/bootstrap-customized.css"
);
}
}
````
Em seguida, você pode usar esse contribuidor da seguinte maneira:
````C#
services.Configure<AbpBundlingOptions>(options =>
{
options
.ScriptBundles
.Configure("MyGlobalBundle", bundle => {
bundle.AddContributors(typeof(MyExtensionGlobalStyleContributor));
});
});
````
> Você também pode adicionar contribuidores ao criar um novo pacote.
Os contribuidores também podem ser usados nos tag helpers de pacote. Exemplo:
````xml
<abp-style-bundle>
<abp-style type="@typeof(BootstrapStyleContributor)" />
<abp-style src="/libs/font-awesome/css/font-awesome.css" />
<abp-style src="/libs/toastr/toastr.css" />
</abp-style-bundle>
````
As tags `abp-style` e `abp-script` podem receber atributos `type` (em vez de atributos `src`) como mostrado neste exemplo. Quando você adiciona um contribuidor de pacote, suas dependências também são adicionadas automaticamente ao pacote.
### Dependências de Contribuidores
Um contribuidor de pacote pode ter uma ou mais dependências de outros contribuidores.
Exemplo:
````C#
[DependsOn(typeof(MyDependedBundleContributor))] //Define a dependência
public class MyExtensionStyleBundleContributor : BundleContributor
{
//...
}
````
Quando um contribuidor de pacote é adicionado, suas dependências são adicionadas **automaticamente e recursivamente**. As dependências são adicionadas pela **ordem de dependência** evitando **duplicatas**. As duplicatas são evitadas mesmo que estejam em pacotes separados. O ABP organiza todos os pacotes em uma página e elimina duplicações.
Criar contribuidores e definir dependências é uma maneira de organizar a criação de pacotes em diferentes módulos.
### Extensões de Contribuidores
Em alguns cenários avançados, você pode querer fazer alguma configuração adicional sempre que um contribuidor de pacote for usado. As extensões de contribuidor funcionam perfeitamente quando o contribuidor estendido é usado.
O exemplo abaixo adiciona alguns estilos para a biblioteca prism.js:
````csharp
public class MyPrismjsStyleExtension : BundleContributor
{
public override void ConfigureBundle(BundleConfigurationContext context)
{
context.Files.AddIfNotContains("/libs/prismjs/plugins/toolbar/prism-toolbar.css");
}
}
````
Em seguida, você pode configurar `AbpBundleContributorOptions` para estender o `PrismjsStyleBundleContributor` existente.
````csharp
Configure<AbpBundleContributorOptions>(options =>
{
options
.Extensions<PrismjsStyleBundleContributor>()
.Add<MyPrismjsStyleExtension>();
});
````
Sempre que `PrismjsStyleBundleContributor` for adicionado a um pacote, `MyPrismjsStyleExtension` também será adicionado automaticamente.
### Acessando o IServiceProvider
Embora raramente seja necessário, `BundleConfigurationContext` possui uma propriedade `ServiceProvider` que permite resolver dependências de serviço dentro do método `ConfigureBundle`.
### Contribuidores de Pacotes Padrão
Adicionar um recurso específico do pacote NPM (arquivos js, css) a um pacote é bastante simples para esse pacote. Por exemplo, você sempre adiciona o arquivo `bootstrap.css` para o pacote NPM do bootstrap.
Existem contribuidores embutidos para todos os [pacotes NPM padrão](Client-Side-Package-Management.md). Por exemplo, se seu contribuidor depende do bootstrap, você pode apenas declará-lo, em vez de adicionar o bootstrap.css você mesmo.
````C#
[DependsOn(typeof(BootstrapStyleContributor))] //Define a dependência de estilo do bootstrap
public class MyExtensionStyleBundleContributor : BundleContributor
{
//...
}
````
Usando os contribuidores embutidos para pacotes padrão;
* Impede que você digite **os caminhos de recursos inválidos**.
* Impede a alteração do seu contribuidor se o **caminho do recurso mudar** (o contribuidor dependente lidará com isso).
* Impede que vários módulos adicionem **arquivos duplicados**.
* Gerencia **dependências recursivamente** (adiciona dependências de dependências, se necessário).
#### Pacote Volo.Abp.AspNetCore.Mvc.UI.Packages
> Este pacote já está instalado por padrão nos modelos de inicialização. Portanto, na maioria das vezes, você não precisa instalá-lo manualmente.
Se você não estiver usando um modelo de inicialização, pode usar o [ABP CLI](../../CLI.md) para instalá-lo em seu projeto. Execute o seguinte comando na pasta que contém o arquivo .csproj do seu projeto:
````
abp add-package Volo.Abp.AspNetCore.Mvc.UI.Packages
````
> Se você ainda não o fez, primeiro precisa instalar o [ABP CLI](../../CLI.md). Para outras opções de instalação, consulte [a página de descrição do pacote](https://abp.io/package-detail/Volo.Abp.AspNetCore.Mvc.UI.Packages).
### Herança de Pacotes
Em alguns casos específicos, pode ser necessário criar um **novo** pacote **herdado** de outro(s) pacote(s). Ao herdar de um pacote (recursivamente), todos os arquivos/contribuidores desse pacote são herdados. Em seguida, o pacote derivado pode adicionar ou modificar arquivos/contribuidores **sem modificar** o pacote original.
Exemplo:
````c#
services.Configure<AbpBundlingOptions>(options =>
{
options
.StyleBundles
.Add("MyTheme.MyGlobalBundle", bundle => {
bundle
.AddBaseBundles("MyGlobalBundle") //Pode adicionar vários
.AddFiles(
"/styles/mytheme-global-styles.css"
);
});
});
````
## Opções Adicionais
Esta seção mostra outras opções úteis para o sistema de agrupamento e minificação.
### Modo de Agrupamento
O ABP adiciona arquivos de pacote individualmente à página para o ambiente `development`. Ele agrupa e minifica automaticamente para outros ambientes (`staging`, `production`...). Na maioria das vezes, esse é o comportamento desejado. No entanto, você pode configurá-lo manualmente em alguns casos. Existem quatro modos;
* `Auto`: Determina automaticamente o modo com base no ambiente.
* `None`: Sem agrupamento ou minificação.
* `Bundle`: Agrupado, mas não minificado.
* `BundleAndMinify`: Agrupado e minificado.
Você pode configurar `AbpBundlingOptions` no `ConfigureServices` do seu [módulo](../../Module-Development-Basics.md).
**Exemplo:**
````csharp
Configure<AbpBundlingOptions>(options =>
{
options.Mode = BundlingMode.Bundle;
});
````
### Ignorar para Minificação
É possível ignorar um arquivo específico para a minificação.
**Exemplo:**
````csharp
Configure<AbpBundlingOptions>(options =>
{
options.MinificationIgnoredFiles.Add("/scripts/myscript.js");
});
````
O arquivo fornecido ainda é adicionado ao pacote, mas não é minificado neste caso.
### Carregar JavaScript e CSS de forma assíncrona
Você pode configurar `AbpBundlingOptions` para carregar todos ou um único arquivo js/css de forma assíncrona.
**Exemplo:**
````csharp
Configure<AbpBundlingOptions>(options =>
{
options.PreloadStyles.Add("/__bundles/Basic.Global");
options.DeferScriptsByDefault = true;
});
````
**HTML de saída:**
````html
<link rel="preload" href="/__bundles/Basic.Global.F4FA61F368098407A4C972D0A6914137.css?_v=637697363694828051" as="style" onload="this.rel='stylesheet'"/>
<script defer src="/libs/timeago/locales/jquery.timeago.en.js?_v=637674729040000000"></script>
````
### Suporte a Arquivos Externos/CDN
O sistema de agrupamento reconhece automaticamente os arquivos externos/CDN e os adiciona à página sem nenhuma alteração.
#### Usando Arquivos Externos/CDN em `AbpBundlingOptions`
````csharp
Configure<AbpBundlingOptions>(options =>
{
options.StyleBundles
.Add("MyStyleBundle", configuration =>
{
configuration
.AddFiles("/styles/my-style1.css")
.AddFiles("/styles/my-style2.css")
.AddFiles("https://cdn.abp.io/bootstrap.css")
.AddFiles("/styles/my-style3.css")
.AddFiles("/styles/my-style4.css");
});
options.ScriptBundles
.Add("MyScriptBundle", configuration =>
{
configuration
.AddFiles("/scripts/my-script1.js")
.AddFiles("/scripts/my-script2.js")
.AddFiles("https://cdn.abp.io/bootstrap.js")
.AddFiles("/scripts/my-script3.js")
.AddFiles("/scripts/my-script4.js");
});
});
````
**HTML de saída:**
````html
<link rel="stylesheet" href="/__bundles/MyStyleBundle.EA8C28419DCA43363E9670973D4C0D15.css?_v=638331889644609730" />
<link rel="stylesheet" href="https://cdn.abp.io/bootstrap.css" />
<link rel="stylesheet" href="/__bundles/MyStyleBundle.AC2E0AA6C461A0949A1295E9BDAC049C.css?_v=638331889644623860" />
<script src="/__bundles/MyScriptBundle.C993366DF8840E08228F3EE685CB08E8.js?_v=638331889644937120"></script>
<script src="https://cdn.abp.io/bootstrap.js"></script>
<script src="/__bundles/MyScriptBundle.2E8D0FDC6334D2A6B847393A801525B7.js?_v=638331889644943970"></script>
````
#### Usando Arquivos Externos/CDN em Tag Helpers.
````html
<abp-style-bundle name="MyStyleBundle">
<abp-style src="/styles/my-style1.css" />
<abp-style src="/styles/my-style2.css" />
<abp-style src="https://cdn.abp.io/bootstrap.css" />
<abp-style src="/styles/my-style3.css" />
<abp-style src="/styles/my-style4.css" />
</abp-style-bundle>
<abp-script-bundle name="MyScriptBundle">
<abp-script src="/scripts/my-script1.js" />
<abp-script src="/scripts/my-script2.js" />
<abp-script src="https://cdn.abp.io/bootstrap.js" />
<abp-script src="/scripts/my-script3.js" />
<abp-script src="/scripts/my-script4.js" />
</abp-script-bundle>
````
**HTML de saída:**
````html
<link rel="stylesheet" href="/__bundles/MyStyleBundle.C60C7B9C1F539659623BB6E7227A7C45.css?_v=638331889645002500" />
<link rel="stylesheet" href="https://cdn.abp.io/bootstrap.css" />
<link rel="stylesheet" href="/__bundles/MyStyleBundle.464328A06039091534650B0E049904C6.css?_v=638331889645012300" />
<script src="/__bundles/MyScriptBundle.55FDCBF2DCB9E0767AE6FA7487594106.js?_v=638331889645050410"></script>
<script src="https://cdn.abp.io/bootstrap.js"></script>
<script src="/__bundles/MyScriptBundle.191CB68AB4F41C8BF3A7AE422F19A3D2.js?_v=638331889645055490"></script>
````
## Temas
Os temas usam os contribuidores de pacotes padrão para adicionar recursos de biblioteca aos layouts de página. Os temas também podem definir alguns pacotes padrão/globais, para que qualquer módulo possa contribuir para esses pacotes padrão/globais. Consulte a documentação de [temas](Theming.md) para mais informações.
## Melhores Práticas e Sugestões
É sugerido definir vários pacotes para uma aplicação, cada um usado para diferentes propósitos.
* **Pacote global**: Pacotes de estilo/script globais são incluídos em todas as páginas da aplicação. Os temas já definem pacotes de estilo e script globais. Seu módulo pode contribuir para eles.
* **Pacotes de layout**: Este é um pacote específico para um layout individual. Contém apenas recursos compartilhados entre todas as páginas que usam o layout. Use os tag helpers de agrupamento para criar o pacote como uma boa prática.
* **Pacotes de módulo**: Para recursos compartilhados entre as páginas de um módulo individual.
* **Pacotes de página**: Pacotes específicos criados para cada página. Use os tag helpers de agrupamento para criar o pacote como uma melhor prática.
Estabeleça um equilíbrio entre desempenho, uso de largura de banda da rede e quantidade de pacotes.
## Veja também
* [Gerenciamento de Pacotes do Lado do Cliente](Client-Side-Package-Management.md)
* [Temas](Theming.md)

115
docs/pt-BR/UI/AspNetCore/Client-Side-Package-Management.md

@ -0,0 +1,115 @@
## Gerenciamento de Pacotes do Lado do Cliente no ASP.NET Core MVC
O framework ABP pode funcionar com qualquer tipo de sistema de gerenciamento de pacotes do lado do cliente. Você até pode decidir não usar nenhum sistema de gerenciamento de pacotes e gerenciar suas dependências manualmente.
No entanto, o framework ABP funciona melhor com o **NPM/Yarn**. Por padrão, os módulos integrados são configurados para funcionar com o NPM/Yarn.
Por fim, sugerimos o [**Yarn**](https://classic.yarnpkg.com/) em vez do NPM, pois ele é mais rápido, estável e também compatível com o NPM.
### Pacotes NPM do ABP
O ABP é uma plataforma modular. Todo desenvolvedor pode criar módulos e os módulos devem funcionar juntos em um estado **compatível** e **estável**.
Um desafio são as **versões dos pacotes NPM dependentes**. E se dois módulos diferentes usarem a mesma biblioteca JavaScript, mas em versões diferentes (e potencialmente incompatíveis)?
Para resolver o problema de versionamento, criamos um **conjunto padrão de pacotes** que dependem de algumas bibliotecas de terceiros comuns. Alguns exemplos de pacotes são [@abp/jquery](https://www.npmjs.com/package/@abp/jquery), [@abp/bootstrap](https://www.npmjs.com/package/@abp/bootstrap) e [@abp/font-awesome](https://www.npmjs.com/package/@abp/font-awesome). Você pode ver a **lista de pacotes** no [repositório do GitHub](https://github.com/volosoft/abp/tree/master/npm/packs).
A vantagem de um **pacote padrão** é:
* Ele depende de uma **versão padrão** de um pacote. Depender desse pacote é **seguro** porque todos os módulos dependem da mesma versão.
* Ele contém os mapeamentos para copiar os recursos da biblioteca (arquivos js, css, img...) da pasta `node_modules` para a pasta `wwwroot/libs`. Consulte a seção *Mapeando os Recursos da Biblioteca* para mais informações.
Depender de um pacote padrão é fácil. Basta adicioná-lo ao seu arquivo **package.json** como você normalmente faria. Exemplo:
```json
{
...
"dependencies": {
"@abp/bootstrap": "^1.0.0"
}
}
```
É sugerido depender de um pacote padrão em vez de depender diretamente de um pacote de terceiros.
#### Instalação do Pacote
Depois de depender de um pacote NPM, tudo o que você precisa fazer é executar o comando **yarn** no terminal para instalar todos os pacotes e suas dependências:
```bash
yarn
```
Alternativamente, você pode usar `npm install`, mas o [Yarn](https://classic.yarnpkg.com/) é sugerido como mencionado anteriormente.
#### Contribuição de Pacotes
Se você precisar de um pacote NPM de terceiros que não esteja no conjunto padrão de pacotes, você pode criar uma Pull Request no repositório do Github [repositório](https://github.com/volosoft/abp). Uma Pull Request que segue essas regras é aceita:
* O nome do pacote deve ser `@abp/nome-do-pacote` para um `nome-do-pacote` no NPM (exemplo: `@abp/bootstrap` para o pacote `bootstrap`).
* Deve ser a versão **mais recente estável** do pacote.
* Deve depender apenas de um pacote de terceiros. Pode depender de vários pacotes `@abp/*`.
* O pacote deve incluir um arquivo `abp.resourcemapping.js` formatado como definido na seção *Mapeando os Recursos da Biblioteca*. Este arquivo deve mapear apenas os recursos do pacote dependente.
* Você também precisa criar [contribuidor(es) de pacote](Bundling-Minification.md) para o pacote que você criou.
Veja os pacotes padrão atuais para exemplos.
### Mapeando os Recursos da Biblioteca
O uso de pacotes NPM e da ferramenta NPM/Yarn é o padrão de fato para bibliotecas do lado do cliente. A ferramenta NPM/Yarn cria uma pasta **node_modules** na pasta raiz do seu projeto da web.
O próximo desafio é copiar os recursos necessários (arquivos js, css, img...) da pasta `node_modules` para uma pasta dentro da pasta **wwwroot** para torná-los acessíveis aos clientes/navegadores.
O comando `abp install-libs` da CLI do ABP **copia os recursos** da pasta **node_modules** para a pasta **wwwroot/libs**. Cada **pacote padrão** (consulte a seção *@ABP NPM Packages*) define o mapeamento para seus próprios arquivos. Portanto, na maioria das vezes, você só precisa configurar as dependências.
Os modelos de inicialização já estão configurados para funcionar com tudo isso. Esta seção explicará as opções de configuração.
#### Arquivo de Definição de Mapeamento de Recursos
Um módulo deve definir um arquivo JavaScript chamado `abp.resourcemapping.js` formatado como no exemplo abaixo:
```json
module.exports = {
aliases: {
"@node_modules": "./node_modules",
"@libs": "./wwwroot/libs"
},
clean: [
"@libs",
"!@libs/**/foo.txt"
],
mappings: {
}
}
```
* A seção **aliases** define aliases padrão (placeholders) que podem ser usados nos caminhos de mapeamento. **@node_modules** e **@libs** são obrigatórios (pelos pacotes padrão), você pode definir seus próprios aliases para reduzir a duplicação.
* A seção **clean** é uma lista de pastas a serem limpas antes de copiar os arquivos. A correspondência de glob e a negação estão habilitadas, então você pode ajustar o que excluir e manter. O exemplo acima limpará tudo dentro de `./wwwroot/libs`, mas manterá quaisquer arquivos `foo.txt`.
* A seção **mappings** é uma lista de mapeamentos de arquivos/pastas a serem copiados. Este exemplo não copia nenhum recurso em si, mas depende de um pacote padrão.
Um exemplo de configuração de mapeamento é mostrado abaixo:
```json
mappings: {
"@node_modules/bootstrap/dist/css/bootstrap.css": "@libs/bootstrap/css/",
"@node_modules/bootstrap/dist/js/bootstrap.bundle.js": "@libs/bootstrap/js/",
"@node_modules/bootstrap-datepicker/dist/locales/*.*": "@libs/bootstrap-datepicker/locales/",
"@node_modules/bootstrap-v4-rtl/dist/**/*": "@libs/bootstrap-v4-rtl/dist/"
}
```
#### Comando install-libs
Depois de configurar corretamente o arquivo `abp.resourcemapping.js`, você pode executar o seguinte comando da CLI do ABP no terminal:
````bash
abp install-libs
````
Quando você executar este comando, todos os pacotes copiarão seus próprios recursos para a pasta `wwwroot/libs`. Executar `abp install-libs` é necessário apenas se você fizer uma alteração em suas dependências no arquivo **package.json**.
#### Veja também
* [Empacotamento e Minificação](Bundling-Minification.md)
* [Tematização](Theming.md)

477
docs/pt-BR/UI/AspNetCore/Customization-User-Interface.md

@ -0,0 +1,477 @@
# Guia de Customização da Interface do Usuário do ASP.NET Core (MVC / Razor Pages)
Este documento explica como substituir a interface do usuário de um módulo de aplicativo dependente [módulo de aplicativo](../../Modules/Index.md) ou [tema](Theming.md) para aplicativos ASP.NET Core MVC / Razor Page.
## Substituindo uma Página
Esta seção aborda o desenvolvimento de [Razor Pages](https://docs.microsoft.com/en-us/aspnet/core/razor-pages/), que é a abordagem recomendada para criar interfaces de usuário renderizadas no servidor para o ASP.NET Core. Os módulos pré-construídos geralmente usam a abordagem Razor Pages em vez do padrão clássico MVC (as próximas seções também abordarão o padrão MVC).
Normalmente, você tem três tipos de requisitos de substituição para uma página:
* Substituir apenas o lado do **Modelo de Página** (C#) para executar lógica adicional sem alterar a interface do usuário da página.
* Substituir apenas a **Página Razor** (arquivo .chtml) para alterar a interface do usuário sem alterar o código C# por trás da página.
* **Substituir completamente** a página.
### Substituindo um Modelo de Página (C#)
````csharp
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Identity;
using Volo.Abp.Identity.Web.Pages.Identity.Users;
namespace Acme.BookStore.Web.Pages.Identity.Users
{
[Dependency(ReplaceServices = true)]
[ExposeServices(typeof(EditModalModel))]
public class MyEditModalModel : EditModalModel
{
public MyEditModalModel(
IIdentityUserAppService identityUserAppService,
IIdentityRoleAppService identityRoleAppService
) : base(
identityUserAppService,
identityRoleAppService)
{
}
public async override Task<IActionResult> OnPostAsync()
{
//TODO: Lógica adicional
await base.OnPostAsync();
//TODO: Lógica adicional
}
}
}
````
* Esta classe herda e substitui o `EditModalModel` para os usuários e substitui o método `OnPostAsync` para executar lógica adicional antes e depois do código subjacente.
* Ele usa os atributos `ExposeServices` e `Dependency` para substituir a classe.
### Substituindo uma Página Razor (.CSHTML)
Substituir um arquivo `.cshtml` (página razor, visualização razor, componente de visualização... etc.) é possível criando o mesmo arquivo `.cshtml` no mesmo caminho.
#### Exemplo
Este exemplo substitui a interface do usuário da **página de login** definida pelo [Módulo de Conta](../../Modules/Account.md).
O módulo de conta define um arquivo `Login.cshtml` na pasta `Pages/Account`. Portanto, você pode substituí-lo criando um arquivo no mesmo caminho:
![substituindo-login-cshtml](../../images/overriding-login-cshtml.png)
Normalmente, você deseja copiar o arquivo `.cshtml` original do módulo e fazer as alterações necessárias. Você pode encontrar o arquivo original [aqui](https://github.com/abpframework/abp/blob/dev/modules/account/src/Volo.Abp.Account.Web/Pages/Account/Login.cshtml). Não copie o arquivo `Login.cshtml.cs`, que é o arquivo de código por trás da página razor e não queremos substituí-lo ainda (veja a próxima seção).
> Não se esqueça de adicionar [_ViewImports.cshtml](https://learn.microsoft.com/en-us/aspnet/core/mvc/views/layout?view=aspnetcore-7.0#importing-shared-directives) se a página que você deseja substituir contiver [ABP Tag Helpers](../AspNetCore/Tag-Helpers/Index.md).
````csharp
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
@addTagHelper *, Volo.Abp.AspNetCore.Mvc.UI
@addTagHelper *, Volo.Abp.AspNetCore.Mvc.UI.Bootstrap
@addTagHelper *, Volo.Abp.AspNetCore.Mvc.UI.Bundling
````
Isso é tudo, você pode alterar o conteúdo do arquivo como desejar.
### Substituindo Completamente uma Página Razor
Você pode querer substituir completamente uma página; a página razor e o arquivo C# relacionado à página.
Nesse caso;
1. Substitua a classe do modelo de página C# como descrito acima, mas não substitua a classe de modelo de página existente.
2. Substitua a Página Razor conforme descrito acima, mas também altere a diretiva @model para apontar para o novo modelo de página.
#### Exemplo
Este exemplo substitui a **página de login** definida pelo [Módulo de Conta](../../Modules/Account.md).
Crie uma classe de modelo de página derivada de `LoginModel` (definida no namespace `Volo.Abp.Account.Web.Pages.Account`):
````csharp
public class MyLoginModel : LoginModel
{
public MyLoginModel(
IAuthenticationSchemeProvider schemeProvider,
IOptions<AbpAccountOptions> accountOptions
) : base(
schemeProvider,
accountOptions)
{
}
public override Task<IActionResult> OnPostAsync(string action)
{
//TODO: Adicionar lógica
return base.OnPostAsync(action);
}
//TODO: Adicionar novos métodos e propriedades...
}
````
Você pode substituir qualquer método ou adicionar novas propriedades/métodos, se necessário.
> Observe que não usamos `[Dependency(ReplaceServices = true)]` ou `[ExposeServices(typeof(LoginModel))]` porque não queremos substituir a classe existente na injeção de dependência, definimos uma nova.
Copie o arquivo `Login.cshtml` para a sua solução conforme descrito acima. Altere a diretiva **@model** para apontar para o `MyLoginModel`:
````xml
@page
...
@model Acme.BookStore.Web.Pages.Account.MyLoginModel
...
````
Isso é tudo! Faça qualquer alteração na visualização e execute seu aplicativo.
#### Substituindo o Modelo de Página Sem Herança
Você não precisa herdar da classe de modelo de página original (como feito no exemplo anterior). Em vez disso, você pode **reimplementar completamente** a página você mesmo. Nesse caso, basta derivar de `PageModel`, `AbpPageModel` ou qualquer classe base adequada que você precise.
## Substituindo um Componente de Visualização
O ABP Framework, temas pré-construídos e módulos definem alguns **componentes de visualização reutilizáveis**. Esses componentes de visualização podem ser substituídos da mesma forma que uma página descrita acima.
### Exemplo
A captura de tela abaixo foi tirada do [Tema Básico](Basic-Theme.md) fornecido com o modelo de inicialização do aplicativo.
![bookstore-brand-area-highlighted](../../images/bookstore-brand-area-highlighted.png)
O [Tema Básico](Basic-Theme.md) define alguns componentes de visualização para o layout. Por exemplo, a área destacada com o retângulo vermelho acima é chamada de **componente de marca**. Você provavelmente deseja personalizar esse componente adicionando seu **próprio logotipo do aplicativo**. Vamos ver como fazer isso.
Primeiro, crie seu logotipo e coloque-o em uma pasta em seu aplicativo da web. Usamos o caminho `wwwroot/logos/bookstore-logo.png`. Em seguida, copie a visualização do componente de marca ([aqui](https://github.com/abpframework/abp/blob/dev/modules/basic-theme/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Components/Brand/Default.cshtml)) dos arquivos do tema básico na pasta `Themes/Basic/Components/Brand`. O resultado deve ser semelhante à imagem abaixo:
![bookstore-added-brand-files](../../images/bookstore-added-brand-files.png)
Em seguida, altere o `Default.cshtml` como desejar. O conteúdo de exemplo pode ser assim:
````xml
<a href="/">
<img src="~/logos/bookstore-logo.png" width="250" height="60"/>
</a>
````
Agora, você pode executar o aplicativo para ver o resultado:
![bookstore-added-logo](../../images/bookstore-added-logo.png)
Se necessário, você também pode substituir [o arquivo c# de código por trás](https://github.com/abpframework/abp/blob/dev/modules/basic-theme/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Components/Brand/MainNavbarBrandViewComponent.cs) do componente usando o sistema de injeção de dependência.
### Substituindo o Tema
Assim como explicado acima, você pode substituir qualquer componente, layout ou classe c# do tema usado. Consulte o documento [tematização](Theming.md) para obter mais informações sobre o sistema de tematização.
## Substituindo Recursos Estáticos
Substituir um recurso estático incorporado (como arquivos JavaScript, CSS ou de imagem) de um módulo é bastante fácil. Basta colocar um arquivo no mesmo caminho em sua solução e deixar o [Sistema de Arquivos Virtual](../../Virtual-File-System.md) lidar com ele.
## Manipulando os Pacotes
O sistema de [Empacotamento e Minificação](Bundling-Minification.md) fornece um sistema **extensível e dinâmico** para criar pacotes de **scripts** e **estilos**. Ele permite que você estenda e manipule os pacotes existentes.
### Exemplo: Adicionar um Arquivo CSS Global
Por exemplo, o ABP Framework define um **pacote de estilo global** que é adicionado a todas as páginas (na verdade, adicionado ao layout pelos temas). Vamos adicionar um **arquivo de estilo personalizado** ao final dos arquivos do pacote, para que possamos substituir qualquer estilo global.
Primeiro, crie um arquivo CSS e coloque-o em uma pasta dentro do `wwwroot`:
![bookstore-global-css-file](../../images/bookstore-global-css-file.png)
Defina algumas regras CSS personalizadas dentro do arquivo. Exemplo:
````css
.card-title {
color: orange;
font-size: 2em;
text-decoration: underline;
}
.btn-primary {
background-color: red;
}
````
Em seguida, adicione este arquivo ao pacote global de estilo padrão no método `ConfigureServices` do seu [módulo](../../Module-Development-Basics.md):
````csharp
Configure<AbpBundlingOptions>(options =>
{
options.StyleBundles.Configure(
StandardBundles.Styles.Global, //O nome do pacote!
bundleConfiguration =>
{
bundleConfiguration.AddFiles("/styles/my-global-styles.css");
}
);
});
````
#### O Pacote de Script Global
Assim como o `StandardBundles.Styles.Global`, há um `StandardBundles.Scripts.Global` que você pode adicionar arquivos ou manipular os existentes.
### Exemplo: Manipular os Arquivos do Pacote
O exemplo acima adiciona um novo arquivo ao pacote. Você pode fazer mais se criar uma classe de **contribuinte de pacote**. Exemplo:
````csharp
public class MyGlobalStyleBundleContributor : BundleContributor
{
public override void ConfigureBundle(BundleConfigurationContext context)
{
context.Files.Clear();
context.Files.Add("/styles/my-global-styles.css");
}
}
````
Em seguida, você pode adicionar o contribuinte a um pacote existente:
````csharp
Configure<AbpBundlingOptions>(options =>
{
options.StyleBundles.Configure(
StandardBundles.Styles.Global,
bundleConfiguration =>
{
bundleConfiguration.AddContributors(typeof(MyGlobalStyleBundleContributor));
}
);
});
````
Não é uma boa ideia limpar todos os arquivos CSS. Em um cenário do mundo real, você pode encontrar e substituir um arquivo específico pelo seu próprio arquivo.
### Exemplo: Adicionar um Arquivo JavaScript para uma Página Específica
Os exemplos acima funcionam com o pacote global adicionado ao layout. E se você quiser adicionar um arquivo CSS/JavaScript (ou substituir um arquivo) para uma página específica definida em um módulo dependente?
Suponha que você queira executar um código **JavaScript** assim que o usuário entrar na página de **Gerenciamento de Funções** do Módulo de Identidade.
Primeiro, crie um arquivo JavaScript padrão no `wwwroot`, `Pages` ou `Views` (o ABP suporta adicionar recursos estáticos dentro dessas pastas por padrão). Preferimos a pasta `Pages/Identity/Roles` para seguir as convenções:
![bookstore-added-role-js-file](../../images/bookstore-added-role-js-file.png)
O conteúdo do arquivo é simples:
````js
$(function() {
abp.log.info('Meu arquivo de script de função personalizado foi carregado!');
});
````
Em seguida, adicione este arquivo ao pacote da página de gerenciamento de funções:
````csharp
Configure<AbpBundlingOptions>(options =>
{
options.ScriptBundles
.Configure(
typeof(Volo.Abp.Identity.Web.Pages.Identity.Roles.IndexModel).FullName,
bundleConfig =>
{
bundleConfig.AddFiles("/Pages/Identity/Roles/my-role-script.js");
});
});
````
`typeof(Volo.Abp.Identity.Web.Pages.Identity.Roles.IndexModel).FullName` é a maneira segura de obter o nome do pacote para a página de gerenciamento de funções.
> Observe que nem todas as páginas definem esses pacotes de página. Eles definem apenas se necessário.
Além de adicionar um novo arquivo CSS/JavaScript a uma página, você também pode substituir o existente (definindo um contribuinte de pacote).
## Customização do Layout
Os layouts são definidos pelo tema ([consulte a documentação de tematização](Theming.md)) por design. Eles não estão incluídos em uma solução de aplicativo baixada. Dessa forma, você pode facilmente **atualizar** o tema e obter novos recursos. Você não pode **alterar diretamente** o código do layout em seu aplicativo, a menos que o substitua por seu próprio layout (será explicado nas próximas seções).
Existem algumas maneiras comuns de **personalizar o layout** descritas nas seções a seguir.
### Contribuintes de Menu
Existem dois **menus padrão** definidos pelo ABP Framework:
![bookstore-menus-highlighted](../../images/bookstore-menus-highlighted.png)
* `StandardMenus.Main`: O menu principal do aplicativo.
* `StandardMenus.User`: O menu do usuário (geralmente no canto superior direito da tela).
A renderização dos menus é de responsabilidade do tema, mas os **itens do menu** são determinados pelos módulos e pelo código do seu aplicativo. Basta implementar a interface `IMenuContributor` e **manipular os itens do menu** no método `ConfigureMenuAsync`.
Os contribuintes de menu são executados sempre que precisam renderizar o menu. Já existe um contribuinte de menu definido no **modelo de inicialização do aplicativo**, para que você possa usá-lo como exemplo e melhorar, se necessário. Consulte o documento [menu de navegação](Navigation-Menu.md) para obter mais informações.
### Contribuintes de Barra de Ferramentas
O sistema de [barra de ferramentas](Toolbars.md) é usado para definir **barras de ferramentas** na interface do usuário. Os módulos (ou seu aplicativo) podem adicionar **itens** a uma barra de ferramentas e, em seguida, o tema renderiza a barra de ferramentas no **layout**.
Existe apenas uma **barra de ferramentas padrão** (chamada "Principal" - definida como uma constante: `StandardToolbars.Main`). Para o tema básico, ele é renderizado como mostrado abaixo:![bookstore-toolbar-highlighted](../../images/bookstore-toolbar-highlighted.png)
Na captura de tela acima, existem dois itens adicionados à barra de ferramentas principal: componente de troca de idioma e menu do usuário. Você pode adicionar seus próprios itens aqui.
#### Exemplo: Adicionar um Ícone de Notificação
Neste exemplo, adicionaremos um **ícone de notificação (sino)** à esquerda do item de troca de idioma. Um item na barra de ferramentas deve ser um **componente de visualização**. Portanto, primeiro, crie um novo componente de visualização em seu projeto:
![bookstore-notification-view-component](../../images/bookstore-notification-view-component.png)
**NotificationViewComponent.cs**
````csharp
public class NotificationViewComponent : AbpViewComponent
{
public async Task<IViewComponentResult> InvokeAsync()
{
return View("/Pages/Shared/Components/Notification/Default.cshtml");
}
}
````
**Default.cshtml**
````xml
<div id="MainNotificationIcon" style="color: white; margin: 8px;">
<i class="far fa-bell"></i>
</div>
````
Agora, podemos criar uma classe que implementa a interface `IToolbarContributor`:
````csharp
public class MyToolbarContributor : IToolbarContributor
{
public Task ConfigureToolbarAsync(IToolbarConfigurationContext context)
{
if (context.Toolbar.Name == StandardToolbars.Main)
{
context.Toolbar.Items
.Insert(0, new ToolbarItem(typeof(NotificationViewComponent)));
}
return Task.CompletedTask;
}
}
````
Esta classe adiciona o `NotificationViewComponent` como o primeiro item na barra de ferramentas `Main`.
Finalmente, você precisa adicionar este contribuinte ao `AbpToolbarOptions`, no `ConfigureServices` do seu módulo:
````csharp
Configure<AbpToolbarOptions>(options =>
{
options.Contributors.Add(new MyToolbarContributor());
});
````
Isso é tudo, você verá o ícone de notificação na barra de ferramentas quando executar o aplicativo:
![bookstore-notification-icon-on-toolbar](../../images/bookstore-notification-icon-on-toolbar.png)
O `NotificationViewComponent` neste exemplo simplesmente retorna uma visualização sem nenhum dado. Na vida real, você provavelmente desejará **consultar o banco de dados** (ou chamar uma API HTTP) para obter notificações e passá-las para a visualização. Se necessário, você pode adicionar um arquivo `JavaScript` ou `CSS` ao pacote global (como descrito anteriormente) para o item da barra de ferramentas.
Consulte o documento [barras de ferramentas](Toolbars.md) para obter mais informações sobre o sistema de barras de ferramentas.
### Hooks de Layout
O sistema de [Hooks de Layout](Layout-Hooks.md) permite que você **adicione código** em algumas partes específicas do layout. Todos os layouts de todos os temas devem implementar esses hooks. Em seguida, você pode adicionar um **componente de visualização** em um ponto de hook.
#### Exemplo: Adicionar Script do Google Analytics
Suponha que você precise adicionar o script do Google Analytics ao layout (que estará disponível para todas as páginas). Primeiro, **crie um componente de visualização** em seu projeto:
![bookstore-google-analytics-view-component](../../images/bookstore-google-analytics-view-component.png)
**GoogleAnalyticsViewComponent.cs**
````csharp
public class GoogleAnalyticsViewComponent : AbpViewComponent
{
public IViewComponentResult Invoke()
{
return View("/Pages/Shared/Components/GoogleAnalytics/Default.cshtml");
}
}
````
**Default.cshtml**
````html
<script>
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
ga('create', 'UA-xxxxxx-1', 'auto');
ga('send', 'pageview');
</script>
````
Altere `UA-xxxxxx-1` para o seu próprio código.
Você pode então adicionar este componente a qualquer um dos pontos de hook no `ConfigureServices` do seu módulo:
````csharp
Configure<AbpLayoutHookOptions>(options =>
{
options.Add(
LayoutHooks.Head.Last, //O nome do hook
typeof(GoogleAnalyticsViewComponent) //O componente a ser adicionado
);
});
````
Agora, o código do GA será inserido no `head` da página como o último item. Você (ou os módulos que você está usando) pode adicionar vários itens ao mesmo hook. Todos eles serão adicionados ao layout.
A configuração acima adiciona o `GoogleAnalyticsViewComponent` a todos os layouts. Talvez você queira adicionar apenas a um layout específico:
````csharp
Configure<AbpLayoutHookOptions>(options =>
{
options.Add(
LayoutHooks.Head.Last,
typeof(GoogleAnalyticsViewComponent),
layout: StandardLayouts.Application //Defina o layout a ser adicionado
);
});
````
Consulte a seção de layouts abaixo para saber mais sobre o sistema de layout.
### Layouts
O sistema de layout permite que os temas definam layouts padrão e nomeados e permite que qualquer página selecione um layout adequado para seu propósito. Existem três layouts predefinidos:
* "**Application**": O layout principal (e o padrão) para um aplicativo. Normalmente, contém cabeçalho, menu (barra lateral), rodapé, barra de ferramentas... etc.
* "**Account**": Este layout é usado para login, registro e outras páginas semelhantes. É usado para as páginas na pasta `/Pages/Account` por padrão.
* "**Empty**": Layout vazio e mínimo.
Esses nomes são definidos na classe `StandardLayouts` como constantes. Você pode definitivamente criar seus próprios layouts, mas esses são os nomes padrão dos layouts e são implementados por todos os temas por padrão.
#### Localização do Layout
Você pode encontrar os arquivos de layout [aqui](https://github.com/abpframework/abp/blob/dev/modules/basic-theme/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Layouts) para o tema básico. Você pode usá-los como referência para criar seus próprios layouts ou pode substituí-los, se necessário.
#### ITheme
O ABP Framework usa o serviço `ITheme` para obter a localização do layout pelo nome do layout. Você pode substituir este serviço para selecionar dinamicamente a localização do layout.
#### IThemeManager
`IThemeManager` é usado para obter o tema atual e obter o caminho do layout. Qualquer página pode determinar seu próprio layout. Exemplo:
````html
@using Volo.Abp.AspNetCore.Mvc.UI.Theming
@inject IThemeManager ThemeManager
@{
Layout = ThemeManager.CurrentTheme.GetLayout(StandardLayouts.Empty);
}
````
Esta página usará o layout vazio. Você usa o método de extensão `ThemeManager.CurrentTheme.GetEmptyLayout();` como atalho.
Se você deseja definir o layout para todas as páginas em uma pasta específica, escreva o código acima em um arquivo `_ViewStart.cshtml` dentro dessa pasta.

161
docs/pt-BR/UI/AspNetCore/Data-Table-Column-Extensions.md

@ -0,0 +1,161 @@
# Extensões de Colunas de Tabela de Dados para a Interface do Usuário ASP.NET Core
## Introdução
O sistema de extensão de colunas de tabela de dados permite adicionar uma **nova coluna de tabela** na interface do usuário. O exemplo abaixo adiciona uma nova coluna com o título "Número de Seguro Social":
![user-action-extension-click-me](../../images/table-column-extension-example.png)
Você pode usar as opções de coluna padrão para controlar a coluna da tabela com precisão.
> Observe que esta é uma API de baixo nível para controlar a coluna da tabela. Se você deseja mostrar uma propriedade de extensão na tabela, consulte o documento [extensão de entidade de módulo](../../Module-Entity-Extensions.md).
## Como Configurar
### Criar um Arquivo JavaScript
Primeiro, adicione um novo arquivo JavaScript à sua solução. Nós adicionamos dentro da pasta `/Pages/Identity/Users` do projeto `.Web`:
![user-action-extension-on-solution](../../images/user-action-extension-on-solution.png)
Aqui está o conteúdo deste arquivo JavaScript:
```js
abp.ui.extensions.tableColumns
.get('identity.user')
.addContributor(function (columnList) {
columnList.addTail({ //adicionar como a última coluna
title: 'Número de Seguro Social',
data: 'extraProperties.SocialSecurityNumber',
orderable: false,
render: function (data, type, row) {
if (row.extraProperties.SocialSecurityNumber) {
return '<strong>' +
row.extraProperties.SocialSecurityNumber +
'<strong>';
} else {
return '<i class="text-muted">indefinido</i>';
}
}
});
});
```
Este exemplo define uma função `render` personalizada para retornar um HTML personalizado para ser renderizado na coluna.
### Adicionar o Arquivo à Página de Gerenciamento de Usuários
Em seguida, você precisa adicionar este arquivo JavaScript à página de gerenciamento de usuários. Você pode aproveitar o poder do sistema de [Agrupamento e Minificação](https://docs.abp.io/en/abp/latest/UI/AspNetCore/Bundling-Minification).
Escreva o seguinte código dentro do método `ConfigureServices` da sua classe de módulo:
```csharp
Configure<AbpBundlingOptions>(options =>
{
options.ScriptBundles.Configure(
typeof(Volo.Abp.Identity.Web.Pages.Identity.Users.IndexModel).FullName,
bundleConfiguration =>
{
bundleConfiguration.AddFiles(
"/Pages/Identity/Users/my-user-extensions.js"
);
});
});
```
Esta configuração adiciona `my-user-extensions.js` à página de gerenciamento de usuários do Módulo de Identidade. `typeof(Volo.Abp.Identity.Web.Pages.Identity.Users.IndexModel).FullName` é o nome do pacote na página de gerenciamento de usuários. Esta é uma convenção comum usada para todos os módulos comerciais do ABP.
### Renderizando a Coluna
Este exemplo pressupõe que você definiu uma propriedade extra `SocialSecurityNumber` usando o sistema de [extensão de entidade de módulo](../../Module-Entity-Extensions.md). No entanto;
* Você pode adicionar uma nova coluna relacionada a uma propriedade existente do usuário (que não foi adicionada à tabela por padrão). Exemplo:
````js
abp.ui.extensions.tableColumns
.get('identity.user')
.addContributor(function (columnList) {
columnList.addTail({
title: 'Telefone confirmado?',
data: 'phoneNumberConfirmed',
render: function (data, type, row) {
if (row.phoneNumberConfirmed) {
return '<strong style="color: green">SIM<strong>';
} else {
return '<i class="text-muted">NÃO</i>';
}
}
});
});
````
* Você pode adicionar uma nova coluna personalizada que não está relacionada a nenhuma propriedade da entidade, mas sim a uma informação completamente personalizada. Exemplo:
````js
abp.ui.extensions.tableColumns
.get('identity.user')
.addContributor(function (columnList) {
columnList.addTail({
title: 'Coluna personalizada',
data: {},
orderable: false,
render: function (data) {
if (data.phoneNumber) {
return "ligar: " + data.phoneNumber;
} else {
return '';
}
}
});
});
````
## API
Esta seção explica os detalhes da API JavaScript `abp.ui.extensions.tableColumns`.
### abp.ui.extensions.tableColumns.get(nomeEntidade)
Este método é usado para acessar as colunas da tabela para uma entidade de um módulo específico. Ele recebe um parâmetro:
* **nomeEntidade**: O nome da entidade definido pelo módulo relacionado.
### abp.ui.extensions.tableColumns.get(nomeEntidade).columns
A propriedade `columns` é usada para recuperar uma [lista duplamente encadeada](../Common/Utils/Linked-List.md) de colunas previamente definidas para uma tabela. Todos os contribuidores são executados na ordem para preparar a lista final de colunas. Isso é normalmente chamado pelos módulos para mostrar as colunas na tabela. No entanto, você pode usá-lo se estiver construindo suas próprias interfaces extensíveis.
### abp.ui.extensions.tableColumns.get(nomeEntidade).addContributor(contributeCallback [, order])
O método `addContributor` cobre todos os cenários, por exemplo, se você deseja adicionar sua coluna em uma posição diferente na lista, alterar ou remover uma coluna existente. `addContributor` tem os seguintes parâmetros:
* **contributeCallback**: Uma função de retorno de chamada que é chamada sempre que a lista de colunas deve ser criada. Você pode modificar livremente a lista de colunas dentro deste método de retorno de chamada.
* **order** (opcional): A ordem da chamada na lista de chamadas. Sua chamada é adicionada ao final da lista (portanto, você tem a oportunidade de modificar as colunas adicionadas pelos contribuidores anteriores). Você pode definir `0` para adicionar seu contribuidor como o primeiro item.
#### Exemplo
```js
var myColumnDefinition = {
title: 'Coluna personalizada',
data: {},
orderable: false,
render: function(data) {
if (data.phoneNumber) {
return "ligar: " + data.phoneNumber;
} else {
return '';
}
}
};
abp.ui.extensions.tableColumns
.get('identity.user')
.addContributor(function (columnList) {
// Remover um item da lista de ações
columnList.dropHead();
// Adicionar um novo item à lista de ações
columnList.addHead(myColumnDefinition);
});
```
> `columnList` é uma [lista encadeada](../Common/Utils/Linked-List.md). Você pode usar seus métodos para construir uma lista de colunas da maneira que precisar.

298
docs/pt-BR/UI/AspNetCore/Data-Tables.md

@ -0,0 +1,298 @@
# ASP.NET Core MVC / Razor Pages: Tabelas de Dados
Uma Tabela de Dados (também conhecida como Data Grid) é um componente de interface do usuário para mostrar dados tabulares aos usuários. Existem muitos componentes/bibliotecas de Tabela de Dados e **você pode usar qualquer um que preferir** com o ABP Framework. No entanto, os modelos de inicialização vêm com a biblioteca [DataTables.Net](https://datatables.net/) já **pré-instalada e configurada**. O ABP Framework fornece adaptadores para essa biblioteca e facilita o uso com os endpoints da API.
Uma captura de tela de exemplo da página de gerenciamento de usuários que mostra a lista de usuários em uma tabela de dados:
![exemplo-datatables](../../images/exemplo-datatables.png)
## Integração com o DataTables.Net
Antes de tudo, você pode seguir a documentação oficial para entender como o [DataTables.Net](https://datatables.net/) funciona. Esta seção se concentrará nos complementos e pontos de integração do ABP, em vez de cobrir completamente o uso dessa biblioteca.
### Um Exemplo Rápido
Você pode seguir o [tutorial de desenvolvimento de aplicativos da web](https://docs.abp.io/en/abp/latest/Tutorials/Part-1?UI=MVC) para um exemplo completo de aplicativo que usa o DataTables.Net como Tabela de Dados. Esta seção mostra um exemplo minimalista.
Você não precisa fazer nada para adicionar a biblioteca DataTables.Net à página, pois ela já está adicionada ao [pacote](Bundling-Minification.md) global por padrão.
Primeiro, adicione um `abp-table` como mostrado abaixo, com um `id`:
````html
<abp-table striped-rows="true" id="BooksTable"></abp-table>
````
> `abp-table` é um [Tag Helper](Tag-Helpers/Index.md) definido pelo ABP Framework, mas uma simples tag `<table...>` também funcionaria.
Em seguida, chame o plugin `DataTable` no seletor da tabela:
````js
var dataTable = $('#BooksTable').DataTable(
abp.libs.datatables.normalizeConfiguration({
serverSide: true,
paging: true,
order: [[1, "asc"]],
searching: false,
ajax: abp.libs.datatables.createAjax(acme.bookStore.books.book.getList),
columnDefs: [
{
title: l('Ações'),
rowAction: {
items:
[
{
text: l('Editar'),
action: function (data) {
///...
}
}
]
}
},
{
title: l('Nome'),
data: "name"
},
{
title: l('Data de Publicação'),
data: "publishDate",
render: function (data) {
return luxon
.DateTime
.fromISO(data, {
locale: abp.localization.currentCulture.name
}).toLocaleString();
}
},
{
title: l('Preço'),
data: "price"
}
]
})
);
````
O código de exemplo acima usa algumas funcionalidades de integração do ABP que serão explicadas nas próximas seções.
### Normalização de Configuração
A função `abp.libs.datatables.normalizeConfiguration` recebe uma configuração do DataTables e a normaliza para simplificá-la;
* Define a opção `scrollX` como `true`, se não estiver definida.
* Define o índice `target` para as definições de coluna.
* Define a opção `language` para [localizar](../../Localization.md) a tabela no idioma atual.
#### Configuração Padrão
`normalizeConfiguration` usa a configuração padrão. Você pode alterar a configuração padrão usando o objeto `abp.libs.datatables.defaultConfigurations`. Exemplo:
````js
abp.libs.datatables.defaultConfigurations.scrollX = false;
````
Aqui estão todas as opções de configuração;
* `scrollX`: `false` por padrão.
* `dom`: O valor padrão é `<"dataTable_filters"f>rt<"row dataTable_footer"<"col-auto"l><"col-auto"i><"col"p>>`.
* `language`: Uma função que retorna o texto de localização usando o idioma atual.
### Adaptador AJAX
O DataTables.Net possui seu próprio formato de dados esperado ao obter os resultados de uma chamada AJAX para o servidor para obter os dados da tabela. Eles estão especialmente relacionados a como os parâmetros de paginação e ordenação são enviados e recebidos. O ABP Framework também oferece suas próprias convenções para a comunicação [AJAX](JavaScript-API/Ajax.md) cliente-servidor.
O método `abp.libs.datatables.createAjax` (usado no exemplo acima) adapta o formato dos dados de solicitação e resposta e funciona perfeitamente com o sistema [Dynamic JavaScript Client Proxy](Dynamic-JavaScript-Proxies.md).
Isso funciona automaticamente, então na maioria das vezes você não precisa saber como funciona. Consulte o documento [DTO](../../Data-Transfer-Objects.md) se você quiser aprender mais sobre `IPagedAndSortedResultRequest`, `IPagedResult` e outras interfaces padrão e classes DTO base usadas na comunicação cliente-servidor.
O `createAjax` também permite que você personalize os parâmetros de solicitação e manipule as respostas.
**Exemplo:**
````csharp
var inputAction = function (requestData, dataTableSettings) {
return {
id: $('#Id').val(),
name: $('#Name').val(),
};
};
var responseCallback = function(result) {
// seu código personalizado.
return {
recordsTotal: result.totalCount,
recordsFiltered: result.totalCount,
data: result.items
};
};
ajax: abp.libs.datatables.createAjax(acme.bookStore.books.book.getList, inputAction, responseCallback)
````
Se você não precisa acessar ou modificar o `requestData` ou o `dataTableSettings`, você pode especificar um objeto simples como segundo parâmetro.
````js
ajax: abp.libs.datatables.createAjax(
acme.bookStore.books.book.getList,
{ id: $('#Id').val(), name: $('#Name').val() }
)
````
### Ações de Linha
`rowAction` é uma opção definida pelo ABP Framework para as definições de coluna para mostrar um botão suspenso para executar ações para uma linha na tabela.
A captura de tela de exemplo abaixo mostra as ações para cada usuário na tabela de gerenciamento de usuários:
![exemplo-datatables](../../images/exemplo-datatables-acao-linha.png)
`rowAction` é definido como parte de uma definição de coluna:
````csharp
{
title: l('Ações'),
rowAction: {
//TODO: CONFIGURAÇÃO
}
},
````
**Exemplo: Mostrar ações *Editar* e *Excluir* para uma linha de livro**
````js
{
title: l('Ações'),
rowAction: {
items:
[
{
text: l('Editar'),
action: function (data) {
//TODO: Abrir um modal para editar o livro
}
},
{
text: l('Excluir'),
confirmMessage: function (data) {
return "Tem certeza de que deseja excluir o livro " + data.record.name;
},
action: function (data) {
acme.bookStore.books.book
.delete(data.record.id)
.then(function() {
abp.notify.info("Excluído com sucesso!");
data.table.ajax.reload();
});
}
}
]
}
},
````
#### Itens de Ação
`items` é uma matriz de definições de ação. Uma definição de ação pode ter as seguintes opções;
* `text`: O texto (uma `string`) para esta ação a ser mostrada no menu suspenso de ações.
* `action`: Uma `function` que é executada quando o usuário clica na ação. A função recebe um argumento `data` que possui os seguintes campos;
* `data.record`: Este é o objeto de dados relacionado à linha. Você pode acessar os campos de dados como `data.record.id`, `data.record.name`... etc.
* `data.table`: A instância DataTables.
* `confirmMessage`: Uma `function` (veja o exemplo acima) que retorna uma mensagem (`string`) para mostrar um diálogo para obter uma confirmação do usuário antes de executar a `action`. Exemplo de diálogo de confirmação:
![exemplo-datatables-acao-linha-confirmacao](../../images/exemplo-datatables-acao-linha-confirmacao.png)
Você pode usar o sistema de [localização](JavaScript-API/Localization.md) para mostrar uma mensagem localizada.
* `visible`: Um `bool` ou uma `function` que retorna um `bool`. Se o resultado for `false`, então a ação não é mostrada no menu suspenso de ações. Isso geralmente é combinado com o sistema de [autorização](JavaScript-API/Auth.md) para ocultar a ação se o usuário não tiver permissão para executar essa ação. Exemplo:
````js
visible: abp.auth.isGranted('BookStore.Books.Delete');
````
Se você definir uma `function`, então a `function` tem dois argumentos: `record` (o objeto de dados da linha relacionada) e a `table` (a instância DataTables). Portanto, você pode decidir mostrar/ocultar a ação dinamicamente, com base nos dados da linha e em outras condições.
* `iconClass`: Pode ser usado para mostrar um ícone de fonte, como um ícone [Font-Awesome](https://fontawesome.com/) (ex: `fas fa-trash-alt`), próximo ao texto da ação. Captura de tela de exemplo:
![exemplo-datatables-acao-linha-icon](../../images/exemplo-datatables-acao-linha-icon.png)
* `enabled`: Uma `function` que retorna um `bool` para desabilitar a ação. A `function` recebe um objeto `data` com dois campos: `data.record` é o objeto de dados relacionado à linha e `data.table` é a instância DataTables.
* `displayNameHtml`: Defina isso como `true` se o valor `text` contiver tags HTML.
Existem algumas regras com os itens de ação;
* Se nenhum dos itens de ação for visível, a coluna de ações não será renderizada.
### Formato de Dados
#### O Problema
Veja a coluna *Data de Criação* no exemplo abaixo:
````js
{
title: l('CreationTime'),
data: "creationTime",
render: function (data) {
return luxon
.DateTime
.fromISO(data, {
locale: abp.localization.currentCulture.name
}).toLocaleString(luxon.DateTime.DATETIME_SHORT);
}
}
````
O `render` é uma opção padrão do DataTables para renderizar o conteúdo da coluna por uma função personalizada. Este exemplo usa a biblioteca [luxon](https://moment.github.io/luxon/) (que é instalada por padrão) para escrever um valor legível por humanos do `creationTime` no idioma atual do usuário. Exemplo de saída da coluna:
![exemplo-datatables-custom-render-date](../../images/exemplo-datatables-custom-render-date.png)
Se você não definir a opção de renderização, o resultado será feio e não amigável ao usuário:
![exemplo-datatables-custom-render-date](../../images/exemplo-datatables-default-render-date.png)
No entanto, renderizar um `DateTime` é quase o mesmo e repetir a mesma lógica de renderização em todos os lugares vai contra o princípio DRY (Don't Repeat Yourself!).
#### Opção dataFormat
A opção `dataFormat` da coluna especifica o formato de dados que é usado para renderizar os dados da coluna. A mesma saída poderia ser alcançada usando a seguinte definição de coluna:
````js
{
title: l('CreationTime'),
data: "creationTime",
dataFormat: 'datetime'
}
````
`dataFormat: 'datetime'` especifica o formato de dados para esta coluna. Existem alguns `dataFormat`s pré-definidos:
* `boolean`: Mostra um ícone de `check` para o valor `true` e um ícone de `times` para o valor `false` e é útil para renderizar valores `bool`.
* `date`: Mostra a parte da data de um valor `DateTime`, formatado com base na cultura atual.
* `datetime`: Mostra a data e a hora (excluindo segundos) de um valor `DateTime`, formatado com base na cultura atual.
### Renderizadores Padrão
A opção `abp.libs.datatables.defaultRenderers` permite que você defina novos formatos de dados e defina renderizadores para eles.
**Exemplo: Renderizar ícones de masculino/feminino com base no gênero**
````js
abp.libs.datatables.defaultRenderers['gender'] = function(value) {
if (value === 'f') {
return '<i class="fa fa-venus"></i>';
} else {
return '<i class="fa fa-mars"></i>';
}
};
````
Supondo que os valores possíveis para os dados de uma coluna sejam `f` e `m`, o formato de dados `gender` mostra ícones femininos/masculinos em vez dos textos `f` e `m`. Agora você pode definir `dataFormat: 'gender'` para uma definição de coluna que tenha os valores de dados adequados.
> Você pode escrever os renderizadores padrão em um único arquivo JavaScript e adicioná-lo ao [Pacote de Scripts Global](Bundling-Minification.md), para que você possa reutilizá-los em todas as páginas.
## Outras Tabelas de Dados
Você pode usar qualquer biblioteca que preferir. Por exemplo, [veja este artigo](https://community.abp.io/articles/using-devextreme-components-with-the-abp-framework-zb8z7yqv) para aprender como usar o DevExtreme Data Grid em seus aplicativos.

97
docs/pt-BR/UI/AspNetCore/Dynamic-JavaScript-Proxies.md

@ -0,0 +1,97 @@
# Proxies de Cliente de API JavaScript Dinâmico
É comum consumir suas APIs HTTP a partir do seu código JavaScript. Para fazer isso, normalmente você lida com chamadas AJAX de baixo nível, como $.ajax, ou melhor [abp.ajax](JavaScript-API/Ajax.md). O ABP Framework fornece **uma maneira melhor** de chamar suas APIs HTTP a partir do seu código JavaScript: Proxies de Cliente de API JavaScript!
## Proxies de Cliente JavaScript Estáticos vs Dinâmicos
O ABP fornece **dois tipos** de sistema de geração de proxy de cliente. Este documento explica os **proxies de cliente dinâmicos**, que geram proxies do lado do cliente em tempo de execução. Você também pode ver a documentação de [Proxies de Cliente de API JavaScript Estáticos](Static-JavaScript-Proxies.md) para aprender como gerar proxies em tempo de desenvolvimento.
A geração de proxy de cliente em tempo de desenvolvimento (estático) tem uma **ligeira vantagem de desempenho**, pois não precisa obter a definição da API HTTP em tempo de execução. No entanto, você deve **regenerar** o código do proxy de cliente sempre que alterar a definição do ponto de extremidade da API. Por outro lado, os proxies de cliente dinâmicos são gerados em tempo de execução e oferecem uma **experiência de desenvolvimento mais fácil**.
## Um Exemplo Rápido
Suponha que você tenha um serviço de aplicativo definido como mostrado abaixo:
````csharp
using System;
using System.Threading.Tasks;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Application.Services;
namespace Acme.BookStore.Authors
{
public interface IAuthorAppService : IApplicationService
{
Task<AuthorDto> GetAsync(Guid id);
Task<PagedResultDto<AuthorDto>> GetListAsync(GetAuthorListDto input);
Task<AuthorDto> CreateAsync(CreateAuthorDto input);
Task UpdateAsync(Guid id, UpdateAuthorDto input);
Task DeleteAsync(Guid id);
}
}
````
> Você pode seguir o [tutorial de desenvolvimento de aplicativos da web](../../Tutorials/Part-1.md) para aprender como criar [serviços de aplicativos](../../Application-Services.md), expô-los como [APIs HTTP](../../API/Auto-API-Controllers.md) e consumir do código JavaScript como um exemplo completo.
Você pode chamar qualquer um dos métodos como se estivesse chamando uma função JavaScript. A função JavaScript tem o mesmo **nome**, **parâmetros** e **valor de retorno** do método C#.
**Exemplo: Obter a lista de autores**
````js
acme.bookStore.authors.author.getList({
maxResultCount: 10
}).then(function(result){
console.log(result.items);
});
````
**Exemplo: Excluir um autor**
```js
acme.bookStore.authors.author
.delete('7245a066-5457-4941-8aa7-3004778775f0') //Obtenha o id de algum lugar!
.then(function() {
abp.notify.info('Excluído com sucesso!');
});
```
## Detalhes do AJAX
As funções de proxy de cliente JavaScript usam o [abp.ajax](JavaScript-API/Ajax.md) por baixo dos panos. Portanto, você tem os mesmos benefícios, como **tratamento automático de erros**. Além disso, você pode controlar totalmente a chamada AJAX fornecendo as opções.
### O Valor de Retorno
Cada função retorna um [objeto Deferred](https://api.jquery.com/category/deferred-object/). Isso significa que você pode encadear com `then` para obter o resultado, `catch` para lidar com o erro, `always` para executar uma ação assim que a operação for concluída (com sucesso ou falha).
### Opções do AJAX
Cada função recebe um **último parâmetro** adicional após seus próprios parâmetros. O último parâmetro é chamado de `ajaxParams`. É um objeto que substitui as opções do AJAX.
**Exemplo: Definir as opções do AJAX `type` e `dataType`**
````js
acme.bookStore.authors.author
.delete('7245a066-5457-4941-8aa7-3004778775f0', {
type: 'POST',
dataType: 'xml'
})
.then(function() {
abp.notify.info('Excluído com sucesso!');
});
````
Consulte a documentação do [jQuery.ajax](https://api.jquery.com/jQuery.ajax/) para todas as opções disponíveis.
## Endpoint do Script de Proxy de Serviço
A mágica é feita pelo endpoint `/Abp/ServiceProxyScript` definido pelo ABP Framework e adicionado automaticamente ao layout. Você pode visitar este endpoint em sua aplicação para ver as definições das funções de proxy de cliente. Este arquivo de script é gerado automaticamente pelo ABP Framework com base nas definições dos métodos do lado do servidor e nos detalhes do ponto de extremidade HTTP relacionado.
## Veja Também
* [Proxies de Cliente de API JavaScript Estáticos](Static-JavaScript-Proxies.md)
* [Controladores de API Automáticos](../../API/Auto-API-Controllers.md)
* [Tutorial de Desenvolvimento de Aplicativos da Web](../../Tutorials/Part-1.md)

108
docs/pt-BR/UI/AspNetCore/Entity-Action-Extensions.md

@ -0,0 +1,108 @@
# Extensões de Ação de Entidade para a Interface do Usuário do ASP.NET Core
## Introdução
O sistema de extensão de ação de entidade permite adicionar uma **nova ação** ao menu de ações de uma entidade. Uma ação **Clique em Mim** foi adicionada à página de *Gerenciamento de Usuários* abaixo:
![user-action-extension-click-me](../../images/user-action-extension-click-me.png)
Você pode executar qualquer ação (abrir um modal, fazer uma chamada de API HTTP, redirecionar para outra página... etc) escrevendo seu código personalizado. Você pode acessar a entidade atual em seu código.
## Como Configurar
Neste exemplo, adicionaremos uma ação "Clique em Mim!" e executaremos um código JavaScript para a página de gerenciamento de usuários do [Módulo de Identidade](../../Modules/Identity.md).
### Criar um Arquivo JavaScript
Primeiro, adicione um novo arquivo JavaScript à sua solução. Nós adicionamos dentro da pasta `/Pages/Identity/Users` do projeto `.Web`:
![user-action-extension-on-solution](../../images/user-action-extension-on-solution.png)
Aqui está o conteúdo deste arquivo JavaScript:
```js
var clickMeAction = {
text: 'Clique em Mim!',
action: function(data) {
//TODO: Escreva seu código personalizado
alert(data.record.userName);
}
};
abp.ui.extensions.entityActions
.get('identity.user')
.addContributor(function(actionList) {
actionList.addTail(clickMeAction);
});
```
Na função `action`, você pode fazer qualquer coisa que precisar. Consulte a seção API para obter um uso detalhado.
### Adicionar o Arquivo à Página de Gerenciamento de Usuários
Em seguida, você precisa adicionar este arquivo JavaScript à página de gerenciamento de usuários. Você pode aproveitar o poder do [Sistema de Agrupamento e Minificação](Bundling-Minification.md).
Escreva o seguinte código dentro do método `ConfigureServices` da sua classe de módulo:
```csharp
Configure<AbpBundlingOptions>(options =>
{
options.ScriptBundles.Configure(
typeof(Volo.Abp.Identity.Web.Pages.Identity.Users.IndexModel).FullName,
bundleConfiguration =>
{
bundleConfiguration.AddFiles(
"/Pages/Identity/Users/my-user-extensions.js"
);
});
});
```
Essa configuração adiciona `my-user-extensions.js` à página de gerenciamento de usuários do Módulo de Identidade. `typeof(Volo.Abp.Identity.Web.Pages.Identity.Users.IndexModel).FullName` é o nome do pacote na página de gerenciamento de usuários. Essa é uma convenção comum usada para todos os módulos comerciais do ABP.
Isso é tudo. Execute sua aplicação para ver o resultado.
## API
Esta seção explica os detalhes da API JavaScript `abp.ui.extensions.entityActions`.
### abp.ui.extensions.entityActions.get(entityName)
Este método é usado para acessar as ações de entidade de um módulo específico. Ele recebe um parâmetro:
* **entityName**: O nome da entidade definido pelo módulo relacionado.
### abp.ui.extensions.entityActions.get(entityName).actions
A propriedade `actions` é usada para recuperar uma [lista duplamente encadeada](../Common/Utils/Linked-List.md) de ações previamente definidas para uma entidade. Todos os contribuidores são executados para preparar a lista final de ações. Isso é normalmente chamado pelos módulos para mostrar as ações na grade. No entanto, você pode usá-lo se estiver construindo suas próprias interfaces extensíveis.
### abp.ui.extensions.entityActions.get(entityName).addContributor(contributeCallback)
O método `addContributor` cobre todos os cenários, por exemplo, se você deseja adicionar sua ação em uma posição diferente na lista, alterar ou remover um item de ação existente. `addContributor` com o seguinte parâmetro:
* **contributeCallback**: Uma função de retorno de chamada que é chamada sempre que a lista de ações deve ser criada. Você pode modificar livremente a lista de ações dentro deste método de retorno de chamada.
#### Exemplo
```js
var clickMe2Action = {
text: 'Clique em Mim 2!',
icon: 'fas fa-hand-point-right',
action: function(data) {
//TODO: Escreva seu código personalizado
alert(data.record.userName);
}
};
abp.ui.extensions.entityActions
.get('identity.user')
.addContributor(function(actionList) {
// Remover um item da actionList
actionList.dropHead();
// Adicionar o novo item à actionList
actionList.addHead(clickMe2Action);
});
```
> `actionList` é uma [lista encadeada](../Common/Utils/Linked-List.md). Você pode usar seus métodos para construir uma lista de colunas da maneira que precisar.

227
docs/pt-BR/UI/AspNetCore/Forms-Validation.md

@ -0,0 +1,227 @@
# ASP.NET Core MVC / Razor Pages: Formulários e Validação
O ABP Framework fornece infraestrutura e convenções para facilitar a criação de formulários, localizar nomes de exibição para os elementos do formulário e lidar com validação no lado do servidor e do cliente;
* O helper de tag [abp-dynamic-form](Tag-Helpers/Dynamic-Forms.md) automatiza a criação de um **formulário completo** a partir de uma classe de modelo C#: cria os elementos de entrada, lida com a localização e validação no lado do cliente.
* Os helpers de tag [ABP Form](Tag-Helpers/Form-elements.md) (`abp-input`, `abp-select`, `abp-radio`...) renderizam **um único elemento de formulário** com localização e validação no lado do cliente.
* O ABP Framework automaticamente **localiza o nome de exibição** de um elemento do formulário sem a necessidade de adicionar um atributo `[DisplayName]`.
* Os **erros de validação** são automaticamente localizados com base na cultura do usuário.
> Este documento é para a **validação no lado do cliente** e não cobre a validação no lado do servidor. Verifique o [documento de validação](../../Validation.md) para a infraestrutura de validação no lado do servidor.
## O Modo Clássico
Em uma típica interface de usuário ASP.NET Core MVC / Razor Pages baseada no Bootstrap, você [precisa escrever](https://docs.microsoft.com/en-us/aspnet/core/mvc/models/validation#client-side-validation) um código boilerplate como este para criar um elemento de formulário simples:
````html
<div class="form-group">
<label asp-for="Movie.ReleaseDate" class="control-label"></label>
<input asp-for="Movie.ReleaseDate" class="form-control" />
<span asp-validation-for="Movie.ReleaseDate" class="text-danger"></span>
</div>
````
Você pode continuar usando essa abordagem se precisar ou preferir. No entanto, os helpers de tag do ABP Form podem produzir a mesma saída com um código mínimo.
## ABP Dynamic Forms
O helper de tag [abp-dynamic-form](Tag-Helpers/Dynamic-Forms.md) automatiza completamente a criação do formulário. Considere esta classe de modelo como exemplo:
```csharp
using System;
using System.ComponentModel.DataAnnotations;
using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form;
namespace MyProject.Web.Pages
{
public class MovieViewModel
{
[Required]
[StringLength(256)]
public string Name { get; set; }
[Required]
[DataType(DataType.Date)]
public DateTime ReleaseDate { get; set; }
[Required]
[TextArea]
[StringLength(1000)]
public string Description { get; set; }
public Genre Genre { get; set; }
public float? Price { get; set; }
public bool PreOrder { get; set; }
}
}
```
Ele usa os atributos de anotação de dados para definir regras de validação e estilos de UI para as propriedades. `Genre` é um `enum` neste exemplo:
````csharp
namespace MyProject.Web.Pages
{
public enum Genre
{
Classic,
Action,
Fiction,
Fantasy,
Animation
}
}
````
Para criar o formulário em uma página razor, crie uma propriedade na sua classe `PageModel`:
```csharp
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
namespace MyProject.Web.Pages
{
public class CreateMovieModel : PageModel
{
[BindProperty]
public MovieViewModel Movie { get; set; }
public void OnGet()
{
Movie = new MovieViewModel();
}
public async Task OnPostAsync()
{
if (ModelState.IsValid)
{
//TODO: Salvar o Filme
}
}
}
}
```
Em seguida, você pode renderizar o formulário no arquivo `.cshtml`:
```html
@page
@model MyProject.Web.Pages.CreateMovieModel
<h2>Criar um novo Filme</h2>
<abp-dynamic-form abp-model="Movie" submit-button="true" />
```
O resultado é mostrado abaixo:
![abp-dynamic-form-result](../../images/abp-dynamic-form-result.png)
Consulte a seção *Localização e Validação* abaixo para localizar os nomes de exibição dos campos e ver como a validação funciona.
> Consulte [seu próprio documento](Tag-Helpers/Dynamic-Forms.md) para todas as opções do helper de tag `abp-dynamic-form`.
## ABP Form Tag Helpers
O `abp-dynamic-form` cobre a maioria dos cenários e permite controlar e personalizar o formulário usando os atributos.
No entanto, se você quiser **renderizar o corpo do formulário você mesmo** (por exemplo, se você quiser ter controle total sobre o **layout do formulário**), você pode usar diretamente os [ABP Form Tag Helpers](Tag-Helpers/Form-elements.md). O mesmo formulário auto-gerado acima pode ser criado usando os ABP Form Tag Helpers, como mostrado abaixo:
```html
@page
@model MyProject.Web.Pages.CreateMovieModel
<h2>Criar um novo Filme</h2>
<form method="post">
<abp-input asp-for="Movie.Name"/>
<abp-input asp-for="Movie.ReleaseDate"/>
<abp-input asp-for="Movie.Description"/>
<abp-select asp-for="Movie.Genre"/>
<abp-input asp-for="Movie.Price"/>
<abp-input asp-for="Movie.PreOrder"/>
<abp-button button-type="Primary" type="submit">Salvar</abp-button>
</form>
```
> Consulte o documento [ABP Form Tag Helpers](Tag-Helpers/Form-elements.md) para obter detalhes desses helpers de tag e suas opções.
## Validação e Localização
Tanto o Dynamic Form quanto os Form Tag Helpers **validam automaticamente** a entrada com base nos atributos de anotação de dados e exibem mensagens de erro de validação na interface do usuário. As mensagens de erro são **automaticamente localizadas** com base na cultura atual.
**Exemplo: O usuário deixa vazio uma propriedade de string obrigatória**
![abp-form-input-validation-error](../../images/abp-form-input-validation-error.png)
A mensagem de erro abaixo é mostrada se o idioma for francês:
![abp-form-input-validation-error](../../images/abp-form-input-validation-error-french.png)
Os erros de validação já estão [traduzidos](https://github.com/abpframework/abp/tree/dev/framework/src/Volo.Abp.Validation/Volo/Abp/Validation/Localization) em muitos idiomas. Você pode [contribuir](../../Contribution/Index.md) para a tradução do seu próprio idioma ou substituir os textos para sua própria aplicação seguindo a documentação de [localização](../../Localization.md).
## Localização do Nome de Exibição
O ABP Framework usa o nome da propriedade como o nome do campo na interface do usuário. Normalmente, você deseja [localizar](../../Localization.md) esse nome com base na cultura atual.
O ABP Framework pode localizar convencionalmente os campos na interface do usuário quando você adiciona as chaves de localização aos arquivos JSON de localização.
Exemplo: Localização em francês para a propriedade *Name* (adicionar ao `fr.json` na aplicação):
````js
"Name": "Nom"
````
Então, a interface do usuário usará o nome fornecido para o idioma francês:
![abp-form-input-validation-error](../../images/abp-form-input-validation-error-french-name.png)
### Usando o Prefixo `DisplayName:`
Usar diretamente o nome da propriedade como chave de localização pode ser um problema se você precisar usar o nome da propriedade para outro propósito, com um valor de tradução diferente. Nesse caso, use o prefixo `DisplayName:` para a chave de localização:
````js
"DisplayName:Name": "Nom"
````
O ABP prefere usar a chave `DisplayName:Name` em vez da chave `Name` se ela existir.
### Usando uma Chave de Localização Personalizada
Se necessário, você pode usar o atributo `[DisplayName]` para especificar a chave de localização para uma propriedade específica:
````csharp
[DisplayName("MyNameKey")]
public string Name { get; set; }
````
Nesse caso, você pode adicionar uma entrada ao arquivo de localização usando a chave `MyNameKey`.
> Se você usar o `[DisplayName]` mas não adicionar uma entrada correspondente ao arquivo de localização, o ABP Framework mostrará a chave fornecida como o nome do campo, `MyNameKey` para esse caso. Portanto, ele fornece uma maneira de especificar um nome de exibição codificado mesmo se você não precisar usar o sistema de localização.
### Localização de Enum
Os membros do Enum também são automaticamente localizados sempre que possível. Por exemplo, quando adicionamos `<abp-select asp-for="Movie.Genre"/>` ao formulário (como fizemos na seção *ABP Form Tag Helpers*), o ABP pode preencher automaticamente os nomes localizados dos membros do Enum. Para habilitar isso, você deve definir os valores localizados no arquivo JSON de localização. Exemplo de entradas para o Enum `Genre` definido na seção *ABP Form Tag Helpers*:
````json
"Enum:Genre.0": "Filme Clássico",
"Enum:Genre.1": "Filme de Ação",
"Enum:Genre.2": "Ficção",
"Enum:Genre.3": "Fantasia",
"Enum:Genre.4": "Animação/Desenho"
````
Você pode usar uma das seguintes sintaxes para as chaves de localização:
* `Enum:<nome-do-tipo-enum>.<valor-do-enum>`
* `<nome-do-tipo-enum>.<valor-do-enum>`
> Lembre-se de que se você não especificar valores para o seu Enum, os valores serão ordenados, começando em `0`.
> Os helpers de tag do MVC também suportam o uso de nomes de membros do Enum em vez de valores (então, você pode definir `"Enum:Genre.Action"` em vez de `"Enum:Genre.1"`, por exemplo), mas isso não é sugerido. Porque, quando você serializa propriedades Enum para JSON e envia para clientes, o serializador padrão usa os valores Enum em vez dos nomes do Enum. Portanto, o nome do Enum não estará disponível para os clientes, e isso será um problema se você quiser usar os mesmos valores de localização no lado do cliente.
## Veja também
* [Validação no Lado do Servidor](../../Validation.md)

150
docs/pt-BR/UI/AspNetCore/JavaScript-API/Ajax.md

@ -0,0 +1,150 @@
# ASP.NET Core MVC / Páginas Razor UI JavaScript AJAX API
A API `abp.ajax` fornece uma maneira conveniente de realizar chamadas AJAX para o servidor. Ela usa internamente o `$.ajax` do JQuery, mas automatiza algumas tarefas comuns para você:
* Lida automaticamente com os erros e localiza-os, informando o usuário (usando o [abp.message](Message.md)). Então, normalmente você não precisa se preocupar com os erros.
* Adiciona automaticamente um token de **anti-falsificação** ao cabeçalho HTTP para satisfazer a validação de proteção CSRF no lado do servidor.
* Define automaticamente as opções padrão e permite configurar as opções padrão em um único local.
* Pode **bloquear** uma parte da interface do usuário (ou a página inteira) durante a operação AJAX.
* Permite personalizar completamente qualquer chamada AJAX, usando as opções padrão do `$.ajax`.
> Embora o `abp.ajax` torne a chamada AJAX mais fácil, normalmente você usará o sistema [Dynamic JavaScript Client Proxy](../Dynamic-JavaScript-Proxies.md) para fazer chamadas às suas APIs HTTP do lado do servidor. O `abp.ajax` pode ser usado quando você precisa realizar operações AJAX de baixo nível.
## Uso básico
O `abp.ajax` aceita um objeto de opções que é aceito pelo [$.ajax](https://api.jquery.com/jquery.ajax/#jQuery-ajax-settings) padrão. Todas as opções padrão são válidas. Ele retorna uma [promessa](https://api.jquery.com/category/deferred-object/) como valor de retorno.
**Exemplo: Obter a lista de usuários**
````js
abp.ajax({
type: 'GET',
url: '/api/identity/users'
}).then(function(result){
console.log(result);
});
````
Este comando registra a lista de usuários no console, se você estiver **logado** na aplicação e tiver [permissão](../../../Authorization.md) para a página de gerenciamento de usuários do [Módulo de Identidade](../../../Modules/Identity.md).
## Tratamento de erros
A chamada AJAX de exemplo acima mostra uma **mensagem de erro** se você não estiver logado na aplicação ou não tiver as permissões necessárias para realizar essa solicitação:
![ajax-error](../../../images/ajax-error.png)
Todos os tipos de erros são tratados automaticamente pelo `abp.ajax`, a menos que você queira desabilitá-lo.
### Resposta de erro padrão
O `abp.ajax` é compatível com o sistema de tratamento de exceções do [ABP Framework](../../../Exception-Handling.md) e lida corretamente com o formato de erro padrão retornado pelo servidor. Uma mensagem de erro típica é um JSON como o abaixo:
````json
{
"error": {
"code": "App:010042",
"message": "Este tópico está bloqueado e não é possível adicionar uma nova mensagem",
"details": "Informações mais detalhadas sobre o erro..."
}
}
````
A mensagem de erro é mostrada diretamente ao usuário, usando as propriedades `message` e `details`.
### Resposta de erro não padrão e códigos de status HTTP
Ele também lida com erros mesmo se o formato de erro padrão não for enviado pelo servidor. Isso pode acontecer se você ignorar o sistema de tratamento de exceções do ABP e construir manualmente a resposta HTTP no servidor. Nesse caso, os **códigos de status HTTP** são considerados.
Os seguintes códigos de status HTTP são predefinidos:
* **401**: Mostra uma mensagem de erro como "*Você deve estar autenticado (fazer login) para realizar esta operação*". Quando os usuários clicam no botão OK, eles são redirecionados para a página inicial da aplicação para fazer login novamente.
* **403**: Mostra uma mensagem de erro como "*Você não tem permissão para realizar esta operação*".
* **404**: Mostra uma mensagem de erro como "*O recurso solicitado não foi encontrado no servidor*".
* **Outros**: Mostra uma mensagem de erro genérica como "*Ocorreu um erro. Detalhes do erro não enviados pelo servidor*".
Todas essas mensagens são localizadas com base no idioma atual do usuário.
### Tratando manualmente os erros
Como o `abp.ajax` retorna uma promessa, você sempre pode encadear uma chamada `.catch(...)` para registrar um retorno de chamada que é executado se a solicitação AJAX falhar.
**Exemplo: Mostrar um alerta se a solicitação AJAX falhar**
````js
abp.ajax({
type: 'GET',
url: '/api/identity/users'
}).then(function(result){
console.log(result);
}).catch(function(){
alert("solicitação falhou :(");
});
````
Enquanto seu retorno de chamada é executado, o ABP ainda trata o erro por si só. Se você quiser desabilitar o tratamento automático de erros, passe `abpHandleError: false` nas opções do `abp.ajax`.
**Exemplo: Desabilitar o tratamento automático de erros**
````js
abp.ajax({
type: 'GET',
url: '/api/identity/users',
abpHandleError: false // DESABILITAR O TRATAMENTO AUTOMÁTICO DE ERROS
}).then(function(result){
console.log(result);
}).catch(function(){
alert("solicitação falhou :(");
});
````
Se você definir `abpHandleError: false` e não capturar o erro você mesmo, então o erro será ocultado e a solicitação falhará silenciosamente. O `abp.ajax` ainda registra o erro no console do navegador (consulte a seção *Configuração* para substituí-lo).
## Configuração
O `abp.ajax` possui uma **configuração global** que você pode personalizar com base em seus requisitos.
### Opções padrão do AJAX
O objeto `abp.ajax.defaultOpts` é usado para configurar as opções padrão usadas ao realizar uma chamada AJAX, a menos que você as substitua. O valor padrão deste objeto é mostrado abaixo:
````js
{
dataType: 'json',
type: 'POST',
contentType: 'application/json',
headers: {
'X-Requested-With': 'XMLHttpRequest'
}
}
````
Portanto, se você quiser alterar o tipo de solicitação padrão, pode fazer da seguinte forma:
````js
abp.ajax.defaultOpts.type = 'GET';
````
Escreva este código antes de todo o seu código JavaScript. Normalmente, você deseja colocar essa configuração em um arquivo JavaScript separado e adicioná-lo ao layout usando o [bundle](../Bundling-Minification.md) global.
### Registrar/Mostrar erros
As seguintes funções podem ser substituídas para personalizar o registro e a exibição das mensagens de erro:
* A função `abp.ajax.logError` registra os erros usando o [abp.log.error(...)](Logging.md) por padrão.
* A função `abp.ajax.showError` mostra a mensagem de erro usando o [abp.message.error(...)](Message.md) por padrão.
* A função `abp.ajax.handleErrorStatusCode` trata diferentes códigos de status HTTP e mostra mensagens diferentes com base no código.
* A função `abp.ajax.handleAbpErrorResponse` trata os erros enviados com o formato de erro padrão do ABP.
* A função `abp.ajax.handleNonAbpErrorResponse` trata as respostas de erro não padrão.
* A função `abp.ajax.handleUnAuthorizedRequest` trata as respostas com o código de status `401` e redireciona os usuários para a página inicial da aplicação.
**Exemplo: Substituir a função `logError`**
````js
abp.ajax.logError = function(error) {
//...
}
````
### Outras opções
* A função `abp.ajax.ajaxSendHandler` é usada para interceptar as solicitações AJAX e adicionar um token de anti-falsificação ao cabeçalho HTTP. Observe que isso funciona para todas as solicitações AJAX, mesmo se você não usar o `abp.ajax`.

23
docs/pt-BR/UI/AspNetCore/JavaScript-API/Auth.md

@ -0,0 +1,23 @@
# ASP.NET Core MVC / Razor Pages UI: JavaScript Auth API
A API de autenticação permite que você verifique as permissões (políticas) para o usuário atual no lado do cliente. Dessa forma, você pode mostrar/ocultar partes da interface do usuário condicionalmente ou executar sua lógica no lado do cliente com base nas permissões atuais.
> Este documento explica apenas a API JavaScript. Consulte o [documento de autorização](../../../Authorization.md) para entender o sistema de autorização e permissão do ABP.
## Uso básico
A função `abp.auth.isGranted(...)` é usada para verificar se uma permissão/política foi concedida ou não:
````js
if (abp.auth.isGranted('DeleteUsers')) {
//TODO: Excluir o usuário
} else {
alert("Você não tem permissão para excluir um usuário!");
}
````
## Outros campos e funções
* `abp.auth.isAnyGranted(...)`: Recebe um ou mais nomes de permissão/política e retorna `true` se pelo menos um deles foi concedido.
* `abp.auth.areAllGranted(...)`: Recebe um ou mais nomes de permissão/política e retorna `true` se todos eles foram concedidos.
* `abp.auth.grantedPolicies`: Este é um objeto onde as chaves são os nomes de permissão/política. Aqui você pode encontrar os nomes de permissão/política concedidos.

56
docs/pt-BR/UI/AspNetCore/JavaScript-API/Block-Busy.md

@ -0,0 +1,56 @@
# ASP.NET Core MVC / Razor Pages UI: API de Bloqueio/Busy em JavaScript
A API de Bloqueio desabilita (bloqueia) a página ou uma parte da página.
## Uso Básico
**Exemplo: Bloquear (desabilitar) a página completa**
````js
abp.ui.block();
````
**Exemplo: Bloquear (desabilitar) um elemento HTML**
````js
abp.ui.block('#MyContainer');
````
**Exemplo: Habilitar novamente o elemento ou página previamente bloqueados:**
````js
abp.ui.unblock();
````
## Opções
O método `abp.ui.block()` pode receber um objeto de opções que pode conter os seguintes campos:
* `elm`: Um seletor opcional para encontrar o elemento a ser bloqueado (por exemplo, `#MyContainerId`). Se não for fornecido, a página inteira será bloqueada. O seletor também pode ser passado diretamente para o método `block()` como mostrado acima.
* `busy`: Defina como `true` para mostrar um indicador de progresso na área bloqueada.
* `promise`: Um objeto de promessa com callbacks `always` ou `finally`. Isso pode ser útil se você quiser desbloquear automaticamente a área bloqueada quando uma operação adiada for concluída.
**Exemplo: Bloquear um elemento com indicador de ocupado**
````js
abp.ui.block({
elm: '#MySection',
busy: true
});
````
A interface resultante será parecida com a seguinte:
![ui-busy](../../../images/ui-busy.png)
## setBusy
`abp.ui.setBusy(...)` e `abp.ui.clearBusy()` são funções de atalho se você quiser usar o bloqueio com a opção `busy`.
**Exemplo: Bloquear com ocupado**
````js
abp.ui.setBusy('#MySection');
````
Então você pode usar `abp.ui.clearBusy();` para reabilitar a área/página ocupada.

49
docs/pt-BR/UI/AspNetCore/JavaScript-API/CurrentUser.md

@ -0,0 +1,49 @@
# ASP.NET Core MVC / Razor Pages UI: API JavaScript do Usuário Atual
`abp.currentUser` é um objeto que contém informações sobre o usuário atual da aplicação.
> Este documento explica apenas a API JavaScript. Consulte o documento [CurrentUser](../../../CurrentUser.md) para obter informações sobre o usuário atual no lado do servidor.
## Usuário Autenticado
Se o usuário estiver autenticado, este objeto será algo como abaixo:
````js
{
isAuthenticated: true,
id: "34f1f4a7-13cc-4b91-84d1-b91c87afa95f",
tenantId: null,
userName: "john",
name: "John",
surName: "Nash",
email: "john.nash@abp.io",
emailVerified: true,
phoneNumber: null,
phoneNumberVerified: false,
roles: ["moderator","supporter"]
}
````
Portanto, `abp.currentUser.userName` retorna `john` neste caso.
## Usuário Anônimo
Se o usuário não estiver autenticado, este objeto será algo como abaixo:
````js
{
isAuthenticated: false,
id: null,
tenantId: null,
userName: null,
name: null,
surName: null,
email: null,
emailVerified: false,
phoneNumber: null,
phoneNumberVerified: false,
roles: []
}
````
Você pode verificar `abp.currentUser.isAuthenticated` para entender se o usuário está autenticado ou não.

116
docs/pt-BR/UI/AspNetCore/JavaScript-API/DOM.md

@ -0,0 +1,116 @@
# ASP.NET Core MVC / Razor Pages UI: API DOM JavaScript
`abp.dom` (Document Object Model) fornece eventos aos quais você pode se inscrever para ser notificado quando elementos são adicionados e removidos dinamicamente da página (DOM).
Isso é especialmente útil se você deseja inicializar os novos elementos carregados. Isso geralmente é necessário quando você adiciona elementos dinamicamente ao DOM (por exemplo, obtém alguns elementos HTML via AJAX) após a inicialização da página.
> O ABP usa o [MutationObserver](https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver) para observar as alterações feitas no DOM.
## Eventos de Nó
### onNodeAdded
Esse evento é acionado quando um elemento é adicionado ao DOM. Exemplo:
````js
abp.dom.onNodeAdded(function(args){
console.log(args.$el);
});
````
O objeto `args` possui os seguintes campos:
* `$el`: A seleção JQuery para obter o novo elemento inserido no DOM.
### onNodeRemoved
Esse evento é acionado quando um elemento é removido do DOM. Exemplo:
````js
abp.dom.onNodeRemoved(function(args){
console.log(args.$el);
});
````
O objeto `args` possui os seguintes campos:
* `$el`: A seleção JQuery para obter o elemento removido do DOM.
## Inicializadores Pré-Construídos
O ABP Framework usa os eventos DOM para inicializar algum tipo de elementos HTML quando eles são adicionados ao DOM após a inicialização da página.
> Observe que os mesmos inicializadores também funcionam se esses elementos já estiverem incluídos no DOM inicial. Portanto, se eles forem carregados inicialmente ou de forma tardia, eles funcionam como esperado.
### Inicializador de Formulário
O inicializador de formulário (definido como `abp.dom.initializers.initializeForms`) inicializa os formulários carregados de forma tardia;
* Habilita automaticamente a validação `unobtrusive` no formulário.
* Pode mostrar automaticamente uma mensagem de confirmação quando você envia o formulário. Para habilitar esse recurso, basta adicionar o atributo `data-confirm` com uma mensagem (como `data-confirm="Tem certeza?"`) ao elemento `form`.
* Se o elemento `form` tiver o atributo `data-ajaxForm="true"`, então chama automaticamente o `.abpAjaxForm()` no elemento `form`, para enviar o formulário via AJAX.
Consulte o documento [Forms & Validation](../Forms-Validation.md) para mais informações.
### Inicializador de Script
O inicializador de script (`abp.dom.initializers.initializeScript`) pode executar um código JavaScript para um elemento DOM.
**Exemplo: Carregar de forma tardia um componente e executar algum código quando o elemento for carregado**
Suponha que você tenha um contêiner para carregar o elemento dentro:
````html
<div id="LazyComponent"></div>
````
E este é o componente que será carregado via AJAX do servidor e inserido no contêiner:
````html
<div data-script-class="MyCustomClass">
<p>Mensagem de exemplo</p>
</div>
````
`data-script-class="MyCustomClass"` indica a classe JavaScript que será usada para executar alguma lógica nesse elemento:
`MyCustomClass` é um objeto global definido da seguinte forma:
````js
MyCustomClass = function(){
function initDom($el){
$el.css('color', 'red');
}
return {
initDom: initDom
}
};
````
`initDom` é a função que é chamada pelo ABP Framework. O argumento `$el` é o elemento HTML carregado como uma seleção JQuery.
Finalmente, você pode carregar o componente dentro do contêiner após uma chamada AJAX:
````js
$(function () {
setTimeout(function(){
$.get('/get-my-element').then(function(response){
$('#LazyComponent').html(response);
});
}, 2000);
});
````
O sistema de Inicialização de Script é especialmente útil se você não sabe como e quando o componente será carregado no DOM. Isso pode ser possível se você desenvolveu um componente de IU reutilizável em uma biblioteca e deseja que o desenvolvedor do aplicativo não precise se preocupar com a inicialização do componente em diferentes casos de uso.
> A inicialização de script não funciona se o componente for carregado no DOM inicial. Nesse caso, você é responsável por inicializá-lo.
### Outros Inicializadores
Os seguintes componentes e bibliotecas do Bootstrap são inicializados automaticamente quando são adicionados ao DOM:
* Tooltip
* Popover
* Timeago

87
docs/pt-BR/UI/AspNetCore/JavaScript-API/Events.md

@ -0,0 +1,87 @@
# ASP.NET Core MVC / Razor Pages UI: API de Eventos JavaScript
O objeto `abp.event` é um serviço simples que é usado para publicar e se inscrever em eventos globais **no navegador**.
> Esta API não está relacionada a eventos locais ou distribuídos do lado do servidor. Ela funciona dentro dos limites do navegador para permitir que os componentes da interface do usuário (partes do código) se comuniquem de forma desacoplada.
## Uso Básico
### Publicando Eventos
Use `abp.event.trigger` para publicar eventos.
**Exemplo: Publicar um evento *Basket Updated* (Carrinho Atualizado)**
````js
abp.event.trigger('basketUpdated');
````
Isso acionará todas as chamadas de retorno inscritas.
### Se inscrevendo nos Eventos
Use `abp.event.on` para se inscrever em eventos.
**Exemplo: Consumir o evento *Basket Updated* (Carrinho Atualizado)**
````js
abp.event.on('basketUpdated', function() {
console.log('Manipulou o evento basketUpdated...');
});
````
Você começará a receber eventos depois de se inscrever no evento.
### Cancelando a inscrição nos Eventos
Se você precisar cancelar a inscrição em um evento pré-inscrito, poderá usar a função `abp.event.off(eventName, callback)`. Nesse caso, você tem a chamada de retorno como uma declaração de função separada.
**Exemplo: Inscrever e cancelar a inscrição**
````js
function onBasketUpdated() {
console.log('Manipulou o evento basketUpdated...');
}
//Inscrever
abp.event.on('basketUpdated', onBasketUpdated);
//Cancelar a inscrição
abp.event.off('basketUpdated', onBasketUpdated);
````
Você não receberá mais eventos depois de cancelar a inscrição no evento.
## Argumentos do Evento
Você pode passar argumentos (de qualquer quantidade) para o método `trigger` e obtê-los na chamada de retorno da inscrição.
**Exemplo: Adicionar o carrinho como argumento do evento**
````js
//Inscrever-se no evento
abp.event.on('basketUpdated', function(basket) {
console.log('O novo objeto do carrinho: ');
console.log(basket);
});
//Acionar o evento
abp.event.trigger('basketUpdated', {
items: [
{
"productId": "123",
"count": 2
},
{
"productId": "832",
"count": 1
}
]
});
````
### Múltiplos Argumentos
Se você deseja passar vários argumentos, pode passar como `abp.event.on('basketUpdated', arg0, arg1, agr2)`. Em seguida, você pode adicionar a mesma lista de argumentos à função de chamada de retorno no lado do assinante.
> **Dica:** Alternativamente, você pode enviar um único objeto que possui um campo separado para cada argumento. Isso facilita a extensão/mudança dos argumentos do evento no futuro sem quebrar os assinantes.

29
docs/pt-BR/UI/AspNetCore/JavaScript-API/Features.md

@ -0,0 +1,29 @@
# ASP.NET Core MVC / Razor Pages UI: API de Recursos JavaScript
A API `abp.features` permite que você verifique recursos ou obtenha os valores dos recursos no lado do cliente. Você pode ler o valor atual de um recurso apenas no lado do cliente se for permitido pela definição do recurso (no lado do servidor).
> Este documento explica apenas a API JavaScript. Consulte o documento [Recursos](../../../Recursos.md) para entender o sistema de Recursos do ABP.
## Uso Básico
````js
// Obtém um valor como string.
var valor = abp.features.get('ExportarParaExcel');
// Verifica se o recurso está habilitado
var habilitado = abp.features.isEnabled('ExportarParaExcel.Habilitado');
````
## Todos os Valores
`abp.features.values` pode ser usado para acessar todos os valores dos recursos.
Um exemplo de valor desse objeto é mostrado abaixo:
````js
{
Identity.DoisFatores: "Opcional",
ExportarParaExcel.Habilitado: "true",
...
}
````

24
docs/pt-BR/UI/AspNetCore/JavaScript-API/GlobalFeatures.md

@ -0,0 +1,24 @@
# ASP.NET Core MVC / Razor Pages UI: API de Recursos Globais JavaScript
A API `abp.globalFeatures` permite que você obtenha os recursos habilitados dos [Recursos Globais](../../../Global-Features.md) no lado do cliente.
> Este documento apenas explica a API JavaScript. Consulte o documento [Recursos Globais](../../../Global-Features.md) para entender o sistema de Recursos Globais do ABP.
## Uso
````js
// Obtém todos os recursos globais habilitados.
> abp.globalFeatures.enabledFeatures
[ 'Shopping.Payment', 'Ecommerce.Subscription' ]
// Verifica se o recurso global está habilitado.
> abp.globalFeatures.isEnabled('Ecommerce.Subscription')
true
> abp.globalFeatures.isEnabled('My.Subscription')
false
````

20
docs/pt-BR/UI/AspNetCore/JavaScript-API/Index.md

@ -0,0 +1,20 @@
# API JavaScript
ABP fornece um conjunto de APIs JavaScript para aplicações ASP.NET Core MVC / Razor Pages. Elas podem ser usadas para realizar facilmente requisitos comuns de aplicativos no lado do cliente e integrar ao lado do servidor.
## APIs
* [AJAX](Ajax.md)
* [Auth](Auth.md)
* [CurrentUser](CurrentUser.md)
* [DOM](DOM.md)
* [Events](Events.md)
* [Features](Features.md)
* [Global Features](GlobalFeatures.md)
* [Localization](Localization.md)
* [Logging](Logging.md)
* [ResourceLoader](ResourceLoader.md)
* [Settings](Settings.md)
* [UI Block/Busy](Block-Busy.md)
* [UI Message](Message.md)
* [UI Notification](Notify.md)

146
docs/pt-BR/UI/AspNetCore/JavaScript-API/Localization.md

@ -0,0 +1,146 @@
# ASP.NET Core MVC / Razor Pages UI: API de Localização JavaScript
A API de localização permite que você reutilize os recursos de localização do lado do servidor no lado do cliente.
> Este documento explica apenas a API JavaScript. Consulte o [documento de localização](../../../Localization.md) para entender o sistema de localização do ABP.
## Uso básico
A função `abp.localization.getResource(...)` é usada para obter um recurso de localização:
````js
var testResource = abp.localization.getResource('Test');
````
Em seguida, você pode localizar uma string com base nesse recurso:
````js
var str = testResource('HelloWorld');
````
A função `abp.localization.localize(...)` é um atalho onde você pode especificar tanto o nome do texto quanto o nome do recurso:
````js
var str = abp.localization.localize('HelloWorld', 'Test');
````
`HelloWorld` é o texto a ser localizado, onde `Test` é o nome do recurso de localização aqui.
### Lógica de fallback
Se os textos fornecidos não forem localizados, o método de localização retorna a chave fornecida como resultado da localização.
### Recurso de Localização Padrão
Se você não especificar o nome do recurso de localização, ele usará o **recurso de localização padrão** definido nas `AbpLocalizationOptions` (consulte o [documento de localização](../../../Localization.md)).
**Exemplo: Usando o recurso de localização padrão**
````js
var str = abp.localization.localize('HelloWorld'); // usa o recurso padrão
````
### Argumentos de Formato
Se sua string localizada contiver argumentos, como `Olá {0}, bem-vindo!`, você pode passar argumentos para os métodos de localização. Exemplos:
````js
var testSource = abp.localization.getResource('Test');
var str1 = testSource('HelloWelcomeMessage', 'John');
var str2 = abp.localization.localize('HelloWelcomeMessage', 'Test', 'John');
````
Supondo que `HelloWelcomeMessage` seja localizado como `Olá {0}, bem-vindo!`, ambos os exemplos acima produzem a saída `Olá John, bem-vindo!`.
## Outras Propriedades e Métodos
### abp.localization.resources
A propriedade `abp.localization.resources` armazena todos os recursos de localização, chaves e seus valores.
### abp.localization.isLocalized
Retorna um booleano indicando se o texto fornecido foi localizado ou não.
**Exemplo**
````js
abp.localization.isLocalized('ProductName', 'MyResource');
````
Retorna `true` se o texto `ProductName` foi localizado para o recurso `MyResource`. Caso contrário, retorna `false`. Você pode deixar o nome do recurso vazio para usar o recurso de localização padrão.
### abp.localization.defaultResourceName
`abp.localization.defaultResourceName` pode ser definido para alterar o recurso de localização padrão. Normalmente, você não define isso, pois o ABP Framework o define automaticamente com base na configuração do lado do servidor.
### abp.localization.currentCulture
`abp.localization.currentCulture` retorna um objeto para obter informações sobre o **idioma atualmente selecionado**.
Um exemplo de valor desse objeto é mostrado abaixo:
````js
{
"displayName": "Inglês",
"englishName": "Inglês",
"threeLetterIsoLanguageName": "eng",
"twoLetterIsoLanguageName": "en",
"isRightToLeft": false,
"cultureName": "en",
"name": "en",
"nativeName": "Inglês",
"dateTimeFormat": {
"calendarAlgorithmType": "Calendário Solar",
"dateTimeFormatLong": "dddd, d 'de' MMMM 'de' yyyy",
"shortDatePattern": "dd/MM/yyyy",
"fullDateTimePattern": "dddd, d 'de' MMMM 'de' yyyy HH:mm:ss",
"dateSeparator": "/",
"shortTimePattern": "HH:mm",
"longTimePattern": "HH:mm:ss"
}
}
````
### abp.localization.languages
Usado para obter a lista de todos os **idiomas disponíveis** na aplicação. Um exemplo de valor desse objeto é mostrado abaixo:
````js
[
{
"cultureName": "en",
"uiCultureName": "en",
"displayName": "Inglês",
"flagIcon": null
},
{
"cultureName": "fr",
"uiCultureName": "fr",
"displayName": "Francês",
"flagIcon": null
},
{
"cultureName": "pt-BR",
"uiCultureName": "pt-BR",
"displayName": "Português",
"flagIcon": null
},
{
"cultureName": "tr",
"uiCultureName": "tr",
"displayName": "Turco",
"flagIcon": null
},
{
"cultureName": "zh-Hans",
"uiCultureName": "zh-Hans",
"displayName": "Chinês Simplificado",
"flagIcon": null
}
]
````
## Veja também
* [Tutorial em vídeo](https://abp.io/video-courses/essentials/localization)

49
docs/pt-BR/UI/AspNetCore/JavaScript-API/Logging.md

@ -0,0 +1,49 @@
# ASP.NET Core MVC / Razor Pages UI: API de Registro de JavaScript
A API `abp.log` é usada para escrever logs simples no lado do cliente.
> Os logs são escritos no console, usando o `console.log`, por padrão.
> Este documento é para registro simples no lado do cliente. Consulte o documento [Logging](../../../Logging.md) para o sistema de registro no lado do servidor.
## Uso Básico
Use um dos métodos `abp.log.xxx(...)` com base na gravidade da mensagem de log.
````js
abp.log.debug("Algum log de debug aqui..."); // Registrando uma mensagem de debug simples
abp.log.info({ name: "john", age: 42 }); // Registrando um objeto como um log de informação
abp.log.warn("Uma mensagem de aviso"); // Registrando uma mensagem de aviso
abp.log.error('Ocorreu um erro...'); // Mensagem de erro
abp.log.fatal('A conexão de rede foi perdida!'); // Erro fatal
````
## Níveis de Log
Existem 5 níveis para uma mensagem de log:
* DEBUG = 1
* INFO = 2
* WARN = 3
* ERROR = 4
* FATAL = 5
Esses são definidos no objeto `abp.log.levels` (como `abp.log.levels.WARN`).
### Alterando o Nível de Log Atual
Você pode controlar o nível de log da seguinte forma:
````js
abp.log.level = abp.log.levels.WARN;
````
O nível de log padrão é `DEBUG`.
### Registrando Especificando o Nível
Em vez de chamar a função `abp.log.info(...)`, você pode usar o `abp.log.log` especificando o nível de log como parâmetro:
````js
abp.log.log("mensagem de log...", abp.log.levels.INFO);
````

127
docs/pt-BR/UI/AspNetCore/JavaScript-API/Message.md

@ -0,0 +1,127 @@
# ASP.NET Core MVC / Razor Pages UI: API de Mensagens JavaScript
A API de Mensagens é usada para mostrar mensagens agradáveis ao usuário como um diálogo bloqueante. A API de Mensagens é uma abstração fornecida pelo ABP Framework e implementada usando a biblioteca [SweetAlert](https://sweetalert.js.org/) por padrão.
## Exemplo Rápido
Use a função `abp.message.success(...)` para mostrar uma mensagem de sucesso:
````js
abp.message.success('Suas alterações foram salvas com sucesso!', 'Parabéns');
````
Isso mostrará um diálogo na interface do usuário:
![js-message-success](../../../images/js-message-success.png)
## Mensagens Informativas
Existem quatro tipos de funções de mensagem informativa:
* `abp.message.info(...)`
* `abp.message.success(...)`
* `abp.message.warn(...)`
* `abp.message.error(...)`
Todos esses métodos recebem dois parâmetros:
* `message`: A mensagem (`string`) a ser mostrada.
* `title`: Um título opcional (`string`).
**Exemplo: Mostrar uma mensagem de erro**
````js
abp.message.error('O número do seu cartão de crédito não é válido!');
````
![js-message-error](../../../images/js-message-error.png)
## Mensagem de Confirmação
A função `abp.message.confirm(...)` pode ser usada para obter uma confirmação do usuário.
**Exemplo**
Use o seguinte código para obter um resultado de confirmação do usuário:
````js
abp.message.confirm('Tem certeza de que deseja excluir a função "admin"?')
.then(function(confirmed){
if(confirmed){
console.log('TODO: excluindo a função...');
}
});
````
A interface resultante será como mostrado abaixo:
![js-message-confirm](../../../images/js-message-confirm.png)
Se o usuário clicou no botão `Sim`, o argumento `confirmed` na função de retorno `then` será `true`.
> "*Tem certeza?*" é o título padrão (localizado com base no idioma atual) e você pode substituí-lo.
### O Valor de Retorno
O valor de retorno da função `abp.message.confirm(...)` é uma promessa, então você pode encadear um retorno de chamada `then` como mostrado acima.
### Parâmetros
A função `abp.message.confirm(...)` possui os seguintes parâmetros:
* `message`: Uma mensagem (string) para mostrar ao usuário.
* `titleOrCallback` (opcional): Um título ou uma função de retorno de chamada. Se você fornecer uma string, ela será mostrada como título. Se você fornecer uma função de retorno de chamada (que recebe um parâmetro `bool`), ela será chamada com o resultado.
* `callback` (opcional): Se você passou um título para o segundo parâmetro, pode passar sua função de retorno de chamada como o terceiro parâmetro.
Passar uma função de retorno de chamada é uma alternativa ao retorno de chamada `then` mostrado acima.
**Exemplo: Fornecendo todos os parâmetros e obtendo o resultado com a função de retorno de chamada**
````js
abp.message.confirm(
'Tem certeza de que deseja excluir a função "admin"?',
'Cuidado!',
function(confirmed){
if(confirmed){
console.log('TODO: excluindo a função...');
}
});
````
## Configuração do SweetAlert
A API de Mensagens é implementada usando a biblioteca [SweetAlert](https://sweetalert.js.org/) por padrão. Se você deseja alterar sua configuração, pode definir as opções no objeto `abp.libs.sweetAlert.config`. O objeto de configuração padrão é mostrado abaixo:
````js
{
'default': {
},
info: {
icon: 'info'
},
success: {
icon: 'success'
},
warn: {
icon: 'warning'
},
error: {
icon: 'error'
},
confirm: {
icon: 'warning',
title: 'Tem certeza?',
buttons: ['Cancelar', 'Sim']
}
}
````
> "Tem certeza?", "Cancelar" e "Sim" são textos automaticamente localizados com base no idioma atual.
Portanto, se você deseja definir o ícone `warn`, pode definir assim:
````js
abp.libs.sweetAlert.config.warn.icon = 'error';
````
Consulte a [documentação do SweetAlert](https://sweetalert.js.org/) para todas as opções de configuração.

45
docs/pt-BR/UI/AspNetCore/JavaScript-API/Notify.md

@ -0,0 +1,45 @@
# ASP.NET Core MVC / Razor Pages UI: API de Notificação JavaScript
A API de Notificação é usada para mostrar notificações de interface do usuário no estilo toast, que desaparecem automaticamente para o usuário final. Por padrão, ela é implementada pela biblioteca [Toastr](https://github.com/CodeSeven/toastr).
## Exemplo Rápido
Use a função `abp.notify.success(...)` para mostrar uma mensagem de sucesso:
````js
abp.notify.success(
'O produto "Acme Atom Re-Arranger" foi excluído com sucesso.',
'Produto Excluído'
);
````
Uma mensagem de notificação é exibida na parte inferior direita da página:
![js-message-success](../../../images/js-notify-success.png)
## Tipos de Notificação
Existem quatro tipos de notificações pré-definidas;
* `abp.notify.success(...)`
* `abp.notify.info(...)`
* `abp.notify.warn(...)`
* `abp.notify.error(...)`
Todos os métodos acima recebem os seguintes parâmetros;
* `message`: Uma mensagem (`string`) para mostrar ao usuário.
* `title`: Um título opcional (`string`).
* `options`: Opções adicionais a serem passadas para a biblioteca subjacente, para o Toastr por padrão.
## Configuração do Toastr
A API de notificação é implementada pela biblioteca [Toastr](https://github.com/CodeSeven/toastr) por padrão. Você pode ver suas próprias opções de configuração.
**Exemplo: Mostrar mensagens toast no canto superior direito da página**
````js
toastr.options.positionClass = 'toast-top-right';
````
> O ABP define essa opção como `toast-bottom-right` por padrão. Você pode substituí-la como mostrado acima.

39
docs/pt-BR/UI/AspNetCore/JavaScript-API/ResourceLoader.md

@ -0,0 +1,39 @@
# ASP.NET Core MVC / Razor Pages UI: API de Carregamento de Recursos JavaScript
`abp.ResourceLoader` é um serviço que pode carregar um arquivo JavaScript ou CSS sob demanda. Ele garante que o arquivo seja carregado apenas uma vez, mesmo que seja solicitado várias vezes.
## Carregando Arquivos de Script
A função `abp.ResourceLoader.loadScript(...)` **carrega** um arquivo JavaScript do servidor e o **executa**.
**Exemplo: Carregar um arquivo JavaScript**
````js
abp.ResourceLoader.loadScript('/Pages/my-script.js');
````
### Parâmetros
A função `loadScript` pode receber três parâmetros;
* `url` (obrigatório, `string`): A URL do arquivo de script a ser carregado.
* `loadCallback` (opcional, `function`): Uma função de retorno de chamada que é chamada assim que o script é carregado e executado. Nessa função de retorno de chamada, você pode usar com segurança o código no arquivo de script. Essa função de retorno de chamada é chamada mesmo se o arquivo já tiver sido carregado anteriormente.
* `failCallback` (opcional, `function`): Uma função de retorno de chamada que é chamada se o carregamento do script falhar.
**Exemplo: Fornecer o argumento `loadCallback`**
````js
abp.ResourceLoader.loadScript('/Pages/my-script.js', function() {
console.log('carregado com sucesso :)');
});
````
## Carregando Arquivos de Estilo
A função `abp.ResourceLoader.loadStyle(...)` adiciona um elemento `link` à `head` do documento para a URL fornecida, para que o arquivo CSS seja carregado automaticamente pelo navegador.
**Exemplo: Carregar um arquivo CSS**
````js
abp.ResourceLoader.loadStyle('/Pages/my-styles.css');
````

32
docs/pt-BR/UI/AspNetCore/JavaScript-API/Settings.md

@ -0,0 +1,32 @@
# ASP.NET Core MVC / Razor Pages UI: API de Configuração JavaScript
A API de localização permite que você obtenha os valores das configurações no lado do cliente. Você pode ler o valor atual de uma configuração apenas no lado do cliente se isso for permitido pela definição da configuração (no lado do servidor).
> Este documento explica apenas a API JavaScript. Consulte o [documento de configurações](../../../Settings.md) para entender o sistema de configurações do ABP.
## Uso básico
````js
// Obtém um valor como string.
var language = abp.setting.get('Abp.Localization.DefaultLanguage');
// Obtém um valor inteiro.
var requiredLength = abp.setting.getInt('Abp.Identity.Password.RequiredLength');
// Obtém um valor booleano.
var requireDigit = abp.setting.getBoolean('Abp.Identity.Password.RequireDigit');
````
## Todos os valores
`abp.setting.values` pode ser usado para obter todos os valores de configuração como um objeto, onde as propriedades do objeto são os nomes das configurações e os valores das propriedades são os valores das configurações.
Um exemplo de valor desse objeto é mostrado abaixo:
````js
{
Abp.Localization.DefaultLanguage: "en",
Abp.Timing.TimeZone: "UTC",
...
}
````

105
docs/pt-BR/UI/AspNetCore/Layout-Hooks.md

@ -0,0 +1,105 @@
# ASP.NET Core MVC / Razor Pages: Hooks de Layout
O sistema de temas do ABP Framework coloca o layout da página nos pacotes NuGet do [tema](Theming.md). Isso significa que a aplicação final não inclui um `Layout.cshtml`, portanto, você não pode alterar diretamente o código do layout para personalizá-lo.
Você copia o código do tema para a sua solução. Nesse caso, você tem total liberdade para personalizá-lo. No entanto, você não poderá obter atualizações automáticas do tema (atualizando o pacote NuGet do tema).
O ABP Framework oferece diferentes maneiras de [personalizar a interface do usuário](Customization-User-Interface.md).
O **Sistema de Hooks de Layout** permite que você **adicione código** em partes específicas do layout. Todos os layouts de todos os temas devem implementar esses hooks. Por fim, você pode adicionar um **componente de visualização** em um ponto de hook.
## Exemplo: Adicionar Script do Google Analytics
Suponha que você precise adicionar o script do Google Analytics ao layout (que estará disponível para todas as páginas). Primeiro, **crie um componente de visualização** em seu projeto:
![bookstore-google-analytics-view-component](../../images/bookstore-google-analytics-view-component.png)
**NotificationViewComponent.cs**
````csharp
public class GoogleAnalyticsViewComponent : AbpViewComponent
{
public IViewComponentResult Invoke()
{
return View("/Pages/Shared/Components/GoogleAnalytics/Default.cshtml");
}
}
````
**Default.cshtml**
````html
<script>
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
ga('create', 'UA-xxxxxx-1', 'auto');
ga('send', 'pageview');
</script>
````
Altere `UA-xxxxxx-1` pelo seu próprio código.
Em seguida, você pode adicionar esse componente a qualquer um dos pontos de hook no `ConfigureServices` do seu módulo:
````csharp
Configure<AbpLayoutHookOptions>(options =>
{
options.Add(
LayoutHooks.Head.Last, //O nome do hook
typeof(GoogleAnalyticsViewComponent) //O componente a ser adicionado
);
});
````
Agora, o código do GA será inserido no `head` da página como o último item.
### Especificando o Layout
A configuração acima adiciona o `GoogleAnalyticsViewComponent` a todos os layouts. Talvez você queira adicionar apenas a um layout específico:
````csharp
Configure<AbpLayoutHookOptions>(options =>
{
options.Add(
LayoutHooks.Head.Last,
typeof(GoogleAnalyticsViewComponent),
layout: StandardLayouts.Application //Defina o layout a ser adicionado
);
});
````
Consulte a seção *Layouts* abaixo para saber mais sobre o sistema de layout.
## Pontos de Hook de Layout
Existem alguns pontos de hook de layout predefinidos. O `LayoutHooks.Head.Last` usado acima foi um deles. Os pontos de hook padrão são:
* `LayoutHooks.Head.First`: Usado para adicionar um componente como o primeiro item na tag HTML head.
* `LayoutHooks.Head.Last`: Usado para adicionar um componente como o último item na tag HTML head.
* `LayoutHooks.Body.First`: Usado para adicionar um componente como o primeiro item na tag HTML body.
* `LayoutHooks.Body.Last`: Usado para adicionar um componente como o último item na tag HTML body.
* `LayoutHooks.PageContent.First`: Usado para adicionar um componente logo antes do conteúdo da página (o `@RenderBody()` no layout).
* `LayoutHooks.PageContent.Last`: Usado para adicionar um componente logo após o conteúdo da página (o `@RenderBody()` no layout).
> Você (ou os módulos que você está usando) pode adicionar **vários itens ao mesmo ponto de hook**. Todos eles serão adicionados ao layout na ordem em que foram adicionados.
## Layouts
O sistema de layout permite que os temas definam layouts padrão e nomeados e permite que qualquer página selecione um layout adequado para o seu propósito. Existem três layouts predefinidos:
* "**Application**": O layout principal (e padrão) para uma aplicação. Normalmente, contém cabeçalho, menu (barra lateral), rodapé, barra de ferramentas, etc.
* "**Account**": Este layout é usado pelo login, registro e outras páginas semelhantes. É usado para as páginas na pasta `/Pages/Account` por padrão.
* "**Empty**": Layout vazio e mínimo.
Esses nomes são definidos na classe `StandardLayouts` como constantes. Você pode criar seus próprios layouts, mas esses são os nomes de layout padrão e implementados por todos os temas por padrão.
### Localização do Layout
Você pode encontrar os arquivos de layout [aqui](https://github.com/abpframework/abp/blob/dev/modules/basic-theme/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Layouts) para o tema básico. Você pode usá-los como referência para construir seus próprios layouts ou pode substituí-los, se necessário.
## Veja também
* [Personalizando a Interface do Usuário](Customization-User-Interface.md)

412
docs/pt-BR/UI/AspNetCore/Modals.md

@ -0,0 +1,412 @@
# ASP.NET Core MVC / Razor Pages UI: Modais
Embora você possa continuar usando o [método padrão do Bootstrap](https://getbootstrap.com/docs/4.5/components/modal/) para criar, abrir e gerenciar modais em suas aplicações, o ABP Framework fornece uma maneira **flexível** de gerenciar modais, automatizando tarefas comuns para você.
**Exemplo: Um diálogo modal para criar uma nova entidade de função**
![modal-manager-example-modal](../../images/modal-manager-example-modal.png)
O ABP Framework oferece os seguintes benefícios para um modal com um formulário dentro dele:
* **Carrega preguiçosamente** o HTML do modal na página e o **remove** do DOM assim que for fechado. Isso facilita o consumo de um diálogo modal reutilizável. Além disso, toda vez que você abrir o modal, ele será um novo modal, para que você não precise lidar com a redefinição do conteúdo do modal.
* **Dá foco automaticamente** ao primeiro campo de entrada do formulário assim que o modal for aberto. Você também pode especificar isso usando uma `function` ou um seletor `jquery`.
* Determina automaticamente o **formulário** dentro de um modal e envia o formulário via **AJAX** em vez de uma postagem normal da página.
* Verifica automaticamente se o formulário dentro do modal **foi alterado, mas não salvo**. Ele avisa o usuário nesse caso.
* Desabilita automaticamente os botões do modal (salvar e cancelar) até que a operação AJAX seja concluída.
* Facilita o registro de um **objeto JavaScript que é inicializado** assim que o modal é carregado.
Portanto, você escreve menos código ao lidar com os modais, especialmente os modais com um formulário dentro.
## Uso básico
### Criando um modal como uma página Razor
Para demonstrar o uso, estamos criando uma página Razor simples, chamada `ProductInfoModal.cshtml`, na pasta `/Pages/Products`:
![modal-page-on-rider](../../images/modal-page-on-rider.png)
**Conteúdo do ProductInfoModal.cshtml:**
````html
@page
@model MyProject.Web.Pages.Products.ProductInfoModalModel
@{
Layout = null;
}
<abp-modal>
<abp-modal-header title="Informações do Produto"></abp-modal-header>
<abp-modal-body>
<h3>@Model.ProductName</h3>
<div>
<img src="@Model.ProductImageUrl" />
</div>
<p>
@Model.ProductDescription
</p>
<p>
<small><i>Referência: https://acme.com/catalog/</i></small>
</p>
</abp-modal-body>
<abp-modal-footer buttons="Fechar"></abp-modal-footer>
</abp-modal>
````
* Esta página define o `Layout` como `null`, pois mostraremos isso como um modal. Portanto, não é necessário envolvê-lo com um layout.
* Ele usa o [tag helper abp-modal](Tag-Helpers/Modals.md) para simplificar a criação do código HTML do modal. Você pode usar o código padrão do modal do Bootstrap se preferir.
**Conteúdo do ProductInfoModalModel.cshtml.cs:**
```csharp
using Volo.Abp.AspNetCore.Mvc.UI.RazorPages;
namespace MyProject.Web.Pages.Products
{
public class ProductInfoModalModel : AbpPageModel
{
public string ProductName { get; set; }
public string ProductDescription { get; set; }
public string ProductImageUrl { get; set; }
public void OnGet()
{
ProductName = "Bola de Aço Indestrutível Acme";
ProductDescription = "A Bola de Aço Indestrutível Acme é completamente indestrutível, não há nada que possa destruí-la!";
ProductImageUrl = "https://acme.com/catalog/acmeindestructo.jpg";
}
}
}
```
Você pode obter as informações do produto de um banco de dados ou API. Estamos definindo as propriedades codificadas para simplificar.
### Definindo o Modal Manager
Depois de ter um modal, você pode abri-lo em qualquer página usando algum código JavaScript simples.
Primeiro, crie um objeto `abp.ModalManager` definindo o `viewUrl`, no arquivo JavaScript da página que usará o modal:
````js
var productInfoModal = new abp.ModalManager({
viewUrl: '/Products/ProductInfoModal'
});
````
> Se você só precisa especificar o `viewUrl`, você pode passá-lo diretamente para o construtor `ModalManager`, como um atalho. Exemplo: `new abp.ModalManager('/Products/ProductInfoModal');`
### Abrindo o Modal
Em seguida, abra o modal sempre que precisar:
````js
productInfoModal.open();
````
Normalmente, você deseja abrir o modal quando algo acontece; Por exemplo, quando o usuário clica em um botão:
````js
$('#OpenProductInfoModal').click(function(){
productInfoModal.open();
});
````
O modal resultante será assim:
![modal-example-product-info](../../images/modal-example-product-info.png)
#### Abrindo o Modal com Argumentos
Ao chamar o método `open()`, o `ModalManager` carrega o HTML do modal solicitando-o do `viewUrl`. Você pode passar alguns **parâmetros de string de consulta** para esta URL ao abrir o modal.
**Exemplo: Passando o ID do produto ao abrir o modal**
````js
productInfoModal.open({
productId: 42
});
````
Você pode adicionar um parâmetro `productId` ao método `get`:
````csharp
using Volo.Abp.AspNetCore.Mvc.UI.RazorPages;
namespace MyProject.Web.Pages.Products
{
public class ProductInfoModalModel : AbpPageModel
{
//...
public async Task OnGetAsync(int productId) //Adicione o parâmetro productId
{
//TODO: Obter o produto do banco de dados com o productId fornecido
//...
}
}
}
````
Dessa forma, você pode usar o `productId` para consultar o produto em uma fonte de dados.
## Modais com Formulários
`abp.ModalManager` lida com várias tarefas comuns (descritas na introdução) quando você deseja usar um formulário dentro do modal.
### Exemplo de Modal com um Formulário
Esta seção mostra um exemplo de formulário para criar um novo produto.
#### Criando a Página Razor
Para este exemplo, crie uma nova página Razor, chamada `ProductCreateModal.cshtml`, na pasta `/Pages/Products`:
![product-create-modal-page-on-rider](../../images/product-create-modal-page-on-rider.png)
**Conteúdo do ProductCreateModal.cshtml:**
````html
@page
@using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Modal
@model MyProject.Web.Pages.Products.ProductCreateModalModel
@{
Layout = null;
}
<form method="post" action="@Url.Page("/Products/ProductCreateModal")">
<abp-modal>
<abp-modal-header title="Criar Novo Produto"></abp-modal-header>
<abp-modal-body>
<abp-input asp-for="Product.Name"/>
<abp-input asp-for="Product.Description"/>
<abp-input asp-for="Product.ReleaseDate"/>
</abp-modal-body>
<abp-modal-footer buttons="@AbpModalButtons.Save | @AbpModalButtons.Cancel"></abp-modal-footer>
</abp-modal>
</form>
````
* O `abp-modal` foi envolvido pelo `form`. Isso é necessário para colocar os botões `Salvar` e `Cancelar` dentro do formulário. Dessa forma, o botão `Salvar` age como o botão `submit` para o `form`.
* Usamos os [tag helpers abp-input](Tag-Helpers/Form-elements.md) para simplificar a criação dos elementos do formulário. Caso contrário, você precisaria escrever mais HTML.
**Conteúdo do ProductCreateModalModel.cshtml.cs:**
```csharp
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Volo.Abp.AspNetCore.Mvc.UI.RazorPages;
namespace MyProject.Web.Pages.Products
{
public class ProductCreateModalModel : AbpPageModel
{
[BindProperty]
public PoductCreationDto Product { get; set; }
public async Task OnGetAsync()
{
//TODO: Lógica de obtenção, se disponível
}
public async Task<IActionResult> OnPostAsync()
{
//TODO: Salvar o Produto...
return NoContent();
}
}
}
```
* Esta é uma classe `PageModal` simples. O `[BindProperty]` faz com que o formulário seja vinculado ao modelo quando você envia (submete) o formulário; É o sistema padrão do ASP.NET Core.
* `OnPostAsync` retorna `NoContent` (este método é definido pela classe base `AbpPageModel`). Porque não precisamos de um valor de retorno no lado do cliente, após a operação de envio do formulário.
**PoductCreationDto:**
`ProductCreateModalModel` usa uma classe `PoductCreationDto` definida da seguinte forma:
````csharp
using System;
using System.ComponentModel.DataAnnotations;
using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form;
namespace MyProject.Web.Pages.Products
{
public class PoductCreationDto
{
[Required]
[StringLength(128)]
public string Name { get; set; }
[TextArea(Rows = 4)]
[StringLength(2000)]
public string Description { get; set; }
[DataType(DataType.Date)]
public DateTime ReleaseDate { get; set; }
}
}
````
* O Tag Helper `abp-input` pode entender os atributos de anotação de dados e usá-los para moldar e validar os elementos do formulário. Consulte o documento [tag helpers abp-input](Tag-Helpers/Form-elements.md) para saber mais.
#### Definindo o Modal Manager
Novamente, crie um objeto `abp.ModalManager` definindo o `viewUrl`, no arquivo JavaScript da página que usará o modal:
````js
var productCreateModal = new abp.ModalManager({
viewUrl: '/Products/ProductCreateModal'
});
````
#### Abrindo o Modal
Em seguida, abra o modal sempre que precisar:
````js
productCreateModal.open();
````
Normalmente, você deseja abrir o modal quando algo acontece; Por exemplo, quando o usuário clica em um botão:
````js
$('#OpenProductCreateModal').click(function(){
productCreateModal.open();
});
````
Portanto, o código completo será algo assim (supondo que você tenha um `button` com `id` igual a `OpenProductCreateModal` no lado da visualização):
```js
$(function () {
var productCreateModal = new abp.ModalManager({
viewUrl: '/Products/ProductCreateModal'
});
$('#OpenProductCreateModal').click(function () {
productCreateModal.open();
});
});
```
O modal resultante será assim:
![modal-example-product-create](../../images/modal-example-product-create.png)
#### Salvando o Modal
Quando você clica no botão `Salvar`, o formulário é enviado para o servidor. Se o servidor retornar uma **resposta de sucesso**, o evento `onResult` é acionado com alguns argumentos, incluindo a resposta do servidor, e o modal é fechado automaticamente.
Um exemplo de retorno de chamada que registra os argumentos passados para o método `onResult`:
````js
productCreateModal.onResult(function(){
console.log(arguments);
});
````
Se o servidor retornar uma resposta de falha, ele mostra a mensagem de erro retornada pelo servidor e mantém o modal aberto.
> Consulte a seção *Referência do Modal Manager* abaixo para outros eventos do modal.
#### Cancelando o Modal
Se você clicar no botão Cancelar com algumas alterações feitas, mas não salvas, você receberá uma mensagem de aviso como esta:
![modal-manager-cancel-warning](../../images/modal-manager-cancel-warning.png)
Se você não deseja essa verificação e mensagem, pode adicionar o atributo `data-check-form-on-close="false"` ao seu elemento `form`. Exemplo:
````html
<form method="post"
action="@Url.Page("/Products/ProductCreateModal")"
data-check-form-on-close="false">
````
### Validação do Formulário
`ModalManager` aciona automaticamente a validação do formulário quando você clica no botão `Salvar` ou pressiona a tecla `Enter` no formulário:
![modal-manager-validation](../../images/modal-manager-validation.png)
Consulte o documento [Forms & Validation](Forms-Validation.md) para saber mais sobre a validação.
## Modais com Arquivos de Script
Você pode precisar executar alguma lógica para o seu modal. Para fazer isso, crie um arquivo JavaScript como abaixo:
````js
abp.modals.ProductInfo = function () {
function initModal(modalManager, args) {
var $modal = modalManager.getModal();
var $form = modalManager.getForm();
$modal.find('h3').css('color', 'red');
console.log('initialized the modal...');
};
return {
initModal: initModal
};
};
````
* Este código simplesmente adiciona uma classe `ProductInfo` ao namespace `abp.modals`. A classe `ProductInfo` expõe uma única função pública: `initModal`.
* O método `initModal` é chamado pelo `ModalManager` assim que o HTML do modal é inserido no DOM e está pronto para a lógica de inicialização.
* O parâmetro `modalManager` é o objeto `ModalManager` relacionado a essa instância do modal. Portanto, você pode usar qualquer função nele em seu código. Consulte a seção *Referência do ModalManager*.
Em seguida, inclua este arquivo na página que você usa o modal:
````html
<abp-script src="/Pages/Products/ProductInfoModal.js"/>
<abp-script src="/Pages/Products/Index.js"/>
````
* Usamos o `abp-script` Tag Helper aqui. Consulte o documento [Bundling & Minification](Bundling-Minification.md) se você quiser entender isso. Você pode usar a tag `script` padrão. Não importa para este caso.
Por fim, defina a opção `modalClass` ao criar a instância `ModalManager`:
````js
var productInfoModal = new abp.ModalManager({
viewUrl: '/Products/ProductInfoModal',
modalClass: 'ProductInfo' //Corresponde a abp.modals.ProductInfo
});
````
### Carregamento Preguiçoso do Arquivo de Script
Em vez de adicionar o `ProductInfoModal.js` à página em que você usa o modal, você pode configurá-lo para carregar preguiçosamente o arquivo de script quando o modal for aberto pela primeira vez.
Exemplo:
````js
var productInfoModal = new abp.ModalManager({
viewUrl: '/Products/ProductInfoModal',
scriptUrl: '/Pages/Products/ProductInfoModal.js', //URL de carregamento preguiçoso
modalClass: 'ProductInfo'
});
````
* `scriptUrl` é usado para definir a URL para carregar o arquivo de script do modal.
* Nesse caso, você não precisa mais incluir o `ProductInfoModal.js` na página. Ele será carregado sob demanda.
#### Dica: Bundling & Minification
Embora o carregamento preguiçoso pareça legal no início, ele requer uma chamada adicional ao servidor quando você abre o modal pela primeira vez.
Em vez disso, você pode usar o sistema de [Bundling & Minification](Bundling-Minification.md) para criar um pacote (que é um único arquivo minificado na produção) para todos os arquivos de script usados em uma página:
````html
<abp-script-bundle>
<abp-script src="/Pages/Products/ProductInfoModal.js"/>
<abp-script src="/Pages/Products/Index.js"/>
</abp-script-bundle>
````
Isso é eficiente se o arquivo de script não for grande e for aberto com frequência enquanto os usuários usam a página.
Alternativamente, você pode definir a classe `abp.modals.ProductInfo` no arquivo JavaScript principal da página se o modal for usado apenas e sempre na mesma página. Nesse caso, você não precisa de outro arquivo de script externo.

288
docs/pt-BR/UI/AspNetCore/Navigation-Menu.md

@ -0,0 +1,288 @@
# ASP.NET Core MVC / Razor Pages UI: Menu de Navegação
Toda aplicação possui um menu principal que permite aos usuários navegar para páginas/telas da aplicação. Algumas aplicações podem conter mais de um menu em diferentes seções da interface do usuário.
O ABP Framework é um framework de desenvolvimento de aplicações [modular](../../Module-Development-Basics.md). **Cada módulo pode precisar adicionar itens ao menu**.
Portanto, o ABP Framework **fornece uma infraestrutura de menu** onde:
* A aplicação ou os módulos podem adicionar itens a um menu, sem saber como o menu é renderizado.
* O [tema](Theming.md) renderiza corretamente o menu.
## Adicionando Itens ao Menu
Para adicionar itens ao menu (ou manipular os itens existentes), você precisa criar uma classe que implemente a interface `IMenuContributor`.
> O [modelo de inicialização da aplicação](../../Startup-Templates/Application.md) já contém uma implementação do `IMenuContributor`. Portanto, você pode adicionar itens dentro dessa classe em vez de criar uma nova.
**Exemplo: Adicionar um item de menu *CRM* com subitens *Clientes* e *Pedidos***
```csharp
using System.Threading.Tasks;
using MyProject.Localization;
using Volo.Abp.UI.Navigation;
namespace MyProject.Web.Menus
{
public class MyProjectMenuContributor : IMenuContributor
{
public async Task ConfigureMenuAsync(MenuConfigurationContext context)
{
if (context.Menu.Name == StandardMenus.Main)
{
await ConfigureMainMenuAsync(context);
}
}
private async Task ConfigureMainMenuAsync(MenuConfigurationContext context)
{
var l = context.GetLocalizer<MyProjectResource>();
context.Menu.AddItem(
new ApplicationMenuItem("MyProject.Crm", l["Menu:CRM"])
.AddItem(new ApplicationMenuItem(
name: "MyProject.Crm.Customers",
displayName: l["Menu:Customers"],
url: "/crm/customers")
).AddItem(new ApplicationMenuItem(
name: "MyProject.Crm.Orders",
displayName: l["Menu:Orders"],
url: "/crm/orders")
)
);
}
}
}
```
* Este exemplo adiciona itens apenas ao menu principal (`StandardMenus.Main`: veja a seção *Menus Padrão* abaixo).
* Ele obtém um `IStringLocalizer` do `context` para [localizar](../../Localization.md) os nomes de exibição dos itens do menu.
* Adiciona os Clientes e Pedidos como filhos do menu CRM.
Depois de criar um contribuidor de menu, você precisa adicioná-lo às `AbpNavigationOptions` no método `ConfigureServices` do seu módulo:
````csharp
Configure<AbpNavigationOptions>(options =>
{
options.MenuContributors.Add(new MyProjectMenuContributor());
});
````
Este exemplo usa algumas chaves de localização como nomes de exibição, que devem ser definidas no arquivo de localização:
````json
"Menu:CRM": "CRM",
"Menu:Orders": "Pedidos",
"Menu:Customers": "Clientes"
````
Consulte o [documento de localização](../../Localization.md) para saber mais sobre a localização.
Quando você executar a aplicação, verá os itens do menu adicionados ao menu principal:
![nav-main-menu](../../images/nav-main-menu.png)
> O menu é renderizado pelo tema de interface do usuário atual. Portanto, a aparência do menu principal pode ser completamente diferente com base no seu tema.
Aqui estão algumas observações sobre os contribuidores de menu;
* O ABP Framework chama o método `ConfigureMenuAsync` **sempre que precisar renderizar** o menu.
* Cada item do menu pode ter **filhos**. Portanto, você pode adicionar itens de menu com **profundidade ilimitada** (no entanto, seu tema de interface do usuário pode não suportar profundidade ilimitada).
* Apenas os itens de menu folha normalmente têm `url`s. Quando você clica em um menu pai, seu submenu é aberto ou fechado, você não navega para a `url` de um item de menu pai.
* Se um item de menu não tiver filhos e não tiver uma `url` definida, ele não será renderizado na interface do usuário. Isso simplifica a autorização dos itens do menu: você só autoriza os itens filhos (veja a próxima seção). Se nenhum dos filhos for autorizado, o pai desaparece automaticamente.
### Propriedades do Item do Menu
Existem mais opções de um item do menu (o construtor da classe `ApplicationMenuItem`). Aqui está a lista de todas as opções disponíveis;
* `name` (`string`, obrigatório): O **nome único** do item do menu.
* `displayName` (`string`, obrigatório): Nome de exibição/texto do item do menu. Você pode [localizar](../../Localization.md) isso como mostrado anteriormente.
* `url` (`string`): A URL do item do menu.
* `icon` (`string`): Um nome de ícone. Classes de ícone gratuitas do [Font Awesome](https://fontawesome.com/) são suportadas por padrão. Exemplo: `fa fa-book`. Você pode usar qualquer classe de ícone de fonte CSS, desde que inclua os arquivos CSS necessários em sua aplicação.
* `order` (`int`): A ordem do item do menu. O valor padrão é `1000`. Os itens são classificados pela ordem de adição, a menos que você especifique um valor de ordem.
* `customData` (`Dictionary<string, object>`): Um dicionário que permite armazenar objetos personalizados que você pode associar ao item do menu e usá-lo ao renderizar o item do menu.
* `target` (`string`): Destino do item do menu. Pode ser `null` (padrão), "\_*blank*", "\_*self*", "\_*parent*", "\_*top*" ou um nome de frame para aplicações web.
* `elementId` (`string`): Pode ser usado para renderizar o elemento com um atributo HTML `id` específico.
* `cssClass` (`string`): Classes de string adicionais para o item do menu.
* `groupName` (`string`): Pode ser usado para agrupar itens do menu.
### Autorização
Como visto acima, um contribuidor de menu contribui para o menu dinamicamente. Portanto, você pode executar qualquer lógica personalizada ou obter itens do menu de qualquer fonte.
Um caso de uso é a [autorização](../../Authorization.md). Normalmente, você deseja adicionar itens de menu verificando uma permissão.
**Exemplo: Verificar se o usuário atual possui uma permissão**
````csharp
if (await context.IsGrantedAsync("NomeDaMinhaPermissao"))
{
//...adicionar itens do menu
}
````
Para a autorização, você pode usar o método de extensão `RequirePermissions` como atalho. Ele também é mais eficiente, o ABP otimiza a verificação de permissão para todos os itens.
````csharp
context.Menu.AddItem(
new ApplicationMenuItem("MyProject.Crm", l["Menu:CRM"])
.AddItem(new ApplicationMenuItem(
name: "MyProject.Crm.Customers",
displayName: l["Menu:Customers"],
url: "/crm/customers")
.RequirePermissions("MyProject.Crm.Customers")
).AddItem(new ApplicationMenuItem(
name: "MyProject.Crm.Orders",
displayName: l["Menu:Orders"],
url: "/crm/orders")
.RequirePermissions("MyProject.Crm.Orders")
)
);
````
> Você pode usar `context.AuthorizationService` para acessar diretamente o `IAuthorizationService`.
### Resolvendo Dependências
`context.ServiceProvider` pode ser usado para resolver qualquer dependência de serviço.
**Exemplo: Obter um serviço**
````csharp
var meuServico = context.ServiceProvider.GetRequiredService<IMeuServico>();
//...usar o serviço
````
> Você não precisa se preocupar em liberar/descartar serviços. O ABP Framework cuida disso.
### O Menu de Administração
Há um item de menu especial no menu que é adicionado pelo ABP Framework: O menu *Administração*. Ele é normalmente usado pelos módulos de administração pré-construídos [application modules](../../Modules/Index.md):
![nav-main-menu-administration](../../images/nav-main-menu-administration.png)
Se você deseja adicionar itens de menu sob o item de menu *Administração*, pode usar o método de extensão `context.Menu.GetAdministration()`:
````csharp
context.Menu.GetAdministration().AddItem(...)
````
### Manipulando os Itens do Menu Existente
O ABP Framework executa os contribuidores de menu pela [ordem de dependência do módulo](../../Module-Development-Basics.md). Portanto, você pode manipular os itens do menu nos quais sua aplicação ou módulo (direta ou indiretamente) depende.
**Exemplo: Definir um ícone para o item de menu `Usuários` adicionado pelo [Módulo de Identidade](../../Modules/Identity.md)**
````csharp
var menuUsuario = context.Menu.FindMenuItem(IdentityMenuNames.Users);
menuUsuario.Icon = "fa fa-users";
````
> `context.Menu` permite acessar todos os itens do menu que foram adicionados pelos contribuidores de menu anteriores.
### Grupos de Menu
Você pode definir grupos e associar itens de menu a um grupo.
Exemplo:
```csharp
using System.Threading.Tasks;
using MyProject.Localization;
using Volo.Abp.UI.Navigation;
namespace MyProject.Web.Menus
{
public class MyProjectMenuContributor : IMenuContributor
{
public async Task ConfigureMenuAsync(MenuConfigurationContext context)
{
if (context.Menu.Name == StandardMenus.Main)
{
await ConfigureMainMenuAsync(context);
}
}
private async Task ConfigureMainMenuAsync(MenuConfigurationContext context)
{
var l = context.GetLocalizer<MyProjectResource>();
context.Menu.AddGroup(
new ApplicationMenuGroup(
name: "Main",
displayName: l["Main"]
)
)
context.Menu.AddItem(
new ApplicationMenuItem("MyProject.Crm", l["Menu:CRM"], groupName: "Main")
.AddItem(new ApplicationMenuItem(
name: "MyProject.Crm.Customers",
displayName: l["Menu:Customers"],
url: "/crm/customers")
).AddItem(new ApplicationMenuItem(
name: "MyProject.Crm.Orders",
displayName: l["Menu:Orders"],
url: "/crm/orders")
)
);
}
}
}
```
> O tema de interface do usuário decidirá se renderizará ou não os grupos e, se decidir renderizar, a forma como é renderizado depende do tema. Apenas o tema LeptonX implementa o grupo de menu.
## Menus Padrão
Um menu é um componente **nomeado**. Uma aplicação pode conter mais de um menu com nomes diferentes e exclusivos. Existem dois menus padrão pré-definidos:
* `Main`: O menu principal da aplicação. Contém links para as páginas da aplicação. Definido como uma constante: `Volo.Abp.UI.Navigation.StandardMenus.Main`.
* `User`: Menu do perfil do usuário. Definido como uma constante: `Volo.Abp.UI.Navigation.StandardMenus.User`.
O menu `Main` já foi abordado acima. O menu `User` está disponível quando um usuário faz login:
![user-menu](../../images/user-menu.png)
Você pode adicionar itens ao menu `User` verificando o `context.Menu.Name` como mostrado abaixo:
```csharp
if (context.Menu.Name == StandardMenus.User)
{
//...adicionar itens
}
```
## IMenuManager
O `IMenuManager` é geralmente usado pelo [tema](Theming.md) de interface do usuário para renderizar os itens do menu na interface do usuário. Portanto, **geralmente você não precisa usar diretamente** o `IMenuManager`.
**Exemplo: Obtendo os itens do menu `Main`**
```csharp
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Volo.Abp.UI.Navigation;
namespace MyProject.Web.Pages
{
public class IndexModel : PageModel
{
private readonly IMenuManager _menuManager;
public IndexModel(IMenuManager menuManager)
{
_menuManager = menuManager;
}
public async Task OnGetAsync()
{
var mainMenu = await _menuManager.GetAsync(StandardMenus.Main);
foreach (var menuItem in mainMenu.Items)
{
//...
}
}
}
}
```

160
docs/pt-BR/UI/AspNetCore/Overall.md

@ -0,0 +1,160 @@
# ASP.NET Core MVC / Razor Pages UI
## Introdução
O ABP Framework oferece uma maneira conveniente e confortável de criar aplicativos da web usando o ASP.NET Core MVC / Razor Pages como framework de interface do usuário.
> O ABP não oferece uma nova/forma personalizada de desenvolvimento de UI. Você pode continuar usando suas habilidades atuais para criar a UI. No entanto, ele oferece muitos recursos para facilitar o desenvolvimento e ter uma base de código mais sustentável.
### MVC vs Razor Pages
O ASP.NET Core oferece dois modelos para o desenvolvimento de UI:
* **[MVC (Model-View-Controller)](https://docs.microsoft.com/en-us/aspnet/core/mvc/)** é a maneira clássica que existe desde a versão 1.0. Este modelo pode ser usado para criar páginas/componentes de UI e APIs HTTP.
* **[Razor Pages](https://docs.microsoft.com/en-us/aspnet/core/razor-pages/)** foi introduzido com o ASP.NET Core 2.0 como uma nova maneira de criar páginas da web.
**O ABP Framework suporta ambos** os modelos MVC e Razor Pages. No entanto, é sugerido criar as **páginas de UI com a abordagem Razor Pages** e usar o **modelo MVC para construir APIs HTTP**. Portanto, todos os módulos pré-construídos, exemplos e documentação são baseados nas Razor Pages para o desenvolvimento de UI, enquanto você sempre pode aplicar o padrão MVC para criar suas próprias páginas.
### Modularidade
A [modularidade](../../Module-Development-Basics.md) é um dos principais objetivos do ABP Framework. Não é diferente para a UI; É possível desenvolver aplicativos modulares e módulos de aplicativos reutilizáveis com páginas e componentes de UI isolados e reutilizáveis.
O [modelo de inicialização do aplicativo](../../Startup-Templates/Application.md) vem com alguns módulos de aplicativos pré-instalados. Esses módulos têm suas próprias páginas de UI incorporadas em seus próprios pacotes NuGet. Você não vê o código deles em sua solução, mas eles funcionam como esperado em tempo de execução.
## Sistema de Temas
O ABP Framework fornece um completo [sistema de temas](Theming.md) com os seguintes objetivos:
* Módulos de aplicativos reutilizáveis são desenvolvidos de forma **independente de temas**, para que possam funcionar com qualquer tema de UI.
* O tema de UI é **decidido pelo aplicativo final**.
* O tema é distribuído por meio de pacotes NuGet/NPM, para que seja **facilmente atualizável**.
* O aplicativo final pode **personalizar** o tema selecionado.
### Temas Atuais
Atualmente, três temas são **oficialmente fornecidos**:
* O [Tema Básico](Basic-Theme.md) é o tema minimalista com o estilo Bootstrap simples. É **open source e gratuito**.
* O [Tema Lepton](https://commercial.abp.io/themes) é um tema **comercial** desenvolvido pela equipe principal do ABP e faz parte da licença [ABP Commercial](https://commercial.abp.io/).
* O [Tema LeptonX](https://x.leptontheme.com/) é um tema que possui escolhas [comerciais](https://docs.abp.io/en/commercial/latest/themes/lepton-x/mvc) e [lite](../../Themes/LeptonXLite/AspNetCore.md).
Também existem alguns temas desenvolvidos pela comunidade para o ABP Framework (você pode pesquisar na web).
### Bibliotecas Base
Existem um conjunto de bibliotecas JavaScript/CSS padrão que são pré-instaladas e suportadas por todos os temas:
- [Twitter Bootstrap](https://getbootstrap.com/) como o framework HTML/CSS fundamental.
- [JQuery](https://jquery.com/) para manipulação do DOM.
- [DataTables.Net](https://datatables.net/) para grades de dados.
- [JQuery Validation](https://jqueryvalidation.org/) para validação do lado do cliente e [unobtrusive](https://github.com/aspnet/jquery-validation-unobtrusive) validation
- [FontAwesome](https://fontawesome.com/) como a biblioteca fundamental de fontes CSS.
- [SweetAlert](https://sweetalert.js.org/) para mostrar mensagens de alerta e caixas de diálogo de confirmação.
- [Toastr](https://github.com/CodeSeven/toastr) para mostrar notificações de toast.
- [Lodash](https://lodash.com/) como uma biblioteca de utilitários.
- [Luxon](https://moment.github.io/luxon/) para operações de data/hora.
- [JQuery Form](https://github.com/jquery-form/form) para formulários AJAX.
- [bootstrap-datepicker](https://github.com/uxsolutions/bootstrap-datepicker) para mostrar seletores de data.
- [Select2](https://select2.org/) para melhores caixas de seleção/combo.
- [Timeago](http://timeago.yarp.com/) para mostrar carimbos de data/hora fuzzy atualizados automaticamente.
- [malihu-custom-scrollbar-plugin](https://github.com/malihu/malihu-custom-scrollbar-plugin) para barras de rolagem personalizadas.
Você pode usar essas bibliotecas diretamente em seus aplicativos, sem precisar importar manualmente sua página.
### Layouts
Os temas fornecem os layouts padrão. Portanto, você tem layouts responsivos com os recursos padrão já implementados. A captura de tela abaixo foi tirada do Layout do Aplicativo do [Tema Básico](Basic-Theme.md):
![basic-theme-application-layout](../../images/basic-theme-application-layout.png)
Consulte o documento [Theming](Theming.md) para obter mais opções de layout e outros detalhes.
### Partes do Layout
Um layout típico consiste em várias partes. O sistema de [temas](Theming.md) fornece [menus](Navigation-Menu.md), [toolbars](Toolbars.md), [hooks de layout](Layout-Hooks.md) e mais para controlar dinamicamente o layout pelo seu aplicativo e pelos módulos que você está usando.
## Recursos
Esta seção destaca alguns dos recursos fornecidos pelo ABP Framework para a UI do ASP.NET Core MVC / Razor Pages.
### Proxies de Cliente de API JavaScript Dinâmico
O sistema de Proxies de Cliente de API JavaScript Dinâmico permite que você consuma suas APIs HTTP do lado do servidor a partir do seu código de cliente JavaScript, assim como chamar funções locais.
**Exemplo: Obter uma lista de autores do servidor**
````js
acme.bookStore.authors.author.getList({
maxResultCount: 10
}).then(function(result){
console.log(result.items);
});
````
`acme.bookStore.authors.author.getList` é uma função gerada automaticamente que faz internamente uma chamada AJAX para o servidor.
Consulte o documento [Proxies de Cliente de API JavaScript Dinâmico](Dynamic-JavaScript-Proxies.md) para mais informações.
### Tag Helpers do Bootstrap
O ABP torna mais fácil e seguro escrever HTML do Bootstrap.
**Exemplo: Renderizar um modal do Bootstrap**
````html
<abp-modal>
<abp-modal-header title="Título do Modal" />
<abp-modal-body>
Uau, você está lendo este texto em um modal!
</abp-modal-body>
<abp-modal-footer buttons="@(AbpModalButtons.Save|AbpModalButtons.Close)"></abp-modal-footer>
</abp-modal>
````
Consulte o documento [Tag Helpers](Tag-Helpers/Index.md) para mais informações.
### Formulários e Validação
O ABP fornece os tag helpers `abp-dynamic-form` e `abp-input` para simplificar drasticamente a criação de um formulário totalmente funcional que automatiza a localização, validação e envio AJAX.
**Exemplo: Use `abp-dynamic-form` para criar um formulário completo com base em um modelo**
````html
<abp-dynamic-form abp-model="Movie" submit-button="true" />
````
Consulte o documento [Formulários e Validação](Forms-Validation.md) para obter mais detalhes.
### Agrupamento e Minificação / Bibliotecas do Lado do Cliente
O ABP fornece um sistema de Agrupamento e Minificação flexível e modular para criar pacotes e minificar arquivos de estilo/script em tempo de execução.
````html
<abp-style-bundle>
<abp-style src="/libs/bootstrap/css/bootstrap.css" />
<abp-style src="/libs/font-awesome/css/font-awesome.css" />
<abp-style src="/libs/toastr/toastr.css" />
<abp-style src="/styles/my-global-style.css" />
</abp-style-bundle>
````
Além disso, o sistema de Gerenciamento de Pacotes do Lado do Cliente oferece uma maneira modular e consistente de gerenciar dependências de bibliotecas de terceiros.
Consulte os documentos [Agrupamento e Minificação](Bundling-Minification.md) e [Gerenciamento de Pacotes do Lado do Cliente](Client-Side-Package-Management.md).
### APIs JavaScript
As [APIs JavaScript](JavaScript-API/Index.md) fornecem abstrações sólidas para a localização, configurações, permissões, recursos... etc. do lado do servidor. Elas também fornecem uma maneira simples de mostrar mensagens e **notificações** ao usuário.
### Modais, Alertas, Widgets e Mais
O ABP Framework fornece muitas soluções integradas para requisitos comuns de aplicativos;
* O [Sistema de Widgets](Widgets.md) pode ser usado para criar widgets reutilizáveis e criar painéis de controle.
* Os [Alertas de Página](Page-Alerts.md) facilitam a exibição de alertas ao usuário.
* O [Gerenciador de Modais](Modals.md) fornece uma maneira simples de construir e usar modais.
* A integração com [Data Tables](Data-Tables.md) facilita a criação de grades de dados.
## Personalização
Existem muitas maneiras de personalizar o tema e as UIs dos módulos pré-construídos. Você pode substituir componentes, páginas, recursos estáticos, pacotes e muito mais. Consulte o [Guia de Personalização da Interface do Usuário](Customization-User-Interface.md) para mais informações.

84
docs/pt-BR/UI/AspNetCore/Page-Alerts.md

@ -0,0 +1,84 @@
# ASP.NET Core MVC / Razor Pages: Alertas de Página
É comum mostrar alertas de erro, aviso ou informação para informar o usuário. Um exemplo de alerta de *Interrupção de Serviço* é mostrado abaixo:
![exemplo-alerta-pagina](../../images/exemplo-alerta-pagina.png)
## Uso Básico
Se você herda diretamente ou indiretamente de `AbpPageModel`, você pode usar a propriedade `Alerts` para adicionar alertas que serão renderizados após a conclusão da solicitação.
**Exemplo: Mostrar um alerta de aviso**
```csharp
namespace MyProject.Web.Pages
{
public class IndexModel : MyProjectPageModel //ou herde de AbpPageModel
{
public void OnGet()
{
Alerts.Warning(
text: "Teremos uma interrupção de serviço entre 02:00 e 04:00 em 23 de outubro de 2023!",
title: "Interrupção de Serviço"
);
}
}
}
```
Este uso renderiza um alerta que foi mostrado acima. Se você precisar localizar as mensagens, você sempre pode usar o sistema padrão de [localização](../../Localization.md).
### Exceções / Estados Inválidos do Modelo
É comum mostrar alertas quando você manipula manualmente exceções (com declarações try/catch) ou deseja lidar com o caso `!ModelState.IsValid` e avisar o usuário. Por exemplo, o Módulo de Conta mostra um aviso se o usuário inserir um nome de usuário ou senha incorretos:
![layout-alerta-conta](../../images/layout-alerta-conta.png)
> Observe que geralmente você não precisa manipular exceções manualmente, pois o ABP Framework fornece um sistema automático de [manipulação de exceções](../../Exception-Handling.md).
### Tipos de Alerta
`Warning` é usado para mostrar um alerta de aviso. Outros métodos comuns são `Info`, `Danger` e `Success`.
Além dos métodos padrão, você pode usar o método `Alerts.Add` passando um `enum` `AlertType` com um desses valores: `Default`, `Primary`, `Secondary`, `Success`, `Danger`, `Warning`, `Info`, `Light`, `Dark`.
### Dispensável
Todos os métodos de alerta recebem um parâmetro opcional `dismissible`. O valor padrão é `true`, o que torna a caixa de alerta dispensável. Defina-o como `false` para criar uma caixa de alerta fixa.
## IAlertManager
Se você precisar adicionar mensagens de alerta de outra parte do seu código, você pode injetar o serviço `IAlertManager` e usar sua lista `Alerts`.
**Exemplo: Injetar o `IAlertManager`**
```csharp
using Volo.Abp.AspNetCore.Mvc.UI.Alerts;
using Volo.Abp.DependencyInjection;
namespace MyProject.Web.Pages
{
public class MyService : ITransientDependency
{
private readonly IAlertManager _alertManager;
public MyService(IAlertManager alertManager)
{
_alertManager = alertManager;
}
public void Test()
{
_alertManager.Alerts.Add(AlertType.Danger, "Mensagem de teste!");
}
}
}
```
## Notas
### Requisições AJAX
O sistema de Alerta de Página foi projetado para ser usado em uma solicitação regular de página completa. Não é para requisições AJAX/partial. Os alertas são renderizados no layout da página, portanto, é necessário atualizar a página inteira.
Para requisições AJAX, é mais adequado lançar exceções (por exemplo, `UserFriendlyException`). Consulte o documento de [manipulação de exceções](../../Exception-Handling.md).

62
docs/pt-BR/UI/AspNetCore/Page-Header.md

@ -0,0 +1,62 @@
# ASP.NET Core MVC / Razor Pages: Cabeçalho da Página
O serviço `IPageLayout` pode ser usado para definir o título da página, o item de menu selecionado e os itens do breadcrumb para uma página. É responsabilidade do [tema](Theming.md) renderar esses elementos na página.
## IPageLayout
O `IPageLayout` pode ser injetado em qualquer página/view para definir as propriedades do cabeçalho da página.
### Título da Página
O título da página pode ser definido da seguinte forma:
```csharp
@inject IPageLayout PageLayout
@{
PageLayout.Content.Title = "Lista de Livros";
}
```
* O título da página é definido na tag HTML `title` (além do [nome da marca/aplicativo](Branding.md)).
* O tema pode renderizar o título da página antes do conteúdo da página (ainda não implementado pelo Tema Básico).
### Breadcrumb
> **O [Tema Básico](Basic-Theme.md) atualmente não implementa o breadcrumb.**
>
> O [Tema LeptonX Lite](../../Themes/LeptonXLite/AspNetCore.md) suporta o breadcrumb.
Itens do breadcrumb podem ser adicionados ao `PageLayout.Content.BreadCrumb`.
**Exemplo: Adicionar Gerenciamento de Idioma aos itens do breadcrumb.**
```
PageLayout.Content.BreadCrumb.Add("Gerenciamento de Idioma");
```
O tema então renderiza o breadcrumb. Um exemplo do resultado renderizado pode ser:
![exemplo-breadcrumb](../../images/exemplo-breadcrumb.png)
* O ícone Home é renderizado por padrão. Defina `PageLayout.Content.BreadCrumb.ShowHome` como `false` para ocultá-lo.
* O nome da página atual (obtido do `PageLayout.Content.Title`) é adicionado por padrão como o último item. Defina `PageLayout.Content.BreadCrumb.ShowCurrent` como `false` para ocultá-lo.
Qualquer item que você adicionar é inserido entre o Home e os itens da página atual. Você pode adicionar quantos itens forem necessários. O método `BreadCrumb.Add(...)` recebe três parâmetros:
* `text`: O texto a ser exibido para o item do breadcrumb.
* `url` (opcional): Uma URL para navegar, se o usuário clicar no item do breadcrumb.
* `icon` (opcional): Uma classe de ícone (como `fas fa-user-tie` para Font-Awesome) para exibir junto com o `text`.
### O Item de Menu Selecionado
> **O [Tema Básico](Basic-Theme.md) atualmente não implementa o item de menu selecionado, pois não é aplicável ao menu superior, que é a única opção para o Tema Básico no momento.**
>
> O [Tema LeptonX Lite](../../Themes/LeptonXLite/AspNetCore.md) suporta o item de menu selecionado.
Você pode definir o nome do item de menu relacionado a esta página:
```csharp
PageLayout.Content.MenuItemName = "BookStore.Books";
```
O nome do item de menu deve corresponder a um nome de item de menu único definido usando o sistema de [Navegação / Menu](Navigation-Menu.md). Nesse caso, espera-se que o tema torne o item de menu "ativo" no menu principal.

162
docs/pt-BR/UI/AspNetCore/Page-Toolbar-Extensions.md

@ -0,0 +1,162 @@
# Extensões da Barra de Ferramentas da Página para a Interface do Usuário ASP.NET Core
O sistema de barra de ferramentas da página permite adicionar componentes à barra de ferramentas de qualquer página. A barra de ferramentas da página é a área à direita do cabeçalho de uma página. Um botão ("Importar usuários do Excel") foi adicionado à página de gerenciamento de usuários abaixo:
![botão-barra-ferramentas-página](../../images/page-toolbar-button.png)
Você pode adicionar qualquer tipo de componente de visualização à barra de ferramentas da página ou modificar os itens existentes.
## Como Configurar
Neste exemplo, adicionaremos um botão "Importar usuários do Excel" e executaremos um código JavaScript para a página de gerenciamento de usuários do [Módulo de Identidade](../../Modules/Identity.md).
### Adicionar um Novo Botão à Página de Gerenciamento de Usuários
Escreva o seguinte código dentro do método `ConfigureServices` da classe do seu módulo web:
````csharp
Configure<AbpPageToolbarOptions>(options =>
{
options.Configure<Volo.Abp.Identity.Web.Pages.Identity.Users.IndexModel>(toolbar =>
{
toolbar.AddButton(
LocalizableString.Create<MyProjectNameResource>("ImportFromExcel"),
icon: "file-import",
id: "ImportUsersFromExcel",
type: AbpButtonType.Secondary
);
});
});
````
`AddButton` é um atalho para simplesmente adicionar um componente de botão. Observe que você precisa adicionar a chave `ImportFromExcel` ao seu dicionário de localização (arquivo json) para localizar o texto.
Quando você executar a aplicação, verá o botão adicionado ao lado da lista de botões atual. Existem outros parâmetros do método `AddButton` (por exemplo, use `order` para definir a ordem do componente de botão em relação aos outros componentes).
### Criar um Arquivo JavaScript
Agora, podemos ir para o lado do cliente para lidar com o evento de clique do novo botão. Primeiro, adicione um novo arquivo JavaScript à sua solução. Nós adicionamos dentro da pasta `/Pages/Identity/Users` do projeto `.Web`:
![extensão-ação-usuário-na-solução](../../images/user-action-extension-on-solution.png)
Aqui está o conteúdo deste arquivo JavaScript:
````js
$(function () {
$('#ImportUsersFromExcel').click(function (e) {
e.preventDefault();
alert('TODO: importar usuários do Excel');
});
});
````
No evento `click`, você pode fazer qualquer coisa que precise fazer.
### Adicionar o Arquivo à Página de Gerenciamento de Usuários
Em seguida, você precisa adicionar este arquivo JavaScript à página de gerenciamento de usuários. Você pode aproveitar o poder do sistema de [Agrupamento e Minificação](Bundling-Minification.md).
Escreva o seguinte código dentro do método `ConfigureServices` da classe do seu módulo:
````csharp
Configure<AbpBundlingOptions>(options =>
{
options.ScriptBundles.Configure(
typeof(Volo.Abp.Identity.Web.Pages.Identity.Users.IndexModel).FullName,
bundleConfiguration =>
{
bundleConfiguration.AddFiles(
"/Pages/Identity/Users/my-user-extensions.js"
);
});
});
````
Essa configuração adiciona `my-user-extensions.js` à página de gerenciamento de usuários do Módulo de Identidade. `typeof(Volo.Abp.Identity.Web.Pages.Identity.Users.IndexModel).FullName` é o nome do pacote na página de gerenciamento de usuários. Essa é uma convenção comum usada para todos os módulos comerciais do ABP.
## Casos de Uso Avançados
Embora você normalmente queira adicionar uma ação de botão à barra de ferramentas da página, é possível adicionar qualquer tipo de componente.
### Adicionar um Componente de Visualização à Barra de Ferramentas da Página
Primeiro, crie um novo componente de visualização em seu projeto:
![componente-personalizado-barra-ferramentas-página](../../images/page-toolbar-custom-component.png)
Para este exemplo, criamos um componente de visualização `MyToolbarItem` na pasta `/Pages/Identity/Users/MyToolbarItem`.
Conteúdo de `MyToolbarItemViewComponent.cs`:
````csharp
public class MyToolbarItemViewComponent : AbpViewComponent
{
public IViewComponentResult Invoke()
{
return View("~/Pages/Identity/Users/MyToolbarItem/Default.cshtml");
}
}
````
Conteúdo de `Default.cshtml`:
````xml
<span>
<button type="button" class="btn btn-dark">CLIQUE AQUI</button>
</span>
````
* O arquivo `.cshtml` pode conter qualquer tipo de componente(s). É um componente de visualização típico.
* `MyToolbarItemViewComponent` pode injetar e usar qualquer serviço, se necessário.
Em seguida, você pode adicionar o `MyToolbarItemViewComponent` à página de gerenciamento de usuários:
````csharp
Configure<AbpPageToolbarOptions>(options =>
{
options.Configure<Volo.Abp.Identity.Web.Pages.Identity.Users.IndexModel>(
toolbar =>
{
toolbar.AddComponent<MyToolbarItemViewComponent>();
}
);
});
````
* Se o seu componente aceitar argumentos (no método `Invoke`/`InvokeAsync`), você pode passá-los para o método `AddComponent` como um objeto anônimo.
#### Permissões
Se o seu botão/componente deve estar disponível com base em uma [permissão/política](../../Authorization.md), você pode passar o nome da permissão/política como parâmetro `requiredPolicyName` para os métodos `AddButton` e `AddComponent`.
### Adicionar um Contribuidor da Barra de Ferramentas da Página
Se você realizar uma lógica personalizada avançada ao adicionar um item à barra de ferramentas de uma página, pode criar uma classe que implementa a interface `IPageToolbarContributor` ou herda da classe `PageToolbarContributor`:
````csharp
public class MyToolbarContributor : PageToolbarContributor
{
public override Task ContributeAsync(PageToolbarContributionContext context)
{
context.Items.Insert(0, new PageToolbarItem(typeof(MyToolbarItemViewComponent)));
return Task.CompletedTask;
}
}
````
* Você pode usar `context.ServiceProvider` para resolver dependências, se necessário.
Em seguida, adicione sua classe à lista `Contributors`:
````csharp
Configure<AbpPageToolbarOptions>(options =>
{
options.Configure<Volo.Abp.Identity.Web.Pages.Identity.Users.IndexModel>(
toolbar =>
{
toolbar.Contributors.Add(new MyToolbarContributor());
}
);
});
````

99
docs/pt-BR/UI/AspNetCore/Security-Headers.md

@ -0,0 +1,99 @@
# Cabeçalhos de Segurança
O ABP Framework permite que você adicione cabeçalhos de segurança frequentemente usados em sua aplicação. Os seguintes cabeçalhos de segurança serão adicionados como cabeçalhos de resposta à sua aplicação se você usar o middleware `UseAbpSecurityHeaders`:
* `X-Content-Type-Options`: Informa ao navegador para não tentar adivinhar qual pode ser o tipo MIME de um recurso e apenas aceitar o tipo MIME retornado pelo servidor.
* `X-XSS-Protection`: Esta é uma funcionalidade do Internet Explorer, Chrome e Safari que impede o carregamento de páginas quando detectam ataques de cross-site scripting (XSS) refletidos.
* `X-Frame-Options`: Este cabeçalho pode ser usado para indicar se um navegador deve ou não ser permitido a renderizar uma página em uma tag `<iframe>`. Ao especificar o valor desse cabeçalho como *SAMEORIGIN*, você pode fazer com que a página seja exibida em um frame na mesma origem da própria página.
* `Content-Security-Policy`: Este cabeçalho de resposta permite restringir quais recursos (como JavaScript, CSS, imagens, manifestos, etc.) podem ser carregados e os URLs de onde eles podem ser carregados. Esse cabeçalho de segurança só será adicionado se você configurar a classe `AbpSecurityHeadersOptions` e ativá-lo.
## Configuração
### AbpSecurityHeadersOptions
`AbpSecurityHeadersOptions` é a classe principal para habilitar o cabeçalho `Content-Security-Policy`, definir seu valor e adicionar outros cabeçalhos de segurança que você deseja adicionar à sua aplicação.
**Exemplo:**
```csharp
Configure<AbpSecurityHeadersOptions>(options =>
{
options.UseContentSecurityPolicyHeader = true; //false por padrão
options.ContentSecurityPolicyValue = "object-src 'none'; form-action 'self'; frame-ancestors 'none'"; //valor padrão
//adicionando cabeçalhos de segurança adicionais
options.Headers["Referrer-Policy"] = "no-referrer";
});
```
> Se o cabeçalho for o mesmo, os cabeçalhos de segurança adicionais que você definiu têm precedência sobre os cabeçalhos de segurança padrão. Em outras palavras, eles substituem os valores padrão dos cabeçalhos de segurança.
## Middleware de Cabeçalhos de Segurança
O middleware de Cabeçalhos de Segurança é um middleware da pipeline de solicitação do ASP.NET Core que adiciona cabeçalhos de segurança predefinidos à sua aplicação, incluindo `X-Content-Type-Options`, `X-XSS-Protection` e `X-Frame-Options`. Além disso, esse middleware também inclui esses cabeçalhos de segurança exclusivos em sua aplicação se você configurar a classe `AbpSecurityHeadersOptions` conforme mencionado acima.
**Exemplo:**
```csharp
app.UseAbpSecurityHeaders();
```
> Você pode adicionar esse middleware após `app.UseRouting()` no método `OnApplicationInitialization` da classe do seu módulo para registrá-lo na pipeline de solicitação. Esse middleware já está configurado nos [ABP Commercial Startup Templates](https://docs.abp.io/en/commercial/latest/startup-templates/index), portanto, você não precisa adicioná-lo manualmente se estiver usando um desses modelos de inicialização.
Depois de registrar o middleware `UseAbpSecurityHeaders` na pipeline de solicitação, os cabeçalhos de segurança definidos serão exibidos nos cabeçalhos de resposta, como na figura abaixo:
![](../../images/security-response-headers.png)
## Nonce de Script da Política de Segurança de Conteúdo
O Abp Framework fornece uma propriedade para adicionar um valor de nonce dinâmico ao cabeçalho Content-Security-Policy. Com esse recurso, ele adiciona automaticamente um valor de nonce dinâmico ao lado do cabeçalho. E com a ajuda do helper de tag de script, ele adiciona esse valor de [`nonce de script`](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/nonce) às tags de script em suas páginas (o `ScriptNonceTagHelper` no namespace `Volo.Abp.AspNetCore.Mvc.UI.Bundling` deve ser anexado como um taghelper).
> Se você precisar adicionar manualmente o nonce de script, pode usar 'Html.GetScriptNonce()' para adicionar o valor de nonce ou 'Html.GetScriptNonceAttribute()' para adicionar o valor do atributo nonce.
Esse recurso está desabilitado por padrão. Você pode ativá-lo definindo a propriedade `UseContentSecurityPolicyScriptNonce` da classe `AbpSecurityHeadersOptions` como `true`.
### Ignorar Nonce de Script
Você pode ignorar o nonce de script para algumas páginas ou alguns seletores. Você pode usar as propriedades `IgnoredScriptNoncePaths` e `IgnoredScriptNonceSelectors` da classe `AbpSecurityHeadersOptions`.
**Exemplo:**
```csharp
Configure<AbpSecurityHeadersOptions>(options =>
{
//adicionando nonce de script-src
options.UseContentSecurityPolicyScriptNonce = true; //false por padrão
//ignorar a origem do nonce de script para esses caminhos
options.IgnoredScriptNoncePaths.Add("/minha-pagina");
//ignorar o nonce de script por Elsa Workflows e outros seletores
options.IgnoredScriptNonceSelectors.Add(context =>
{
var endpoint = context.GetEndpoint();
return Task.FromResult(endpoint?.Metadata.GetMetadata<PageRouteMetadata>()?.RouteTemplate == "/{SUA_PAGINA_PRINCIPAL}");
});
});
```
### Ignorar Cabeçalhos de Segurança do Abp
Você pode ignorar os Cabeçalhos de Segurança do Abp para algumas ações ou páginas. Você pode usar o atributo `IgnoreAbpSecurityHeaderAttribute` para isso.
**Exemplo:**
```csharp
@using Volo.Abp.AspNetCore.Security
@attribute [IgnoreAbpSecurityHeaderAttribute]
```
**Exemplo:**
```csharp
[IgnoreAbpSecurityHeaderAttribute]
public class IndexModel : AbpPageModel
{
public void OnGet()
{
}
}
```

157
docs/pt-BR/UI/AspNetCore/Static-JavaScript-Proxies.md

@ -0,0 +1,157 @@
# Proxies de Cliente Estático da API JavaScript
É comum consumir suas APIs HTTP a partir do seu código JavaScript. Para fazer isso, normalmente você lida com chamadas AJAX de baixo nível, como $.ajax, ou melhor [abp.ajax](JavaScript-API/Ajax.md). O ABP Framework fornece **uma maneira melhor** de chamar suas APIs HTTP a partir do seu código JavaScript: Proxies de Cliente da API JavaScript!
## Proxies de Cliente JavaScript Estáticos vs Dinâmicos
O ABP fornece **dois tipos** de sistema de geração de proxy de cliente. Este documento explica os **proxies de cliente estáticos**, que geram código do lado do cliente durante o desenvolvimento. Você também pode ver a documentação [Proxies de Cliente JavaScript Dinâmicos da API](Dynamic-JavaScript-Proxies.md) para aprender como usar proxies gerados em tempo de execução.
A geração de proxy de cliente em tempo de desenvolvimento (estático) tem uma **ligeira vantagem de desempenho**, pois não precisa obter a definição da API HTTP em tempo de execução. No entanto, você deve **regenerar** o código do proxy do cliente sempre que alterar a definição do ponto de extremidade da API. Por outro lado, os proxies de cliente dinâmicos são gerados em tempo de execução e oferecem uma **experiência de desenvolvimento mais fácil**.
## Um Exemplo Rápido
### O Serviço de Aplicativo
Suponha que você tenha um serviço de aplicativo definido como mostrado abaixo:
````csharp
using System;
using System.Threading.Tasks;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Application.Services;
namespace Acme.BookStore.Authors
{
public interface IAuthorAppService : IApplicationService
{
Task<AuthorDto> GetAsync(Guid id);
Task<PagedResultDto<AuthorDto>> GetListAsync(GetAuthorListDto input);
Task<AuthorDto> CreateAsync(CreateAuthorDto input);
Task UpdateAsync(Guid id, UpdateAuthorDto input);
Task DeleteAsync(Guid id);
}
}
````
> Você pode seguir o [tutorial de desenvolvimento de aplicativos da web](../../Tutorials/Part-1.md) para aprender como criar [serviços de aplicativos](../../Application-Services.md), expô-los como [APIs HTTP](../../API/Auto-API-Controllers.md) e consumir do código JavaScript como um exemplo completo.
### Gerando o Código JavaScript
O lado do servidor deve estar em execução ao gerar o código do proxy do cliente. Portanto, execute primeiro a aplicação que hospeda suas APIs HTTP (pode ser a aplicação Web ou a aplicação HttpApi.Host, dependendo da estrutura da sua solução).
Abra um terminal de linha de comando na pasta raiz do seu projeto da web (`.csproj`) e digite o seguinte comando:
````bash
abp generate-proxy -t js -u https://localhost:53929/
````
> Se você ainda não instalou, deve instalar o [ABP CLI](../../CLI.md). Altere a URL de exemplo para a URL raiz da sua aplicação.
Este comando deve gerar os seguintes arquivos na pasta `ClientProxies`:
![static-js-proxy-example](../../images/static-js-proxy-example.png)
`app-proxy.js` é o arquivo de proxy gerado neste exemplo. Aqui, um exemplo de função de proxy neste arquivo:
````js
acme.bookStore.authors.author.get = function(id, ajaxParams) {
return abp.ajax($.extend(true, {
url: abp.appPath + 'api/app/author/' + id + '',
type: 'GET'
}, ajaxParams));
};
````
> O comando `generate-proxy` gera proxies apenas para as APIs que você definiu em sua aplicação (assume `app` como o nome do módulo). Se você está desenvolvendo uma aplicação modular, pode especificar o parâmetro `-m` (ou `--module`) para especificar o módulo para o qual deseja gerar proxies. Consulte a seção *generate-proxy* na documentação do [ABP CLI](../CLI.md) para outras opções.
### Usando as Funções de Proxy
Para usar as funções de proxy, primeiro importe o arquivo `app-proxy.js` para a sua página:
````html
<abp-script src="/client-proxies/app-proxy.js"/>
````
> Usamos o [abp-script tag helper](Bundling-Minification.md) neste exemplo. Você pode usar a tag `script` padrão, mas o `abp-script` é a maneira recomendada de importar arquivos JavaScript para suas páginas.
Agora, você pode chamar qualquer um dos métodos do serviço de aplicativo a partir do seu código JavaScript, assim como chamar uma função JavaScript. A função JavaScript tem o mesmo **nome**, **parâmetros** e **valor de retorno** do método C#.
**Exemplo: Obter um único autor**
````js
acme.bookStore.authors.author
.get("7245a066-5457-4941-8aa7-3004778775f0") //Obtenha o id de algum lugar!
.then(function(result){
console.log(result);
});
````
**Exemplo: Obter a lista de autores**
````js
acme.bookStore.authors.author.getList({
maxResultCount: 10
}).then(function(result){
console.log(result.items);
});
````
**Exemplo: Excluir um autor**
```js
acme.bookStore.authors.author
.delete('7245a066-5457-4941-8aa7-3004778775f0') //Obtenha o id de algum lugar!
.then(function() {
abp.notify.info('Excluído com sucesso!');
});
```
## Desabilitando Proxies JavaScript Dinâmicos
Quando você cria um aplicativo ou módulo, a abordagem de [geração dinâmica de proxy de cliente](Dynamic-JavaScript-Proxies.md) é usada por padrão. Se você deseja usar os proxies de cliente gerados estaticamente para o seu aplicativo, você deve desabilitá-lo explicitamente para o seu aplicativo ou módulo no método `ConfigureServices` da sua [classe de módulo](../../Module-Development-Basics.md), como no exemplo a seguir:
````csharp
Configure<DynamicJavaScriptProxyOptions>(options =>
{
options.DisableModule("app");
});
````
`app` representa o aplicativo principal neste exemplo, o que funciona se você estiver criando um aplicativo. Se você estiver desenvolvendo um módulo de aplicativo, use o nome do seu módulo.
## Detalhes do AJAX
As funções de proxy do cliente JavaScript usam o [abp.ajax](JavaScript-API/Ajax.md) por baixo dos panos. Portanto, você tem os mesmos benefícios, como **tratamento automático de erros**. Além disso, você pode controlar totalmente a chamada AJAX fornecendo as opções.
### O Valor de Retorno
Cada função retorna um [objeto Deferred](https://api.jquery.com/category/deferred-object/). Isso significa que você pode encadear com `then` para obter o resultado, `catch` para lidar com o erro, `always` para executar uma ação assim que a operação for concluída (sucesso ou falha).
### Opções do AJAX
Cada função recebe um **último parâmetro** adicional após seus próprios parâmetros. O último parâmetro é chamado de `ajaxParams`. É um objeto que substitui as opções do AJAX.
**Exemplo: Definir as opções do AJAX `type` e `dataType`**
````js
acme.bookStore.authors.author
.delete('7245a066-5457-4941-8aa7-3004778775f0', {
type: 'POST',
dataType: 'xml'
})
.then(function() {
abp.notify.info('Excluído com sucesso!');
});
````
Consulte a documentação do [jQuery.ajax](https://api.jquery.com/jQuery.ajax/) para todas as opções disponíveis.
## Veja Também
* [Proxies de Cliente JavaScript Dinâmicos da API](Dynamic-JavaScript-Proxies.md)
* [Controladores de API Automáticos](../../API/Auto-API-Controllers.md)
* [Tutorial de Desenvolvimento de Aplicativos da Web](../../Tutorials/Part-1.md)

82
docs/pt-BR/UI/AspNetCore/Tag-Helpers/Alerts.md

@ -0,0 +1,82 @@
# Alertas
## Introdução
`abp-alert` é um elemento principal para criar um alerta.
Uso básico:
````xml
<abp-alert alert-type="Primary">
Um alerta primário simples - confira!
</abp-alert>
````
## Demonstração
Veja a página de demonstração de [alertas](https://bootstrap-taghelpers.abp.io/Components/Alerts) para vê-lo em ação.
## Atributos
### alert-type
Um valor que indica o tipo de alerta. Deve ser um dos seguintes valores:
* `Default` (valor padrão)
* `Primary`
* `Secondary`
* `Success`
* `Danger`
* `Warning`
* `Info`
* `Light`
* `Dark`
Exemplo:
````xml
<abp-alert alert-type="Warning">
Um alerta de aviso simples - confira!
</abp-alert>
````
### alert-link
Um valor que fornece links coloridos correspondentes dentro de qualquer alerta.
Exemplo:
````xml
<abp-alert alert-type="Danger">
Um alerta de perigo simples com <a abp-alert-link href="#">um exemplo de link</a>. Clique nele se quiser.
</abp-alert>
````
### dismissible
Um valor para tornar o alerta dispensável.
Exemplo:
````xml
<abp-alert alert-type="Warning" dismissible="true">
Santo guacamole! Você deve verificar alguns desses campos abaixo.
</abp-alert>
````
### Conteúdo adicional
`abp-alert` também pode conter elementos HTML adicionais, como títulos, parágrafos e divisores.
Exemplo:
````xml
<abp-alert alert-type="Success">
<h4>Bom trabalho!</h4>
<p>Aww yeah, você leu com sucesso esta importante mensagem de alerta. Este texto de exemplo vai ficar um pouco mais longo para que você possa ver como o espaçamento dentro de um alerta funciona com esse tipo de conteúdo.</p>
<hr>
<p class="mb-0">Sempre que precisar, certifique-se de usar utilitários de margem para manter as coisas organizadas.</p>
</abp-alert>
````

37
docs/pt-BR/UI/AspNetCore/Tag-Helpers/Badges.md

@ -0,0 +1,37 @@
# Distintivos
## Introdução
`abp-badge` e `abp-badge-pill` são atributos de Tag Helper ABP para tags html `a` e `span`.
Uso básico:
````html
<span abp-badge="Primary">Primary</span>
<a abp-badge="Info" href="#">Info</a>
<a abp-badge-pill="Danger" href="#">Danger</a>
````
## Demonstração
Veja a página de demonstração de [distintivos](https://bootstrap-taghelpers.abp.io/Components/Badges) para vê-los em ação.
### Valores
* Indica o tipo de distintivo. Deve ser um dos seguintes valores:
* `Default`
* `Primary`
* `Secondary`
* `Success`
* `Danger`
* `Warning`
* `Info`
* `Light`
* `Dark`
Exemplo:
````html
<span abp-badge-pill="Danger">Danger</span>
````

18
docs/pt-BR/UI/AspNetCore/Tag-Helpers/Blockquote.md

@ -0,0 +1,18 @@
# Blockquote
`abp-blockquote` é o contêiner principal para os itens de blockquote.
Usos básicos:
````html
<abp-blockquote>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer posuere erat a ante.</p>
</abp-blockquote>
<abp-blockquote>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer posuere erat a ante.</p>
<footer>Alguém famoso em Título da Fonte</footer>
</abp-blockquote>
````
Ele adiciona a classe `blockquote` ao contêiner principal, também adiciona a classe `blockquote-footer` ao elemento `footer` interno e a classe `mb-0` ao elemento `p` interno.

126
docs/pt-BR/UI/AspNetCore/Tag-Helpers/Borders.md

@ -0,0 +1,126 @@
# Bordas
## Introdução
`abp-border` é um atributo do ABP Tag Helper para estilização de bordas.
Uso básico:
````html
<span abp-border="Default"></span>
<span abp-border="Top"></span>
<span abp-border="Right"></span>
<span abp-border="Bottom"></span>
<span abp-border="Left"></span>
````
## Demonstração
Veja a página de demonstração de [bordas](https://bootstrap-taghelpers.abp.io/Components/Borders) para vê-lo em ação.
## Valores
Um valor indica o tipo, posição e a cor da borda. Deve ser um dos seguintes valores:
* `Default`
* `_0`
* `Primary`
* `Secondary`
* `Success`
* `Danger`
* `Warning`
* `Info`
* `Light`
* `Dark`
* `White`
* `Primary_0`
* `Secondary_0`
* `Success_0`
* `Danger_0`
* `Warning_0`
* `Info_0`
* `Light_0`
* `Dark_0`
* `White_0`
* `Top`
* `Top_0`
* `Top_Primary`
* `Top_Secondary`
* `Top_Success`
* `Top_Danger`
* `Top_Warning`
* `Top_Info`
* `Top_Light`
* `Top_Dark`
* `Top_White`
* `Top_Primary_0`
* `Top_Secondary_0`
* `Top_Success_0`
* `Top_Danger_0`
* `Top_Warning_0`
* `Top_Info_0`
* `Top_Light_0`
* `Top_Dark_0`
* `Top_White_0`
* `Right`
* `Right_0`
* `Right_Primary`
* `Right_Secondary`
* `Right_Success`
* `Right_Danger`
* `Right_Warning`
* `Right_Info`
* `Right_Light`
* `Right_Dark`
* `Right_White`
* `Right_Primary_0`
* `Right_Secondary_0`
* `Right_Success_0`
* `Right_Danger_0`
* `Right_Warning_0`
* `Right_Info_0`
* `Right_Light_0`
* `Right_Dark_0`
* `Right_White_0`
* `Left`
* `Left_0`
* `Left_Primary`
* `Left_Secondary`
* `Left_Success`
* `Left_Danger`
* `Left_Warning`
* `Left_Info`
* `Left_Light`
* `Left_Dark`
* `Left_White`
* `Left_Primary_0`
* `Left_Secondary_0`
* `Left_Success_0`
* `Left_Danger_0`
* `Left_Warning_0`
* `Left_Info_0`
* `Left_Light_0`
* `Left_Dark_0`
* `Left_White_0`
* `Bottom`
* `Bottom_0`
* `Bottom_Primary`
* `Bottom_Secondary`
* `Bottom_Success`
* `Bottom_Danger`
* `Bottom_Warning`
* `Bottom_Info`
* `Bottom_Light`
* `Bottom_Dark`
* `Bottom_White`
* `Bottom_Primary_0`
* `Bottom_Secondary_0`
* `Bottom_Success_0`
* `Bottom_Danger_0`
* `Bottom_Warning_0`
* `Bottom_Info_0`
* `Bottom_Light_0`
* `Bottom_Dark_0`
* `Bottom_White_0`
(Valores com `_0` no final são para usos [Subtrativos](https://getbootstrap.com/docs/4.0/utilities/borders/#subtractive))

25
docs/pt-BR/UI/AspNetCore/Tag-Helpers/Breadcrumbs.md

@ -0,0 +1,25 @@
# Trilha de navegação
## Introdução
`abp-breadcrumb` é o contêiner principal para os itens da trilha de navegação.
Uso básico:
````html
<abp-breadcrumb>
<abp-breadcrumb-item href="#" title="Início" />
<abp-breadcrumb-item href="#" title="Biblioteca"/>
<abp-breadcrumb-item title="Página"/>
</abp-breadcrumb>
````
## Demonstração
Veja a página de demonstração de [trilhas de navegação](https://bootstrap-taghelpers.abp.io/Components/Breadcrumbs) para vê-la em ação.
## Atributos do abp-breadcrumb-item
- **title**: Define o texto do item da trilha de navegação.
- **active**: Define o item da trilha de navegação ativo. O último item é ativo por padrão, se nenhum outro item estiver ativo.
- **href**: Um valor que indica se um `abp-breadcrumb-item` possui um link. Deve ser um valor de link em formato de string.

37
docs/pt-BR/UI/AspNetCore/Tag-Helpers/Button-groups.md

@ -0,0 +1,37 @@
# Grupos de botões
## Introdução
`abp-button-group` é o contêiner principal para elementos de botão agrupados.
Uso básico:
````html
<abp-button-group>
<abp-button button-type="Secondary">Esquerda</abp-button>
<abp-button button-type="Secondary">Meio</abp-button>
<abp-button button-type="Secondary">Direita</abp-button>
</abp-button-group>
````
## Demonstração
Veja a página de demonstração de [grupos de botões](https://bootstrap-taghelpers.abp.io/Components/Button-groups) para vê-lo em ação.
## Atributos
### direction
Um valor que indica a direção dos botões. Deve ser um dos seguintes valores:
* `Horizontal` (valor padrão)
* `Vertical`
### size
Um valor que indica o tamanho dos botões no grupo. Deve ser um dos seguintes valores:
* `Default` (valor padrão)
* `Small`
* `Medium`
* `Large`

98
docs/pt-BR/UI/AspNetCore/Tag-Helpers/Buttons.md

@ -0,0 +1,98 @@
# Botões
## Introdução
`abp-button` é o elemento principal para criar botões.
Uso básico:
````xml
<abp-button button-type="Primary">Clique em Mim</abp-button>
````
## Demonstração
Veja a página de demonstração de [botões](https://bootstrap-taghelpers.abp.io/Components/Buttons) para vê-lo em ação.
## Atributos
### button-type
Um valor que indica o estilo/tipo principal do botão. Deve ser um dos seguintes valores:
* `Default` (valor padrão)
* `Primary`
* `Secondary`
* `Success`
* `Danger`
* `Warning`
* `Info`
* `Light`
* `Dark`
* `Outline_Primary`
* `Outline_Secondary`
* `Outline_Success`
* `Outline_Danger`
* `Outline_Warning`
* `Outline_Info`
* `Outline_Light`
* `Outline_Dark`
* `Link`
### size
Um valor que indica o tamanho do botão. Deve ser um dos seguintes valores:
* `Default` (valor padrão)
* `Small`
* `Medium`
* `Large`
* `Block`
* `Block_Small`
* `Block_Medium`
* `Block_Large`
### busy-text
Um texto que é mostrado quando o botão está ocupado.
Para tornar o botão ocupado:
````xml
$('#btnTest').buttonBusy(true);
````
Para torná-lo utilizável novamente:
````xml
$('#btnTest').buttonBusy(false);
````
### text
O texto do botão. Isso é um atalho se você simplesmente deseja definir um texto para o botão. Exemplo:
````xml
<abp-button button-type="Primary" text="Clique em Mim" />
````
Nesse caso, você pode usar uma tag de auto-fechamento para torná-lo mais curto.
### icon
Usado para definir um ícone para o botão. Funciona com as classes de ícone do [Font Awesome](https://fontawesome.com/) por padrão. Exemplo:
````xml
<abp-button icon="address-card" text="Endereço" />
````
##### icon-type
Se você não deseja usar o font-awesome, você tem duas opções:
1. Defina `icon-type` como `Other` e escreva a classe CSS do ícone de fonte que você está usando.
2. Se você não usa um ícone de fonte, use as tags de abertura e fechamento manualmente e escreva qualquer código dentro das tags.
### disabled
Defina `true` para desabilitar o botão inicialmente.

188
docs/pt-BR/UI/AspNetCore/Tag-Helpers/Cards.md

@ -0,0 +1,188 @@
# Cartões
## Introdução
`abp-card` é um contêiner de conteúdo derivado do elemento de cartão do Bootstrap.
Uso básico:
````xml
<abp-card style="width: 18rem;">
<img abp-card-image="Top" src="~/imgs/demo/300x200.png"/>
<abp-card-body>
<abp-card-title>Título do Cartão</abp-card-title>
<abp-card-text>Algum texto de exemplo rápido para construir o título do cartão e compor a maior parte do conteúdo do cartão.</abp-card-text>
<a abp-button="Primary" href="#">Ir para algum lugar</a>
</abp-card-body>
</abp-card>
````
##### Usando Títulos, Texto e Links:
As seguintes tags podem ser usadas sob a tag principal `abp-card`
* `abp-card-title`
* `abp-card-subtitle`
* `a abp-card-link`
Exemplo:
````xml
<abp-card style="width: 18rem;">
<abp-card-body>
<abp-card-title>Título do cartão</abp-card-title>
<abp-card-subtitle class="mb-2 text-muted">Subtítulo do cartão</abp-card-subtitle>
<abp-card-text>Algum texto de exemplo rápido para construir o título do cartão e compor a maior parte do conteúdo do cartão.</abp-card-text>
<a abp-card-link href="#">Link do cartão</a>
<a abp-card-link href="#">Outro link</a>
</abp-card-body>
</abp-card>
````
##### Usando Grupos de Listas:
* `abp-list-group flush="true"` : O atributo `flush` renderiza a classe `list-group-flush` do Bootstrap, que é usada para remover bordas e cantos arredondados para renderizar os itens do grupo de listas de ponta a ponta em um contêiner pai.
* `abp-list-group-item`
Exemplo completo:
````xml
<abp-card style="width: 18rem;">
<img abp-card-image="Top" src="~/imgs/demo/300x200.png" />
<abp-card-body>
<abp-card-title>Título do Cartão</abp-card-title>
<abp-card-text>Algum texto de exemplo rápido para construir o título do cartão e compor a maior parte do conteúdo do cartão.</abp-card-text>
</abp-card-body>
<abp-list-group flush="true">
<abp-list-group-item>Cras justo odio</abp-list-group-item>
<abp-list-group-item>Dapibus ac facilisis in</abp-list-group-item>
<abp-list-group-item>Vestibulum at eros</abp-list-group-item>
</abp-list-group>
<abp-card-body>
<a abp-card-link href="#">Link do cartão</a>
<a abp-card-link href="#">Outro link</a>
</abp-card-body>
</abp-card>
````
##### Usando Cabeçalho, Rodapé e Citação:
* `abp-card-header`
* `abp-card-footer`
* `abp-blockquote`
Exemplo:
```xml
<abp-card style="width: 18rem;">
<abp-card-header>Destaque</abp-card-header>
<abp-card-body>
<abp-card-title>Tratamento especial de título</abp-card-title>
<abp-card-text>Com texto de suporte abaixo como uma introdução natural a conteúdo adicional.</abp-card-text>
<a abp-button="Primary" href="#">Ir para algum lugar</a>
</abp-card-body>
</abp-card>
```
Exemplo de citação:
```xml
<abp-card>
<abp-card-header>Citação</abp-card-header>
<abp-card-body>
<abp-blockquote>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer posuere erat a ante.</p>
<footer>Alguém famoso em Título da Fonte</footer>
</abp-blockquote>
</abp-card-body>
</abp-card>
```
Exemplo de rodapé:
```xml
<abp-card class="text-center">
<abp-card-header>Destaque</abp-card-header>
<abp-card-body>
<abp-blockquote>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer posuere erat a ante.</p>
<footer>Alguém famoso em Título da Fonte</footer>
</abp-blockquote>
</abp-card-body>
<abp-card-footer class="text-muted">2 dias atrás</abp-card-footer>
</abp-card>
```
## Demonstração
Veja a [página de demonstração de cartões](https://bootstrap-taghelpers.abp.io/Components/Cards) para vê-lo em ação.
## Atributos do abp-card
- **background:** Um valor que indica a cor de fundo do cartão.
- **text-color**: Um valor que indica a cor do texto dentro do cartão.
- **border:** Um valor que indica a cor da borda dentro do cartão.
Deve ser um dos seguintes valores:
* `Default` (valor padrão)
* `Primary`
* `Secondary`
* `Success`
* `Danger`
* `Warning`
* `Info`
* `Light`
* `Dark`
Exemplo:
````xml
<abp-card background="Success" text-color="Danger" border="Dark">
````
### dimensionamento
Os cartões têm largura padrão de 100% e podem ser alterados com CSS personalizado, classes de grade, mixins de grade Sass ou [utilitários](https://getbootstrap.com/docs/4.0/utilities/sizing/).
````xml
<abp-card style="width: 18rem;">
````
### card-deck e card-columns
`abp-card` também pode ser usado dentro de `card-deck` ou `card-columns`.
````xml
<div class="card-deck">
<abp-card background="Primary">
<abp-card-header>Primeiro Deck</abp-card-header>
<abp-card-body>
<abp-card-title>Ás</abp-card-title>
<abp-card-text>Aqui está o conteúdo para Ás.</abp-card-text>
</abp-card-body>
</abp-card>
<abp-card background="Info">
<abp-card-header>Segundo Deck</abp-card-header>
<abp-card-body>
<abp-card-title>Beta</abp-card-title>
<abp-card-text>Conteúdo Beta.</abp-card-text>
</abp-card-body>
</abp-card>
<abp-card background="Warning">
<abp-card-header>Terceiro Deck</abp-card-header>
<abp-card-body>
<abp-card-title>Epsilon</abp-card-title>
<abp-card-text>Conteúdo para Epsilon.</abp-card-text>
</abp-card-body>
</abp-card>
</div>
````

71
docs/pt-BR/UI/AspNetCore/Tag-Helpers/Carousel.md

@ -0,0 +1,71 @@
# Carrossel
## Introdução
`abp-carousel` é a tag abp para o elemento carrossel.
Uso básico:
````html
<abp-carousel>
<abp-carousel-item src=""></abp-carousel-item>
<abp-carousel-item src=""></abp-carousel-item>
<abp-carousel-item src=""></abp-carousel-item>
</abp-carousel>
````
## Demonstração
Veja a página [carousel_demo](https://bootstrap-taghelpers.abp.io/Components/Carousel) para vê-lo em ação.
## Atributos
### id
Um valor que define o id do carrossel. Se não for definido, um id gerado será definido quando a tag for criada.
### controls
Um valor para habilitar os controles (botões anterior e próximo) no carrossel. Deve ser um dos seguintes valores:
* `false`
* `true`
### indicators
Um valor para habilitar os indicadores no carrossel. Deve ser um dos seguintes valores:
* `false`
* `true`
### crossfade
Um valor para habilitar a animação de fade em vez de slide no carrossel. Deve ser um dos seguintes valores:
* `false`
* `true`
## Atributos do abp-carousel-item
### caption-title
Um valor que define o título da legenda do item do carrossel.
### caption
Um valor que define a legenda do item do carrossel.
### src
Um valor de link que define a origem da imagem exibida no item do carrossel.
### active
Um valor para definir o item ativo do carrossel. Deve ser um dos seguintes valores:
* `false`
* `true`
### alt
Um valor que define o texto alternativo para a imagem do item do carrossel quando a imagem não pode ser exibida.

92
docs/pt-BR/UI/AspNetCore/Tag-Helpers/Collapse.md

@ -0,0 +1,92 @@
# Colapso
## Introdução
`abp-collapse-body` é o contêiner principal para mostrar e ocultar conteúdo. `abp-collapse-id` é usado para mostrar e ocultar o contêiner de conteúdo. Pode ser acionado tanto com `abp-button` quanto com tags `a`.
Uso básico:
````html
<abp-button button-type="Primary" abp-collapse-id="collapseExample" text="Botão com data-target" />
<a abp-button="Primary" abp-collapse-id="collapseExample"> Link com href </a>
<abp-collapse-body id="collapseExample">
Anim pariatur wolf moon tempor,,, sunt aliqua put a bird on it squid single-origin coffee nulla assumenda shoreditch et. Nihil anim keffiyeh helvetica, craft beer labore wes anderson cred nesciunt sapiente ea proident. Ad vegan excepteur butcher vice lomo. Leggings occaecat craft beer farm-to-table, raw denim aesthetic synth nesciunt you probably haven't heard of them accusamus labore sustainable VHS.
</abp-collapse-body>
````
## Demonstração
Veja a [página de demonstração de colapso](https://bootstrap-taghelpers.abp.io/Components/Collapse) para vê-lo em ação.
## Atributos
### show
Um valor que indica se o corpo do colapso será inicializado visível ou oculto. Deve ser um dos seguintes valores:
* `false` (valor padrão)
* `true`
### multi
Um valor que indica se um `abp-collapse-body` pode ser mostrado ou ocultado por um elemento que pode mostrar/ocultar vários corpos de colapso. Basicamente, esse atributo adiciona a classe "multi-collapse" a `abp-collapse-body`. Deve ser um dos seguintes valores:
* `false` (valor padrão)
* `true`
Exemplo:
````xml
<a abp-button="Primary" abp-collapse-id="FirstCollapseExample"> Alternar primeiro elemento </a>
<abp-button button-type="Primary" abp-collapse-id="SecondCollapseExample" text="Alternar segundo elemento" />
<abp-button button-type="Primary" abp-collapse-id="FirstCollapseExample SecondCollapseExample" text="Alternar ambos os elementos" />
<abp-row class="mt-3">
<abp-column size-sm="_6">
<abp-collapse-body id="FirstCollapseExample" multi="true">
Curabitur porta porttitor libero eu luctus. Praesent ultrices mattis commodo. Integer sodales massa risus, in molestie enim sagittis blandit
</abp-collapse-body>
</abp-column>
<abp-column size-sm="_6">
<abp-collapse-body id="SecondCollapseExample" multi="true">
Anim pariatur wolf moon tempor,,, sunt aliqua put a bird on it squid single-origin coffee nulla assumenda shoreditch et.
</abp-collapse-body>
</abp-column>
</abp-row>
````
## Exemplo de acordeão
`abp-accordion` é o contêiner principal para os itens do acordeão.
Uso básico:
````xml
<abp-accordion>
<abp-accordion-item title="Item do Grupo Colapsável #1">
Anim pariatur cliche reprehenderit, enim eiusmod high life accusamus terry rtat skateboard dolor brunch. Food truck quinoa nesciunt laborum eiusmod. Brunch 3 wolf moon tempor, sunt aliqua put a bird on it squid single-origin coffee nulla assumenda shoreditch et. Nihil anim keffiyeh helvetica, craft beer labore wes anderson cred nesciunt sapiente ea proident. Ad vegan excepteur butcher vice lomo. Leggings occaecat craft beer farm-to-table, raw denim aesthetic synth nesciunt you probably haven't heard of them accusamus labore sustainable VHS.
</abp-accordion-item>
<abp-accordion-item title="Item do Grupo Colapsável #2">
Anim pariatur cliche reprehenderit, enim eiusmod high life accusamus terry richardson ad squid. 3 wolf moon officia aute, non cupidatat skateboard dolor brunch. Food truck quinoa nesciunt laborum eiusmod. Brunch 3 wolf moon tempor, sunt aliqua put a bird on it squid single-origin coffee nulla assumenda shoreditch et. Nihil anim keffiyeh helvetica, craft beer labore wes anderson cred nesciunt sapiente ea proident. Ad vegan excepteur butcher vice lomo. Leggings occaecat craft beer farm-to-table, raw denim aesthetic synth nesciunt you probably haven't heard of them accusamus labore sustainable VHS.
</abp-accordion-item>
<abp-accordion-item title="Item do Grupo Colapsável #3">
Anim pariatur wolf moon tempor, sunt aliqua put a bird on it squid single-origin coffee nulla assumenda shoreditch et. Nihil anim keffiyeh helvetica, craft beer labore wes anderson cred nesciunt sapiente ea proident. Ad vegan excepteur butcher vice lomo. Leggings occaecat craft beer farm-to-table, raw denim aesthetic synth nesciunt you probably haven't heard of them accusamus labore sustainable VHS.
</abp-accordion-item>
</abp-accordion>
````
## Atributos
### active
Um valor que indica se o item do acordeão será inicializado visível ou oculto. Deve ser um dos seguintes valores:
* `false` (valor padrão)
* `true`
### title
Um valor que indica o título visível do item do acordeão. Deve ser um valor de string.

93
docs/pt-BR/UI/AspNetCore/Tag-Helpers/Dropdowns.md

@ -0,0 +1,93 @@
# Dropdowns
## Introdução
`abp-dropdown` é o contêiner principal para o conteúdo do dropdown.
Uso básico:
````xml
<abp-dropdown>
<abp-dropdown-button text="Botão do dropdown" />
<abp-dropdown-menu>
<abp-dropdown-item href="#">Ação</abp-dropdown-item>
<abp-dropdown-item href="#">Outra ação</abp-dropdown-item>
<abp-dropdown-item href="#">Algo mais aqui</abp-dropdown-item>
</abp-dropdown-menu>
</abp-dropdown>
````
## Demonstração
Veja a [página de demonstração do dropdown](https://bootstrap-taghelpers.abp.io/Components/Dropdowns) para vê-lo em ação.
## Atributos
### direction
Um valor que indica em qual direção os botões do dropdown serão exibidos. Deve ser um dos seguintes valores:
* `Down` (valor padrão)
* `Up`
* `Right`
* `Left`
### dropdown-style
Um valor que indica se um `abp-dropdown-button` terá um ícone dividido para o dropdown. Deve ser um dos seguintes valores:
* `Single` (valor padrão)
* `Split`
## Itens do menu
`abp-dropdown-menu` é o contêiner principal para os itens do menu dropdown.
Uso básico:
````xml
<abp-dropdown>
<abp-dropdown-button button-type="Secondary" text="Dropdown"/>
<abp-dropdown-menu>
<abp-dropdown-header>Cabeçalho do Dropdown</abp-dropdown-header>
<abp-dropdown-item href="#">Ação</abp-dropdown-item>
<abp-dropdown-item active="true" href="#">Ação ativa</abp-dropdown-item>
<abp-dropdown-item disabled="true" href="#">Ação desativada</abp-dropdown-item>
<abp-dropdown-divider/>
<abp-dropdown-item-text>Texto do item do dropdown</abp-dropdown-item-text>
<abp-dropdown-item href="#">Algo mais aqui</abp-dropdown-item>
</abp-dropdown-menu>
</abp-dropdown>
````
## Atributos
### align
Um valor que indica em qual direção os itens do `abp-dropdown-menu` serão alinhados. Deve ser um dos seguintes valores:
* `Start` (valor padrão)
* `End`
### Conteúdo adicional
`abp-dropdown-menu` também pode conter elementos HTML adicionais como títulos, parágrafos, divisores ou elementos de formulário.
Exemplo:
````xml
<abp-dropdown >
<abp-dropdown-button button-type="Secondary" text="Dropdown com Formulário"/>
<abp-dropdown-menu>
<form class="px-4 py-3">
<abp-input asp-for="EmailAddress"></abp-input>
<abp-input asp-for="Password"></abp-input>
<abp-input asp-for="RememberMe"></abp-input>
<abp-button button-type="Primary" text="Entrar" type="submit" />
</form>
<abp-dropdown-divider></abp-dropdown-divider>
<abp-dropdown-item href="#">Novo por aqui? Cadastre-se</abp-dropdown-item>
<abp-dropdown-item href="#">Esqueceu a senha?</abp-dropdown-item>
</abp-dropdown-menu>
</abp-dropdown>
````

281
docs/pt-BR/UI/AspNetCore/Tag-Helpers/Dynamic-Forms.md

@ -0,0 +1,281 @@
# Formulários Dinâmicos
## Introdução
`abp-dynamic-form` cria um formulário bootstrap para um modelo C# fornecido.
Uso básico:
````xml
<abp-dynamic-form abp-model="@Model.MyDetailedModel"/>
````
Modelo:
````csharp
public class DynamicFormsModel : PageModel
{
[BindProperty]
public DetailedModel MyDetailedModel { get; set; }
public List<SelectListItem> CountryList { get; set; } = new List<SelectListItem>
{
new SelectListItem { Value = "CA", Text = "Canadá"},
new SelectListItem { Value = "US", Text = "EUA"},
new SelectListItem { Value = "UK", Text = "Reino Unido"},
new SelectListItem { Value = "RU", Text = "Rússia"}
};
public void OnGet()
{
MyDetailedModel = new DetailedModel
{
Name = "",
Description = "Lorem ipsum dolor sit amet.",
IsActive = true,
Age = 65,
Day = DateTime.Now,
MyCarType = CarType.Coupe,
YourCarType = CarType.Sedan,
Country = "RU",
NeighborCountries = new List<string>() { "UK", "CA" }
};
}
public class DetailedModel
{
[Required]
[Placeholder("Digite seu nome...")]
[Display(Name = "Nome")]
public string Name { get; set; }
[TextArea(Rows = 4)]
[Display(Name = "Descrição")]
[InputInfoText("Descreva-se")]
public string Description { get; set; }
[Required]
[DataType(DataType.Password)]
[Display(Name = "Senha")]
public string Password { get; set; }
[Display(Name = "Ativo")]
public bool IsActive { get; set; }
[Required]
[Display(Name = "Idade")]
public int Age { get; set; }
[Required]
[Display(Name = "Meu Tipo de Carro")]
public CarType MyCarType { get; set; }
[Required]
[AbpRadioButton(Inline = true)]
[Display(Name = "Seu Tipo de Carro")]
public CarType YourCarType { get; set; }
[DataType(DataType.Date)]
[Display(Name = "Dia")]
public DateTime Day { get; set; }
[SelectItems(nameof(CountryList))]
[Display(Name = "País")]
public string Country { get; set; }
[SelectItems(nameof(CountryList))]
[Display(Name = "Países Vizinhos")]
public List<string> NeighborCountries { get; set; }
}
public enum CarType
{
Sedan,
Hatchback,
StationWagon,
Coupe
}
}
````
## Demonstração
Veja a [página de demonstração de formulários dinâmicos](https://bootstrap-taghelpers.abp.io/Components/DynamicForms) para vê-lo em ação.
## Atributos
### abp-model
Define o modelo C# para o formulário dinâmico. As propriedades deste modelo são convertidas em campos de entrada no formulário.
### column-size
Aqui, use 'col-sm' para definir o tamanho. Ao definir essa propriedade, 'col-12' será adicionado ao mesmo tempo.
### submit-button
Pode ser `True` ou `False`.
Se `True`, um botão de envio será gerado na parte inferior do formulário.
O valor padrão é `False`.
### required-symbols
Pode ser `True` ou `False`.
Se `True`, as entradas obrigatórias terão um símbolo (*) que indica que são obrigatórias.
O valor padrão é `True`.
## Posicionamento do Conteúdo do Formulário
Por padrão, `abp-dynamic-form` limpa o HTML interno e coloca os campos de entrada nele. Se você quiser adicionar conteúdo adicional ao formulário dinâmico ou colocar os campos de entrada em uma área específica, você pode usar a tag `<abp-form-content />`. Essa tag será substituída pelo conteúdo do formulário e o restante do HTML interno da tag `abp-dynamic-form` permanecerá inalterado.
Uso:
````xml
<abp-dynamic-form abp-model="@Model.MyExampleModel">
<div>
Algum conteúdo....
</div>
<div class="input-area">
<abp-form-content />
</div>
<div>
Mais algum conteúdo....
</div>
</abp-dynamic-form>
````
## Ordem de Entrada
`abp-dynamic-form` ordena as propriedades pelo atributo `DisplayOrder` e, em seguida, pela ordem das propriedades na classe do modelo.
O número padrão do atributo `DisplayOrder` é 10000 para todas as propriedades.
Veja o exemplo abaixo:
````csharp
public class OrderExampleModel
{
[DisplayOrder(10004)]
public string Name{ get; set; }
[DisplayOrder(10005)]
public string Surname{ get; set; }
//Padrão 10000
public string EmailAddress { get; set; }
[DisplayOrder(10003)]
public string PhoneNumber { get; set; }
[DisplayOrder(9999)]
public string City { get; set; }
}
````
Neste exemplo, os campos de entrada serão exibidos com a seguinte ordem: `City` > `EmailAddress` > `PhoneNumber` > `Name` > `Surname`.
## Ignorando uma propriedade
Por padrão, `abp-dynamic-form` gera uma entrada para cada propriedade na classe do modelo. Se você quiser ignorar uma propriedade, use o atributo `DynamicFormIgnore`.
Veja o exemplo abaixo:
````csharp
public class MyModel
{
public string Name { get; set; }
[DynamicFormIgnore]
public string Surname { get; set; }
}
````
Neste exemplo, nenhuma entrada será gerada para a propriedade `Surname`.
## Indicando Caixa de Texto, Grupo de Rádio e Combobox
Se você leu o documento [Elementos de Formulário](Form-elements.md), você percebeu que as tags `abp-radio` e `abp-select` são muito semelhantes no modelo C#. Portanto, temos que usar o atributo `[AbpRadioButton()]` para informar ao `abp-dynamic-form` qual das suas propriedades será um grupo de rádio e qual será uma combobox. Veja o exemplo abaixo:
````xml
<abp-dynamic-form abp-model="@Model.MyDetailedModel"/>
````
Modelo:
````csharp
public class DynamicFormsModel : PageModel
{
[BindProperty]
public DetailedModel MyDetailedModel { get; set; }
public List<SelectListItem> CountryList { get; set; } = new List<SelectListItem>
{
new SelectListItem { Value = "CA", Text = "Canadá"},
new SelectListItem { Value = "US", Text = "EUA"},
new SelectListItem { Value = "UK", Text = "Reino Unido"},
new SelectListItem { Value = "RU", Text = "Rússia"}
};
public void OnGet()
{
MyDetailedModel = new DetailedModel
{
ComboCarType = CarType.Coupe,
RadioCarType = CarType.Sedan,
ComboCountry = "RU",
RadioCountry = "UK"
};
}
public class DetailedModel
{
public CarType ComboCarType { get; set; }
[AbpRadioButton(Inline = true)]
public CarType RadioCarType { get; set; }
[SelectItems(nameof(CountryList))]
public string ComboCountry { get; set; }
[AbpRadioButton()]
[SelectItems(nameof(CountryList))]
public string RadioCountry { get; set; }
}
public enum CarType
{
Sedan,
Hatchback,
StationWagon,
Coupe
}
}
````
Como você pode ver no exemplo acima:
* Se `[AbpRadioButton()]` for usado em uma propriedade **Enum**, será um grupo de rádio. Caso contrário, será uma combobox.
* Se `[SelectItems()]` e `[AbpRadioButton()]` forem usados em uma propriedade, será um grupo de rádio.
* Se apenas `[SelectItems()]` for usado em uma propriedade, será uma combobox.
* Se nenhum desses atributos for usado em uma propriedade, será uma caixa de texto.
## Localização
`abp-dynamic-form` também lida com localização.
Por padrão, ele tentará encontrar as chaves de localização "DisplayName:{PropertyName}" ou "{PropertyName}" e definir o valor de localização como rótulo de entrada.
Você pode definir isso você mesmo usando o atributo `[Display()]` do Asp.Net Core. Você pode usar uma chave de localização neste atributo. Veja o exemplo abaixo:
````csharp
[Display(Name = "Nome")]
public string Name { get; set; }
````
## Veja Também
* [Elementos de Formulário](Form-elements.md)

14
docs/pt-BR/UI/AspNetCore/Tag-Helpers/Figure.md

@ -0,0 +1,14 @@
# Figuras
`abp-figure` é o contêiner principal para os itens de figura do bootstrap.
Uso básico:
````html
<abp-figure>
<abp-image src="..." class="img-fluid rounded" alt="Uma imagem de espaço reservado quadrado genérico com cantos arredondados em uma figura.">
<abp-figcaption class="text-end">Uma legenda para a imagem acima.</abp-figcaption>
</abp-figure>
````
Ele adiciona a classe `figure` ao contêiner principal, também adiciona a classe `figure-img` ao elemento `abp-image` interno e a classe `figure-caption` ao elemento `abp-figcaption` interno.

435
docs/pt-BR/UI/AspNetCore/Tag-Helpers/Form-elements.md

@ -0,0 +1,435 @@
# Elementos de Formulário
## Introdução
O Abp fornece ajudantes de tag de entrada de formulário para facilitar a construção de formulários.
## Demonstração
Veja a página de demonstração dos [elementos de formulário](https://bootstrap-taghelpers.abp.io/Components/FormElements) para vê-los em ação.
## abp-input
A tag `abp-input` cria um campo de entrada de formulário do Bootstrap para uma propriedade C# específica. Ela usa o [Asp.Net Core Input Tag Helper](https://docs.microsoft.com/en-us/aspnet/core/mvc/views/working-with-forms?view=aspnetcore-7.0#the-input-tag-helper) em segundo plano, portanto, todos os atributos de anotação de dados da tag `input` do Asp.Net Core também são válidos para `abp-input`.
Uso:
````xml
<abp-input asp-for="@Model.MyModel.Name"/>
<abp-input asp-for="@Model.MyModel.Description"/>
<abp-input asp-for="@Model.MyModel.Password"/>
<abp-input asp-for="@Model.MyModel.IsActive"/>
````
Modelo:
````csharp
public class FormElementsModel : PageModel
{
public SampleModel MyModel { get; set; }
public void OnGet()
{
MyModel = new SampleModel();
}
public class SampleModel
{
[Required]
[Placeholder("Digite seu nome...")]
[InputInfoText("Qual é o seu nome?")]
public string Name { get; set; }
[Required]
[FormControlSize(AbpFormControlSize.Large)]
public string SurName { get; set; }
[TextArea(Rows = 4)]
public string Description { get; set; }
[Required]
[DataType(DataType.Password)]
public string Password { get; set; }
public bool IsActive { get; set; }
}
}
````
### Atributos
Você pode definir alguns atributos na propriedade C# ou diretamente na tag HTML. Se você for usar essa propriedade em um [abp-dynamic-form](Dynamic-Forms.md), só poderá definir essas propriedades por meio de atributos de propriedade.
#### Atributos de Propriedade
- `[TextArea()]`: Converte a entrada em uma área de texto.
* `[Placeholder()]`: Define a descrição da entrada. Você pode usar uma chave de localização diretamente.
* `[InputInfoText()]`: Define o texto para a entrada. Você pode usar uma chave de localização diretamente.
* `[FormControlSize()]`: Define o tamanho do elemento de wrapper form-control. Os valores disponíveis são:
- `AbpFormControlSize.Default`
- `AbpFormControlSize.Small`
- `AbpFormControlSize.Medium`
- `AbpFormControlSize.Large`
* `[DisabledInput]` : Define a entrada como desabilitada.
* `[ReadOnlyInput]`: Define a entrada como somente leitura.
#### Atributos de Tag
* `info`: Define o texto para a entrada. Você pode usar uma chave de localização diretamente.
* `auto-focus`: Permite que o navegador defina o foco no elemento quando o valor for verdadeiro.
* `size`: Define o tamanho do elemento de wrapper form-control. Os valores disponíveis são:
- `AbpFormControlSize.Default`
- `AbpFormControlSize.Small`
- `AbpFormControlSize.Medium`
- `AbpFormControlSize.Large`
* `disabled`: Define a entrada como desabilitada.
* `readonly`: Define a entrada como somente leitura.
* `label`: Define o rótulo da entrada.
* `required-symbol`: Adiciona o símbolo de obrigatório `(*)` ao rótulo quando a entrada é obrigatória. O valor padrão é `True`.
* `floating-label`: Define o rótulo como rótulo flutuante. O valor padrão é `False`.
Os atributos `asp-format`, `name` e `value` do [Asp.Net Core Input Tag Helper](https://docs.microsoft.com/en-us/aspnet/core/mvc/views/working-with-forms?view=aspnetcore-7.0#the-input-tag-helper) também são válidos para o ajudante de tag `abp-input`.
### Rótulo e Localização
Você pode definir o rótulo da entrada de várias maneiras:
- Você pode usar o atributo `Label` para definir o rótulo diretamente. Essa propriedade não localiza automaticamente o texto. Para localizar o rótulo, use `label="@L["{LocalizationKey}"].Value"`.
- Você pode defini-lo usando o atributo `[Display(name="{LocalizationKey}")]` do ASP.NET Core.
- Você pode deixar o **abp** encontrar a chave de localização para a propriedade. Ele tentará encontrar as chaves de localização "DisplayName:{PropertyName}" ou "{PropertyName}", se os atributos `label` ou `[DisplayName]` não estiverem definidos.
## abp-select
A tag `abp-select` cria um seletor de formulário do Bootstrap para uma propriedade C# específica. Ela usa o [ASP.NET Core Select Tag Helper](https://docs.microsoft.com/tr-tr/aspnet/core/mvc/views/working-with-forms?view=aspnetcore-3.1#the-select-tag-helper) em segundo plano, portanto, todos os atributos de anotação de dados da tag `select` do ASP.NET Core também são válidos para `abp-select`.
A tag `abp-select` precisa de uma lista de `Microsoft.AspNetCore.Mvc.Rendering.SelectListItem` para funcionar. Ela pode ser fornecida pelo atributo `asp-items` na tag ou pelo atributo `[SelectItems()]` na propriedade C# (se você estiver usando [abp-dynamic-form](Dynamic-Forms.md), o atributo C# é a única opção).
O `abp-select` suporta seleção múltipla.
O `abp-select` cria automaticamente uma lista de seleção para propriedades **Enum**. Nenhum dado extra é necessário. Se a propriedade for nula, uma chave e valor vazios serão adicionados no topo da lista gerada automaticamente.
Uso:
````xml
<abp-select asp-for="@Model.MyModel.City" asp-items="@Model.CityList"/>
<abp-select asp-for="@Model.MyModel.AnotherCity"/>
<abp-select asp-for="@Model.MyModel.MultipleCities" asp-items="@Model.CityList"/>
<abp-select asp-for="@Model.MyModel.MyCarType"/>
<abp-select asp-for="@Model.MyModel.MyNullableCarType"/>
````
Modelo:
````csharp
public class FormElementsModel : PageModel
{
public SampleModel MyModel { get; set; }
public List<SelectListItem> CityList { get; set; }
public void OnGet()
{
MyModel = new SampleModel();
CityList = new List<SelectListItem>
{
new SelectListItem { Value = "NY", Text = "Nova York"},
new SelectListItem { Value = "LDN", Text = "Londres"},
new SelectListItem { Value = "IST", Text = "Istambul"},
new SelectListItem { Value = "MOS", Text = "Moscou"}
};
}
public class SampleModel
{
public string City { get; set; }
[SelectItems(nameof(CityList))]
public string AnotherCity { get; set; }
public List<string> MultipleCities { get; set; }
public CarType MyCarType { get; set; }
public CarType? MyNullableCarType { get; set; }
}
public enum CarType
{
Sedan,
Hatchback,
StationWagon,
Coupe
}
}
````
### Atributos
Você pode definir alguns atributos na propriedade C# ou diretamente na tag HTML. Se você for usar essa propriedade em um [abp-dynamic-form](Dynamic-Forms.md), só poderá definir essas propriedades por meio de atributos de propriedade.
#### Atributos de Propriedade
* `[SelectItems()]`: Define os dados do seletor. O parâmetro deve ser o nome da lista de dados. (veja o exemplo acima)
- `[InputInfoText()]`: Define o texto para a entrada. Você pode usar uma chave de localização diretamente.
- `[FormControlSize()]`: Define o tamanho do elemento de wrapper form-control. Os valores disponíveis são:
- `AbpFormControlSize.Default`
- `AbpFormControlSize.Small`
- `AbpFormControlSize.Medium`
- `AbpFormControlSize.Large`
#### Atributos de Tag
- `asp-items`: Define os dados do seletor. Isso deve ser uma lista de SelectListItem.
- `info`: Define o texto para a entrada. Você pode usar uma chave de localização diretamente.
- `size`: Define o tamanho do elemento de wrapper form-control. Os valores disponíveis são:
- `AbpFormControlSize.Default`
- `AbpFormControlSize.Small`
- `AbpFormControlSize.Medium`
- `AbpFormControlSize.Large`
- `label`: Define o rótulo da entrada.
- `required-symbol`: Adiciona o símbolo de obrigatório `(*)` ao rótulo quando a entrada é obrigatória. O valor padrão é `True`.
### Rótulo e Localização
Você pode definir o rótulo da entrada de várias maneiras:
- Você pode usar o atributo `Label` e definir diretamente o rótulo. Mas isso não localiza automaticamente sua chave de localização. Portanto, use-o como `label="@L["{LocalizationKey}"].Value".`
- Você pode defini-lo usando o atributo `[Display(name="{LocalizationKey}")]` do ASP.NET Core.
- Você pode deixar o **abp** encontrar a chave de localização para a propriedade. Ele tentará encontrar as chaves de localização "DisplayName:{PropertyName}" ou "{PropertyName}".
As localizações dos valores do combobox são definidas pelo `abp-select` para a propriedade **Enum**. Ele procura pelas chaves de localização "{EnumTypeName}.{EnumPropertyName}" ou "{EnumPropertyName}". Por exemplo, no exemplo acima, ele usará as chaves "CarType.StationWagon" ou "StationWagon" para localizar os valores do combobox.
## abp-radio
A tag `abp-radio` cria um grupo de rádio do Bootstrap para uma propriedade C# específica. O uso é muito semelhante à tag `abp-select`.
Uso:
````xml
<abp-radio asp-for="@Model.MyModel.CityRadio" asp-items="@Model.CityList" inline="true"/>
<abp-radio asp-for="@Model.MyModel.CityRadio2"/>
````
Modelo:
````csharp
public class FormElementsModel : PageModel
{
public SampleModel MyModel { get; set; }
public List<SelectListItem> CityList { get; set; } = new List<SelectListItem>
{
new SelectListItem { Value = "NY", Text = "Nova York"},
new SelectListItem { Value = "LDN", Text = "Londres"},
new SelectListItem { Value = "IST", Text = "Istambul"},
new SelectListItem { Value = "MOS", Text = "Moscou"}
};
public void OnGet()
{
MyModel = new SampleModel();
MyModel.CityRadio = "IST";
MyModel.CityRadio2 = "MOS";
}
public class SampleModel
{
public string CityRadio { get; set; }
[SelectItems(nameof(CityList))]
public string CityRadio2 { get; set; }
}
}
````
### Atributos
Você pode definir alguns atributos na propriedade C# ou diretamente na tag HTML. Se você for usar essa propriedade em um [abp-dynamic-form](Dynamic-Forms.md), só poderá definir essas propriedades por meio de atributos de propriedade.
#### Atributos de Propriedade
- `[SelectItems()]`: Define os dados do seletor. O parâmetro deve ser o nome da lista de dados. (veja o exemplo acima)
#### Atributos de Tag
- `asp-items`: Define os dados do seletor. Isso deve ser uma lista de SelectListItem.
- `Inline`: Se verdadeiro, os botões de rádio serão exibidos em uma única linha, um ao lado do outro. Se falso, eles serão exibidos um abaixo do outro.
## abp-date-picker & abp-date-range-picker
As tags `abp-date-picker` e `abp-date-range-picker` criam um seletor de data do Bootstrap para uma propriedade C# específica. O `abp-date-picker` é para seleção de uma única data, o `abp-date-range-picker` é para seleção de um intervalo de datas. Elas usam o plugin jQuery [datepicker](https://www.daterangepicker.com/).
Uso:
````xml
<abp-date-picker asp-for="@Model.MyModel.MyDate" />
<abp-date-range-picker asp-for-start="@Model.MyModel.MyDateRangeStart" asp-for-end="@Model.MyModel.MyDateRangeEnd" />
<abp-dynamic-form abp-model="DynamicFormExample"></abp-dynamic-form>
````
Modelo:
````csharp
public class FormElementsModel : PageModel
{
public SampleModel MyModel { get; set; }
public DynamicForm DynamicFormExample { get; set; }
public void OnGet()
{
MyModel = new SampleModel();
DynamicFormExample = new DynamicForm();
}
public class SampleModel
{
public DateTime MyDate { get; set; }
public DateTime MyDateRangeStart { get; set; }
public DateTime MyDateRangeEnd { get; set; }
}
public class DynamicForm
{
[DateRangePicker("MyPicker",true)]
public DateTime StartDate { get; set; }
[DateRangePicker("MyPicker",false)]
[DatePickerOptions(nameof(DatePickerOptions))]
public DateTime EndDate { get; set; }
public DateTime DateTime { get; set; }
public DynamicForm()
{
StartDate = DateTime.Now;
EndDate = DateTime.Now;
DateTime = DateTime.Now;
}
}
public AbpDatePickerOptions DatePickerOptions { get; set; }
}
````
### Atributos
Você pode definir alguns atributos na propriedade C# ou diretamente na tag HTML. Se você for usar essa propriedade em um [abp-dynamic-form](Dynamic-Forms.md), só poderá definir essas propriedades por meio de atributos de propriedade.
#### Atributos de Propriedade
* `[Placeholder()]`: Define a descrição da entrada. Você pode usar uma chave de localização diretamente.
* `[InputInfoText()]`: Define o texto para a entrada. Você pode usar uma chave de localização diretamente.
* `[FormControlSize()]`: Define o tamanho do elemento de wrapper form-control. Os valores disponíveis são:
- `AbpFormControlSize.Default`
- `AbpFormControlSize.Small`
- `AbpFormControlSize.Medium`
- `AbpFormControlSize.Large`
* `[DisabledInput]` : Define a entrada como desabilitada.
* `[ReadOnlyInput]`: Define a entrada como somente leitura.
- `[DatePickerOptions()]`: Define as opções predefinidas do seletor de data. O parâmetro deve ser o nome da propriedade de opções (veja o exemplo acima). Veja as opções de [datepicker disponíveis](https://www.daterangepicker.com/#options). Você pode usar uma chave de localização diretamente.
##### abp-date-picker
`[DatePicker]` : Define a entrada como seletor de data. Especialmente para propriedades de string.
##### abp-date-range-picker
`[DateRangePicker()]` : Define o ID do seletor para o seletor de intervalo de datas. Você pode definir a propriedade como uma data de início definindo IsStart=true ou deixá-la como padrão/falso para definir como uma data de término.
#### Atributos de Tag
* `info`: Define o texto para a entrada. Você pode usar uma chave de localização diretamente.
* `auto-focus`: Permite que o navegador defina o foco no elemento quando o valor for verdadeiro.
* `size`: Define o tamanho do elemento de wrapper form-control. Os valores disponíveis são:
- `AbpFormControlSize.Default`
- `AbpFormControlSize.Small`
- `AbpFormControlSize.Medium`
- `AbpFormControlSize.Large`
* `disabled`: Define a entrada como desabilitada.
* `readonly`: Define a entrada como somente leitura.
* `label`: Define o rótulo da entrada.
* `required-symbol`: Adiciona o símbolo de obrigatório `(*)` ao rótulo quando a entrada é obrigatória. O valor padrão é `True`.
* `open-button`: Um botão para abrir o seletor de data será adicionado quando for `True`. O valor padrão é `True`.
* `clear-button`: Um botão para limpar o seletor de data será adicionado quando for `True`. O valor padrão é `True`.
* `single-open-and-clear-button`: Mostra os botões de abrir e limpar em um único botão quando for `True`. O valor padrão é `True`.
* `is-utc`: Converte a data para UTC quando for `True`. O valor padrão é `False`.
* `is-iso`: Converte a data para o formato ISO quando for `True`. O valor padrão é `False`.
* `visible-date-format`: Define o formato de data da entrada. O formato padrão é o formato de data da cultura do usuário. Você precisa fornecer uma convenção de formato de data JavaScript. Por exemplo: `YYYY-MM-DDTHH:MM:SSZ`.
* `input-date-format`: Define o formato de data do input oculto para compatibilidade com o backend. O formato padrão é `YYYY-MM-DD`. Você precisa fornecer uma convenção de formato de data JavaScript. Por exemplo: `YYYY-MM-DDTHH:MM:SSZ`.
* `date-separator`: Define um caractere para separar as datas de início e término. O valor padrão é `-`
* Outros atributos não mapeados serão adicionados automaticamente ao elemento de entrada como estão. Veja as opções de [datepicker disponíveis](https://www.daterangepicker.com/#options). Por exemplo: `data-start-date="2020-01-01"`
##### abp-date-picker
* `asp-date`: Define o valor da data. Isso deve ser um valor `DateTime`, `DateTime?`, `DateTimeOffset`, `DateTimeOffset?` ou `string`.
##### abp-date-range-picker
* `asp-for-start`: Define o valor da data de início. Isso deve ser um valor `DateTime`, `DateTime?`, `DateTimeOffset`, `DateTimeOffset?` ou `string`.
* `asp-for-end`: Define o valor da data de término. Isso deve ser um valor `DateTime`, `DateTime?`, `DateTimeOffset`, `DateTimeOffset?` ou `string`.
### Rótulo e Localização
Você pode definir o rótulo da entrada de várias maneiras:
- Você pode usar o atributo `Label` para definir o rótulo diretamente. Essa propriedade não localiza automaticamente o texto. Para localizar o rótulo, use `label="@L["{LocalizationKey}"].Value"`.
- Você pode defini-lo usando o atributo `[Display(name="{LocalizationKey}")]` do ASP.NET Core.
- Você pode deixar o **abp** encontrar a chave de localização para a propriedade. Ele tentará encontrar as chaves de localização "DisplayName:{PropertyName}" ou "{PropertyName}".
### Uso em JavaScript
````javascript
var newPicker = abp.libs.bootstrapDateRangePicker.createDateRangePicker(
{
label: "Novo Seletor",
}
);
newPicker.insertAfter($('body'));
````
````javascript
var newPicker = abp.libs.bootstrapDateRangePicker.createSinglePicker(
{
label: "Novo Seletor",
}
);
newPicker.insertAfter($('body'));
````
#### Opções
* `label`: Define o rótulo da entrada.
* `placeholder`: Define o espaço reservado da entrada.
* `value`: Define o valor da entrada.
* `name`: Define o nome da entrada.
* `id`: Define o ID da entrada.
* `required`: Define a entrada como obrigatória.
* `disabled`: Define a entrada como desabilitada.
* `readonly`: Define a entrada como somente leitura.
* `size`: Define o tamanho do elemento de wrapper form-control. Os valores disponíveis são:
- `AbpFormControlSize.Default`
- `AbpFormControlSize.Small`
- `AbpFormControlSize.Medium`
- `AbpFormControlSize.Large`
* `openButton`: Um botão para abrir o seletor de data será adicionado quando for `True`. O valor padrão é `True`.
* `clearButton`: Um botão para limpar o seletor de data será adicionado quando for `True`. O valor padrão é `True`.
* `singleOpenAndClearButton`: Mostra os botões de abrir e limpar em um único botão quando for `True`. O valor padrão é `True`.
* `isUtc`: Converte a data para UTC quando for `True`. O valor padrão é `False`.
* `isIso`: Converte a data para o formato ISO quando for `True`. O valor padrão é `False`.
* `visibleDateFormat`: Define o formato de data da entrada. O formato padrão é o formato de data da cultura do usuário. Você precisa fornecer uma convenção de formato de data JavaScript. Por exemplo: `YYYY-MM-DDTHH:MM:SSZ`.
* `inputDateFormat`: Define o formato de data do input oculto para compatibilidade com o backend. O formato padrão é `YYYY-MM-DD`. Você precisa fornecer uma convenção de formato de data JavaScript. Por exemplo: `YYYY-MM-DDTHH:MM:SSZ`.
* `dateSeparator`: Define um caractere para separar as datas de início e término. O valor padrão é `-`.
* `startDateName`: Define o nome do input de data de início oculto.
* `endDateName`: Define o nome do input de data de término oculto.
* `dateName`: Define o nome do input de data oculto.
* Outras [opções de datepicker](https://www.daterangepicker.com/#options). Por exemplo: `startDate: "2020-01-01"`.

273
docs/pt-BR/UI/AspNetCore/Tag-Helpers/Grids.md

@ -0,0 +1,273 @@
# Grids
## Introdução
Abp tag helpers para o sistema de grid baseado no bootstrap.
## Demonstração
Veja a página de demonstração [grids demo page](https://bootstrap-taghelpers.abp.io/Components/Grids) para ver em ação.
### Dimensionamento
**Largura igual:** Cria colunas com largura igual.
Exemplo:
````xml
<abp-container>
<abp-row>
<abp-column abp-border="Info">1 de 2</abp-column>
<abp-column abp-border="Danger">2 de 2</abp-column>
</abp-row>
<abp-row>
<abp-column abp-border="Primary">1 de 3</abp-column>
<abp-column abp-border="Secondary">2 de 3</abp-column>
<abp-column abp-border="Dark">3 de 3</abp-column>
</abp-row>
</abp-container>
````
**Quebra de coluna:** `abp-column-breaker` é usado para quebrar a largura automática de colocação da linha atual e iniciar em uma nova linha em seguida.
Exemplo:
````xml
<abp-container>
<abp-row>
<abp-column>coluna</abp-column>
<abp-column>coluna</abp-column>
<abp-column-breaker/>
<abp-column>coluna</abp-column>
<abp-column>coluna</abp-column>
</abp-row>
</abp-container>
````
**Definindo a largura de uma coluna:** o atributo size é usado para definir a largura de uma coluna específica.
Exemplo:
```xml
<abp-container>
<abp-row>
<abp-column>1 de 3</abp-column>
<abp-column size="_6">2 de 3 (mais larga)</abp-column>
<abp-column>3 de 3</abp-column>
</abp-row>
<abp-row>
<abp-column>1 de 3</abp-column>
<abp-column size="_5">2 de 3 (mais larga)</abp-column>
<abp-column>3 de 3</abp-column>
</abp-row>
</abp-container>
```
**Conteúdo de largura variável:** Coluna de redimensionamento automático com base no conteúdo.
```xml
<abp-container>
<abp-row h-align="Center">
<abp-column size-lg="_2" abp-border="Info">1 de 3</abp-column>
<abp-column size-md="Auto" abp-border="Danger">Contrary to popular belief, Lorem Ipsum is not simply random text.</abp-column>
<abp-column size-lg="_2" abp-border="Warning">3 de 3</abp-column>
</abp-row>
<abp-row>
<abp-column>1 de 3</abp-column>
<abp-column size-md="Auto">Conteúdo de largura variável</abp-column>
<abp-column size-lg="_2">3 de 3</abp-column>
</abp-row>
</abp-container>
```
### Classes Responsivas
As classes responsivas podem ser usadas de forma fortemente tipada dentro das tags abp.
```xml
<abp-row>
<abp-column size-sm="_8">col-sm-8</abp-column>
<abp-column size-sm="_4">col-sm-4</abp-column>
</abp-row>
<abp-row>
<abp-column size-sm="_">col-sm</abp-column>
<abp-column size-sm="_">col-sm</abp-column>
<abp-column size-sm="_">col-sm</abp-column>
<abp-column size-sm="_">col-sm</abp-column>
</abp-row>
<!-- Empilhe as colunas em dispositivos móveis, tornando uma em largura total e a outra em meia largura -->
<abp-row>
<abp-column size="_12" size-md="_8">.col-12 .col-md-8</abp-column>
<abp-column size="_6" size-md="_4">.col-6 .col-md-4</abp-column>
</abp-row>
<!-- As colunas começam com 50% de largura em dispositivos móveis e aumentam para 33,3% de largura em desktop -->
<abp-row>
<abp-column size="_6" size-md="_4">.col-6 .col-md-4</abp-column>
<abp-column size="_6" size-md="_4">.col-6 .col-md-4</abp-column>
<abp-column size="_6" size-md="_4">.col-6 .col-md-4</abp-column>
</abp-row>
<!-- As colunas têm sempre 50% de largura, em dispositivos móveis e desktop -->
<abp-row>
<abp-column size="_6">.col-6</abp-column>
<abp-column size="_6">.col-6</abp-column>
</abp-row>
```
### Alinhamento
Os alinhamentos de coluna podem ser feitos de forma fortemente tipada nas tags abp, tanto vertical quanto horizontalmente.
**Alinhamento vertical**: o valor do atributo `v-align` é usado para alinhar as colunas verticalmente.
Exemplo:
```xml
<abp-container>
<abp-row v-align="Start">
<abp-column>coluna</abp-column>
<abp-column>coluna</abp-column>
<abp-column>coluna</abp-column>
</abp-row>
<abp-row v-align="Center">
<abp-column>coluna</abp-column>
<abp-column>coluna</abp-column>
<abp-column>coluna</abp-column>
</abp-row>
<abp-row v-align="End">
<abp-column>coluna</abp-column>
<abp-column>coluna</abp-column>
<abp-column>coluna</abp-column>
</abp-row>
</abp-container>
```
**Alinhamento horizontal**: o valor do atributo `h-align` é usado para alinhar as colunas horizontalmente.
Exemplo:
```xml
<abp-container>
<abp-row h-align="Start">
<abp-column size="_4">Uma de duas colunas</abp-column>
<abp-column size="_4">Uma de duas colunas</abp-column>
</abp-row>
<abp-row h-align="Center">
<abp-column size="_4">Uma de duas colunas</abp-column>
<abp-column size="_4">Uma de duas colunas</abp-column>
</abp-row>
<abp-row h-align="End">
<abp-column size="_4">Uma de duas colunas</abp-column>
<abp-column size="_4">Uma de duas colunas</abp-column>
</abp-row>
<abp-row h-align="Around">
<abp-column size="_4">Uma de duas colunas</abp-column>
<abp-column size="_4">Uma de duas colunas</abp-column>
</abp-row>
<abp-row h-align="Between">
<abp-column size="_4">Uma de duas colunas</abp-column>
<abp-column size="_4">Uma de duas colunas</abp-column>
</abp-row>
</abp-container>
```
**Sem margens**: as margens entre as colunas nas classes de grade predefinidas podem ser removidas com `gutters="false"`. Isso remove as margens negativas de `abp-row` e o preenchimento horizontal de todas as colunas filhas imediatas.
Exemplo:
```xml
<abp-row gutters="false">
<abp-column size="_8">Uma de duas colunas</abp-column>
<abp-column size="_4">Uma de duas colunas</abp-column>
</abp-row>
```
**Quebra de coluna**: se mais de 12 colunas forem colocadas em uma única linha, cada grupo de colunas extras será, como uma unidade, quebrado em uma nova linha.
Exemplo:
```xml
<abp-row>
<abp-column size="_9">.col-9</abp-column>
<abp-column size="_4">.col-4<br>Since 9 + 4 = 13 &gt; 12, this 4-column-wide div gets wrapped onto a new line as one contiguous unit.</abp-column>
<abp-column size="_6">.col-6<br>Subsequent columns continue along the new line.s</abp-column>
</abp-row>
```
### Reordenamento
**Classes de ordem**: o atributo `order` é usado para controlar a ordem visual do conteúdo.
Exemplo:
```xml
<abp-container>
<abp-row>
<abp-column order="_12">Primeiro, mas último</abp-column>
<abp-column>Segundo, mas não ordenado</abp-column>
<abp-column order="_6">Terceiro, mas segundo</abp-column>
</abp-row>
</abp-container>
```
**Deslocamento de colunas**: o atributo `offset` é usado para definir o deslocamento das colunas da grade.
Exemplo:
```xml
<abp-container>
<abp-row>
<abp-column size-md="_4">.col-md-4</abp-column>
<abp-column size-md="_4" offset-md="_4">.col-md-4 .offset-md-4</abp-column>
</abp-row>
<abp-row>
<abp-column size-md="_3" offset-md="_3">.col-md-3 .offset-md-3</abp-column>
<abp-column size-md="_3" offset-md="_3">.col-md-3 .offset-md-3</abp-column>
</abp-row>
<abp-row>
<abp-column size-md="_6" offset-md="_3">.col-md-6 .offset-md-3</abp-column>
</abp-row>
<abp-row>
<abp-column size-sm="_5" size-md="_6">.col-sm-5 .col-md-6</abp-column>
<abp-column size-sm="_5" offset-sm="_2" size-md="_6" offset-md="_">.col-sm-5 .offset-sm-2 .col-md-6 .offset-md-0</abp-column>
</abp-row>
<abp-row>
<abp-column size-sm="_6" size-md="_5" size-lg="_6">col-sm-6 .col-md-5 .col-lg-6</abp-column>
<abp-column size-sm="_6" size-md="_5" offset-md="_2" size-lg="_6" offset-lg="_">.col-sm-6 .col-md-5 .offset-md-2 .col-lg-6 .offset-lg-0</abp-column>
</abp-row>
</abp-container>
```
## Atributos de abp-row
- **v-align:** Um valor que indica o posicionamento vertical das colunas contidas. Deve ser um dos seguintes valores:
* `Default` (valor padrão)
* `Start`
* `Center`
* `End`
- **h-align**: Um valor que indica o posicionamento horizontal das colunas contidas. Deve ser um dos seguintes valores:
* `Default` (valor padrão)
* `Start`
* `Center`
* `Around`
* `Between`
* `End`
- **gutter**: Um valor que indica se as margens negativas e o preenchimento horizontal serão removidos de todas as colunas filhas. Atuará como valor `true` se esse atributo não for definido. Deve ser um dos seguintes valores:
* `true`
* `false`
## Atributos de abp-column
- **size:** Um valor que indica a largura da coluna de `_`, `Undefined`, `_1`..`_12`, `Auto`. Ou pode ser usado com valores predefinidos como:
- `size-sm`
- `size-md`
- `size-lg`
- `size-xl`
- **order**: Um valor que indica a ordem da coluna de `Undefined`, `_1`..`_12`, `First` e `Last`.
- **offset:** Um valor que indica o deslocamento da coluna de `_`, `Undefined`, `_1`..`_12`, `Auto`. Ou pode ser usado com valores predefinidos como:
- `offset-sm`
- `offset-md`
- `offset-lg`
- `offset-xl`

45
docs/pt-BR/UI/AspNetCore/Tag-Helpers/Index.md

@ -0,0 +1,45 @@
# ABP Tag Helpers
O ABP Framework define um conjunto de **componentes de tag helper** para simplificar o desenvolvimento da interface do usuário para aplicativos ASP.NET Core (MVC / Razor Pages).
## Wrappers de Componentes Bootstrap
A maioria dos tag helpers são wrappers do [Bootstrap](https://getbootstrap.com/) (v5+). Codificar o Bootstrap não é tão fácil, não é tão seguro em termos de tipo e contém muitas tags HTML repetitivas. Os ABP Tag Helpers tornam isso mais **fácil** e **seguro em termos de tipo**.
Não temos como objetivo envolver 100% dos componentes do Bootstrap. Ainda é possível escrever **código de estilo nativo do Bootstrap** (na verdade, os tag helpers geram código nativo do Bootstrap no final), mas sugerimos usar os tag helpers sempre que possível.
O ABP Framework também adiciona alguns **recursos úteis** aos componentes padrão do Bootstrap.
Aqui está a lista de componentes que são envolvidos pelo ABP Framework:
* [Alertas](Alerts.md)
* [Badges](Badges.md)
* [Blockquote](Blockquote.md)
* [Bordas](Borders.md)
* [Breadcrumb](Breadcrumbs.md)
* [Botões](Buttons.md)
* [Cards](Cards.md)
* [Carousel](Carousel.md)
* [Collapse](Collapse.md)
* [Dropdowns](Dropdowns.md)
* [Figuras](Figure.md)
* [Grids](Grids.md)
* [List Groups](List-Groups.md)
* [Modals](Modals.md)
* [Navegação](Navs.md)
* [Paginator](Paginator.md)
* [Popovers](Popovers.md)
* [Barras de Progresso](Progress-Bars.md)
* [Tabelas](Tables.md)
* [Abas](Tabs.md)
* [Tooltips](Tooltips.md)
> Até que todos os tag helpers sejam documentados, você pode visitar https://bootstrap-taghelpers.abp.io/ para vê-los com exemplos ao vivo.
## Elementos de Formulário
Os **Abp Tag Helpers** adicionam novos recursos aos **Tag Helpers de entrada e seleção do Asp.Net Core MVC** padrão e os envolvem com controles de formulário do **Bootstrap**. Consulte a documentação de [Elementos de Formulário](Form-elements.md).
## Formulários Dinâmicos
Os **Abp Tag Helpers** oferecem uma maneira fácil de construir formulários completos do **Bootstrap**. Consulte a documentação de [Formulários Dinâmicos](Dynamic-Forms.md).

76
docs/pt-BR/UI/AspNetCore/Tag-Helpers/List-Groups.md

@ -0,0 +1,76 @@
# Listas de Grupos
## Introdução
`abp-list-group` é o contêiner principal para o conteúdo do grupo de listas.
Uso básico:
````xml
<abp-list-group>
<abp-list-group-item>Cras justo odio</abp-list-group-item>
<abp-list-group-item>Dapibus ac facilisis in</abp-list-group-item>
<abp-list-group-item>Morbi leo risus</abp-list-group-item>
<abp-list-group-item>Vestibulum at eros</abp-list-group-item>
</abp-list-group>
````
## Demonstração
Veja a [página de demonstração de grupos de listas](https://bootstrap-taghelpers.abp.io/Components/ListGroup) para vê-lo em ação.
## Atributos
### flush
Um valor indica que os itens `abp-list-group` devem remover algumas bordas e cantos arredondados para renderizar os itens do grupo de listas de ponta a ponta em um contêiner pai. Deve ser um dos seguintes valores:
* `false` (valor padrão)
* `true`
### active
Um valor indica se um `abp-list-group-item` deve estar ativo. Deve ser um dos seguintes valores:
* `false` (valor padrão)
* `true`
### disabled
Um valor indica se um `abp-list-group-item` deve estar desativado. Deve ser um dos seguintes valores:
* `false` (valor padrão)
* `true`
### href
Um valor indica se um `abp-list-group-item` possui um link. Deve ser um valor de link de string.
### type
Um valor indica uma classe de estilo `abp-list-group-item` com um plano de fundo e cor com estado. Deve ser um dos seguintes valores:
* `Default` (valor padrão)
* `Primary`
* `Secondary`
* `Success`
* `Danger`
* `Warning`
* `Info`
* `Light`
* `Dark`
* `Link`
### Conteúdo adicional
`abp-list-group-item` também pode conter elementos HTML adicionais, como spans.
Exemplo:
````xml
<abp-list-group>
<abp-list-group-item>Cras justo odio <span abp-badge-pill="Primary">14</span></abp-list-group-item>
<abp-list-group-item>Dapibus ac facilisis in <span abp-badge-pill="Primary">2</span></abp-list-group-item>
<abp-list-group-item>Morbi leo risus <span abp-badge-pill="Primary">1</span></abp-list-group-item>
</abp-list-group>
````

88
docs/pt-BR/UI/AspNetCore/Tag-Helpers/Modals.md

@ -0,0 +1,88 @@
# Modais
> Este documento explica os detalhes do `abp-modal` Tag Helper, que simplifica a construção da marcação HTML para uma caixa de diálogo modal. Leia [essa documentação](../Modals.md) para aprender como trabalhar com modais.
## Introdução
`abp-modal` é um elemento principal para criar um modal.
Uso básico:
````xml
<abp-button button-type="Primary" data-toggle="modal" data-target="#myModal">Abrir modal</abp-button>
<abp-modal centered="true" scrollable="true" size="Large" id="myModal">
<abp-modal-header title="Título do modal"></abp-modal-header>
<abp-modal-body>
Uau, você está lendo este texto em um modal!
</abp-modal-body>
<abp-modal-footer buttons="Fechar"></abp-modal-footer>
</abp-modal>
````
## Demonstração
Veja a [página de demonstração de modais](https://bootstrap-taghelpers.abp.io/Components/Modals) para vê-lo em ação.
## Atributos
### centered
Um valor que indica o posicionamento do modal. Deve ser um dos seguintes valores:
* `false` (valor padrão)
* `true`
### Scrollable
Um valor que indica a rolagem do modal. Deve ser um dos seguintes valores:
* `false` (valor padrão)
* `true`
### size
Um valor que indica o tamanho do modal. Deve ser um dos seguintes valores:
* `Default` (valor padrão)
* `Small`
* `Large`
* `ExtraLarge`
### static
Um valor que indica se o modal será estático. Deve ser um dos seguintes valores:
* `false` (valor padrão)
* `true`
### Conteúdo adicional
`abp-modal-footer` pode ter vários botões com opção de alinhamento.
Adicione `@using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Modal` à sua página.
Exemplo:
````xml
<abp-button button-type="Primary" data-toggle="modal" data-target="#myModal">Abrir modal</abp-button>
<abp-modal centered="true" size="Large" id="myModal" static="true">
<abp-modal-header title="Título do modal"></abp-modal-header>
<abp-modal-body>
Uau, você está lendo este texto em um modal!
</abp-modal-body>
<abp-modal-footer buttons="@(AbpModalButtons.Save|AbpModalButtons.Close)" button-alignment="Between"></abp-modal-footer>
</abp-modal>
````
### button-alignment
Um valor que indica o posicionamento dos botões do rodapé do modal. Deve ser um dos seguintes valores:
* `Default` (valor padrão)
* `Start`
* `Center`
* `Around`
* `Between`
* `End`

114
docs/pt-BR/UI/AspNetCore/Tag-Helpers/Navs.md

@ -0,0 +1,114 @@
# Navs
## Introdução
`abp-nav` é o componente básico de tag helper derivado do elemento de navegação do bootstrap.
Uso básico:
````html
<abp-nav nav-style="Pill" align="Center">
<abp-nav-item>
<a abp-nav-link active="true" href="#">Ativo</a>
</abp-nav-item>
<abp-nav-item>
<a abp-nav-link href="#">Link de navegação mais longo</a>
</abp-nav-item>
<abp-nav-item>
<a abp-nav-link href="#">link</a>
</abp-nav-item>
<abp-nav-item>
<a abp-nav-link disabled="true" href="#">desativado</a>
</abp-nav-item>
</abp-nav>
````
## Demonstração
Veja a [página de demonstração de navegação](https://bootstrap-taghelpers.abp.io/Components/Navs) para vê-la em ação.
## Atributos do abp-nav
- **nav-style**: O valor indica o posicionamento e estilo dos itens contidos. Deve ser um dos seguintes valores:
* `Default` (valor padrão)
* `Vertical`
* `Pill`
* `PillVertical`
- **align:** O valor indica o alinhamento dos itens contidos:
* `Default` (valor padrão)
* `Start`
* `Center`
* `End`
### Atributos do abp-nav-bar
- **nav-style**: O valor indica o layout de cores da barra de navegação base. Deve ser um dos seguintes valores:
* `Default` (valor padrão)
* `Dark`
* `Light`
* `Dark_Primary`
* `Dark_Secondary`
* `Dark_Success`
* `Dark_Danger`
* `Dark_Warning`
* `Dark_Info`
* `Dark_Dark`
* `Dark_Link`
* `Light_Primary`
* `Light_Secondary`
* `Light_Success`
* `Light_Danger`
* `Light_Warning`
* `Light_Info`
* `Light_Dark`
* `Light_Link`
- **size:** O valor indica o tamanho da barra de navegação base. Deve ser um dos seguintes valores:
* `Default` (valor padrão)
* `Sm`
* `Md`
* `Lg`
* `Xl`
### Atributos do abp-nav-item
**dropdown**: Um valor que define o item de navegação como um menu suspenso, se fornecido. Pode ser um dos seguintes valores:
* `false` (valor padrão)
* `true`
Exemplo:
````html
<abp-nav-bar size="Lg" navbar-style="Dark_Warning">
<a abp-navbar-brand href="#">Navbar</a>
<abp-navbar-toggle>
<abp-navbar-nav>
<abp-nav-item active="true">
<a abp-nav-link href="#">Início <span class="sr-only">(atual)</span></a>
</abp-nav-item>
<abp-nav-item>
<a abp-nav-link href="#">Link</a>
</abp-nav-item>
<abp-nav-item dropdown="true">
<abp-dropdown>
<abp-dropdown-button nav-link="true" text="Dropdown" />
<abp-dropdown-menu>
<abp-dropdown-header>Cabeçalho do menu suspenso</abp-dropdown-header>
<abp-dropdown-item href="#" active="true">Ação</abp-dropdown-item>
<abp-dropdown-item href="#" disabled="true">Outra ação desativada</abp-dropdown-item>
<abp-dropdown-item href="#">Algo mais aqui</abp-dropdown-item>
<abp-dropdown-divider />
<abp-dropdown-item href="#">Link separado</abp-dropdown-item>
</abp-dropdown-menu>
</abp-dropdown>
</abp-nav-item>
<abp-nav-item>
<a abp-nav-link disabled="true" href="#">Desativado</a>
</abp-nav-item>
</abp-navbar-nav>
<span abp-navbar-text>
Texto de exemplo
</span>
</abp-navbar-toggle>
</abp-nav-bar>
```

57
docs/pt-BR/UI/AspNetCore/Tag-Helpers/Paginator.md

@ -0,0 +1,57 @@
# Paginador
## Introdução
`abp-paginator` é a tag abp para paginação. Requer um modelo do tipo `Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Pagination.PagerModel`.
Uso básico:
````xml
<abp-paginator model="Model.PagerModel" show-info="true"></abp-paginator>
````
Modelo:
````csharp
using Microsoft.AspNetCore.Mvc.RazorPages;
using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Pagination;
namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Demo.Pages.Components
{
public class PaginatorModel : PageModel
{
public PagerModel PagerModel { get; set; }
public void OnGet(int currentPage, string sort)
{
PagerModel = new PagerModel(100, 10, currentPage, 10, "/Components/Paginator", sort);
}
}
}
````
## Demonstração
Veja a [página de demonstração do paginador](https://bootstrap-taghelpers.abp.io/Components/Paginator) para vê-lo em ação.
## Atributos
### model
O modelo do tipo `Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Pagination.PagerModel` pode ser inicializado com os seguintes dados:
* `totalCount`
* `shownItemsCount`
* `currentPage`
* `pageSize`
* `pageUrl`
* `sort` (padrão nulo)
### show-info
Um valor que indica se uma informação extra sobre o início, fim e total de registros será exibida. Deve ser um dos seguintes valores:
* `false` (valor padrão)
* `true`

40
docs/pt-BR/UI/AspNetCore/Tag-Helpers/Popovers.md

@ -0,0 +1,40 @@
# Popovers
## Introdução
`abp-popover` é a tag abp para mensagens de popover.
Uso básico:
````xml
<abp-button abp-popover="Oi, eu sou o conteúdo do popover!">
Popover Padrão
</abp-button>
````
## Demonstração
Veja a página de demonstração de [popovers](https://bootstrap-taghelpers.abp.io/Components/Popovers) para vê-lo em ação.
## Atributos
### disabled
Um valor que indica se o elemento deve ser desabilitado para interação. Se esse valor for definido como `true`, o atributo `dismissable` será ignorado. Deve ser um dos seguintes valores:
* `false` (valor padrão)
* `true`
### dismissable
Um valor que indica se os popovers devem ser fechados no próximo clique do usuário em um elemento diferente do elemento de ativação. Deve ser um dos seguintes valores:
* `false` (valor padrão)
* `true`
### hoverable
Um valor que indica se o conteúdo do popover será exibido ao passar o mouse sobre ele. Deve ser um dos seguintes valores:
* `false` (valor padrão)
* `true`

68
docs/pt-BR/UI/AspNetCore/Tag-Helpers/Progress-Bars.md

@ -0,0 +1,68 @@
# Barras de Progresso
## Introdução
`abp-progress-bar` é a tag abp para o status da barra de progresso.
Uso básico:
````xml
<abp-progress-bar value="70" />
<abp-progress-bar type="Warning" value="25"> %25 </abp-progress-bar>
<abp-progress-bar type="Success" value="40" strip="true"/>
<abp-progress-bar type="Dark" value="10" min-value="5" max-value="15" strip="true"> %50 </abp-progress-bar>
<abp-progress-group>
<abp-progress-part type="Success" value="25"/>
<abp-progress-part type="Danger" value="10" strip="true"> %10 </abp-progress-part>
<abp-progress-part type="Primary" value="50" animation="true" strip="true" />
</abp-progress-group>
````
## Demonstração
Veja a página de demonstração das [barras de progresso](https://bootstrap-taghelpers.abp.io/Components/Progressbars) para vê-las em ação.
## Atributos
### value
Um valor que indica o progresso atual da barra.
### type
Um valor que indica a cor de fundo da barra de progresso. Deve ser um dos seguintes valores:
* `Default` (valor padrão)
* `Secondary`
* `Success`
* `Danger`
* `Warning`
* `Info`
* `Light`
* `Dark`
### min-value
Valor mínimo da barra de progresso. O padrão é 0.
### max-value
Valor máximo da barra de progresso. O padrão é 100.
### strip
Um valor que indica se o estilo de fundo da barra de progresso é listrado. Deve ser um dos seguintes valores:
* `false` (valor padrão)
* `true`
### animation
Um valor que indica se o estilo de fundo listrado da barra de progresso é animado. Deve ser um dos seguintes valores:
* `false` (valor padrão)
* `true`

61
docs/pt-BR/UI/AspNetCore/Tag-Helpers/Tables.md

@ -0,0 +1,61 @@
# Tabelas
## Introdução
`abp-table` é o componente básico de tag para tabelas no abp.
Uso básico:
````html
<abp-table hoverable-rows="true" responsive-sm="true">
<thead>
<tr>
<th scope="Column">#</th>
<th scope="Column">Primeiro</th>
<th scope="Column">Último</th>
<th scope="Column">Identificador</th>
</tr>
</thead>
<tbody>
<tr>
<th scope="Row">1</th>
<td>Mark</td>
<td>Otto</td>
<td table-style="Danger">mdo</td>
</tr>
<tr table-style="Warning">
<th scope="Row">2</th>
<td>Jacob</td>
<td>Thornton</td>
<td>fat</td>
</tr>
<tr>
<th scope="Row">3</th>
<td table-style="Success">Larry</td>
<td>the Bird</td>
<td>twitter</td>
</tr>
</tbody>
</abp-table>
````
## Demonstração
Veja a página de demonstração de [tabelas](https://bootstrap-taghelpers.abp.io/Components/Tables) para vê-la em ação.
## Atributos do abp-table
- **responsive**: Usado para criar tabelas responsivas até um determinado ponto de interrupção. Veja [específico do ponto de interrupção](https://getbootstrap.com/docs/4.1/content/tables/#breakpoint-specific) para mais informações.
- **responsive-sm**: Se não for definido como false, define a responsividade da tabela para dispositivos de tela pequena.
- **responsive-md**: Se não for definido como false, define a responsividade da tabela para dispositivos de tela média.
- **responsive-lg**: Se não for definido como false, define a responsividade da tabela para dispositivos de tela grande.
- **responsive-xl**: Se não for definido como false, define a responsividade da tabela para dispositivos de tela extra grande.
- **dark-theme**: Se definido como true, define o tema de cor da tabela como escuro.
- **striped-rows**: Se definido como true, adiciona listras zebradas às linhas da tabela.
- **hoverable-rows**: Se definido como true, adiciona estado de hover às linhas da tabela.
- **border-style**: Define o estilo da borda da tabela. Deve ser um dos seguintes valores:
- `Default` (padrão)
- `Bordered`
- `Borderless`

91
docs/pt-BR/UI/AspNetCore/Tag-Helpers/Tabs.md

@ -0,0 +1,91 @@
# Abas
## Introdução
`abp-tab` é o contêiner básico de conteúdo de navegação por abas derivado do elemento de aba do Bootstrap.
Uso básico:
````xml
<abp-tabs>
<abp-tab title="Home">
Conteúdo_Início
</abp-tab>
<abp-tab-link title="Link" href="#" />
<abp-tab title="perfil">
Conteúdo_Perfil
</abp-tab>
<abp-tab-dropdown title="Contato" name="DropdownContato">
<abp-tab title="Contato 1" parent-dropdown-name="DropdownContato">
Conteúdo_1_Conteúdo
</abp-tab>
<abp-tab title="Contato 2" parent-dropdown-name="DropdownContato">
Conteúdo_2_Conteúdo
</abp-tab>
</abp-tab-dropdown>
</abp-tabs>
````
## Demonstração
Veja a [página de demonstração de abas](https://bootstrap-taghelpers.abp.io/Components/Tabs) para vê-la em ação.
## Atributos do abp-tab
- **title**: Define o texto do menu da aba.
- **name:** Define o atributo "id" dos elementos gerados. O valor padrão é um Guid. Não é necessário, a menos que as abas sejam alteradas ou modificadas com Jquery.
- **active**: Define a aba ativa.
Exemplo:
````xml
<abp-tabs name="IdDaAba">
<abp-tab name="nav-inicio" title="Home">
Conteúdo_Início
</abp-tab>
<abp-tab name="nav-perfil" active="true" title="perfil">
Conteúdo_Perfil
</abp-tab>
<abp-tab name="nav-contato" title="Contato">
Conteúdo_Contato
</abp-tab>
</abp-tabs>
````
### Pílulas
Exemplo:
````xml
<abp-tabs tab-style="Pill">
<abp-tab title="Home">
Conteúdo_Início
</abp-tab>
<abp-tab title="perfil">
Conteúdo_Perfil
</abp-tab>
<abp-tab title="Contato">
Conteúdo_Contato
</abp-tab>
</abp-tabs>
````
### Vertical
**vertical-header-size**: Define a largura da coluna dos cabeçalhos das abas.
Exemplo:
````xml
<abp-tabs tab-style="PillVertical" vertical-header-size="_2" >
<abp-tab active="true" title="Home">
Conteúdo_Início
</abp-tab>
<abp-tab title="perfil">
Conteúdo_Perfil
</abp-tab>
<abp-tab title="Contato">
Conteúdo_Contato
</abp-tab>
</abp-tabs>
````

35
docs/pt-BR/UI/AspNetCore/Tag-Helpers/Tooltips.md

@ -0,0 +1,35 @@
# Dicas de Ferramentas
## Introdução
`abp-tooltip` é a tag abp para dicas de ferramentas.
Uso básico:
````xml
<abp-button abp-tooltip="Dica de Ferramenta">
Dica de Ferramenta Padrão
</abp-button>
<abp-button abp-tooltip-top="Dica de Ferramenta">
Dica de Ferramenta no topo
</abp-button>
<abp-button abp-tooltip-right="Dica de Ferramenta">
Dica de Ferramenta à direita
</abp-button>
<abp-button abp-tooltip-bottom="Dica de Ferramenta">
Dica de Ferramenta na parte inferior
</abp-button>
<abp-button disabled="true" abp-tooltip="Dica de Ferramenta">
Dica de Ferramenta do botão desativado
</abp-button>
````
## Demonstração
Veja a página de demonstração de [dicas de ferramentas](https://bootstrap-taghelpers.abp.io/Components/Tooltips) para vê-la em ação.

207
docs/pt-BR/UI/AspNetCore/Testing.md

@ -0,0 +1,207 @@
# ASP.NET Core MVC / Razor Pages: Testando
> Você pode seguir a documentação de Testes de Integração do ASP.NET Core (ASP.NET Core Integration Tests) para aprender detalhes sobre os testes de integração do ASP.NET Core. Este documento explica a infraestrutura de teste adicional fornecida pelo ABP Framework.
## O Modelo de Inicialização do Aplicativo
O Modelo de Inicialização do Aplicativo contém o projeto `.Web` que contém as visualizações/páginas/componentes de interface do usuário do aplicativo e um projeto `.Web.Tests` para testá-los.
![aspnetcore-web-tests-in-solution](../../images/aspnetcore-web-tests-in-solution.png)
## Testando as Páginas Razor
Suponha que você tenha criado uma Página Razor chamada `Issues.cshtml` com o seguinte conteúdo;
**Issues.cshtml.cs**
````csharp
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc.RazorPages;
using MyProject.Issues;
namespace MyProject.Web.Pages
{
public class IssuesModel : PageModel
{
public List<IssueDto> Issues { get; set; }
private readonly IIssueAppService _issueAppService;
public IssuesModel(IIssueAppService issueAppService)
{
_issueAppService = issueAppService;
}
public async Task OnGetAsync()
{
Issues = await _issueAppService.GetListAsync();
}
}
}
````
**Issues.cshtml**
````html
@page
@model MyProject.Web.Pages.IssuesModel
<h2>Lista de Problemas</h2>
<table id="IssueTable" class="table">
<thead>
<tr>
<th>Problema</th>
<th>Fechado?</th>
</tr>
</thead>
<tbody>
@foreach (var issue in Model.Issues)
{
<tr>
<td>@issue.Title</td>
<td>
@if (issue.IsClosed)
{
<span>Fechado</span>
}
else
{
<span>Aberto</span>
}
</td>
</tr>
}
</tbody>
</table>
````
Esta página simplesmente cria uma tabela com os problemas:
![issue-list](../../images/issue-list.png)
Você pode escrever uma classe de teste dentro do projeto `.Web.Tests` da mesma forma que o exemplo abaixo:
````csharp
using System.Threading.Tasks;
using HtmlAgilityPack;
using Shouldly;
using Xunit;
namespace MyProject.Pages
{
public class Issues_Tests : MyProjectWebTestBase
{
[Fact]
public async Task Should_Get_Table_Of_Issues()
{
// Agir
var response = await GetResponseAsStringAsync("/Issues");
// Assert
var htmlDocument = new HtmlDocument();
htmlDocument.LoadHtml(response);
var tableElement = htmlDocument.GetElementbyId("IssueTable");
tableElement.ShouldNotBeNull();
var trNodes = tableElement.SelectNodes("//tbody/tr");
trNodes.Count.ShouldBeGreaterThan(0);
}
}
}
````
`GetResponseAsStringAsync` é um método de atalho que vem da classe base que realiza uma solicitação HTTP GET, verifica se o status HTTP resultante é `200` e retorna a resposta como uma `string`.
> Você pode usar o objeto base `Client` (do tipo `HttpClient`) para realizar qualquer tipo de solicitação ao servidor e ler a resposta você mesmo. `GetResponseAsStringAsync` é apenas um método de atalho.
Este exemplo usa a biblioteca [HtmlAgilityPack](https://html-agility-pack.net/) para analisar o HTML recebido e testar se ele contém a tabela de problemas.
> Este exemplo pressupõe que existam alguns problemas iniciais no banco de dados. Consulte a seção *The Data Seed* do documento de Testes (Testing document) para aprender como inserir dados de teste, para que seus testes possam assumir que alguns dados iniciais estão disponíveis no banco de dados.
## Testando os Controladores
Testar um controlador não é diferente. Basta fazer uma solicitação ao servidor com uma URL adequada, obter a resposta e fazer suas asserções.
### Resultado de Visualização
Se o controlador retornar uma visualização, você pode usar um código semelhante para testar o HTML retornado. Veja o exemplo das Páginas Razor acima.
### Resultado de Objeto
Se o controlador retornar um resultado de objeto, você pode usar o método base `GetResponseAsObjectAsync`.
Suponha que você tenha um controlador definido da seguinte forma:
````csharp
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using MyProject.Issues;
using Volo.Abp.AspNetCore.Mvc;
namespace MyProject.Web.Controllers
{
[Route("api/issues")]
public class IssueController : AbpController
{
private readonly IIssueAppService _issueAppService;
public IssueController(IIssueAppService issueAppService)
{
_issueAppService = issueAppService;
}
[HttpGet]
public async Task<List<IssueDto>> GetAsync()
{
return await _issueAppService.GetListAsync();
}
}
}
````
Você pode escrever um código de teste para executar a API e obter o resultado:
````csharp
using System.Collections.Generic;
using System.Threading.Tasks;
using MyProject.Issues;
using Shouldly;
using Xunit;
namespace MyProject.Pages
{
public class Issues_Tests : MyProjectWebTestBase
{
[Fact]
public async Task Should_Get_Issues_From_Api()
{
var issues = await GetResponseAsObjectAsync<List<IssueDto>>("/api/issues");
issues.ShouldNotBeNull();
issues.Count.ShouldBeGreaterThan(0);
}
}
}
````
## Testando o Código JavaScript
O ABP Framework não fornece nenhuma infraestrutura para testar seu código JavaScript. Você pode usar qualquer estrutura de teste e ferramentas para testar seu código JavaScript.
## A Infraestrutura de Teste
O pacote [Volo.Abp.AspNetCore.TestBase](https://www.nuget.org/packages/Volo.Abp.AspNetCore.TestBase) fornece a infraestrutura de teste que está integrada ao ABP Framework e ao ASP.NET Core.
> O pacote Volo.Abp.AspNetCore.TestBase já está instalado no projeto `.Web.Tests`.
Este pacote fornece a classe base `AbpWebApplicationFactoryIntegratedTest` como a classe base fundamental para derivar as classes de teste. Ela é herdada da classe [WebApplicationFactory](https://learn.microsoft.com/en-us/aspnet/core/test/integration-tests) fornecida pelo ASP.NET Core.
A classe base `MyProjectWebTestBase` usada acima herda da `AbpWebApplicationFactoryIntegratedTest`, então herdamos indiretamente a `AbpWebApplicationFactoryIntegratedTest`.
Veja também
* [Testes de integração no ASP.NET Core](https://learn.microsoft.com/en-us/aspnet/core/test/integration-tests)
* [Testes Gerais / Lado do Servidor](../../Testing.md)

442
docs/pt-BR/UI/AspNetCore/Theming.md

@ -0,0 +1,442 @@
# ASP.NET Core MVC / Razor Pages: Tematização de UI
## Introdução
O ABP Framework fornece um sistema completo de **tematização de UI** com os seguintes objetivos:
* Módulos de aplicativos reutilizáveis são desenvolvidos de forma **independente de tema**, para que possam funcionar com qualquer tema de UI.
* O tema de UI é **decidido pela aplicação final**.
* O tema é distribuído por meio de pacotes NuGet/NPM, para que seja **facilmente atualizável**.
* A aplicação final pode **personalizar** o tema selecionado.
Para alcançar esses objetivos, o ABP Framework:
* Determina um conjunto de **bibliotecas base** usadas e adaptadas por todos os temas. Assim, os desenvolvedores de módulos e aplicativos podem depender e usar essas bibliotecas sem depender de um tema específico.
* Fornece um sistema que consiste em [menus de navegação](../../Navigation-Menu.md), [barras de ferramentas](../../Toolbars.md), [hooks de layout](../../Layout-Hooks.md)... que são implementados por todos os temas. Assim, os módulos e a aplicação contribuem para o layout para compor uma UI de aplicação consistente.
### Temas Atuais
Atualmente, quatro temas são **oficialmente fornecidos**:
* O [Tema Básico](../../Basic-Theme.md) é o tema minimalista com o estilo Bootstrap simples. É **open source e gratuito**.
* O [Tema LeptonX Lite](../../Themes/LeptonXLite/AspNetCore.md) é um tema moderno e elegante de UI Bootstrap. É ideal se você deseja ter um tema de UI pronto para produção. Também é **open source e gratuito**.
* O [Tema Lepton](https://commercial.abp.io/themes) é um tema **comercial** desenvolvido pela equipe central do ABP e faz parte da licença [ABP Commercial](https://commercial.abp.io/).
* O [Tema LeptonX](https://docs.abp.io/en/commercial/latest/themes/lepton-x/index) também é um tema **comercial** desenvolvido pela equipe central do ABP e faz parte da licença [ABP Commercial](https://commercial.abp.io/). Este é o tema padrão após o ABP v6.0.0.
Também existem alguns temas desenvolvidos pela comunidade para o ABP Framework (você pode pesquisar na web).
## Geral
### As Bibliotecas Base
Todos os temas devem depender do pacote NPM [@abp/aspnetcore.mvc.ui.theme.shared](https://www.npmjs.com/package/@abp/aspnetcore.mvc.ui.theme.shared), para que dependam indiretamente das seguintes bibliotecas:
* [Twitter Bootstrap](https://getbootstrap.com/) como o framework HTML/CSS fundamental.
* [JQuery](https://jquery.com/) para manipulação do DOM.
* [DataTables.Net](https://datatables.net/) para grades de dados.
* [JQuery Validation](https://github.com/jquery-validation/jquery-validation) para validação do lado do cliente e [unobtrusive](https://github.com/aspnet/jquery-validation-unobtrusive) validation
* [FontAwesome](https://fontawesome.com/) como a biblioteca fundamental de fontes CSS.
* [SweetAlert](https://sweetalert.js.org/) para exibir mensagens de alerta e caixas de diálogo de confirmação.
* [Toastr](https://github.com/CodeSeven/toastr) para exibir notificações de toast.
* [Lodash](https://lodash.com/) como uma biblioteca de utilitários.
* [Luxon](https://moment.github.io/luxon/) para operações de data/hora.
* [JQuery Form](https://github.com/jquery-form/form) para formulários AJAX.
* [bootstrap-datepicker](https://github.com/uxsolutions/bootstrap-datepicker) para exibir seletores de data.
* [Select2](https://select2.org/) para caixas de seleção/combo melhores.
* [Timeago](http://timeago.yarp.com/) para exibir carimbos de data/hora fuzzy atualizados automaticamente.
* [malihu-custom-scrollbar-plugin](https://github.com/malihu/malihu-custom-scrollbar-plugin) para barras de rolagem personalizadas.
Essas bibliotecas são selecionadas como as bibliotecas base e estão disponíveis para as aplicações e módulos.
#### Abstrações / Wrappers
Existem algumas abstrações no ABP Framework para tornar seu código independente de algumas dessas bibliotecas também. Exemplos:
* [Tag Helpers](../../Tag-Helpers/Index.md) facilitam a geração de UIs do Bootstrap.
* As APIs JavaScript [Message](../../JavaScript-API/Message.md) e [Notification](../../JavaScript-API/Notify.md) fornecem abstrações para usar o Sweetalert e o Toastr.
* O sistema de [Forms & Validation](../../Forms-Validation.md) manipula automaticamente a validação, então você geralmente não digita diretamente nenhum código de validação.
### Os Layouts Padrão
A principal responsabilidade de um tema é fornecer os layouts. Existem **três layouts predefinidos que devem ser implementados por todos os temas**:
* **Application**: O layout padrão usado pelas páginas principais do aplicativo.
* **Account**: Geralmente usado pelo [módulo de conta](../../Modules/Account.md) para páginas de login, registro, esqueci minha senha...
* **Empty**: O layout mínimo que não possui componentes de layout.
Os nomes dos layouts são constantes definidas na classe `Volo.Abp.AspNetCore.Mvc.UI.Theming.StandardLayouts`.
#### O Layout de Aplicativo
Este é o layout padrão usado pelas páginas principais do aplicativo. A imagem a seguir mostra a página de gerenciamento de usuários no layout de aplicativo do [Tema Básico](../../Basic-Theme.md):
![basic-theme-application-layout](../../images/basic-theme-application-layout.png)
E a mesma página é mostrada abaixo com o layout de aplicativo do [Tema Lepton](https://commercial.abp.io/themes):
![lepton-theme-application-layout](../../images/lepton-theme-application-layout.png)
Como você pode ver, a página é a mesma, mas a aparência é completamente diferente nos temas acima.
O layout de aplicativo normalmente inclui as seguintes partes:
* Um [menu principal](../../Navigation-Menu.md)
* Uma [barra de ferramentas](../../Toolbars.md) principal com os seguintes componentes:
* Menu do usuário
* Dropdown de troca de idioma
* [Alertas de página](../../Page-Alerts.md)
* O conteúdo da página (chamado de `RenderBody()`)
* [Hooks de layout](../../Layout-Hooks.md)
Alguns temas podem fornecer mais partes, como breadcrumbs, cabeçalho e barra de ferramentas da página... etc. Veja a seção *Partes do Layout*.
#### O Layout de Conta
O layout de conta é geralmente usado pelo [módulo de conta](../../Modules/Account.md) para páginas de login, registro, esqueci minha senha...
![basic-theme-account-layout](../../images/basic-theme-account-layout.png)
Este layout normalmente fornece as seguintes partes:
* Dropdown de troca de idioma
* Área de troca de locatário (se a aplicação for [multi-tenant](../../Multi-Tenancy.md) e o locatário atual for resolvido pelo cookie)
* [Alertas de página](../../Page-Alerts.md)
* O conteúdo da página (chamado de `RenderBody()`)
* [Hooks de layout](../../Layout-Hooks.md)
O [Tema Básico](../../Basic-Theme.md) também renderiza a barra de navegação superior para este layout (como mostrado acima).
Aqui está o layout de conta do Tema Lepton:
![lepton-theme-account-layout](../../images/lepton-theme-account-layout.png)
O [Tema Lepton](https://commercial.abp.io/themes) mostra o logotipo do aplicativo e o rodapé neste layout.
> Você pode substituir completamente ou parcialmente os layouts do tema em um aplicativo para [personalizá-lo](../../Customization-User-Interface.md).
#### O Layout Vazio
O layout vazio fornece uma página vazia. Normalmente inclui as seguintes partes:
* [Alertas de página](../../Page-Alerts.md)
* O conteúdo da página (chamado de `RenderBody()`)
* [Hooks de layout](../../Layout-Hooks.md)
## Implementando um Tema
### A Forma Mais Fácil
A forma mais fácil de criar um novo tema é adicionar o módulo [Código-fonte do Tema Básico](https://github.com/abpframework/abp/tree/dev/modules/basic-theme) com os códigos-fonte e personalizá-lo.
```bash
abp add-package Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic --with-source-code --add-to-solution-file
```
### A Interface ITheme
A interface `ITheme` é usada pelo ABP Framework para selecionar o layout para a página atual. Um tema deve implementar esta interface para fornecer o caminho do layout solicitado.
Esta é a implementação da `ITheme` do [Tema Básico](../../Basic-Theme.md).
````csharp
using Volo.Abp.AspNetCore.Mvc.UI.Theming;
using Volo.Abp.DependencyInjection;
namespace Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic
{
[ThemeName(Name)]
public class BasicTheme : ITheme, ITransientDependency
{
public const string Name = "Basic";
public virtual string GetLayout(string name, bool fallbackToDefault = true)
{
switch (name)
{
case StandardLayouts.Application:
return "~/Themes/Basic/Layouts/Application.cshtml";
case StandardLayouts.Account:
return "~/Themes/Basic/Layouts/Account.cshtml";
case StandardLayouts.Empty:
return "~/Themes/Basic/Layouts/Empty.cshtml";
default:
return fallbackToDefault
? "~/Themes/Basic/Layouts/Application.cshtml"
: null;
}
}
}
}
````
* O atributo `[ThemeName]` é obrigatório e um tema deve ter um nome único, `Basic` neste exemplo.
* O método `GetLayout` deve retornar um caminho se o layout solicitado (`name`) for fornecido pelo tema. *Os Layouts Padrão* devem ser implementados se o tema for destinado a ser usado por um aplicativo padrão. Ele pode implementar layouts adicionais.
Depois que o tema implementa a interface `ITheme`, ele deve adicionar o tema às `AbpThemingOptions` no método `ConfigureServices` do [módulo](../../Module-Development-Basics.md).
````csharp
Configure<AbpThemingOptions>(options =>
{
options.Themes.Add<BasicTheme>();
});
````
#### O Serviço IThemeSelector
O ABP Framework permite usar vários temas juntos. É por isso que `options.Themes` é uma lista. O serviço `IThemeSelector` seleciona o tema em tempo de execução. O desenvolvedor da aplicação pode definir `AbpThemingOptions.DefaultThemeName` para definir o tema a ser usado ou substituir a implementação do serviço `IThemeSelector` (a implementação padrão é `DefaultThemeSelector`) para controlar completamente a seleção do tema em tempo de execução.
### Bundles
O [sistema de agrupamento](../../Bundling-Minification.md) fornece uma maneira padrão de importar arquivos de estilo e script nas páginas. Existem dois pacotes padrão definidos pelo ABP Framework:
* `StandardBundles.Styles.Global`: O pacote global que inclui os arquivos de estilo usados em todas as páginas. Normalmente, inclui os arquivos CSS das Bibliotecas Base.
* `StandardBundles.Scripts.Global`: O pacote global que inclui os arquivos de script usados em todas as páginas. Normalmente, inclui os arquivos JavaScript das Bibliotecas Base.
Um tema geralmente estende esses pacotes padrão adicionando arquivos CSS/JavaScript específicos do tema.
A melhor maneira de definir novos pacotes é herdar dos pacotes padrão e adicioná-los às `AbpBundlingOptions`, como mostrado abaixo (este código é do [Tema Básico](../../Basic-Theme.md)):
````csharp
Configure<AbpBundlingOptions>(options =>
{
options
.StyleBundles
.Add(BasicThemeBundles.Styles.Global, bundle =>
{
bundle
.AddBaseBundles(StandardBundles.Styles.Global)
.AddContributors(typeof(BasicThemeGlobalStyleContributor));
});
options
.ScriptBundles
.Add(BasicThemeBundles.Scripts.Global, bundle =>
{
bundle
.AddBaseBundles(StandardBundles.Scripts.Global)
.AddContributors(typeof(BasicThemeGlobalScriptContributor));
});
});
````
`BasicThemeGlobalStyleContributor` e `BasicThemeGlobalScriptContributor` são contribuidores de pacotes. Por exemplo, `BasicThemeGlobalStyleContributor` é definido como mostrado abaixo:
```csharp
public class BasicThemeGlobalStyleContributor : BundleContributor
{
public override void ConfigureBundle(BundleConfigurationContext context)
{
context.Files.Add("/themes/basic/layout.css");
}
}
```
Em seguida, o tema pode renderizar esses pacotes em um layout. Por exemplo, você pode renderizar os Estilos Globais como mostrado abaixo:
````html
<abp-style-bundle name="@BasicThemeBundles.Styles.Global" />
````
Consulte o documento [Bundle & Minification](../../Bundling-Minification.md) para entender melhor o sistema de agrupamento.
### Partes do Layout
Um layout típico consiste em várias partes. O tema deve incluir as partes necessárias em cada layout.
**Exemplo: O Tema Básico tem as seguintes partes para o Layout de Aplicativo**
![basic-theme-application-layout-parts](../../images/basic-theme-application-layout-parts.png)
O código do aplicativo e dos módulos só pode mostrar conteúdo na parte de Conteúdo da Página. Se eles precisarem alterar as outras partes (adicionar um item de menu, adicionar um item de barra de ferramentas, alterar o nome do aplicativo na área de marcação...), eles devem usar as APIs do ABP Framework.
As seções a seguir explicam as partes fundamentais pré-definidas pelo ABP Framework e que podem ser implementadas pelos temas.
> É uma boa prática dividir o layout em componentes/partials, para que o aplicativo final possa substituí-los parcialmente para fins de personalização.
#### Marcação
O serviço `IBrandingProvider` deve ser usado para obter o nome e a URL do logotipo do aplicativo para renderizar na parte de Marcação.
O [Modelo de Inicialização do Aplicativo](../../Startup-Templates/Application.md) tem uma implementação dessa interface para definir os valores pelo desenvolvedor da aplicação.
#### Menu Principal
O serviço `IMenuManager` é usado para obter os itens do menu principal e renderizá-los no layout.
**Exemplo: Obter o Menu Principal para renderizar em um componente de visualização**
```csharp
public class MainNavbarMenuViewComponent : AbpViewComponent
{
private readonly IMenuManager _menuManager;
public MainNavbarMenuViewComponent(IMenuManager menuManager)
{
_menuManager = menuManager;
}
public async Task<IViewComponentResult> InvokeAsync()
{
var menu = await _menuManager.GetAsync(StandardMenus.Main);
return View("~/Themes/Basic/Components/Menu/Default.cshtml", menu);
}
}
```
Consulte o documento [Navegação / Menus](../../Navigation-Menu.md) para saber mais sobre o sistema de navegação.
#### Barra de Ferramentas Principal
O serviço `IToolbarManager` é usado para obter os itens da Barra de Ferramentas Principal e renderizá-los no layout. Cada item desta barra de ferramentas é um componente de visualização, então ele pode incluir qualquer tipo de elemento de UI. Injete o `IToolbarManager` e use o `GetAsync` para obter os itens da barra de ferramentas:
````csharp
var toolbar = await _toolbarManager.GetAsync(StandardToolbars.Main);
````
> Consulte o documento [Barras de Ferramentas](../../Toolbars.md) para saber mais sobre o sistema de barras de ferramentas.
O tema tem a responsabilidade de adicionar dois itens pré-definidos à barra de ferramentas principal: Seleção de Idioma e Menu do Usuário. Para fazer isso, crie uma classe que implemente a interface `IToolbarContributor` e adicione-a às `AbpToolbarOptions`, como mostrado abaixo:
```csharp
Configure<AbpToolbarOptions>(options =>
{
options.Contributors.Add(new BasicThemeMainTopToolbarContributor());
});
```
##### Seleção de Idioma
O item de barra de ferramentas Seleção de Idioma é geralmente um dropdown que é usado para alternar entre idiomas. O `ILanguageProvider` é usado para obter a lista de idiomas disponíveis e `CultureInfo.CurrentUICulture` é usado para saber o idioma atual.
O endpoint `/Abp/Languages/Switch` pode ser usado para alternar o idioma. Este endpoint aceita os seguintes parâmetros de string de consulta:
* `culture`: O idioma selecionado, como `en-US` ou `en`.
* `uiCulture`: O idioma de IU selecionado, como `en-US` ou `en`.
* `returnUrl` (opcional): Pode ser usado para retornar uma determinada URL após a troca de idioma.
`culture` e `uiCulture` devem corresponder a um dos idiomas disponíveis. O ABP Framework define um cookie de cultura no endpoint `/Abp/Languages/Switch`.
##### Menu do Usuário
O menu do usuário inclui links relacionados à conta do usuário. O `IMenuManager` é usado da mesma forma que o Menu Principal, mas desta vez com o parâmetro `StandardMenus.User`, como mostrado abaixo:
````csharp
var menu = await _menuManager.GetAsync(StandardMenus.User);
````
Os serviços [ICurrentUser](../../CurrentUser.md) e [ICurrentTenant](../../Multi-Tenancy.md) podem ser usados para obter os nomes do usuário e do locatário atual.
#### Alertas de Página
O serviço `IAlertManager` é usado para obter os alertas de página atuais para renderizar no layout. Use a lista `Alerts` do `IAlertManager`. Geralmente é renderizado logo antes do conteúdo da página (`RenderBody()`).
Consulte o documento [Alertas de Página](../../Page-Alerts.md) para saber mais.
#### Hooks de Layout
Como o Layout está no pacote do tema, o aplicativo final ou qualquer módulo não pode manipular diretamente o conteúdo do layout. O sistema de [Hooks de Layout](../../Layout-Hooks.md) permite injetar componentes em pontos específicos do layout.
O tema é responsável por renderizar os hooks no local correto.
**Exemplo: Renderizar o Hook `LayoutHooks.Head.First` no Layout de Aplicativo**
````html
<head>
@await Component.InvokeLayoutHookAsync(LayoutHooks.Head.First, StandardLayouts.Application)
...
````
Consulte o documento [Hooks de Layout](../../Layout-Hooks.md) para saber mais sobre os hooks de layout padrão.
#### Seções de Script / Estilo
Todo layout deve renderizar as seguintes seções opcionais:
* A seção `styles` é renderizada no final do `head`, logo antes do `LayoutHooks.Head.Last`.
* A seção `scripts` é renderizada no final do `body`, logo antes do `LayoutHooks.Body.Last`.
Dessa forma, a página pode importar estilos e scripts para o layout.
**Exemplo: Renderizar a seção `styles`**
````csharp
@await RenderSectionAsync("styles", required: false)
````
#### Seção de Barra de Ferramentas de Conteúdo
Outra seção pré-definida é a seção de Barra de Ferramentas de Conteúdo, que pode ser usada pelas páginas para adicionar código logo antes do conteúdo da página. O Tema Básico a renderiza da seguinte forma:
````html
<div id="AbpContentToolbar">
<div class="text-end mb-2">
@RenderSection("content_toolbar", false)
</div>
</div>
````
O id da div de contêiner deve ser `AbpContentToolbar`. Esta seção deve vir antes do `RenderBody()`.
#### Recursos de Widgets
O [Sistema de Widgets](../../Widgets.md) permite definir widgets reutilizáveis com seus próprios arquivos de estilo/script. Todos os layouts devem renderizar o estilo e os scripts do widget.
**Estilos de Widget** são renderizados da seguinte forma, logo antes da seção `styles`, após o pacote de estilo global:
````csharp
@await Component.InvokeAsync(typeof(WidgetStylesViewComponent))
````
**Scripts de Widget** são renderizados da seguinte forma, logo antes da seção `scripts`, após o pacote de script global:
````csharp
@await Component.InvokeAsync(typeof(WidgetScriptsViewComponent))
````
#### Scripts ABP
O ABP tem alguns scripts especiais que devem ser incluídos em todos os layouts. Eles não estão incluídos nos pacotes globais, pois são criados dinamicamente com base no usuário atual.
Os scripts do ABP (`ApplicationConfigurationScript` e `ServiceProxyScript`) devem ser adicionados logo após o pacote de script global, como mostrado abaixo:
````html
<script src="~/Abp/ApplicationConfigurationScript"></script>
<script src="~/Abp/ServiceProxyScript"></script>
````
#### Título da Página, Item de Menu Selecionado e Breadcrumbs
O serviço `IPageLayout` pode ser injetado por qualquer página para definir o título da página, o nome do item de menu selecionado e os itens de breadcrumbs. Em seguida, o tema pode usar este serviço para obter esses valores e renderizá-los na UI.
O Tema Básico não implementa este serviço, mas o Tema Lepton implementa:
![breadcrumbs-example](../../images/breadcrumbs-example.png)
Consulte o documento [Cabeçalho da Página](../../Page-Header.md) para saber mais.
#### Troca de Locatário
O Layout de Conta deve permitir ao usuário trocar o locatário atual se a aplicação for multi-tenant e o locatário for resolvido a partir dos cookies. Consulte o [Layout de Conta do Tema Básico](https://github.com/abpframework/abp/blob/dev/modules/basic-theme/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic/Themes/Basic/Layouts/Account.cshtml) como um exemplo de implementação.
### Classes de Layout
Os Layouts Padrão (`Application`, `Account` e `Empty`) devem adicionar as seguintes classes CSS à tag `body`:
* `abp-application-layout` para o layout `Application`.
* `abp-account-layout` para o layout `Account`.
* `abp-empty-layout` para o layout `Empty`.
Dessa forma, os aplicativos ou módulos podem ter seletores com base no layout atual.
### RTL
Para oferecer suporte a idiomas da direita para a esquerda, o Layout deve verificar a cultura atual e adicionar `dir="rtl"` à tag `html` e a classe CSS `rtl` à tag `body`.
Você pode verificar `CultureInfo.CurrentUICulture.TextInfo.IsRightToLeft` para entender se o idioma atual é um idioma RTL.
### O Pacote NPM
Um tema deve ter um pacote NPM que dependa do pacote [@abp/aspnetcore.mvc.ui.theme.shared](https://www.npmjs.com/package/@abp/aspnetcore.mvc.ui.theme.shared). Dessa forma, ele herda todas as Bibliotecas Base. Se o tema exigir bibliotecas adicionais, ele deve definir essas dependências também.
As aplicações usam o sistema de [Gerenciamento de Pacotes do Lado do Cliente](../../Client-Side-Package-Management.md) para adicionar bibliotecas do lado do cliente ao projeto. Portanto, se uma aplicação usar seu tema, ela deve adicionar a dependência do pacote NPM do seu tema, bem como a dependência do pacote NuGet.

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save