@praxisui/settings-panel 3.0.0-beta.6 → 3.0.0-beta.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -3,21 +3,21 @@ import { inject, DestroyRef, ViewContainerRef, HostListener, ViewChild, ChangeDe
3
3
  import { ComponentPortal } from '@angular/cdk/portal';
4
4
  import * as i3 from '@angular/common';
5
5
  import { CommonModule } from '@angular/common';
6
+ import { CdkTrapFocus } from '@angular/cdk/a11y';
6
7
  import * as i3$1 from '@angular/material/button';
7
8
  import { MatButtonModule } from '@angular/material/button';
9
+ import * as i1 from '@angular/material/dialog';
10
+ import { MatDialogModule } from '@angular/material/dialog';
8
11
  import * as i4 from '@angular/material/icon';
9
12
  import { MatIconModule } from '@angular/material/icon';
10
- import { PraxisIconDirective, SETTINGS_PANEL_DATA as SETTINGS_PANEL_DATA$1, GlobalConfigService, FieldControlType, IconPickerService, LoggerService } from '@praxisui/core';
11
- import * as i5 from '@angular/material/tooltip';
12
- import { MatTooltipModule } from '@angular/material/tooltip';
13
- import { CdkTrapFocus } from '@angular/cdk/a11y';
14
13
  import * as i6 from '@angular/material/progress-spinner';
15
14
  import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
16
- import * as i1 from '@angular/material/dialog';
17
- import { MatDialogModule } from '@angular/material/dialog';
15
+ import * as i5 from '@angular/material/tooltip';
16
+ import { MatTooltipModule } from '@angular/material/tooltip';
18
17
  import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
19
- import { isObservable, firstValueFrom, of, Subject, BehaviorSubject } from 'rxjs';
20
18
  import { filter, switchMap, debounceTime, distinctUntilChanged } from 'rxjs/operators';
19
+ import { isObservable, firstValueFrom, of, Subject, BehaviorSubject } from 'rxjs';
20
+ import { providePraxisI18n, PraxisI18nService, PraxisIconDirective, SETTINGS_PANEL_DATA as SETTINGS_PANEL_DATA$1, SETTINGS_PANEL_BRIDGE, GlobalConfigService, FieldControlType, IconPickerService, LoggerService } from '@praxisui/core';
21
21
  import { ConfirmDialogComponent } from '@praxisui/dynamic-fields';
22
22
  import * as i1$1 from '@angular/cdk/overlay';
23
23
  import * as i2 from '@angular/material/snack-bar';
@@ -28,6 +28,457 @@ import * as i9 from '@angular/material/chips';
28
28
  import { MatChipsModule } from '@angular/material/chips';
29
29
  import { AiBackendApiService } from '@praxisui/ai';
30
30
 
31
+ const PRAXIS_SETTINGS_PANEL_GLOBAL_CONFIG_EDITOR_PT_BR = {
32
+ CRUD: 'CRUD',
33
+ 'Dynamic Fields': 'Campos Dinâmicos',
34
+ 'Cache & Persistence': 'Cache & Persistência',
35
+ Table: 'Tabela',
36
+ Dialog: 'Dialog',
37
+ 'Settings saved': 'Configurações salvas',
38
+ 'Save failed.': 'Falha ao salvar configurações.',
39
+ 'Global settings': 'Configurações globais',
40
+ 'Global policies for opening, back and header': 'Políticas globais de abertura, back e header',
41
+ 'Server defaults (env vars)': 'Padrões do servidor (env vars)',
42
+ 'Saved configuration (UI) - overrides server defaults': 'Configuração salva (UI) - sobrescreve os defaults do servidor',
43
+ 'Failed to test connection.': 'Falha ao testar conexão.',
44
+ 'Connection established successfully!': 'Conexão estabelecida com sucesso!',
45
+ 'Unknown error': 'Erro desconhecido',
46
+ 'Key provided': 'Chave informada',
47
+ 'Saved key (****{{last4}})': 'Chave salva (****{{last4}})',
48
+ 'Saved key': 'Chave salva',
49
+ 'Test connection with the provided key': 'Testar conexão com a chave informada',
50
+ 'Test connection': 'Testar conexão',
51
+ 'Refresh model list': 'Atualizar lista de modelos',
52
+ Close: 'Fechar',
53
+ 'This provider has no model catalog.': 'Este provedor não oferece catálogo de modelos.',
54
+ 'Enter an API key to fetch models.': 'Insira uma chave de API para buscar modelos.',
55
+ 'Error fetching models.': 'Erro ao buscar modelos.',
56
+ 'Error fetching models. Check your API key.': 'Erro ao buscar modelos. Verifique a chave de API.',
57
+ 'Model list updated ({{count}} models)': 'Lista de modelos atualizada ({{count}} modelos)',
58
+ 'Enter an API key to test.': 'Insira uma chave de API para testar.',
59
+ 'No model details available.': 'Detalhes do modelo não disponíveis.',
60
+ 'Model: {{model}} | Tokens (in/out): {{in}}/{{out}} | Methods: {{methods}}': 'Modelo: {{model}} | Tokens (in/out): {{in}}/{{out}} | Métodos: {{methods}}',
61
+ 'Global config cleared. Using server defaults.': 'Configuração global limpa. Usando defaults do servidor.',
62
+ 'Clear saved config and return to server defaults': 'Apaga o config salvo e volta aos defaults do servidor',
63
+ 'Failed to clear global config.': 'Falha ao limpar a configuração global.',
64
+ 'No key required': 'Sem chave necessária',
65
+ 'Model & Behavior': 'Modelo & Comportamento',
66
+ 'Choose the model after validating the key.': 'Escolha o modelo após validar a chave.',
67
+ 'API key validated required': 'Requer chave de API validada',
68
+ 'Configure and test your API key to unlock model selection.': 'Configure e teste sua chave de API para desbloquear a seleção de modelos.',
69
+ 'Embeddings (RAG)': 'Embeddings (RAG)',
70
+ 'Use the LLM provider and key for embeddings': 'Aplicar provedor e chave do LLM aos embeddings',
71
+ 'Provider has no embeddings': 'Provedor sem embeddings',
72
+ 'Configure the embeddings provider for vector search (templates and schemas).': 'Configure o provedor de embeddings para buscas vetoriais (templates e schemas).',
73
+ 'Embedding dimension mismatch with database (768). Adjust to 768 or redo the migration.': 'Dimensão de embeddings diferente do banco (768). Ajuste para 768 ou refaça a migração.',
74
+ 'Toolbar, appearance and advanced filter': 'Toolbar, aparência e filtro avançado',
75
+ 'Defaults and variants (danger, info, success, question, error)': 'Defaults e variants (danger, info, success, question, error)',
76
+ 'Icons by profile (shortcuts)': 'Ícones por perfil (atalhos)',
77
+ 'Pick icon': 'Escolher ícone',
78
+ 'Pick icon for {{key}}': 'Escolher ícone para {{key}}',
79
+ 'Clear icon': 'Limpar ícone',
80
+ 'Clear icon for {{key}}': 'Limpar ícone de {{key}}',
81
+ 'The text field above remains editable. These buttons only help with selection/clear preview.': 'O campo de texto acima permanece editável. Estes botões apenas ajudam na seleção/limpeza com preview.',
82
+ 'Fast multimodal models from Google.': 'Modelos rápidos e multimodais do Google.',
83
+ 'Grok models focused on reasoning.': 'Modelos Grok focados em raciocínio.',
84
+ 'Local mode for tests without a key.': 'Modo local para testes sem chave.',
85
+ 'No saved key': 'Sem chave salva',
86
+ 'Aparência: densidade': 'Aparência: densidade',
87
+ compact: 'compact',
88
+ comfortable: 'comfortable',
89
+ spacious: 'spacious',
90
+ 'Aparência: padding das células': 'Aparência: padding das células',
91
+ 'Aceita 1 a 4 medidas CSS com unidade, var(...) ou calc(...). Ex.: 6px 12px': 'Aceita 1 a 4 medidas CSS com unidade, var(...) ou calc(...). Ex.: 6px 12px',
92
+ 'Use 1 a 4 medidas CSS válidas, como 6px 12px.': 'Use 1 a 4 medidas CSS válidas, como 6px 12px.',
93
+ 'Aparência: padding do cabeçalho': 'Aparência: padding do cabeçalho',
94
+ 'Aceita 1 a 4 medidas CSS com unidade, var(...) ou calc(...). Ex.: 8px 12px': 'Aceita 1 a 4 medidas CSS com unidade, var(...) ou calc(...). Ex.: 8px 12px',
95
+ 'Use 1 a 4 medidas CSS válidas, como 8px 12px.': 'Use 1 a 4 medidas CSS válidas, como 8px 12px.',
96
+ 'Aparência: fonte das células': 'Aparência: fonte das células',
97
+ 'Aceita uma medida CSS com unidade, var(...) ou calc(...). Ex.: 13px': 'Aceita uma medida CSS com unidade, var(...) ou calc(...). Ex.: 13px',
98
+ 'Use uma medida CSS válida, como 13px.': 'Use uma medida CSS válida, como 13px.',
99
+ 'Aparência: fonte do cabeçalho': 'Aparência: fonte do cabeçalho',
100
+ 'Filtro: modo de abertura': 'Filtro: modo de abertura',
101
+ overlay: 'overlay',
102
+ 'Filtro: overlay (visual)': 'Filtro: overlay (visual)',
103
+ card: 'card',
104
+ frosted: 'frosted',
105
+ 'Filtro: backdrop no overlay': 'Filtro: backdrop no overlay',
106
+ 'Excluir — confirmação': 'Excluir — confirmação',
107
+ 'Excluir (múltiplos) — confirmação': 'Excluir (múltiplos) — confirmação',
108
+ 'Salvar — confirmação': 'Salvar — confirmação',
109
+ 'Cancelar — confirmação': 'Cancelar — confirmação',
110
+ 'Exportar — confirmação': 'Exportar — confirmação',
111
+ 'Excluir — progresso': 'Excluir — progresso',
112
+ 'Excluir (múltiplos) — progresso': 'Excluir (múltiplos) — progresso',
113
+ 'Excluir — sucesso': 'Excluir — sucesso',
114
+ 'Salvar — sucesso': 'Salvar — sucesso',
115
+ 'Exportar — sucesso': 'Exportar — sucesso',
116
+ 'Importar — sucesso': 'Importar — sucesso',
117
+ 'Excluir — erro': 'Excluir — erro',
118
+ 'Salvar — erro': 'Salvar — erro',
119
+ 'Exportar — erro': 'Exportar — erro',
120
+ 'Rede — erro': 'Rede — erro',
121
+ 'Permissão — erro': 'Permissão — erro',
122
+ 'Modo de abertura padrão': 'Modo de abertura padrão',
123
+ Rota: 'Rota',
124
+ 'Aplicado quando ação/metadado não definem modo.': 'Aplicado quando ação/metadado não definem modo.',
125
+ 'Confirmar ao sair com alterações': 'Confirmar ao sair com alterações',
126
+ 'Back: estratégia': 'Back: estratégia',
127
+ 'Modal: largura (ex.: 900px)': 'Modal: largura (ex.: 900px)',
128
+ 'Modal: largura máxima (ex.: 96vw)': 'Modal: largura máxima (ex.: 96vw)',
129
+ 'Modal: backdrop': 'Modal: backdrop',
130
+ blur: 'blur',
131
+ dim: 'dim',
132
+ transparent: 'transparent',
133
+ 'Estratégia de primeira carga quando metadado não definir.': 'Estratégia de primeira carga quando metadado não definir.',
134
+ 'Async Select, cascade and pagination': 'Async Select, cascata e paginação',
135
+ 'Cascata nativa habilitada': 'Cascata nativa habilitada',
136
+ 'Cascata: loadOnChange': 'Cascata: loadOnChange',
137
+ respectLoadOn: 'respectLoadOn',
138
+ immediate: 'immediate',
139
+ manual: 'manual',
140
+ 'Cascata: debounce (ms)': 'Cascata: debounce (ms)',
141
+ 'Async Select: loadOn': 'Async Select: loadOn',
142
+ open: 'open',
143
+ init: 'init',
144
+ none: 'none',
145
+ 'Async Select: pageSize': 'Async Select: pageSize',
146
+ 'Async Select: usar cursor': 'Async Select: usar cursor',
147
+ 'LLM provider': 'Provedor LLM',
148
+ 'Select the provider to list models and test the key.': 'Selecione o provedor para listar modelos e testar a chave.',
149
+ 'API key': 'Chave de API',
150
+ 'Enter the selected provider key to test.': 'Informe a chave do provedor selecionado para testar.',
151
+ 'AI model': 'Modelo de IA',
152
+ 'Temperature (Creativity)': 'Temperatura (Criatividade)',
153
+ '0.0 (deterministic) to 1.0 (creative)': '0.0 (determinístico) a 1.0 (criativo)',
154
+ 'Assistant: risk validation': 'Assistente: validação de risco',
155
+ 'Standard': 'Padrão',
156
+ 'Strict requires confirmation for medium/high risk. Standard follows the indication returned by the backend.': 'Estrito exige confirmação em risco médio/alto. Padrão segue a indicação retornada pelo backend.',
157
+ 'Use same LLM for embeddings': 'Embeddings: usar mesmo LLM',
158
+ 'Replicates the LLM provider and key for embeddings.': 'Replica provedor e chave do LLM para embeddings.',
159
+ 'Embeddings provider': 'Embeddings: provedor',
160
+ 'Provider used to generate embeddings (RAG).': 'Provedor usado para gerar embeddings (RAG).',
161
+ 'Embeddings API key': 'Embeddings: chave de API',
162
+ 'Embeddings provider key.': 'Chave do provedor de embeddings.',
163
+ 'Embeddings model': 'Embeddings: modelo',
164
+ 'Provider default': 'Padrão do provedor',
165
+ 'OpenAI models for embeddings.': 'Modelos OpenAI para embeddings.',
166
+ 'Embeddings: dimensions': 'Embeddings: dimensões',
167
+ 'Embedding vector dimensions (default 768).': 'Dimensões do vetor de embedding (default 768).',
168
+ 'Artificial Intelligence': 'Inteligência Artificial',
169
+ 'LLM integration': 'Integração com LLM',
170
+ 'Appearance: density': 'Aparência: densidade',
171
+ 'Appearance: cell padding': 'Aparência: padding das células',
172
+ 'Accepts 1 to 4 CSS measures with units, var(...) or calc(...). Example: 6px 12px': 'Aceita 1 a 4 medidas CSS com unidade, var(...) ou calc(...). Ex.: 6px 12px',
173
+ 'Use 1 to 4 valid CSS measures, such as 6px 12px.': 'Use 1 a 4 medidas CSS válidas, como 6px 12px.',
174
+ 'Appearance: header padding': 'Aparência: padding do cabeçalho',
175
+ 'Accepts 1 to 4 CSS measures with units, var(...) or calc(...). Example: 8px 12px': 'Aceita 1 a 4 medidas CSS com unidade, var(...) ou calc(...). Ex.: 8px 12px',
176
+ 'Use 1 to 4 valid CSS measures, such as 8px 12px.': 'Use 1 a 4 medidas CSS válidas, como 8px 12px.',
177
+ 'Appearance: cell font size': 'Aparência: fonte das células',
178
+ 'Accepts a CSS measure with units, var(...) or calc(...). Example: 13px': 'Aceita uma medida CSS com unidade, var(...) ou calc(...). Ex.: 13px',
179
+ 'Use a valid CSS measure, such as 13px.': 'Use uma medida CSS válida, como 13px.',
180
+ 'Appearance: header font size': 'Aparência: fonte do cabeçalho',
181
+ 'Provedor LLM': 'Provedor LLM',
182
+ 'Selecione o provedor para listar modelos e testar a chave.': 'Selecione o provedor para listar modelos e testar a chave.',
183
+ 'Chave de API': 'Chave de API',
184
+ 'Informe a chave do provedor selecionado para testar.': 'Informe a chave do provedor selecionado para testar.',
185
+ 'Modelo de IA': 'Modelo de IA',
186
+ 'Temperatura (Criatividade)': 'Temperatura (Criatividade)',
187
+ '0.0 (determinístico) a 1.0 (criativo)': '0.0 (determinístico) a 1.0 (criativo)',
188
+ 'Max tokens': 'Max tokens',
189
+ 'Limite maximo de tokens na resposta.': 'Limite maximo de tokens na resposta.',
190
+ 'Assistente: validação de risco': 'Assistente: validação de risco',
191
+ 'Estrito (recomendado)': 'Estrito (recomendado)',
192
+ 'Padrão': 'Padrão',
193
+ 'Estrito exige confirmação em risco médio/alto. Padrão segue a indicação retornada pelo backend.': 'Estrito exige confirmação em risco médio/alto. Padrão segue a indicação retornada pelo backend.',
194
+ 'Embeddings: usar mesmo LLM': 'Embeddings: usar mesmo LLM',
195
+ 'Replica provedor e chave do LLM para embeddings.': 'Replica provedor e chave do LLM para embeddings.',
196
+ 'Embeddings: provedor': 'Embeddings: provedor',
197
+ 'Provedor usado para gerar embeddings (RAG).': 'Provedor usado para gerar embeddings (RAG).',
198
+ 'Embeddings: chave de API': 'Embeddings: chave de API',
199
+ 'Chave do provedor de embeddings.': 'Chave do provedor de embeddings.',
200
+ 'Embeddings: modelo': 'Embeddings: modelo',
201
+ 'Padrão do provedor': 'Padrão do provedor',
202
+ 'Modelos OpenAI para embeddings.': 'Modelos OpenAI para embeddings.',
203
+ 'Embeddings: dimensoes': 'Embeddings: dimensões',
204
+ 'Dimensoes do vetor de embedding (default 768).': 'Dimensões do vetor de embedding (default 768).',
205
+ 'GPT models for text and chat.': 'Modelos GPT para texto e chat.',
206
+ 'Synchronized with the LLM. The fields below follow the primary credential.': 'Sincronizado com o LLM. Os campos abaixo acompanham a credencial principal.',
207
+ 'Example JSON: {"containerColor":"var(--md-sys-color-surface)","containerBorderColor":"var(--md-sys-color-outline-variant)","backdropColor":"var(--md-sys-color-scrim)"}': 'Ex.: {"containerColor":"var(--md-sys-color-surface)","containerBorderColor":"var(--md-sys-color-outline-variant)","backdropColor":"var(--md-sys-color-scrim)"}',
208
+ 'Example JSON array: [{"id":"cancel","text":"Cancel","role":"secondary","close":true,"cssClass":"btn"},{"id":"confirm","text":"Delete","role":"primary","close":true,"cssClass":"btn btn-danger","icon":"delete"}]': 'Ex.: [{"id":"cancel","text":"Cancelar","role":"secondary","close":true,"cssClass":"btn"},{"id":"confirm","text":"Excluir","role":"primary","close":true,"cssClass":"btn btn-danger","icon":"delete"}]',
209
+ 'Example JSON: {"containerColor":"var(--md-sys-color-surface)","containerBorderColor":"var(--md-sys-color-outline-variant)","backdropColor":"var(--md-sys-color-scrim)","actionButtonRadius":"8px"}': 'Ex.: {"containerColor":"var(--md-sys-color-surface)","containerBorderColor":"var(--md-sys-color-outline-variant)","backdropColor":"var(--md-sys-color-scrim)","actionButtonRadius":"8px"}',
210
+ 'Desabilitar cache de schema (LocalStorage)': 'Desabilitar cache de schema (LocalStorage)',
211
+ 'Se ativo, sempre baixa o schema do servidor (ignora cache local). Útil para desenvolvimento.': 'Se ativo, sempre baixa o schema do servidor (ignora cache local). Útil para desenvolvimento.',
212
+ 'Paginação habilitada': 'Paginação habilitada',
213
+ 'Tamanho da página': 'Tamanho da página',
214
+ 'Ordenação habilitada': 'Ordenação habilitada',
215
+ 'Seleção habilitada': 'Seleção habilitada',
216
+ 'Paginação: estratégia': 'Paginação: estratégia',
217
+ 'Ordenação: estratégia': 'Ordenação: estratégia',
218
+ 'Paginação: botões Primeiro/Último': 'Paginação: botões Primeiro/Último',
219
+ 'Toolbar visível': 'Toolbar visível',
220
+ 'Cache & Persistência': 'Cache & Persistence',
221
+ Tabela: 'Table',
222
+ Salvar: 'Save',
223
+ Cancelar: 'Cancel',
224
+ Redefinir: 'Reset',
225
+ };
226
+ const PRAXIS_SETTINGS_PANEL_GLOBAL_CONFIG_EDITOR_EN_US = {
227
+ CRUD: 'CRUD',
228
+ 'Dynamic Fields': 'Dynamic Fields',
229
+ 'Cache & Persistence': 'Cache & Persistence',
230
+ Table: 'Table',
231
+ Dialog: 'Dialog',
232
+ 'Settings saved': 'Settings saved',
233
+ 'Save failed.': 'Save failed.',
234
+ 'Global settings': 'Global settings',
235
+ 'Global policies for opening, back and header': 'Global policies for opening, back and header',
236
+ 'Server defaults (env vars)': 'Server defaults (env vars)',
237
+ 'Saved configuration (UI) - overrides server defaults': 'Saved configuration (UI) - overrides server defaults',
238
+ 'Failed to test connection.': 'Failed to test connection.',
239
+ 'Connection established successfully!': 'Connection established successfully!',
240
+ 'Unknown error': 'Unknown error',
241
+ 'Key provided': 'Key provided',
242
+ 'Saved key (****{{last4}})': 'Saved key (****{{last4}})',
243
+ 'Saved key': 'Saved key',
244
+ 'Test connection with the provided key': 'Test connection with the provided key',
245
+ 'Test connection': 'Test connection',
246
+ 'Refresh model list': 'Refresh model list',
247
+ Close: 'Close',
248
+ 'This provider has no model catalog.': 'This provider has no model catalog.',
249
+ 'Enter an API key to fetch models.': 'Enter an API key to fetch models.',
250
+ 'Error fetching models.': 'Error fetching models.',
251
+ 'Error fetching models. Check your API key.': 'Error fetching models. Check your API key.',
252
+ 'Model list updated ({{count}} models)': 'Model list updated ({{count}} models)',
253
+ 'Enter an API key to test.': 'Enter an API key to test.',
254
+ 'No model details available.': 'No model details available.',
255
+ 'Model: {{model}} | Tokens (in/out): {{in}}/{{out}} | Methods: {{methods}}': 'Model: {{model}} | Tokens (in/out): {{in}}/{{out}} | Methods: {{methods}}',
256
+ 'Global config cleared. Using server defaults.': 'Global config cleared. Using server defaults.',
257
+ 'Clear saved config and return to server defaults': 'Clear saved config and return to server defaults',
258
+ 'Failed to clear global config.': 'Failed to clear global config.',
259
+ 'No key required': 'No key required',
260
+ 'Model & Behavior': 'Model & Behavior',
261
+ 'Choose the model after validating the key.': 'Choose the model after validating the key.',
262
+ 'API key validated required': 'Validated API key required',
263
+ 'Configure and test your API key to unlock model selection.': 'Configure and test your API key to unlock model selection.',
264
+ 'Embeddings (RAG)': 'Embeddings (RAG)',
265
+ 'Use the LLM provider and key for embeddings': 'Apply the LLM provider and key to embeddings',
266
+ 'Provider has no embeddings': 'Provider has no embeddings',
267
+ 'Configure the embeddings provider for vector search (templates and schemas).': 'Configure the embeddings provider for vector search (templates and schemas).',
268
+ 'Embedding dimension mismatch with database (768). Adjust to 768 or redo the migration.': 'Embedding dimension mismatch with the database (768). Adjust to 768 or redo the migration.',
269
+ 'Toolbar, appearance and advanced filter': 'Toolbar, appearance and advanced filter',
270
+ 'Defaults and variants (danger, info, success, question, error)': 'Defaults and variants (danger, info, success, question, error)',
271
+ 'Icons by profile (shortcuts)': 'Icons by profile (shortcuts)',
272
+ 'Pick icon': 'Pick icon',
273
+ 'Pick icon for {{key}}': 'Pick icon for {{key}}',
274
+ 'Clear icon': 'Clear icon',
275
+ 'Clear icon for {{key}}': 'Clear icon for {{key}}',
276
+ 'The text field above remains editable. These buttons only help with selection/clear preview.': 'The text field above remains editable. These buttons only help with selection/clear preview.',
277
+ 'No saved key': 'No saved key',
278
+ 'Aparência: densidade': 'Appearance: density',
279
+ compact: 'compact',
280
+ comfortable: 'comfortable',
281
+ spacious: 'spacious',
282
+ 'Aparência: padding das células': 'Appearance: cell padding',
283
+ 'Aceita 1 a 4 medidas CSS com unidade, var(...) ou calc(...). Ex.: 6px 12px': 'Accepts 1 to 4 CSS measures with units, var(...) or calc(...). Example: 6px 12px',
284
+ 'Use 1 a 4 medidas CSS válidas, como 6px 12px.': 'Use 1 to 4 valid CSS measures, such as 6px 12px.',
285
+ 'Aparência: padding do cabeçalho': 'Appearance: header padding',
286
+ 'Aceita 1 a 4 medidas CSS com unidade, var(...) ou calc(...). Ex.: 8px 12px': 'Accepts 1 to 4 CSS measures with units, var(...) or calc(...). Example: 8px 12px',
287
+ 'Use 1 a 4 medidas CSS válidas, como 8px 12px.': 'Use 1 to 4 valid CSS measures, such as 8px 12px.',
288
+ 'Aparência: fonte das células': 'Appearance: cell font size',
289
+ 'Aceita uma medida CSS com unidade, var(...) ou calc(...). Ex.: 13px': 'Accepts a CSS measure with units, var(...) or calc(...). Example: 13px',
290
+ 'Use uma medida CSS válida, como 13px.': 'Use a valid CSS measure, such as 13px.',
291
+ 'Aparência: fonte do cabeçalho': 'Appearance: header font size',
292
+ 'Filtro: modo de abertura': 'Filter: open mode',
293
+ overlay: 'overlay',
294
+ 'Filtro: overlay (visual)': 'Filter: overlay (visual)',
295
+ card: 'card',
296
+ frosted: 'frosted',
297
+ 'Filtro: backdrop no overlay': 'Filter: overlay backdrop',
298
+ 'Excluir — confirmação': 'Delete - confirmation',
299
+ 'Excluir (múltiplos) — confirmação': 'Delete (multiple) - confirmation',
300
+ 'Salvar — confirmação': 'Save - confirmation',
301
+ 'Cancelar — confirmação': 'Cancel - confirmation',
302
+ 'Exportar — confirmação': 'Export - confirmation',
303
+ 'Excluir — progresso': 'Delete - progress',
304
+ 'Excluir (múltiplos) — progresso': 'Delete (multiple) - progress',
305
+ 'Excluir — sucesso': 'Delete - success',
306
+ 'Salvar — sucesso': 'Save - success',
307
+ 'Exportar — sucesso': 'Export - success',
308
+ 'Importar — sucesso': 'Import - success',
309
+ 'Excluir — erro': 'Delete - error',
310
+ 'Salvar — erro': 'Save - error',
311
+ 'Exportar — erro': 'Export - error',
312
+ 'Rede — erro': 'Network - error',
313
+ 'Permissão — erro': 'Permission - error',
314
+ 'Modo de abertura padrão': 'Default opening mode',
315
+ Rota: 'Route',
316
+ 'Aplicado quando ação/metadado não definem modo.': 'Applied when the action/metadata does not define a mode.',
317
+ 'Confirmar ao sair com alterações': 'Confirm when leaving with unsaved changes',
318
+ 'Back: estratégia': 'Back: strategy',
319
+ 'Modal: largura (ex.: 900px)': 'Modal: width (e.g. 900px)',
320
+ 'Modal: largura máxima (ex.: 96vw)': 'Modal: max width (e.g. 96vw)',
321
+ 'Modal: backdrop': 'Modal: backdrop',
322
+ blur: 'blur',
323
+ dim: 'dim',
324
+ transparent: 'transparent',
325
+ 'Estratégia de primeira carga quando metadado não definir.': 'First-load strategy when metadata does not define one.',
326
+ 'Async Select, cascade and pagination': 'Async Select, cascade and pagination',
327
+ 'Cascata nativa habilitada': 'Native cascade enabled',
328
+ 'Cascata: loadOnChange': 'Cascade: loadOnChange',
329
+ respectLoadOn: 'respectLoadOn',
330
+ immediate: 'immediate',
331
+ manual: 'manual',
332
+ 'Cascata: debounce (ms)': 'Cascade: debounce (ms)',
333
+ 'Async Select: loadOn': 'Async Select: loadOn',
334
+ open: 'open',
335
+ init: 'init',
336
+ none: 'none',
337
+ 'Async Select: pageSize': 'Async Select: pageSize',
338
+ 'Async Select: usar cursor': 'Async Select: use cursor',
339
+ 'LLM provider': 'LLM provider',
340
+ 'Select the provider to list models and test the key.': 'Select the provider to list models and test the key.',
341
+ 'API key': 'API key',
342
+ 'Enter the selected provider key to test.': 'Enter the selected provider key to test.',
343
+ 'AI model': 'AI model',
344
+ 'Temperature (Creativity)': 'Temperature (Creativity)',
345
+ '0.0 (deterministic) to 1.0 (creative)': '0.0 (deterministic) to 1.0 (creative)',
346
+ 'Assistant: risk validation': 'Assistant: risk validation',
347
+ 'Standard': 'Standard',
348
+ 'Strict requires confirmation for medium/high risk. Standard follows the indication returned by the backend.': 'Strict requires confirmation for medium/high risk. Standard follows the indication returned by the backend.',
349
+ 'Use same LLM for embeddings': 'Use same LLM for embeddings',
350
+ 'Replicates the LLM provider and key for embeddings.': 'Replicates the LLM provider and key for embeddings.',
351
+ 'Embeddings provider': 'Embeddings provider',
352
+ 'Provider used to generate embeddings (RAG).': 'Provider used to generate embeddings (RAG).',
353
+ 'Embeddings API key': 'Embeddings API key',
354
+ 'Embeddings provider key.': 'Embeddings provider key.',
355
+ 'Embeddings model': 'Embeddings model',
356
+ 'Provider default': 'Provider default',
357
+ 'OpenAI models for embeddings.': 'OpenAI models for embeddings.',
358
+ 'Embeddings: dimensions': 'Embeddings: dimensions',
359
+ 'Embedding vector dimensions (default 768).': 'Embedding vector dimensions (default 768).',
360
+ 'Artificial Intelligence': 'Artificial Intelligence',
361
+ 'LLM integration': 'LLM integration',
362
+ 'Appearance: density': 'Appearance: density',
363
+ 'Appearance: cell padding': 'Appearance: cell padding',
364
+ 'Accepts 1 to 4 CSS measures with units, var(...) or calc(...). Example: 6px 12px': 'Accepts 1 to 4 CSS measures with units, var(...) or calc(...). Example: 6px 12px',
365
+ 'Use 1 to 4 valid CSS measures, such as 6px 12px.': 'Use 1 to 4 valid CSS measures, such as 6px 12px.',
366
+ 'Appearance: header padding': 'Appearance: header padding',
367
+ 'Accepts 1 to 4 CSS measures with units, var(...) or calc(...). Example: 8px 12px': 'Accepts 1 to 4 CSS measures with units, var(...) or calc(...). Example: 8px 12px',
368
+ 'Use 1 to 4 valid CSS measures, such as 8px 12px.': 'Use 1 to 4 valid CSS measures, such as 8px 12px.',
369
+ 'Appearance: cell font size': 'Appearance: cell font size',
370
+ 'Accepts a CSS measure with units, var(...) or calc(...). Example: 13px': 'Accepts a CSS measure with units, var(...) or calc(...). Example: 13px',
371
+ 'Use a valid CSS measure, such as 13px.': 'Use a valid CSS measure, such as 13px.',
372
+ 'Appearance: header font size': 'Appearance: header font size',
373
+ 'Provedor LLM': 'LLM provider',
374
+ 'Selecione o provedor para listar modelos e testar a chave.': 'Select the provider to list models and test the key.',
375
+ 'Chave de API': 'API key',
376
+ 'Informe a chave do provedor selecionado para testar.': 'Enter the selected provider key to test.',
377
+ 'Modelo de IA': 'AI model',
378
+ 'Temperatura (Criatividade)': 'Temperature (Creativity)',
379
+ '0.0 (determinístico) a 1.0 (criativo)': '0.0 (deterministic) to 1.0 (creative)',
380
+ 'Max tokens': 'Max tokens',
381
+ 'Limite maximo de tokens na resposta.': 'Maximum token limit for the response.',
382
+ 'Assistente: validação de risco': 'Assistant: risk validation',
383
+ 'Estrito (recomendado)': 'Strict (recommended)',
384
+ 'Padrão': 'Standard',
385
+ 'Estrito exige confirmação em risco médio/alto. Padrão segue a indicação retornada pelo backend.': 'Strict requires confirmation for medium/high risk. Standard follows the indication returned by the backend.',
386
+ 'Embeddings: usar mesmo LLM': 'Embeddings: use same LLM',
387
+ 'Replica provedor e chave do LLM para embeddings.': 'Replicates the LLM provider and key for embeddings.',
388
+ 'Embeddings: provedor': 'Embeddings: provider',
389
+ 'Provedor usado para gerar embeddings (RAG).': 'Provider used to generate embeddings (RAG).',
390
+ 'Embeddings: chave de API': 'Embeddings: API key',
391
+ 'Chave do provedor de embeddings.': 'Embeddings provider key.',
392
+ 'Embeddings: modelo': 'Embeddings: model',
393
+ 'Padrão do provedor': 'Provider default',
394
+ 'Modelos OpenAI para embeddings.': 'OpenAI models for embeddings.',
395
+ 'Embeddings: dimensoes': 'Embeddings: dimensions',
396
+ 'Dimensoes do vetor de embedding (default 768).': 'Embedding vector dimensions (default 768).',
397
+ 'GPT models for text and chat.': 'GPT models for text and chat.',
398
+ 'Synchronized with the LLM. The fields below follow the primary credential.': 'Synchronized with the LLM. The fields below follow the primary credential.',
399
+ 'Example JSON: {"containerColor":"var(--md-sys-color-surface)","containerBorderColor":"var(--md-sys-color-outline-variant)","backdropColor":"var(--md-sys-color-scrim)"}': 'Example: {"containerColor":"var(--md-sys-color-surface)","containerBorderColor":"var(--md-sys-color-outline-variant)","backdropColor":"var(--md-sys-color-scrim)"}',
400
+ 'Example JSON array: [{"id":"cancel","text":"Cancel","role":"secondary","close":true,"cssClass":"btn"},{"id":"confirm","text":"Delete","role":"primary","close":true,"cssClass":"btn btn-danger","icon":"delete"}]': 'Example: [{"id":"cancel","text":"Cancel","role":"secondary","close":true,"cssClass":"btn"},{"id":"confirm","text":"Delete","role":"primary","close":true,"cssClass":"btn btn-danger","icon":"delete"}]',
401
+ 'Example JSON: {"containerColor":"var(--md-sys-color-surface)","containerBorderColor":"var(--md-sys-color-outline-variant)","backdropColor":"var(--md-sys-color-scrim)","actionButtonRadius":"8px"}': 'Example: {"containerColor":"var(--md-sys-color-surface)","containerBorderColor":"var(--md-sys-color-outline-variant)","backdropColor":"var(--md-sys-color-scrim)","actionButtonRadius":"8px"}',
402
+ 'Desabilitar cache de schema (LocalStorage)': 'Disable schema cache (LocalStorage)',
403
+ 'Se ativo, sempre baixa o schema do servidor (ignora cache local). Útil para desenvolvimento.': 'If enabled, always downloads the schema from the server (ignores local cache). Useful for development.',
404
+ 'Paginação habilitada': 'Pagination enabled',
405
+ 'Tamanho da página': 'Page size',
406
+ 'Ordenação habilitada': 'Sorting enabled',
407
+ 'Seleção habilitada': 'Selection enabled',
408
+ 'Paginação: estratégia': 'Pagination: strategy',
409
+ 'Ordenação: estratégia': 'Sorting: strategy',
410
+ 'Paginação: botões Primeiro/Último': 'Pagination: First/Last buttons',
411
+ 'Toolbar visível': 'Toolbar visible',
412
+ 'Cache & Persistência': 'Cache & Persistence',
413
+ Tabela: 'Table',
414
+ Salvar: 'Save',
415
+ Cancelar: 'Cancel',
416
+ Redefinir: 'Reset',
417
+ };
418
+
419
+ const PRAXIS_SETTINGS_PANEL_EN_US = {
420
+ 'Operation in progress...': 'Operation in progress...',
421
+ 'The form contains errors that need to be fixed.': 'The form contains errors that need to be fixed.',
422
+ 'No changes to apply or save.': 'No changes to apply or save.',
423
+ 'Unsaved changes': 'Unsaved changes',
424
+ 'Saved at {{time}}': 'Saved at {{time}}',
425
+ 'No changes': 'No changes',
426
+ 'Reset Changes': 'Reset Changes',
427
+ 'Are you sure you want to reset all changes?': 'Are you sure you want to reset all changes?',
428
+ Reset: 'Reset',
429
+ Cancel: 'Cancel',
430
+ 'Discard Changes': 'Discard Changes',
431
+ 'You have unsaved changes. Are you sure you want to discard them?': 'You have unsaved changes. Are you sure you want to discard them?',
432
+ Discard: 'Discard',
433
+ 'Continue Editing': 'Continue Editing',
434
+ 'Collapse panel': 'Collapse panel',
435
+ 'Expand panel': 'Expand panel',
436
+ Close: 'Close',
437
+ Apply: 'Apply',
438
+ 'Save & Close': 'Save & Close',
439
+ };
440
+
441
+ const PRAXIS_SETTINGS_PANEL_PT_BR = {
442
+ 'Operation in progress...': 'Operação em andamento...',
443
+ 'The form contains errors that need to be fixed.': 'O formulário contém erros que precisam ser corrigidos.',
444
+ 'No changes to apply or save.': 'Nenhuma alteração para aplicar ou salvar.',
445
+ 'Unsaved changes': 'Alterações não salvas',
446
+ 'Saved at {{time}}': 'Salvo às {{time}}',
447
+ 'No changes': 'Sem alterações',
448
+ 'Reset Changes': 'Redefinir Alterações',
449
+ 'Are you sure you want to reset all changes?': 'Tem certeza de que deseja redefinir todas as alterações?',
450
+ Reset: 'Redefinir',
451
+ Cancel: 'Cancelar',
452
+ 'Discard Changes': 'Descartar Alterações',
453
+ 'You have unsaved changes. Are you sure you want to discard them?': 'Você tem alterações não salvas. Tem certeza de que deseja descartá-las?',
454
+ Discard: 'Descartar',
455
+ 'Continue Editing': 'Continuar Editando',
456
+ 'Collapse panel': 'Reduzir painel',
457
+ 'Expand panel': 'Expandir painel',
458
+ Close: 'Fechar',
459
+ Apply: 'Aplicar',
460
+ 'Save & Close': 'Salvar & Fechar',
461
+ };
462
+
463
+ const PRAXIS_SETTINGS_PANEL_I18N_NAMESPACE = 'praxis-settings-panel';
464
+ const PRAXIS_SETTINGS_PANEL_DEFAULT_TITLE = 'Global settings';
465
+ function providePraxisSettingsPanelI18n() {
466
+ return providePraxisI18n({
467
+ namespaces: {
468
+ [PRAXIS_SETTINGS_PANEL_I18N_NAMESPACE]: {
469
+ 'pt-BR': {
470
+ ...PRAXIS_SETTINGS_PANEL_PT_BR,
471
+ ...PRAXIS_SETTINGS_PANEL_GLOBAL_CONFIG_EDITOR_PT_BR,
472
+ },
473
+ 'en-US': {
474
+ ...PRAXIS_SETTINGS_PANEL_EN_US,
475
+ ...PRAXIS_SETTINGS_PANEL_GLOBAL_CONFIG_EDITOR_EN_US,
476
+ },
477
+ },
478
+ },
479
+ });
480
+ }
481
+
31
482
  class SettingsPanelComponent {
32
483
  cdr;
33
484
  dialog;
@@ -42,6 +493,13 @@ class SettingsPanelComponent {
42
493
  isValid = true;
43
494
  isBusy = false;
44
495
  lastSavedAt = null;
496
+ destroyRef = inject(DestroyRef);
497
+ i18n = inject(PraxisI18nService);
498
+ contentHost;
499
+ constructor(cdr, dialog) {
500
+ this.cdr = cdr;
501
+ this.dialog = dialog;
502
+ }
45
503
  get canApply() {
46
504
  return this.isDirty && this.isValid && !this.isBusy;
47
505
  }
@@ -50,13 +508,13 @@ class SettingsPanelComponent {
50
508
  }
51
509
  get disabledReason() {
52
510
  if (this.isBusy) {
53
- return 'Operação em andamento...';
511
+ return this.tx('Operation in progress...');
54
512
  }
55
513
  if (!this.isValid) {
56
- return 'O formulário contém erros que precisam ser corrigidos.';
514
+ return this.tx('The form contains errors that need to be fixed.');
57
515
  }
58
516
  if (!this.isDirty) {
59
- return 'Nenhuma alteração para aplicar ou salvar.';
517
+ return this.tx('No changes to apply or save.');
60
518
  }
61
519
  return '';
62
520
  }
@@ -71,21 +529,20 @@ class SettingsPanelComponent {
71
529
  }
72
530
  get statusMessage() {
73
531
  if (this.statusTone === 'busy') {
74
- return 'Operação em andamento...';
532
+ return this.tx('Operation in progress...');
75
533
  }
76
534
  if (this.statusTone === 'dirty') {
77
- return 'Alterações não salvas';
535
+ return this.tx('Unsaved changes');
78
536
  }
79
537
  if (this.statusTone === 'saved' && this.lastSavedAt) {
80
- return `Salvo às ${this.formatClock(this.lastSavedAt)}`;
538
+ return this.tx('Saved at {{time}}', {
539
+ time: this.formatClock(this.lastSavedAt),
540
+ });
81
541
  }
82
- return 'Sem alterações';
542
+ return this.tx('No changes');
83
543
  }
84
- destroyRef = inject(DestroyRef);
85
- contentHost;
86
- constructor(cdr, dialog) {
87
- this.cdr = cdr;
88
- this.dialog = dialog;
544
+ tx(text, params) {
545
+ return this.i18n.t(text, params, text, PRAXIS_SETTINGS_PANEL_I18N_NAMESPACE);
89
546
  }
90
547
  attachContent(component, injector, ref, inputs) {
91
548
  this.ref = ref;
@@ -118,7 +575,6 @@ class SettingsPanelComponent {
118
575
  this.cdr.markForCheck();
119
576
  });
120
577
  }
121
- // Generic output bridging: if the embedded component emits `selected`, save and close.
122
578
  try {
123
579
  const selected$ = instance?.selected;
124
580
  if (selected$ && typeof selected$.subscribe === 'function') {
@@ -126,7 +582,6 @@ class SettingsPanelComponent {
126
582
  ? selected$.pipe(takeUntilDestroyed(this.destroyRef))
127
583
  : selected$;
128
584
  obs.subscribe((value) => {
129
- // Apply emits value to the opener without closing the panel.
130
585
  this.ref.apply(value);
131
586
  });
132
587
  }
@@ -164,10 +619,10 @@ class SettingsPanelComponent {
164
619
  }
165
620
  onReset() {
166
621
  const dialogData = {
167
- title: 'Redefinir Alterações',
168
- message: 'Tem certeza de que deseja redefinir todas as alterações?',
169
- confirmText: 'Redefinir',
170
- cancelText: 'Cancelar',
622
+ title: this.tx('Reset Changes'),
623
+ message: this.tx('Are you sure you want to reset all changes?'),
624
+ confirmText: this.tx('Reset'),
625
+ cancelText: this.tx('Cancel'),
171
626
  type: 'warning',
172
627
  icon: 'restart_alt',
173
628
  };
@@ -219,15 +674,21 @@ class SettingsPanelComponent {
219
674
  this.cdr.markForCheck();
220
675
  }
221
676
  formatClock(timestamp) {
677
+ const options = {
678
+ hour: '2-digit',
679
+ minute: '2-digit',
680
+ second: '2-digit',
681
+ };
222
682
  try {
223
- return new Intl.DateTimeFormat('pt-BR', {
224
- hour: '2-digit',
225
- minute: '2-digit',
226
- second: '2-digit',
227
- }).format(timestamp);
683
+ return new Intl.DateTimeFormat(this.i18n.getLocale(), options).format(timestamp);
228
684
  }
229
685
  catch {
230
- return '';
686
+ try {
687
+ return new Intl.DateTimeFormat(this.i18n.getFallbackLocale(), options).format(timestamp);
688
+ }
689
+ catch {
690
+ return '';
691
+ }
231
692
  }
232
693
  }
233
694
  toggleExpand() {
@@ -241,10 +702,10 @@ class SettingsPanelComponent {
241
702
  return of(true);
242
703
  }
243
704
  const dialogData = {
244
- title: 'Descartar Alterações',
245
- message: 'Você tem alterações não salvas. Tem certeza de que deseja descartá-las?',
246
- confirmText: 'Descartar',
247
- cancelText: 'Continuar Editando',
705
+ title: this.tx('Discard Changes'),
706
+ message: this.tx('You have unsaved changes. Are you sure you want to discard them?'),
707
+ confirmText: this.tx('Discard'),
708
+ cancelText: this.tx('Continue Editing'),
248
709
  type: 'warning',
249
710
  icon: 'warning',
250
711
  };
@@ -265,13 +726,14 @@ class SettingsPanelComponent {
265
726
  event.preventDefault();
266
727
  this.onSave();
267
728
  }
268
- else if ((event.key === 's' || event.key === 'S') && (event.ctrlKey || event.metaKey)) {
729
+ else if ((event.key === 's' || event.key === 'S') &&
730
+ (event.ctrlKey || event.metaKey)) {
269
731
  event.preventDefault();
270
732
  this.onSave();
271
733
  }
272
734
  }
273
735
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: SettingsPanelComponent, deps: [{ token: i0.ChangeDetectorRef }, { token: i1.MatDialog }], target: i0.ɵɵFactoryTarget.Component });
274
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.17", type: SettingsPanelComponent, isStandalone: true, selector: "praxis-settings-panel", host: { listeners: { "document:keydown": "handleKeydown($event)" } }, viewQueries: [{ propertyName: "contentHost", first: true, predicate: ["contentHost"], descendants: true, read: ViewContainerRef, static: true }], ngImport: i0, template: "<div\n class=\"settings-panel\"\n data-testid=\"settings-panel-root\"\n [class.expanded]=\"expanded\"\n role=\"dialog\"\n aria-modal=\"true\"\n [attr.aria-labelledby]=\"titleId\"\n cdkTrapFocus\n cdkTrapFocusAutoCapture\n>\n <header class=\"settings-panel-header\">\n <h2 class=\"settings-panel-title\" [id]=\"titleId\">\n <mat-icon *ngIf=\"titleIcon\" class=\"title-icon\" [praxisIcon]=\"titleIcon\"></mat-icon>\n <span>{{ title }}</span>\n </h2>\n <span class=\"spacer\"></span>\n <button\n mat-icon-button\n type=\"button\"\n data-testid=\"settings-panel-toggle-expand\"\n [attr.aria-label]=\"expanded ? 'Reduzir painel' : 'Expandir painel'\"\n [attr.aria-expanded]=\"expanded\"\n [matTooltip]=\"expanded ? 'Reduzir painel' : 'Expandir painel'\"\n (click)=\"toggleExpand()\"\n >\n <mat-icon [praxisIcon]=\"expanded ? 'close_fullscreen' : 'open_in_full'\"></mat-icon>\n </button>\n <button\n mat-icon-button\n type=\"button\"\n data-testid=\"settings-panel-close-icon\"\n aria-label=\"Fechar\"\n matTooltip=\"Fechar\"\n (click)=\"onCancel()\"\n >\n <mat-icon [praxisIcon]=\"'close'\"></mat-icon>\n </button>\n </header>\n <div\n class=\"settings-panel-status\"\n [attr.data-status]=\"statusTone\"\n role=\"status\"\n aria-live=\"polite\"\n >\n <mat-icon\n aria-hidden=\"true\"\n [praxisIcon]=\"\n statusTone === 'dirty'\n ? 'warning'\n : statusTone === 'saved'\n ? 'check_circle'\n : statusTone === 'busy'\n ? 'autorenew'\n : 'info'\n \"\n ></mat-icon>\n <span>{{ statusMessage }}</span>\n </div>\n <div class=\"settings-panel-body\">\n <ng-template #contentHost></ng-template>\n </div>\n <footer class=\"settings-panel-footer\">\n <button mat-button type=\"button\" data-testid=\"settings-panel-reset\" (click)=\"onReset()\" [disabled]=\"isBusy\">\n <mat-icon aria-hidden=\"true\" [praxisIcon]=\"'restart_alt'\"></mat-icon>\n <span>Redefinir</span>\n </button>\n <span class=\"spacer\"></span>\n <button\n mat-button\n type=\"button\"\n data-testid=\"settings-panel-cancel\"\n (click)=\"onCancel()\"\n [disabled]=\"isBusy\"\n >\n <mat-icon aria-hidden=\"true\" [praxisIcon]=\"'close'\"></mat-icon>\n <span>Cancelar</span>\n </button>\n <button\n mat-stroked-button\n type=\"button\"\n data-testid=\"settings-panel-apply\"\n (click)=\"onApply()\"\n [disabled]=\"!canApply\"\n [matTooltip]=\"disabledReason\"\n [matTooltipDisabled]=\"canApply\"\n [attr.aria-busy]=\"isBusy\"\n >\n <mat-progress-spinner\n *ngIf=\"isBusy\"\n mode=\"indeterminate\"\n diameter=\"20\"\n ></mat-progress-spinner>\n <ng-container *ngIf=\"!isBusy\">\n <mat-icon aria-hidden=\"true\" [praxisIcon]=\"'done'\"></mat-icon>\n <span>Aplicar</span>\n </ng-container>\n </button>\n <button\n mat-flat-button\n color=\"primary\"\n type=\"button\"\n data-testid=\"settings-panel-save\"\n (click)=\"onSave()\"\n [disabled]=\"!canSave\"\n [matTooltip]=\"disabledReason\"\n [matTooltipDisabled]=\"canSave\"\n [attr.aria-busy]=\"isBusy\"\n >\n <mat-progress-spinner\n *ngIf=\"isBusy\"\n mode=\"indeterminate\"\n diameter=\"20\"\n ></mat-progress-spinner>\n <ng-container *ngIf=\"!isBusy\">\n <mat-icon aria-hidden=\"true\" [praxisIcon]=\"'save'\"></mat-icon>\n <span>Salvar &amp; Fechar</span>\n </ng-container>\n </button>\n </footer>\n</div>\n", styles: ["@charset \"UTF-8\";:host{display:block;height:100%}.settings-panel{display:grid;grid-template-rows:auto auto 1fr auto;grid-template-areas:\"header\" \"status\" \"body\" \"footer\";height:100%;background:var(--md-sys-color-surface-container);color:var(--md-sys-color-on-surface);border-left:1px solid var(--md-sys-color-outline-variant);width:var(--pfx-settings-panel-width, 720px);transition:width .3s ease;overflow:hidden}.settings-panel.expanded{width:min(var(--pfx-settings-panel-width-expanded, 95vw),var(--pfx-settings-panel-max-width, 2400px))}.settings-panel-header{grid-area:header;display:flex;align-items:center;gap:var(--pfx-settings-panel-header-gap, 8px);padding:0 var(--pfx-settings-panel-header-padding-x, 16px);height:var(--pfx-settings-panel-header-height, 64px);border-bottom:1px solid var(--md-sys-color-outline-variant);background:var(--md-sys-color-surface-container-high);box-shadow:var(--pfx-settings-panel-header-shadow, var(--md-sys-elevation-level1, 0 2px 6px rgba(0, 0, 0, .08)));flex-shrink:0}.settings-panel-header .spacer{flex:1}.settings-panel-status{grid-area:status;display:flex;align-items:center;gap:8px;min-height:36px;padding:6px 16px;border-bottom:1px solid var(--md-sys-color-outline-variant);background:var(--md-sys-color-surface-container-high);color:var(--md-sys-color-on-surface);font-size:.85rem;font-weight:500}.settings-panel-status mat-icon{width:18px;height:18px;font-size:18px}.settings-panel-status[data-status=dirty]{color:var(--md-sys-color-error);background:color-mix(in srgb,var(--md-sys-color-error-container) 30%,var(--md-sys-color-surface-container-high))}.settings-panel-status[data-status=saved]{color:var(--md-sys-color-primary);background:color-mix(in srgb,var(--md-sys-color-primary-container) 28%,var(--md-sys-color-surface-container-high))}.settings-panel-body{grid-area:body;overflow-y:auto;min-height:0;padding:var(--pfx-settings-panel-body-padding, 8px 8px 24px 8px);background:var(--md-sys-color-surface);display:flex;flex-direction:column}.settings-panel-content{display:block}.settings-panel-footer{grid-area:footer;border-top:1px solid var(--md-sys-color-outline-variant);background:var(--md-sys-color-surface-container-high);box-shadow:var(--pfx-settings-panel-footer-shadow, var(--md-sys-elevation-level1, 0 -2px 6px rgba(0, 0, 0, .08)));display:flex;align-items:center;padding:var(--pfx-settings-panel-footer-padding, 12px 16px);column-gap:var(--pfx-settings-panel-footer-gap, 12px);flex-shrink:0}.spacer{flex:1}.settings-panel-title{display:inline-flex;align-items:center;gap:var(--pfx-settings-panel-title-gap, 8px);font-weight:700;letter-spacing:.2px;margin:0}.settings-panel-title mat-icon{color:var(--md-sys-color-primary)}.settings-panel-title .title-icon{width:20px;height:20px;font-size:20px}.settings-panel-footer button+button{margin-left:var(--pfx-settings-panel-footer-gap, 12px)}.settings-panel-footer button{display:inline-flex;align-items:center}.settings-panel-footer button .mat-icon{font-size:20px;width:20px;height:20px;line-height:1;display:inline-flex;align-items:center;justify-content:center}.settings-panel-footer .mat-button-wrapper{display:inline-flex;align-items:center;gap:var(--pfx-settings-panel-button-gap, 8px)}.settings-panel-footer .mat-progress-spinner{margin-right:8px}.settings-panel-footer .mat-flat-button[color=primary]{font-weight:600}:host ::ng-deep .settings-panel .mdc-button__label{display:inline-flex;align-items:center;gap:var(--pfx-settings-panel-button-gap, 8px);line-height:1}:host ::ng-deep .settings-panel .mdc-button__label>span{display:inline-flex;align-items:center;line-height:1}:host ::ng-deep .settings-panel .mdc-button__label .mat-icon{display:inline-flex;align-items:center;justify-content:center;line-height:1}:host ::ng-deep .praxis-settings-panel-backdrop{background:var(--pfx-backdrop, var(--md-sys-color-scrim, rgba(0, 0, 0, .45)));backdrop-filter:blur(var(--pfx-backdrop-blur, 6px)) saturate(110%);-webkit-backdrop-filter:blur(var(--pfx-backdrop-blur, 6px)) saturate(110%)}.settings-panel .mat-divider{background-color:var(--md-sys-color-outline-variant)!important}.settings-panel .mat-expansion-panel{background:var(--md-sys-color-surface-container);border:1px solid var(--md-sys-color-outline-variant);border-radius:var(--md-sys-shape-corner-medium, 12px);box-shadow:var(--md-sys-elevation-level1, 0 2px 8px rgba(0, 0, 0, .08))}.settings-panel .mat-expansion-panel-header{background:var(--md-sys-color-surface-container);color:var(--md-sys-color-on-surface)}.settings-panel .mat-expansion-panel-header mat-icon,.settings-panel .mat-expansion-panel-header .mat-icon{color:var(--md-sys-color-on-surface)!important}.settings-panel .mat-expansion-panel-header .mat-expansion-panel-header-title,.settings-panel .mat-expansion-panel-header .mat-expansion-panel-header-description{color:var(--md-sys-color-on-surface)}.settings-panel .mat-expansion-panel-header .mat-expansion-indicator,.settings-panel .mat-expansion-panel-header .mat-expansion-indicator:after{color:var(--md-sys-color-on-surface-variant);border-color:var(--md-sys-color-on-surface-variant)}:host ::ng-deep .settings-panel .mat-expansion-panel .mat-expansion-panel-body{padding:8px}.settings-panel .mat-mdc-tab-group .mat-mdc-tab-header{border-bottom:1px solid var(--md-sys-color-outline-variant)}.settings-panel .mat-mdc-tab-group .mdc-tab .mdc-tab__text-label{color:var(--md-sys-color-on-surface-variant)}.settings-panel .mat-mdc-tab-group .mdc-tab.mdc-tab--active .mdc-tab__text-label{color:var(--md-sys-color-on-surface)}.settings-panel .mat-mdc-tab-group .mdc-tab-indicator__content--underline{border-color:var(--md-sys-color-primary)}.settings-panel .mat-mdc-form-field{--mdc-outlined-text-field-outline-color: var(--md-sys-color-outline-variant);--mdc-outlined-text-field-hover-outline-color: var(--md-sys-color-secondary, var(--md-sys-color-primary));--mdc-outlined-text-field-focus-outline-color: var(--md-sys-color-primary)}:host ::ng-deep .praxis-settings-panel-pane{position:fixed!important;top:0!important;right:0!important;height:100vh!important;z-index:1000}:host ::ng-deep .praxis-settings-panel-pane .settings-panel{pointer-events:auto}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i3$1.MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }, { kind: "component", type: i3$1.MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i4.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "directive", type: PraxisIconDirective, selector: "mat-icon[praxisIcon]", inputs: ["praxisIcon"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i5.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "directive", type: CdkTrapFocus, selector: "[cdkTrapFocus]", inputs: ["cdkTrapFocus", "cdkTrapFocusAutoCapture"], exportAs: ["cdkTrapFocus"] }, { kind: "ngmodule", type: MatProgressSpinnerModule }, { kind: "component", type: i6.MatProgressSpinner, selector: "mat-progress-spinner, mat-spinner", inputs: ["color", "mode", "value", "diameter", "strokeWidth"], exportAs: ["matProgressSpinner"] }, { kind: "ngmodule", type: MatDialogModule }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
736
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.17", type: SettingsPanelComponent, isStandalone: true, selector: "praxis-settings-panel", host: { listeners: { "document:keydown": "handleKeydown($event)" } }, providers: [providePraxisSettingsPanelI18n()], viewQueries: [{ propertyName: "contentHost", first: true, predicate: ["contentHost"], descendants: true, read: ViewContainerRef, static: true }], ngImport: i0, template: "<div\n class=\"settings-panel\"\n data-testid=\"settings-panel-root\"\n [class.expanded]=\"expanded\"\n role=\"dialog\"\n aria-modal=\"true\"\n [attr.aria-labelledby]=\"titleId\"\n cdkTrapFocus\n cdkTrapFocusAutoCapture\n>\n <header class=\"settings-panel-header\">\n <h2 class=\"settings-panel-title\" [id]=\"titleId\">\n <mat-icon *ngIf=\"titleIcon\" class=\"title-icon\" [praxisIcon]=\"titleIcon\"></mat-icon>\n <span>{{ title }}</span>\n </h2>\n <span class=\"spacer\"></span>\n <button\n mat-icon-button\n type=\"button\"\n data-testid=\"settings-panel-toggle-expand\"\n [attr.aria-label]=\"expanded ? tx('Collapse panel') : tx('Expand panel')\"\n [attr.aria-expanded]=\"expanded\"\n [matTooltip]=\"expanded ? tx('Collapse panel') : tx('Expand panel')\"\n (click)=\"toggleExpand()\"\n >\n <mat-icon [praxisIcon]=\"expanded ? 'close_fullscreen' : 'open_in_full'\"></mat-icon>\n </button>\n <button\n mat-icon-button\n type=\"button\"\n data-testid=\"settings-panel-close-icon\"\n [attr.aria-label]=\"tx('Close')\"\n [matTooltip]=\"tx('Close')\"\n (click)=\"onCancel()\"\n >\n <mat-icon [praxisIcon]=\"'close'\"></mat-icon>\n </button>\n </header>\n <div\n class=\"settings-panel-status\"\n [attr.data-status]=\"statusTone\"\n role=\"status\"\n aria-live=\"polite\"\n >\n <mat-icon\n aria-hidden=\"true\"\n [praxisIcon]=\"\n statusTone === 'dirty'\n ? 'warning'\n : statusTone === 'saved'\n ? 'check_circle'\n : statusTone === 'busy'\n ? 'autorenew'\n : 'info'\n \"\n ></mat-icon>\n <span>{{ statusMessage }}</span>\n </div>\n <div class=\"settings-panel-body\">\n <ng-template #contentHost></ng-template>\n </div>\n <footer class=\"settings-panel-footer\">\n <button mat-button type=\"button\" data-testid=\"settings-panel-reset\" (click)=\"onReset()\" [disabled]=\"isBusy\">\n <mat-icon aria-hidden=\"true\" [praxisIcon]=\"'restart_alt'\"></mat-icon>\n <span>{{ tx('Reset') }}</span>\n </button>\n <span class=\"spacer\"></span>\n <button\n mat-button\n type=\"button\"\n data-testid=\"settings-panel-cancel\"\n (click)=\"onCancel()\"\n [disabled]=\"isBusy\"\n >\n <mat-icon aria-hidden=\"true\" [praxisIcon]=\"'close'\"></mat-icon>\n <span>{{ tx('Cancel') }}</span>\n </button>\n <button\n mat-stroked-button\n type=\"button\"\n data-testid=\"settings-panel-apply\"\n (click)=\"onApply()\"\n [disabled]=\"!canApply\"\n [matTooltip]=\"disabledReason\"\n [matTooltipDisabled]=\"canApply\"\n [attr.aria-busy]=\"isBusy\"\n >\n <mat-progress-spinner\n *ngIf=\"isBusy\"\n mode=\"indeterminate\"\n diameter=\"20\"\n ></mat-progress-spinner>\n <ng-container *ngIf=\"!isBusy\">\n <mat-icon aria-hidden=\"true\" [praxisIcon]=\"'done'\"></mat-icon>\n <span>{{ tx('Apply') }}</span>\n </ng-container>\n </button>\n <button\n mat-flat-button\n color=\"primary\"\n type=\"button\"\n data-testid=\"settings-panel-save\"\n (click)=\"onSave()\"\n [disabled]=\"!canSave\"\n [matTooltip]=\"disabledReason\"\n [matTooltipDisabled]=\"canSave\"\n [attr.aria-busy]=\"isBusy\"\n >\n <mat-progress-spinner\n *ngIf=\"isBusy\"\n mode=\"indeterminate\"\n diameter=\"20\"\n ></mat-progress-spinner>\n <ng-container *ngIf=\"!isBusy\">\n <mat-icon aria-hidden=\"true\" [praxisIcon]=\"'save'\"></mat-icon>\n <span>{{ tx('Save & Close') }}</span>\n </ng-container>\n </button>\n </footer>\n</div>\n", styles: ["@charset \"UTF-8\";:host{display:block;height:100%}.settings-panel{display:grid;grid-template-rows:auto auto 1fr auto;grid-template-areas:\"header\" \"status\" \"body\" \"footer\";height:100%;background:var(--md-sys-color-surface-container);color:var(--md-sys-color-on-surface);border-left:1px solid var(--md-sys-color-outline-variant);width:var(--pfx-settings-panel-width, 720px);transition:width .3s ease;overflow:hidden}.settings-panel.expanded{width:min(var(--pfx-settings-panel-width-expanded, 95vw),var(--pfx-settings-panel-max-width, 2400px))}.settings-panel-header{grid-area:header;display:flex;align-items:center;gap:var(--pfx-settings-panel-header-gap, 8px);padding:0 var(--pfx-settings-panel-header-padding-x, 16px);height:var(--pfx-settings-panel-header-height, 64px);border-bottom:1px solid var(--md-sys-color-outline-variant);background:var(--md-sys-color-surface-container-high);box-shadow:var(--pfx-settings-panel-header-shadow, var(--md-sys-elevation-level1, 0 2px 6px rgba(0, 0, 0, .08)));flex-shrink:0}.settings-panel-header .spacer{flex:1}.settings-panel-status{grid-area:status;display:flex;align-items:center;gap:8px;min-height:36px;padding:6px 16px;border-bottom:1px solid var(--md-sys-color-outline-variant);background:var(--md-sys-color-surface-container-high);color:var(--md-sys-color-on-surface);font-size:.85rem;font-weight:500}.settings-panel-status mat-icon{width:18px;height:18px;font-size:18px}.settings-panel-status[data-status=dirty]{color:var(--md-sys-color-error);background:color-mix(in srgb,var(--md-sys-color-error-container) 30%,var(--md-sys-color-surface-container-high))}.settings-panel-status[data-status=saved]{color:var(--md-sys-color-primary);background:color-mix(in srgb,var(--md-sys-color-primary-container) 28%,var(--md-sys-color-surface-container-high))}.settings-panel-body{grid-area:body;overflow-y:auto;min-height:0;padding:var(--pfx-settings-panel-body-padding, 8px 8px 24px 8px);background:var(--md-sys-color-surface);display:flex;flex-direction:column}.settings-panel-content{display:block}.settings-panel-footer{grid-area:footer;border-top:1px solid var(--md-sys-color-outline-variant);background:var(--md-sys-color-surface-container-high);box-shadow:var(--pfx-settings-panel-footer-shadow, var(--md-sys-elevation-level1, 0 -2px 6px rgba(0, 0, 0, .08)));display:flex;align-items:center;padding:var(--pfx-settings-panel-footer-padding, 12px 16px);column-gap:var(--pfx-settings-panel-footer-gap, 12px);flex-shrink:0}.spacer{flex:1}.settings-panel-title{display:inline-flex;align-items:center;gap:var(--pfx-settings-panel-title-gap, 8px);font-weight:700;letter-spacing:.2px;margin:0}.settings-panel-title mat-icon{color:var(--md-sys-color-primary)}.settings-panel-title .title-icon{width:20px;height:20px;font-size:20px}.settings-panel-footer button+button{margin-left:var(--pfx-settings-panel-footer-gap, 12px)}.settings-panel-footer button{display:inline-flex;align-items:center}.settings-panel-footer button .mat-icon{font-size:20px;width:20px;height:20px;line-height:1;display:inline-flex;align-items:center;justify-content:center}.settings-panel-footer .mat-button-wrapper{display:inline-flex;align-items:center;gap:var(--pfx-settings-panel-button-gap, 8px)}.settings-panel-footer .mat-progress-spinner{margin-right:8px}.settings-panel-footer .mat-flat-button[color=primary]{font-weight:600}:host ::ng-deep .settings-panel .mdc-button__label{display:inline-flex;align-items:center;gap:var(--pfx-settings-panel-button-gap, 8px);line-height:1}:host ::ng-deep .settings-panel .mdc-button__label>span{display:inline-flex;align-items:center;line-height:1}:host ::ng-deep .settings-panel .mdc-button__label .mat-icon{display:inline-flex;align-items:center;justify-content:center;line-height:1}:host ::ng-deep .praxis-settings-panel-backdrop{background:var(--pfx-backdrop, var(--md-sys-color-scrim, rgba(0, 0, 0, .45)));backdrop-filter:blur(var(--pfx-backdrop-blur, 6px)) saturate(110%);-webkit-backdrop-filter:blur(var(--pfx-backdrop-blur, 6px)) saturate(110%)}.settings-panel .mat-divider{background-color:var(--md-sys-color-outline-variant)!important}.settings-panel .mat-expansion-panel{background:var(--md-sys-color-surface-container);border:1px solid var(--md-sys-color-outline-variant);border-radius:var(--md-sys-shape-corner-medium, 12px);box-shadow:var(--md-sys-elevation-level1, 0 2px 8px rgba(0, 0, 0, .08))}.settings-panel .mat-expansion-panel-header{background:var(--md-sys-color-surface-container);color:var(--md-sys-color-on-surface)}.settings-panel .mat-expansion-panel-header mat-icon,.settings-panel .mat-expansion-panel-header .mat-icon{color:var(--md-sys-color-on-surface)!important}.settings-panel .mat-expansion-panel-header .mat-expansion-panel-header-title,.settings-panel .mat-expansion-panel-header .mat-expansion-panel-header-description{color:var(--md-sys-color-on-surface)}.settings-panel .mat-expansion-panel-header .mat-expansion-indicator,.settings-panel .mat-expansion-panel-header .mat-expansion-indicator:after{color:var(--md-sys-color-on-surface-variant);border-color:var(--md-sys-color-on-surface-variant)}:host ::ng-deep .settings-panel .mat-expansion-panel .mat-expansion-panel-body{padding:8px}.settings-panel .mat-mdc-tab-group .mat-mdc-tab-header{border-bottom:1px solid var(--md-sys-color-outline-variant)}.settings-panel .mat-mdc-tab-group .mdc-tab .mdc-tab__text-label{color:var(--md-sys-color-on-surface-variant)}.settings-panel .mat-mdc-tab-group .mdc-tab.mdc-tab--active .mdc-tab__text-label{color:var(--md-sys-color-on-surface)}.settings-panel .mat-mdc-tab-group .mdc-tab-indicator__content--underline{border-color:var(--md-sys-color-primary)}.settings-panel .mat-mdc-form-field{--mdc-outlined-text-field-outline-color: var(--md-sys-color-outline-variant);--mdc-outlined-text-field-hover-outline-color: var(--md-sys-color-secondary, var(--md-sys-color-primary));--mdc-outlined-text-field-focus-outline-color: var(--md-sys-color-primary)}:host ::ng-deep .praxis-settings-panel-pane{position:fixed!important;top:0!important;right:0!important;height:100vh!important;z-index:1000}:host ::ng-deep .praxis-settings-panel-pane .settings-panel{pointer-events:auto}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i3$1.MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }, { kind: "component", type: i3$1.MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i4.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "directive", type: PraxisIconDirective, selector: "mat-icon[praxisIcon]", inputs: ["praxisIcon"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i5.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "directive", type: CdkTrapFocus, selector: "[cdkTrapFocus]", inputs: ["cdkTrapFocus", "cdkTrapFocusAutoCapture"], exportAs: ["cdkTrapFocus"] }, { kind: "ngmodule", type: MatProgressSpinnerModule }, { kind: "component", type: i6.MatProgressSpinner, selector: "mat-progress-spinner, mat-spinner", inputs: ["color", "mode", "value", "diameter", "strokeWidth"], exportAs: ["matProgressSpinner"] }, { kind: "ngmodule", type: MatDialogModule }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
275
737
  }
276
738
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: SettingsPanelComponent, decorators: [{
277
739
  type: Component,
@@ -284,7 +746,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
284
746
  CdkTrapFocus,
285
747
  MatProgressSpinnerModule,
286
748
  MatDialogModule,
287
- ], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div\n class=\"settings-panel\"\n data-testid=\"settings-panel-root\"\n [class.expanded]=\"expanded\"\n role=\"dialog\"\n aria-modal=\"true\"\n [attr.aria-labelledby]=\"titleId\"\n cdkTrapFocus\n cdkTrapFocusAutoCapture\n>\n <header class=\"settings-panel-header\">\n <h2 class=\"settings-panel-title\" [id]=\"titleId\">\n <mat-icon *ngIf=\"titleIcon\" class=\"title-icon\" [praxisIcon]=\"titleIcon\"></mat-icon>\n <span>{{ title }}</span>\n </h2>\n <span class=\"spacer\"></span>\n <button\n mat-icon-button\n type=\"button\"\n data-testid=\"settings-panel-toggle-expand\"\n [attr.aria-label]=\"expanded ? 'Reduzir painel' : 'Expandir painel'\"\n [attr.aria-expanded]=\"expanded\"\n [matTooltip]=\"expanded ? 'Reduzir painel' : 'Expandir painel'\"\n (click)=\"toggleExpand()\"\n >\n <mat-icon [praxisIcon]=\"expanded ? 'close_fullscreen' : 'open_in_full'\"></mat-icon>\n </button>\n <button\n mat-icon-button\n type=\"button\"\n data-testid=\"settings-panel-close-icon\"\n aria-label=\"Fechar\"\n matTooltip=\"Fechar\"\n (click)=\"onCancel()\"\n >\n <mat-icon [praxisIcon]=\"'close'\"></mat-icon>\n </button>\n </header>\n <div\n class=\"settings-panel-status\"\n [attr.data-status]=\"statusTone\"\n role=\"status\"\n aria-live=\"polite\"\n >\n <mat-icon\n aria-hidden=\"true\"\n [praxisIcon]=\"\n statusTone === 'dirty'\n ? 'warning'\n : statusTone === 'saved'\n ? 'check_circle'\n : statusTone === 'busy'\n ? 'autorenew'\n : 'info'\n \"\n ></mat-icon>\n <span>{{ statusMessage }}</span>\n </div>\n <div class=\"settings-panel-body\">\n <ng-template #contentHost></ng-template>\n </div>\n <footer class=\"settings-panel-footer\">\n <button mat-button type=\"button\" data-testid=\"settings-panel-reset\" (click)=\"onReset()\" [disabled]=\"isBusy\">\n <mat-icon aria-hidden=\"true\" [praxisIcon]=\"'restart_alt'\"></mat-icon>\n <span>Redefinir</span>\n </button>\n <span class=\"spacer\"></span>\n <button\n mat-button\n type=\"button\"\n data-testid=\"settings-panel-cancel\"\n (click)=\"onCancel()\"\n [disabled]=\"isBusy\"\n >\n <mat-icon aria-hidden=\"true\" [praxisIcon]=\"'close'\"></mat-icon>\n <span>Cancelar</span>\n </button>\n <button\n mat-stroked-button\n type=\"button\"\n data-testid=\"settings-panel-apply\"\n (click)=\"onApply()\"\n [disabled]=\"!canApply\"\n [matTooltip]=\"disabledReason\"\n [matTooltipDisabled]=\"canApply\"\n [attr.aria-busy]=\"isBusy\"\n >\n <mat-progress-spinner\n *ngIf=\"isBusy\"\n mode=\"indeterminate\"\n diameter=\"20\"\n ></mat-progress-spinner>\n <ng-container *ngIf=\"!isBusy\">\n <mat-icon aria-hidden=\"true\" [praxisIcon]=\"'done'\"></mat-icon>\n <span>Aplicar</span>\n </ng-container>\n </button>\n <button\n mat-flat-button\n color=\"primary\"\n type=\"button\"\n data-testid=\"settings-panel-save\"\n (click)=\"onSave()\"\n [disabled]=\"!canSave\"\n [matTooltip]=\"disabledReason\"\n [matTooltipDisabled]=\"canSave\"\n [attr.aria-busy]=\"isBusy\"\n >\n <mat-progress-spinner\n *ngIf=\"isBusy\"\n mode=\"indeterminate\"\n diameter=\"20\"\n ></mat-progress-spinner>\n <ng-container *ngIf=\"!isBusy\">\n <mat-icon aria-hidden=\"true\" [praxisIcon]=\"'save'\"></mat-icon>\n <span>Salvar &amp; Fechar</span>\n </ng-container>\n </button>\n </footer>\n</div>\n", styles: ["@charset \"UTF-8\";:host{display:block;height:100%}.settings-panel{display:grid;grid-template-rows:auto auto 1fr auto;grid-template-areas:\"header\" \"status\" \"body\" \"footer\";height:100%;background:var(--md-sys-color-surface-container);color:var(--md-sys-color-on-surface);border-left:1px solid var(--md-sys-color-outline-variant);width:var(--pfx-settings-panel-width, 720px);transition:width .3s ease;overflow:hidden}.settings-panel.expanded{width:min(var(--pfx-settings-panel-width-expanded, 95vw),var(--pfx-settings-panel-max-width, 2400px))}.settings-panel-header{grid-area:header;display:flex;align-items:center;gap:var(--pfx-settings-panel-header-gap, 8px);padding:0 var(--pfx-settings-panel-header-padding-x, 16px);height:var(--pfx-settings-panel-header-height, 64px);border-bottom:1px solid var(--md-sys-color-outline-variant);background:var(--md-sys-color-surface-container-high);box-shadow:var(--pfx-settings-panel-header-shadow, var(--md-sys-elevation-level1, 0 2px 6px rgba(0, 0, 0, .08)));flex-shrink:0}.settings-panel-header .spacer{flex:1}.settings-panel-status{grid-area:status;display:flex;align-items:center;gap:8px;min-height:36px;padding:6px 16px;border-bottom:1px solid var(--md-sys-color-outline-variant);background:var(--md-sys-color-surface-container-high);color:var(--md-sys-color-on-surface);font-size:.85rem;font-weight:500}.settings-panel-status mat-icon{width:18px;height:18px;font-size:18px}.settings-panel-status[data-status=dirty]{color:var(--md-sys-color-error);background:color-mix(in srgb,var(--md-sys-color-error-container) 30%,var(--md-sys-color-surface-container-high))}.settings-panel-status[data-status=saved]{color:var(--md-sys-color-primary);background:color-mix(in srgb,var(--md-sys-color-primary-container) 28%,var(--md-sys-color-surface-container-high))}.settings-panel-body{grid-area:body;overflow-y:auto;min-height:0;padding:var(--pfx-settings-panel-body-padding, 8px 8px 24px 8px);background:var(--md-sys-color-surface);display:flex;flex-direction:column}.settings-panel-content{display:block}.settings-panel-footer{grid-area:footer;border-top:1px solid var(--md-sys-color-outline-variant);background:var(--md-sys-color-surface-container-high);box-shadow:var(--pfx-settings-panel-footer-shadow, var(--md-sys-elevation-level1, 0 -2px 6px rgba(0, 0, 0, .08)));display:flex;align-items:center;padding:var(--pfx-settings-panel-footer-padding, 12px 16px);column-gap:var(--pfx-settings-panel-footer-gap, 12px);flex-shrink:0}.spacer{flex:1}.settings-panel-title{display:inline-flex;align-items:center;gap:var(--pfx-settings-panel-title-gap, 8px);font-weight:700;letter-spacing:.2px;margin:0}.settings-panel-title mat-icon{color:var(--md-sys-color-primary)}.settings-panel-title .title-icon{width:20px;height:20px;font-size:20px}.settings-panel-footer button+button{margin-left:var(--pfx-settings-panel-footer-gap, 12px)}.settings-panel-footer button{display:inline-flex;align-items:center}.settings-panel-footer button .mat-icon{font-size:20px;width:20px;height:20px;line-height:1;display:inline-flex;align-items:center;justify-content:center}.settings-panel-footer .mat-button-wrapper{display:inline-flex;align-items:center;gap:var(--pfx-settings-panel-button-gap, 8px)}.settings-panel-footer .mat-progress-spinner{margin-right:8px}.settings-panel-footer .mat-flat-button[color=primary]{font-weight:600}:host ::ng-deep .settings-panel .mdc-button__label{display:inline-flex;align-items:center;gap:var(--pfx-settings-panel-button-gap, 8px);line-height:1}:host ::ng-deep .settings-panel .mdc-button__label>span{display:inline-flex;align-items:center;line-height:1}:host ::ng-deep .settings-panel .mdc-button__label .mat-icon{display:inline-flex;align-items:center;justify-content:center;line-height:1}:host ::ng-deep .praxis-settings-panel-backdrop{background:var(--pfx-backdrop, var(--md-sys-color-scrim, rgba(0, 0, 0, .45)));backdrop-filter:blur(var(--pfx-backdrop-blur, 6px)) saturate(110%);-webkit-backdrop-filter:blur(var(--pfx-backdrop-blur, 6px)) saturate(110%)}.settings-panel .mat-divider{background-color:var(--md-sys-color-outline-variant)!important}.settings-panel .mat-expansion-panel{background:var(--md-sys-color-surface-container);border:1px solid var(--md-sys-color-outline-variant);border-radius:var(--md-sys-shape-corner-medium, 12px);box-shadow:var(--md-sys-elevation-level1, 0 2px 8px rgba(0, 0, 0, .08))}.settings-panel .mat-expansion-panel-header{background:var(--md-sys-color-surface-container);color:var(--md-sys-color-on-surface)}.settings-panel .mat-expansion-panel-header mat-icon,.settings-panel .mat-expansion-panel-header .mat-icon{color:var(--md-sys-color-on-surface)!important}.settings-panel .mat-expansion-panel-header .mat-expansion-panel-header-title,.settings-panel .mat-expansion-panel-header .mat-expansion-panel-header-description{color:var(--md-sys-color-on-surface)}.settings-panel .mat-expansion-panel-header .mat-expansion-indicator,.settings-panel .mat-expansion-panel-header .mat-expansion-indicator:after{color:var(--md-sys-color-on-surface-variant);border-color:var(--md-sys-color-on-surface-variant)}:host ::ng-deep .settings-panel .mat-expansion-panel .mat-expansion-panel-body{padding:8px}.settings-panel .mat-mdc-tab-group .mat-mdc-tab-header{border-bottom:1px solid var(--md-sys-color-outline-variant)}.settings-panel .mat-mdc-tab-group .mdc-tab .mdc-tab__text-label{color:var(--md-sys-color-on-surface-variant)}.settings-panel .mat-mdc-tab-group .mdc-tab.mdc-tab--active .mdc-tab__text-label{color:var(--md-sys-color-on-surface)}.settings-panel .mat-mdc-tab-group .mdc-tab-indicator__content--underline{border-color:var(--md-sys-color-primary)}.settings-panel .mat-mdc-form-field{--mdc-outlined-text-field-outline-color: var(--md-sys-color-outline-variant);--mdc-outlined-text-field-hover-outline-color: var(--md-sys-color-secondary, var(--md-sys-color-primary));--mdc-outlined-text-field-focus-outline-color: var(--md-sys-color-primary)}:host ::ng-deep .praxis-settings-panel-pane{position:fixed!important;top:0!important;right:0!important;height:100vh!important;z-index:1000}:host ::ng-deep .praxis-settings-panel-pane .settings-panel{pointer-events:auto}\n"] }]
749
+ ], changeDetection: ChangeDetectionStrategy.OnPush, providers: [providePraxisSettingsPanelI18n()], template: "<div\n class=\"settings-panel\"\n data-testid=\"settings-panel-root\"\n [class.expanded]=\"expanded\"\n role=\"dialog\"\n aria-modal=\"true\"\n [attr.aria-labelledby]=\"titleId\"\n cdkTrapFocus\n cdkTrapFocusAutoCapture\n>\n <header class=\"settings-panel-header\">\n <h2 class=\"settings-panel-title\" [id]=\"titleId\">\n <mat-icon *ngIf=\"titleIcon\" class=\"title-icon\" [praxisIcon]=\"titleIcon\"></mat-icon>\n <span>{{ title }}</span>\n </h2>\n <span class=\"spacer\"></span>\n <button\n mat-icon-button\n type=\"button\"\n data-testid=\"settings-panel-toggle-expand\"\n [attr.aria-label]=\"expanded ? tx('Collapse panel') : tx('Expand panel')\"\n [attr.aria-expanded]=\"expanded\"\n [matTooltip]=\"expanded ? tx('Collapse panel') : tx('Expand panel')\"\n (click)=\"toggleExpand()\"\n >\n <mat-icon [praxisIcon]=\"expanded ? 'close_fullscreen' : 'open_in_full'\"></mat-icon>\n </button>\n <button\n mat-icon-button\n type=\"button\"\n data-testid=\"settings-panel-close-icon\"\n [attr.aria-label]=\"tx('Close')\"\n [matTooltip]=\"tx('Close')\"\n (click)=\"onCancel()\"\n >\n <mat-icon [praxisIcon]=\"'close'\"></mat-icon>\n </button>\n </header>\n <div\n class=\"settings-panel-status\"\n [attr.data-status]=\"statusTone\"\n role=\"status\"\n aria-live=\"polite\"\n >\n <mat-icon\n aria-hidden=\"true\"\n [praxisIcon]=\"\n statusTone === 'dirty'\n ? 'warning'\n : statusTone === 'saved'\n ? 'check_circle'\n : statusTone === 'busy'\n ? 'autorenew'\n : 'info'\n \"\n ></mat-icon>\n <span>{{ statusMessage }}</span>\n </div>\n <div class=\"settings-panel-body\">\n <ng-template #contentHost></ng-template>\n </div>\n <footer class=\"settings-panel-footer\">\n <button mat-button type=\"button\" data-testid=\"settings-panel-reset\" (click)=\"onReset()\" [disabled]=\"isBusy\">\n <mat-icon aria-hidden=\"true\" [praxisIcon]=\"'restart_alt'\"></mat-icon>\n <span>{{ tx('Reset') }}</span>\n </button>\n <span class=\"spacer\"></span>\n <button\n mat-button\n type=\"button\"\n data-testid=\"settings-panel-cancel\"\n (click)=\"onCancel()\"\n [disabled]=\"isBusy\"\n >\n <mat-icon aria-hidden=\"true\" [praxisIcon]=\"'close'\"></mat-icon>\n <span>{{ tx('Cancel') }}</span>\n </button>\n <button\n mat-stroked-button\n type=\"button\"\n data-testid=\"settings-panel-apply\"\n (click)=\"onApply()\"\n [disabled]=\"!canApply\"\n [matTooltip]=\"disabledReason\"\n [matTooltipDisabled]=\"canApply\"\n [attr.aria-busy]=\"isBusy\"\n >\n <mat-progress-spinner\n *ngIf=\"isBusy\"\n mode=\"indeterminate\"\n diameter=\"20\"\n ></mat-progress-spinner>\n <ng-container *ngIf=\"!isBusy\">\n <mat-icon aria-hidden=\"true\" [praxisIcon]=\"'done'\"></mat-icon>\n <span>{{ tx('Apply') }}</span>\n </ng-container>\n </button>\n <button\n mat-flat-button\n color=\"primary\"\n type=\"button\"\n data-testid=\"settings-panel-save\"\n (click)=\"onSave()\"\n [disabled]=\"!canSave\"\n [matTooltip]=\"disabledReason\"\n [matTooltipDisabled]=\"canSave\"\n [attr.aria-busy]=\"isBusy\"\n >\n <mat-progress-spinner\n *ngIf=\"isBusy\"\n mode=\"indeterminate\"\n diameter=\"20\"\n ></mat-progress-spinner>\n <ng-container *ngIf=\"!isBusy\">\n <mat-icon aria-hidden=\"true\" [praxisIcon]=\"'save'\"></mat-icon>\n <span>{{ tx('Save & Close') }}</span>\n </ng-container>\n </button>\n </footer>\n</div>\n", styles: ["@charset \"UTF-8\";:host{display:block;height:100%}.settings-panel{display:grid;grid-template-rows:auto auto 1fr auto;grid-template-areas:\"header\" \"status\" \"body\" \"footer\";height:100%;background:var(--md-sys-color-surface-container);color:var(--md-sys-color-on-surface);border-left:1px solid var(--md-sys-color-outline-variant);width:var(--pfx-settings-panel-width, 720px);transition:width .3s ease;overflow:hidden}.settings-panel.expanded{width:min(var(--pfx-settings-panel-width-expanded, 95vw),var(--pfx-settings-panel-max-width, 2400px))}.settings-panel-header{grid-area:header;display:flex;align-items:center;gap:var(--pfx-settings-panel-header-gap, 8px);padding:0 var(--pfx-settings-panel-header-padding-x, 16px);height:var(--pfx-settings-panel-header-height, 64px);border-bottom:1px solid var(--md-sys-color-outline-variant);background:var(--md-sys-color-surface-container-high);box-shadow:var(--pfx-settings-panel-header-shadow, var(--md-sys-elevation-level1, 0 2px 6px rgba(0, 0, 0, .08)));flex-shrink:0}.settings-panel-header .spacer{flex:1}.settings-panel-status{grid-area:status;display:flex;align-items:center;gap:8px;min-height:36px;padding:6px 16px;border-bottom:1px solid var(--md-sys-color-outline-variant);background:var(--md-sys-color-surface-container-high);color:var(--md-sys-color-on-surface);font-size:.85rem;font-weight:500}.settings-panel-status mat-icon{width:18px;height:18px;font-size:18px}.settings-panel-status[data-status=dirty]{color:var(--md-sys-color-error);background:color-mix(in srgb,var(--md-sys-color-error-container) 30%,var(--md-sys-color-surface-container-high))}.settings-panel-status[data-status=saved]{color:var(--md-sys-color-primary);background:color-mix(in srgb,var(--md-sys-color-primary-container) 28%,var(--md-sys-color-surface-container-high))}.settings-panel-body{grid-area:body;overflow-y:auto;min-height:0;padding:var(--pfx-settings-panel-body-padding, 8px 8px 24px 8px);background:var(--md-sys-color-surface);display:flex;flex-direction:column}.settings-panel-content{display:block}.settings-panel-footer{grid-area:footer;border-top:1px solid var(--md-sys-color-outline-variant);background:var(--md-sys-color-surface-container-high);box-shadow:var(--pfx-settings-panel-footer-shadow, var(--md-sys-elevation-level1, 0 -2px 6px rgba(0, 0, 0, .08)));display:flex;align-items:center;padding:var(--pfx-settings-panel-footer-padding, 12px 16px);column-gap:var(--pfx-settings-panel-footer-gap, 12px);flex-shrink:0}.spacer{flex:1}.settings-panel-title{display:inline-flex;align-items:center;gap:var(--pfx-settings-panel-title-gap, 8px);font-weight:700;letter-spacing:.2px;margin:0}.settings-panel-title mat-icon{color:var(--md-sys-color-primary)}.settings-panel-title .title-icon{width:20px;height:20px;font-size:20px}.settings-panel-footer button+button{margin-left:var(--pfx-settings-panel-footer-gap, 12px)}.settings-panel-footer button{display:inline-flex;align-items:center}.settings-panel-footer button .mat-icon{font-size:20px;width:20px;height:20px;line-height:1;display:inline-flex;align-items:center;justify-content:center}.settings-panel-footer .mat-button-wrapper{display:inline-flex;align-items:center;gap:var(--pfx-settings-panel-button-gap, 8px)}.settings-panel-footer .mat-progress-spinner{margin-right:8px}.settings-panel-footer .mat-flat-button[color=primary]{font-weight:600}:host ::ng-deep .settings-panel .mdc-button__label{display:inline-flex;align-items:center;gap:var(--pfx-settings-panel-button-gap, 8px);line-height:1}:host ::ng-deep .settings-panel .mdc-button__label>span{display:inline-flex;align-items:center;line-height:1}:host ::ng-deep .settings-panel .mdc-button__label .mat-icon{display:inline-flex;align-items:center;justify-content:center;line-height:1}:host ::ng-deep .praxis-settings-panel-backdrop{background:var(--pfx-backdrop, var(--md-sys-color-scrim, rgba(0, 0, 0, .45)));backdrop-filter:blur(var(--pfx-backdrop-blur, 6px)) saturate(110%);-webkit-backdrop-filter:blur(var(--pfx-backdrop-blur, 6px)) saturate(110%)}.settings-panel .mat-divider{background-color:var(--md-sys-color-outline-variant)!important}.settings-panel .mat-expansion-panel{background:var(--md-sys-color-surface-container);border:1px solid var(--md-sys-color-outline-variant);border-radius:var(--md-sys-shape-corner-medium, 12px);box-shadow:var(--md-sys-elevation-level1, 0 2px 8px rgba(0, 0, 0, .08))}.settings-panel .mat-expansion-panel-header{background:var(--md-sys-color-surface-container);color:var(--md-sys-color-on-surface)}.settings-panel .mat-expansion-panel-header mat-icon,.settings-panel .mat-expansion-panel-header .mat-icon{color:var(--md-sys-color-on-surface)!important}.settings-panel .mat-expansion-panel-header .mat-expansion-panel-header-title,.settings-panel .mat-expansion-panel-header .mat-expansion-panel-header-description{color:var(--md-sys-color-on-surface)}.settings-panel .mat-expansion-panel-header .mat-expansion-indicator,.settings-panel .mat-expansion-panel-header .mat-expansion-indicator:after{color:var(--md-sys-color-on-surface-variant);border-color:var(--md-sys-color-on-surface-variant)}:host ::ng-deep .settings-panel .mat-expansion-panel .mat-expansion-panel-body{padding:8px}.settings-panel .mat-mdc-tab-group .mat-mdc-tab-header{border-bottom:1px solid var(--md-sys-color-outline-variant)}.settings-panel .mat-mdc-tab-group .mdc-tab .mdc-tab__text-label{color:var(--md-sys-color-on-surface-variant)}.settings-panel .mat-mdc-tab-group .mdc-tab.mdc-tab--active .mdc-tab__text-label{color:var(--md-sys-color-on-surface)}.settings-panel .mat-mdc-tab-group .mdc-tab-indicator__content--underline{border-color:var(--md-sys-color-primary)}.settings-panel .mat-mdc-form-field{--mdc-outlined-text-field-outline-color: var(--md-sys-color-outline-variant);--mdc-outlined-text-field-hover-outline-color: var(--md-sys-color-secondary, var(--md-sys-color-primary));--mdc-outlined-text-field-focus-outline-color: var(--md-sys-color-primary)}:host ::ng-deep .praxis-settings-panel-pane{position:fixed!important;top:0!important;right:0!important;height:100vh!important;z-index:1000}:host ::ng-deep .praxis-settings-panel-pane .settings-panel{pointer-events:auto}\n"] }]
288
750
  }], ctorParameters: () => [{ type: i0.ChangeDetectorRef }, { type: i1.MatDialog }], propDecorators: { contentHost: [{
289
751
  type: ViewChild,
290
752
  args: ['contentHost', { read: ViewContainerRef, static: true }]
@@ -348,6 +810,7 @@ class SettingsPanelService {
348
810
  overlay;
349
811
  injector;
350
812
  currentRef;
813
+ i18n = inject(PraxisI18nService);
351
814
  constructor(overlay, injector) {
352
815
  this.overlay = overlay;
353
816
  this.injector = injector;
@@ -373,7 +836,9 @@ class SettingsPanelService {
373
836
  const ref = new SettingsPanelRef(overlayRef);
374
837
  const panelPortal = new ComponentPortal(SettingsPanelComponent);
375
838
  const panelRef = overlayRef.attach(panelPortal);
376
- panelRef.instance.title = config.title;
839
+ panelRef.instance.title = config.title?.trim()
840
+ ? config.title
841
+ : this.i18n.t(PRAXIS_SETTINGS_PANEL_DEFAULT_TITLE, undefined, PRAXIS_SETTINGS_PANEL_DEFAULT_TITLE, PRAXIS_SETTINGS_PANEL_I18N_NAMESPACE);
377
842
  panelRef.instance.titleIcon = config.titleIcon;
378
843
  panelRef.instance.expanded = config.expanded || false;
379
844
  const inputs = config.content.inputs;
@@ -416,6 +881,24 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
416
881
  args: [{ providedIn: 'root' }]
417
882
  }], ctorParameters: () => [{ type: i1$1.Overlay }, { type: i0.Injector }] });
418
883
 
884
+ function providePraxisSettingsPanelBridge() {
885
+ return {
886
+ provide: SETTINGS_PANEL_BRIDGE,
887
+ useFactory: (service) => ({
888
+ open: (opts) => service.open({
889
+ id: opts.id,
890
+ title: opts.title,
891
+ titleIcon: opts.titleIcon,
892
+ content: {
893
+ component: opts.content.component,
894
+ inputs: (opts.content.inputs || undefined),
895
+ },
896
+ }),
897
+ }),
898
+ deps: [SettingsPanelService],
899
+ };
900
+ }
901
+
419
902
  /**
420
903
  * Admin helper to load, patch and persist GlobalConfig.
421
904
  * Intended to be used by the Global Config Editor UI.
@@ -455,6 +938,38 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
455
938
  args: [{ providedIn: 'root' }]
456
939
  }] });
457
940
 
941
+ function normalizeMojibakeText(text) {
942
+ if (!text.includes('\u00C3') &&
943
+ !text.includes('\u00C2') &&
944
+ !text.includes('\u00E2') &&
945
+ !text.includes('\u00AA') &&
946
+ !text.includes('\u00AB')) {
947
+ return text;
948
+ }
949
+ let current = text;
950
+ for (let i = 0; i < 3; i++) {
951
+ let next = current;
952
+ try {
953
+ next = decodeURIComponent(escape(current));
954
+ }
955
+ catch {
956
+ break;
957
+ }
958
+ if (next === current) {
959
+ break;
960
+ }
961
+ current = next;
962
+ if (!current.includes('\u00C3') &&
963
+ !current.includes('\u00C2') &&
964
+ !current.includes('\u00E2') &&
965
+ !current.includes('\u00AA') &&
966
+ !current.includes('\u00AB')) {
967
+ break;
968
+ }
969
+ }
970
+ return current;
971
+ }
972
+
458
973
  const TABLE_COMPACT_LENGTH_TOKEN$1 = '(?:0|(?:\\d+|\\d*\\.\\d+)(?:px|rem|em|%|vh|vw|svh|svw|lvh|lvw|dvh|dvw|ch|ex))';
459
974
  const TABLE_COMPACT_SPACING_PATTERN = `^(?:var\\(.+\\)|calc\\(.+\\)|${TABLE_COMPACT_LENGTH_TOKEN$1}(?:\\s+${TABLE_COMPACT_LENGTH_TOKEN$1}){0,3})$`;
460
975
  const TABLE_COMPACT_FONT_SIZE_PATTERN = `^(?:var\\(.+\\)|calc\\(.+\\)|${TABLE_COMPACT_LENGTH_TOKEN$1})$`;
@@ -465,30 +980,31 @@ function safeName(path) {
465
980
  * Minimal FormConfig schema for the Global Config editor UI.
466
981
  * This can be extended incrementally as new domains/settings are added.
467
982
  */
468
- function buildGlobalConfigFormConfig() {
983
+ function buildGlobalConfigFormConfig(translate = (text) => text) {
984
+ const tx = (text, params) => translate(normalizeMojibakeText(text), params);
469
985
  const fields = [
470
986
  // CRUD
471
987
  {
472
988
  name: safeName('crud.defaults.openMode'),
473
- label: 'Modo de abertura padrão',
989
+ label: tx('Modo de abertura padrão'),
474
990
  controlType: FieldControlType.SELECT,
475
991
  selectOptions: [
476
- { text: 'Rota', value: 'route' },
992
+ { text: tx('Rota'), value: 'route' },
477
993
  { text: 'Modal', value: 'modal' },
478
994
  { text: 'Drawer', value: 'drawer' },
479
995
  ],
480
- hint: 'Aplicado quando ação/metadado não definem modo.',
996
+ hint: tx('Aplicado quando ação/metadado não definem modo.'),
481
997
  dataAttributes: { globalPath: 'crud.defaults.openMode' },
482
998
  },
483
999
  {
484
1000
  name: safeName('crud.defaults.back.confirmOnDirty'),
485
- label: 'Confirmar ao sair com alterações',
1001
+ label: tx('Confirmar ao sair com alterações'),
486
1002
  controlType: FieldControlType.TOGGLE,
487
1003
  dataAttributes: { globalPath: 'crud.defaults.back.confirmOnDirty' },
488
1004
  },
489
1005
  {
490
1006
  name: safeName('crud.defaults.back.strategy'),
491
- label: 'Back: estratégia',
1007
+ label: tx('Back: estratégia'),
492
1008
  controlType: FieldControlType.SELECT,
493
1009
  selectOptions: [
494
1010
  { text: 'auto', value: 'auto' },
@@ -499,13 +1015,13 @@ function buildGlobalConfigFormConfig() {
499
1015
  },
500
1016
  {
501
1017
  name: safeName('crud.defaults.header.showBack'),
502
- label: 'Header: mostrar voltar',
1018
+ label: tx('Header: show back'),
503
1019
  controlType: FieldControlType.TOGGLE,
504
1020
  dataAttributes: { globalPath: 'crud.defaults.header.showBack' },
505
1021
  },
506
1022
  {
507
1023
  name: safeName('crud.defaults.header.variant'),
508
- label: 'Header: variante',
1024
+ label: tx('Header: variant'),
509
1025
  controlType: FieldControlType.SELECT,
510
1026
  selectOptions: [
511
1027
  { text: 'ghost', value: 'ghost' },
@@ -516,31 +1032,31 @@ function buildGlobalConfigFormConfig() {
516
1032
  },
517
1033
  {
518
1034
  name: safeName('crud.defaults.header.sticky'),
519
- label: 'Header: fixo (sticky)',
1035
+ label: tx('Header: sticky'),
520
1036
  controlType: FieldControlType.TOGGLE,
521
1037
  dataAttributes: { globalPath: 'crud.defaults.header.sticky' },
522
1038
  },
523
1039
  {
524
1040
  name: safeName('crud.defaults.header.divider'),
525
- label: 'Header: mostrar divisor',
1041
+ label: tx('Header: show divider'),
526
1042
  controlType: FieldControlType.TOGGLE,
527
1043
  dataAttributes: { globalPath: 'crud.defaults.header.divider' },
528
1044
  },
529
1045
  {
530
1046
  name: safeName('crud.defaults.modal.width'),
531
- label: 'Modal: largura (ex.: 900px)',
1047
+ label: tx('Modal: width (e.g. 900px)'),
532
1048
  controlType: FieldControlType.INPUT,
533
1049
  dataAttributes: { globalPath: 'crud.defaults.modal.width' },
534
1050
  },
535
1051
  {
536
1052
  name: safeName('crud.defaults.modal.maxWidth'),
537
- label: 'Modal: largura máxima (ex.: 96vw)',
1053
+ label: tx('Modal: largura máxima (ex.: 96vw)'),
538
1054
  controlType: FieldControlType.INPUT,
539
1055
  dataAttributes: { globalPath: 'crud.defaults.modal.maxWidth' },
540
1056
  },
541
1057
  {
542
1058
  name: safeName('crud.defaults.modal.backdropStyle'),
543
- label: 'Modal: backdrop',
1059
+ label: tx('Modal: backdrop'),
544
1060
  controlType: FieldControlType.SELECT,
545
1061
  selectOptions: [
546
1062
  { text: 'blur', value: 'blur' },
@@ -552,25 +1068,25 @@ function buildGlobalConfigFormConfig() {
552
1068
  // Dynamic Fields
553
1069
  {
554
1070
  name: safeName('dynamicFields.asyncSelect.loadOn'),
555
- label: 'Async Select: loadOn',
1071
+ label: tx('Async Select: loadOn'),
556
1072
  controlType: FieldControlType.SELECT,
557
1073
  selectOptions: [
558
1074
  { text: 'open', value: 'open' },
559
1075
  { text: 'init', value: 'init' },
560
1076
  { text: 'none', value: 'none' },
561
1077
  ],
562
- hint: 'Estratégia de primeira carga quando metadado não definir.',
1078
+ hint: tx('Estratégia de primeira carga quando metadado não definir.'),
563
1079
  dataAttributes: { globalPath: 'dynamicFields.asyncSelect.loadOn' },
564
1080
  },
565
1081
  {
566
1082
  name: safeName('dynamicFields.cascade.enable'),
567
- label: 'Cascata nativa habilitada',
1083
+ label: tx('Native cascade enabled'),
568
1084
  controlType: FieldControlType.TOGGLE,
569
1085
  dataAttributes: { globalPath: 'dynamicFields.cascade.enable' },
570
1086
  },
571
1087
  {
572
1088
  name: safeName('dynamicFields.cascade.loadOnChange'),
573
- label: 'Cascata: loadOnChange',
1089
+ label: tx('Cascade: loadOnChange'),
574
1090
  controlType: FieldControlType.SELECT,
575
1091
  selectOptions: [
576
1092
  { text: 'respectLoadOn', value: 'respectLoadOn' },
@@ -581,42 +1097,42 @@ function buildGlobalConfigFormConfig() {
581
1097
  },
582
1098
  {
583
1099
  name: safeName('dynamicFields.cascade.debounceMs'),
584
- label: 'Cascata: debounce (ms)',
1100
+ label: tx('Cascade: debounce (ms)'),
585
1101
  controlType: FieldControlType.NUMERIC_TEXT_BOX,
586
1102
  dataAttributes: { globalPath: 'dynamicFields.cascade.debounceMs' },
587
1103
  },
588
1104
  // Dynamic Fields async-select extra
589
1105
  {
590
1106
  name: safeName('dynamicFields.asyncSelect.pageSize'),
591
- label: 'Async Select: pageSize',
1107
+ label: tx('Async Select: pageSize'),
592
1108
  controlType: FieldControlType.NUMERIC_TEXT_BOX,
593
1109
  dataAttributes: { globalPath: 'dynamicFields.asyncSelect.pageSize' },
594
1110
  },
595
1111
  {
596
1112
  name: safeName('dynamicFields.asyncSelect.useCursor'),
597
- label: 'Async Select: usar cursor',
1113
+ label: tx('Async Select: use cursor'),
598
1114
  controlType: FieldControlType.TOGGLE,
599
1115
  dataAttributes: { globalPath: 'dynamicFields.asyncSelect.useCursor' },
600
1116
  },
601
1117
  // AI
602
1118
  {
603
1119
  name: safeName('ai.provider'),
604
- label: 'Provedor LLM',
1120
+ label: tx('LLM provider'),
605
1121
  controlType: FieldControlType.SELECT,
606
1122
  selectOptions: [],
607
- hint: 'Selecione o provedor para listar modelos e testar a chave.',
1123
+ hint: tx('Select the provider to list models and test the key.'),
608
1124
  dataAttributes: { globalPath: 'ai.provider' },
609
1125
  },
610
1126
  {
611
1127
  name: safeName('ai.apiKey'),
612
- label: 'Chave de API',
1128
+ label: tx('API key'),
613
1129
  controlType: FieldControlType.INPUT,
614
- hint: 'Informe a chave do provedor selecionado para testar.',
1130
+ hint: tx('Enter the selected provider key to test.'),
615
1131
  dataAttributes: { globalPath: 'ai.apiKey' },
616
1132
  },
617
1133
  {
618
1134
  name: safeName('ai.model'),
619
- label: 'Modelo de IA',
1135
+ label: tx('AI model'),
620
1136
  controlType: FieldControlType.SEARCHABLE_SELECT,
621
1137
  selectOptions: [],
622
1138
  resourcePath: '',
@@ -624,113 +1140,113 @@ function buildGlobalConfigFormConfig() {
624
1140
  },
625
1141
  {
626
1142
  name: safeName('ai.temperature'),
627
- label: 'Temperatura (Criatividade)',
1143
+ label: tx('Temperature (Creativity)'),
628
1144
  controlType: FieldControlType.NUMERIC_TEXT_BOX,
629
- hint: '0.0 (determinístico) a 1.0 (criativo)',
1145
+ hint: tx('0.0 (deterministic) to 1.0 (creative)'),
630
1146
  dataAttributes: { globalPath: 'ai.temperature' },
631
1147
  },
632
1148
  {
633
1149
  name: safeName('ai.maxTokens'),
634
- label: 'Max tokens',
1150
+ label: tx('Max tokens'),
635
1151
  controlType: FieldControlType.NUMERIC_TEXT_BOX,
636
- hint: 'Limite maximo de tokens na resposta.',
1152
+ hint: tx('Maximum token limit for the response.'),
637
1153
  dataAttributes: { globalPath: 'ai.maxTokens' },
638
1154
  },
639
1155
  {
640
1156
  name: safeName('ai.riskPolicy'),
641
- label: 'Assistente: validação de risco',
1157
+ label: tx('Assistant: risk validation'),
642
1158
  controlType: FieldControlType.SELECT,
643
1159
  selectOptions: [
644
- { text: 'Estrito (recomendado)', value: 'strict' },
645
- { text: 'Padrão', value: 'standard' },
1160
+ { text: 'Strict (recommended)', value: 'strict' },
1161
+ { text: tx('Standard'), value: 'standard' },
646
1162
  ],
647
- hint: 'Estrito exige confirmação em risco médio/alto. Padrão segue a indicação retornada pelo backend.',
1163
+ hint: tx('Strict requires confirmation for medium/high risk. Standard follows the indication returned by the backend.'),
648
1164
  dataAttributes: { globalPath: 'ai.riskPolicy' },
649
1165
  },
650
1166
  {
651
1167
  name: safeName('ai.embedding.useSameAsLlm'),
652
- label: 'Embeddings: usar mesmo LLM',
1168
+ label: tx('Use same LLM for embeddings'),
653
1169
  controlType: FieldControlType.TOGGLE,
654
- hint: 'Replica provedor e chave do LLM para embeddings.',
1170
+ hint: tx('Replicates the LLM provider and key for embeddings.'),
655
1171
  dataAttributes: { globalPath: 'ai.embedding.useSameAsLlm' },
656
1172
  },
657
1173
  {
658
1174
  name: safeName('ai.embedding.provider'),
659
- label: 'Embeddings: provedor',
1175
+ label: tx('Embeddings provider'),
660
1176
  controlType: FieldControlType.SELECT,
661
1177
  selectOptions: [],
662
- hint: 'Provedor usado para gerar embeddings (RAG).',
1178
+ hint: tx('Provider used to generate embeddings (RAG).'),
663
1179
  dataAttributes: { globalPath: 'ai.embedding.provider' },
664
1180
  },
665
1181
  {
666
1182
  name: safeName('ai.embedding.apiKey'),
667
- label: 'Embeddings: chave de API',
1183
+ label: tx('Embeddings API key'),
668
1184
  controlType: FieldControlType.INPUT,
669
- hint: 'Chave do provedor de embeddings.',
1185
+ hint: tx('Embeddings provider key.'),
670
1186
  dataAttributes: { globalPath: 'ai.embedding.apiKey' },
671
1187
  },
672
1188
  {
673
1189
  name: safeName('ai.embedding.model'),
674
- label: 'Embeddings: modelo',
1190
+ label: tx('Embeddings model'),
675
1191
  controlType: FieldControlType.SEARCHABLE_SELECT,
676
1192
  selectOptions: [
677
1193
  { text: 'text-embedding-3-large', value: 'text-embedding-3-large' },
678
1194
  { text: 'text-embedding-3-small', value: 'text-embedding-3-small' },
679
1195
  { text: 'text-embedding-ada-002 (legacy)', value: 'text-embedding-ada-002' },
680
1196
  ],
681
- emptyOptionText: 'Padrão do provedor',
682
- hint: 'Modelos OpenAI para embeddings.',
1197
+ emptyOptionText: tx('Provider default'),
1198
+ hint: tx('OpenAI models for embeddings.'),
683
1199
  dataAttributes: { globalPath: 'ai.embedding.model' },
684
1200
  },
685
1201
  {
686
1202
  name: safeName('ai.embedding.dimensions'),
687
- label: 'Embeddings: dimensoes',
1203
+ label: tx('Embeddings: dimensions'),
688
1204
  controlType: FieldControlType.NUMERIC_TEXT_BOX,
689
- hint: 'Dimensoes do vetor de embedding (default 768).',
1205
+ hint: tx('Embedding vector dimensions (default 768).'),
690
1206
  dataAttributes: { globalPath: 'ai.embedding.dimensions' },
691
1207
  },
692
- // Cache
1208
+ // Cache // Cache
693
1209
  {
694
1210
  name: safeName('cache.disableSchemaCache'),
695
- label: 'Desabilitar cache de schema (LocalStorage)',
1211
+ label: tx('Desabilitar cache de schema (LocalStorage)'),
696
1212
  controlType: FieldControlType.TOGGLE,
697
- hint: 'Se ativo, sempre baixa o schema do servidor (ignora cache local). Útil para desenvolvimento.',
1213
+ hint: tx('Se ativo, sempre baixa o schema do servidor (ignora cache local). Útil para desenvolvimento.'),
698
1214
  dataAttributes: { globalPath: 'cache.disableSchemaCache' },
699
1215
  },
700
1216
  // Table
701
1217
  {
702
1218
  name: safeName('table.behavior.pagination.enabled'),
703
- label: 'Paginação habilitada',
1219
+ label: tx('Paginação habilitada'),
704
1220
  controlType: FieldControlType.TOGGLE,
705
1221
  dataAttributes: { globalPath: 'table.behavior.pagination.enabled' },
706
1222
  },
707
1223
  {
708
1224
  name: safeName('table.behavior.pagination.pageSize'),
709
- label: 'Tamanho da página',
1225
+ label: tx('Tamanho da página'),
710
1226
  controlType: FieldControlType.NUMERIC_TEXT_BOX,
711
1227
  dataAttributes: { globalPath: 'table.behavior.pagination.pageSize' },
712
1228
  },
713
1229
  {
714
1230
  name: safeName('table.behavior.filtering.debounceTime'),
715
- label: 'Debounce do filtro (ms)',
1231
+ label: tx('Filter debounce (ms)'),
716
1232
  controlType: FieldControlType.NUMERIC_TEXT_BOX,
717
1233
  dataAttributes: { globalPath: 'table.behavior.filtering.debounceTime' },
718
1234
  },
719
1235
  {
720
1236
  name: safeName('table.behavior.sorting.enabled'),
721
- label: 'Ordenação habilitada',
1237
+ label: tx('Ordenação habilitada'),
722
1238
  controlType: FieldControlType.TOGGLE,
723
1239
  dataAttributes: { globalPath: 'table.behavior.sorting.enabled' },
724
1240
  },
725
1241
  {
726
1242
  name: safeName('table.behavior.selection.enabled'),
727
- label: 'Seleção habilitada',
1243
+ label: tx('Seleção habilitada'),
728
1244
  controlType: FieldControlType.TOGGLE,
729
1245
  dataAttributes: { globalPath: 'table.behavior.selection.enabled' },
730
1246
  },
731
1247
  {
732
1248
  name: safeName('table.behavior.pagination.strategy'),
733
- label: 'Paginação: estratégia',
1249
+ label: tx('Paginação: estratégia'),
734
1250
  controlType: FieldControlType.SELECT,
735
1251
  selectOptions: [
736
1252
  { text: 'client', value: 'client' },
@@ -740,7 +1256,7 @@ function buildGlobalConfigFormConfig() {
740
1256
  },
741
1257
  {
742
1258
  name: safeName('table.behavior.sorting.strategy'),
743
- label: 'Ordenação: estratégia',
1259
+ label: tx('Ordenação: estratégia'),
744
1260
  controlType: FieldControlType.SELECT,
745
1261
  selectOptions: [
746
1262
  { text: 'client', value: 'client' },
@@ -750,114 +1266,113 @@ function buildGlobalConfigFormConfig() {
750
1266
  },
751
1267
  {
752
1268
  name: safeName('table.behavior.pagination.showFirstLastButtons'),
753
- label: 'Paginação: botões Primeiro/Último',
1269
+ label: tx('Paginação: botões Primeiro/Último'),
754
1270
  controlType: FieldControlType.CHECKBOX,
755
1271
  dataAttributes: { globalPath: 'table.behavior.pagination.showFirstLastButtons' },
756
1272
  },
757
1273
  {
758
1274
  name: safeName('table.toolbar.visible'),
759
- label: 'Toolbar visível',
1275
+ label: tx('Toolbar visível'),
760
1276
  controlType: FieldControlType.CHECKBOX,
761
1277
  dataAttributes: { globalPath: 'table.toolbar.visible' },
762
1278
  },
763
1279
  {
764
1280
  name: safeName('table.appearance.density'),
765
- label: 'Aparência: densidade',
1281
+ label: tx('Appearance: density'),
766
1282
  controlType: FieldControlType.SELECT,
767
1283
  selectOptions: [
768
- { text: 'compact', value: 'compact' },
769
- { text: 'comfortable', value: 'comfortable' },
770
- { text: 'spacious', value: 'spacious' },
1284
+ { text: tx('compact'), value: 'compact' },
1285
+ { text: tx('comfortable'), value: 'comfortable' },
1286
+ { text: tx('spacious'), value: 'spacious' },
771
1287
  ],
772
1288
  dataAttributes: { globalPath: 'table.appearance.density' },
773
1289
  },
774
1290
  {
775
1291
  name: safeName('table.appearance.spacing.cellPadding'),
776
- label: 'Aparência: padding das células',
1292
+ label: tx('Appearance: cell padding'),
777
1293
  controlType: FieldControlType.INPUT,
778
- hint: 'Aceita 1 a 4 medidas CSS com unidade, var(...) ou calc(...). Ex.: 6px 12px',
1294
+ hint: tx('Accepts 1 to 4 CSS measures with units, var(...) or calc(...). Example: 6px 12px'),
779
1295
  pattern: TABLE_COMPACT_SPACING_PATTERN,
780
- patternMessage: 'Use 1 a 4 medidas CSS válidas, como 6px 12px.',
1296
+ patternMessage: tx('Use 1 to 4 valid CSS measures, such as 6px 12px.'),
781
1297
  dataAttributes: { globalPath: 'table.appearance.spacing.cellPadding' },
782
1298
  },
783
1299
  {
784
1300
  name: safeName('table.appearance.spacing.headerPadding'),
785
- label: 'Aparência: padding do cabeçalho',
1301
+ label: tx('Appearance: header padding'),
786
1302
  controlType: FieldControlType.INPUT,
787
- hint: 'Aceita 1 a 4 medidas CSS com unidade, var(...) ou calc(...). Ex.: 8px 12px',
1303
+ hint: tx('Accepts 1 to 4 CSS measures with units, var(...) or calc(...). Example: 8px 12px'),
788
1304
  pattern: TABLE_COMPACT_SPACING_PATTERN,
789
- patternMessage: 'Use 1 a 4 medidas CSS válidas, como 8px 12px.',
1305
+ patternMessage: tx('Use 1 to 4 valid CSS measures, such as 8px 12px.'),
790
1306
  dataAttributes: { globalPath: 'table.appearance.spacing.headerPadding' },
791
1307
  },
792
1308
  {
793
1309
  name: safeName('table.appearance.typography.fontSize'),
794
- label: 'Aparência: fonte das células',
1310
+ label: tx('Appearance: cell font size'),
795
1311
  controlType: FieldControlType.INPUT,
796
- hint: 'Aceita uma medida CSS com unidade, var(...) ou calc(...). Ex.: 13px',
1312
+ hint: tx('Accepts a CSS measure with units, var(...) or calc(...). Example: 13px'),
797
1313
  pattern: TABLE_COMPACT_FONT_SIZE_PATTERN,
798
- patternMessage: 'Use uma medida CSS válida, como 13px.',
1314
+ patternMessage: tx('Use a valid CSS measure, such as 13px.'),
799
1315
  dataAttributes: { globalPath: 'table.appearance.typography.fontSize' },
800
1316
  },
801
1317
  {
802
1318
  name: safeName('table.appearance.typography.headerFontSize'),
803
- label: 'Aparência: fonte do cabeçalho',
1319
+ label: tx('Appearance: header font size'),
804
1320
  controlType: FieldControlType.INPUT,
805
- hint: 'Aceita uma medida CSS com unidade, var(...) ou calc(...). Ex.: 13px',
1321
+ hint: tx('Accepts a CSS measure with units, var(...) or calc(...). Example: 13px'),
806
1322
  pattern: TABLE_COMPACT_FONT_SIZE_PATTERN,
807
- patternMessage: 'Use uma medida CSS válida, como 13px.',
1323
+ patternMessage: tx('Use a valid CSS measure, such as 13px.'),
808
1324
  dataAttributes: { globalPath: 'table.appearance.typography.headerFontSize' },
809
- },
810
- {
1325
+ }, {
811
1326
  name: safeName('table.filteringUi.advancedOpenMode'),
812
- label: 'Filtro: modo de abertura',
1327
+ label: tx('Filtro: modo de abertura'),
813
1328
  controlType: FieldControlType.SELECT,
814
1329
  selectOptions: [
815
- { text: 'overlay', value: 'overlay' },
816
- { text: 'modal', value: 'modal' },
817
- { text: 'drawer', value: 'drawer' },
1330
+ { text: tx('overlay'), value: 'overlay' },
1331
+ { text: tx('modal'), value: 'modal' },
1332
+ { text: tx('drawer'), value: 'drawer' },
818
1333
  ],
819
1334
  dataAttributes: { globalPath: 'table.filteringUi.advancedOpenMode' },
820
1335
  },
821
1336
  {
822
1337
  name: safeName('table.filteringUi.overlayVariant'),
823
- label: 'Filtro: overlay (visual)',
1338
+ label: tx('Filtro: overlay (visual)'),
824
1339
  controlType: FieldControlType.SELECT,
825
1340
  selectOptions: [
826
- { text: 'card', value: 'card' },
827
- { text: 'frosted', value: 'frosted' },
1341
+ { text: tx('card'), value: 'card' },
1342
+ { text: tx('frosted'), value: 'frosted' },
828
1343
  ],
829
1344
  dataAttributes: { globalPath: 'table.filteringUi.overlayVariant' },
830
1345
  },
831
1346
  {
832
1347
  name: safeName('table.filteringUi.overlayBackdrop'),
833
- label: 'Filtro: backdrop no overlay',
1348
+ label: tx('Filtro: backdrop no overlay'),
834
1349
  controlType: FieldControlType.CHECKBOX,
835
1350
  dataAttributes: { globalPath: 'table.filteringUi.overlayBackdrop' },
836
1351
  },
837
1352
  // Table messages - confirmations
838
- { name: safeName('table.messages.actions.confirmations.delete'), label: 'Excluir — confirmação', controlType: FieldControlType.INPUT, dataAttributes: { globalPath: 'table.messages.actions.confirmations.delete' } },
839
- { name: safeName('table.messages.actions.confirmations.deleteMultiple'), label: 'Excluir (múltiplos) — confirmação', controlType: FieldControlType.INPUT, dataAttributes: { globalPath: 'table.messages.actions.confirmations.deleteMultiple' } },
840
- { name: safeName('table.messages.actions.confirmations.save'), label: 'Salvar — confirmação', controlType: FieldControlType.INPUT, dataAttributes: { globalPath: 'table.messages.actions.confirmations.save' } },
841
- { name: safeName('table.messages.actions.confirmations.cancel'), label: 'Cancelar — confirmação', controlType: FieldControlType.INPUT, dataAttributes: { globalPath: 'table.messages.actions.confirmations.cancel' } },
842
- { name: safeName('table.messages.actions.confirmations.export'), label: 'Exportar — confirmação', controlType: FieldControlType.INPUT, dataAttributes: { globalPath: 'table.messages.actions.confirmations.export' } },
1353
+ { name: safeName('table.messages.actions.confirmations.delete'), label: tx('Excluir — confirmação'), controlType: FieldControlType.INPUT, dataAttributes: { globalPath: 'table.messages.actions.confirmations.delete' } },
1354
+ { name: safeName('table.messages.actions.confirmations.deleteMultiple'), label: tx('Excluir (múltiplos) — confirmação'), controlType: FieldControlType.INPUT, dataAttributes: { globalPath: 'table.messages.actions.confirmations.deleteMultiple' } },
1355
+ { name: safeName('table.messages.actions.confirmations.save'), label: tx('Salvar — confirmação'), controlType: FieldControlType.INPUT, dataAttributes: { globalPath: 'table.messages.actions.confirmations.save' } },
1356
+ { name: safeName('table.messages.actions.confirmations.cancel'), label: tx('Cancelar — confirmação'), controlType: FieldControlType.INPUT, dataAttributes: { globalPath: 'table.messages.actions.confirmations.cancel' } },
1357
+ { name: safeName('table.messages.actions.confirmations.export'), label: tx('Exportar — confirmação'), controlType: FieldControlType.INPUT, dataAttributes: { globalPath: 'table.messages.actions.confirmations.export' } },
843
1358
  // Table messages - progress
844
- { name: safeName('table.messages.actions.progress.delete'), label: 'Excluir — progresso', controlType: FieldControlType.INPUT, dataAttributes: { globalPath: 'table.messages.actions.progress.delete' } },
845
- { name: safeName('table.messages.actions.progress.deleteMultiple'), label: 'Excluir (múltiplos) — progresso', controlType: FieldControlType.INPUT, dataAttributes: { globalPath: 'table.messages.actions.progress.deleteMultiple' } },
1359
+ { name: safeName('table.messages.actions.progress.delete'), label: tx('Excluir — progresso'), controlType: FieldControlType.INPUT, dataAttributes: { globalPath: 'table.messages.actions.progress.delete' } },
1360
+ { name: safeName('table.messages.actions.progress.deleteMultiple'), label: tx('Excluir (múltiplos) — progresso'), controlType: FieldControlType.INPUT, dataAttributes: { globalPath: 'table.messages.actions.progress.deleteMultiple' } },
846
1361
  // Table messages - success
847
- { name: safeName('table.messages.actions.success.delete'), label: 'Excluir — sucesso', controlType: FieldControlType.INPUT, dataAttributes: { globalPath: 'table.messages.actions.success.delete' } },
848
- { name: safeName('table.messages.actions.success.save'), label: 'Salvar — sucesso', controlType: FieldControlType.INPUT, dataAttributes: { globalPath: 'table.messages.actions.success.save' } },
849
- { name: safeName('table.messages.actions.success.export'), label: 'Exportar — sucesso', controlType: FieldControlType.INPUT, dataAttributes: { globalPath: 'table.messages.actions.success.export' } },
850
- { name: safeName('table.messages.actions.success.import'), label: 'Importar — sucesso', controlType: FieldControlType.INPUT, dataAttributes: { globalPath: 'table.messages.actions.success.import' } },
1362
+ { name: safeName('table.messages.actions.success.delete'), label: tx('Excluir — sucesso'), controlType: FieldControlType.INPUT, dataAttributes: { globalPath: 'table.messages.actions.success.delete' } },
1363
+ { name: safeName('table.messages.actions.success.save'), label: tx('Salvar — sucesso'), controlType: FieldControlType.INPUT, dataAttributes: { globalPath: 'table.messages.actions.success.save' } },
1364
+ { name: safeName('table.messages.actions.success.export'), label: tx('Exportar — sucesso'), controlType: FieldControlType.INPUT, dataAttributes: { globalPath: 'table.messages.actions.success.export' } },
1365
+ { name: safeName('table.messages.actions.success.import'), label: tx('Importar — sucesso'), controlType: FieldControlType.INPUT, dataAttributes: { globalPath: 'table.messages.actions.success.import' } },
851
1366
  // Table messages - errors
852
- { name: safeName('table.messages.actions.errors.delete'), label: 'Excluir — erro', controlType: FieldControlType.INPUT, dataAttributes: { globalPath: 'table.messages.actions.errors.delete' } },
853
- { name: safeName('table.messages.actions.errors.save'), label: 'Salvar — erro', controlType: FieldControlType.INPUT, dataAttributes: { globalPath: 'table.messages.actions.errors.save' } },
854
- { name: safeName('table.messages.actions.errors.export'), label: 'Exportar — erro', controlType: FieldControlType.INPUT, dataAttributes: { globalPath: 'table.messages.actions.errors.export' } },
855
- { name: safeName('table.messages.actions.errors.network'), label: 'Rede — erro', controlType: FieldControlType.INPUT, dataAttributes: { globalPath: 'table.messages.actions.errors.network' } },
856
- { name: safeName('table.messages.actions.errors.permission'), label: 'Permissão — erro', controlType: FieldControlType.INPUT, dataAttributes: { globalPath: 'table.messages.actions.errors.permission' } },
857
- // Dialog Defaults by type
1367
+ { name: safeName('table.messages.actions.errors.delete'), label: tx('Excluir — erro'), controlType: FieldControlType.INPUT, dataAttributes: { globalPath: 'table.messages.actions.errors.delete' } },
1368
+ { name: safeName('table.messages.actions.errors.save'), label: tx('Salvar — erro'), controlType: FieldControlType.INPUT, dataAttributes: { globalPath: 'table.messages.actions.errors.save' } },
1369
+ { name: safeName('table.messages.actions.errors.export'), label: tx('Exportar — erro'), controlType: FieldControlType.INPUT, dataAttributes: { globalPath: 'table.messages.actions.errors.export' } },
1370
+ { name: safeName('table.messages.actions.errors.network'), label: tx('Rede — erro'), controlType: FieldControlType.INPUT, dataAttributes: { globalPath: 'table.messages.actions.errors.network' } },
1371
+ { name: safeName('table.messages.actions.errors.permission'), label: tx('Permissão — erro'), controlType: FieldControlType.INPUT, dataAttributes: { globalPath: 'table.messages.actions.errors.permission' } },
1372
+ // Dialog - Defaults by type
858
1373
  {
859
1374
  name: safeName('dialog.defaults.confirm.ariaRole'),
860
- label: 'Dialog Defaults: confirm ariaRole',
1375
+ label: tx('Dialog defaults: confirm - ariaRole'),
861
1376
  controlType: FieldControlType.SELECT,
862
1377
  selectOptions: [
863
1378
  { text: 'dialog', value: 'dialog' },
@@ -865,24 +1380,24 @@ function buildGlobalConfigFormConfig() {
865
1380
  ],
866
1381
  dataAttributes: { globalPath: 'dialog.defaults.confirm.ariaRole' },
867
1382
  },
868
- { name: safeName('dialog.defaults.confirm.title'), label: 'Dialog Defaults: confirm título', controlType: FieldControlType.INPUT, dataAttributes: { globalPath: 'dialog.defaults.confirm.title' } },
869
- { name: safeName('dialog.defaults.confirm.icon'), label: 'Dialog Defaults: confirm ícone', controlType: FieldControlType.INPUT, dataAttributes: { globalPath: 'dialog.defaults.confirm.icon' } },
870
- { name: safeName('dialog.defaults.confirm.message'), label: 'Dialog Defaults: confirm mensagem', controlType: FieldControlType.TEXTAREA, dataAttributes: { globalPath: 'dialog.defaults.confirm.message' } },
871
- { name: safeName('dialog.defaults.confirm.themeColor'), label: 'Dialog Defaults: confirm themeColor', controlType: FieldControlType.SELECT, selectOptions: [{ text: 'light', value: 'light' }, { text: 'primary', value: 'primary' }, { text: 'dark', value: 'dark' }], dataAttributes: { globalPath: 'dialog.defaults.confirm.themeColor' } },
1383
+ { name: safeName('dialog.defaults.confirm.title'), label: tx('Dialog defaults: confirm - title'), controlType: FieldControlType.INPUT, dataAttributes: { globalPath: 'dialog.defaults.confirm.title' } },
1384
+ { name: safeName('dialog.defaults.confirm.icon'), label: tx('Dialog defaults: confirm - icon'), controlType: FieldControlType.INPUT, dataAttributes: { globalPath: 'dialog.defaults.confirm.icon' } },
1385
+ { name: safeName('dialog.defaults.confirm.message'), label: tx('Dialog defaults: confirm - message'), controlType: FieldControlType.TEXTAREA, dataAttributes: { globalPath: 'dialog.defaults.confirm.message' } },
1386
+ { name: safeName('dialog.defaults.confirm.themeColor'), label: tx('Dialog defaults: confirm - themeColor'), controlType: FieldControlType.SELECT, selectOptions: [{ text: 'light', value: 'light' }, { text: 'primary', value: 'primary' }, { text: 'dark', value: 'dark' }], dataAttributes: { globalPath: 'dialog.defaults.confirm.themeColor' } },
872
1387
  {
873
1388
  name: safeName('dialog.defaults.confirm.closeOnBackdropClick'),
874
- label: 'Dialog Defaults: confirm fechar ao clicar no backdrop',
1389
+ label: tx('Dialog defaults: confirm - close on backdrop click'),
875
1390
  controlType: FieldControlType.TOGGLE,
876
1391
  dataAttributes: { globalPath: 'dialog.defaults.confirm.closeOnBackdropClick' },
877
1392
  },
878
- { name: safeName('dialog.defaults.confirm.disableClose'), label: 'Dialog Defaults: confirm disableClose', controlType: FieldControlType.TOGGLE, dataAttributes: { globalPath: 'dialog.defaults.confirm.disableClose' } },
879
- { name: safeName('dialog.defaults.confirm.hasBackdrop'), label: 'Dialog Defaults: confirm hasBackdrop', controlType: FieldControlType.TOGGLE, dataAttributes: { globalPath: 'dialog.defaults.confirm.hasBackdrop' } },
880
- { name: safeName('dialog.defaults.confirm.panelClass'), label: 'Dialog Defaults: confirm panelClass', controlType: FieldControlType.INPUT, dataAttributes: { globalPath: 'dialog.defaults.confirm.panelClass' } },
881
- { name: safeName('dialog.defaults.confirm.styles'), label: 'Dialog Defaults: confirm styles (JSON)', controlType: FieldControlType.TEXTAREA, dataAttributes: { globalPath: 'dialog.defaults.confirm.styles', monospace: true }, hint: 'Ex.: {"containerColor":"var(--md-sys-color-surface)","containerBorderColor":"var(--md-sys-color-outline-variant)","backdropColor":"var(--md-sys-color-scrim)"}' },
882
- { name: safeName('dialog.defaults.confirm.animation'), label: 'Dialog Defaults: confirm animation (JSON/boolean)', controlType: FieldControlType.TEXTAREA, dataAttributes: { globalPath: 'dialog.defaults.confirm.animation', monospace: true } },
1393
+ { name: safeName('dialog.defaults.confirm.disableClose'), label: tx('Dialog defaults: confirm - disableClose'), controlType: FieldControlType.TOGGLE, dataAttributes: { globalPath: 'dialog.defaults.confirm.disableClose' } },
1394
+ { name: safeName('dialog.defaults.confirm.hasBackdrop'), label: tx('Dialog defaults: confirm - hasBackdrop'), controlType: FieldControlType.TOGGLE, dataAttributes: { globalPath: 'dialog.defaults.confirm.hasBackdrop' } },
1395
+ { name: safeName('dialog.defaults.confirm.panelClass'), label: tx('Dialog defaults: confirm - panelClass'), controlType: FieldControlType.INPUT, dataAttributes: { globalPath: 'dialog.defaults.confirm.panelClass' } },
1396
+ { name: safeName('dialog.defaults.confirm.styles'), label: tx('Dialog defaults: confirm - styles (JSON)'), controlType: FieldControlType.TEXTAREA, dataAttributes: { globalPath: 'dialog.defaults.confirm.styles', monospace: true }, hint: tx('Example JSON: {"containerColor":"var(--md-sys-color-surface)","containerBorderColor":"var(--md-sys-color-outline-variant)","backdropColor":"var(--md-sys-color-scrim)"}') },
1397
+ { name: safeName('dialog.defaults.confirm.animation'), label: tx('Dialog defaults: confirm - animation (JSON/boolean)'), controlType: FieldControlType.TEXTAREA, dataAttributes: { globalPath: 'dialog.defaults.confirm.animation', monospace: true } },
883
1398
  {
884
1399
  name: safeName('dialog.defaults.alert.ariaRole'),
885
- label: 'Dialog Defaults: alert ariaRole',
1400
+ label: tx('Dialog defaults: alert - ariaRole'),
886
1401
  controlType: FieldControlType.SELECT,
887
1402
  selectOptions: [
888
1403
  { text: 'dialog', value: 'dialog' },
@@ -890,24 +1405,24 @@ function buildGlobalConfigFormConfig() {
890
1405
  ],
891
1406
  dataAttributes: { globalPath: 'dialog.defaults.alert.ariaRole' },
892
1407
  },
893
- { name: safeName('dialog.defaults.alert.title'), label: 'Dialog Defaults: alert título', controlType: FieldControlType.INPUT, dataAttributes: { globalPath: 'dialog.defaults.alert.title' } },
894
- { name: safeName('dialog.defaults.alert.icon'), label: 'Dialog Defaults: alert ícone', controlType: FieldControlType.INPUT, dataAttributes: { globalPath: 'dialog.defaults.alert.icon' } },
895
- { name: safeName('dialog.defaults.alert.message'), label: 'Dialog Defaults: alert mensagem', controlType: FieldControlType.TEXTAREA, dataAttributes: { globalPath: 'dialog.defaults.alert.message' } },
896
- { name: safeName('dialog.defaults.alert.themeColor'), label: 'Dialog Defaults: alert themeColor', controlType: FieldControlType.SELECT, selectOptions: [{ text: 'light', value: 'light' }, { text: 'primary', value: 'primary' }, { text: 'dark', value: 'dark' }], dataAttributes: { globalPath: 'dialog.defaults.alert.themeColor' } },
1408
+ { name: safeName('dialog.defaults.alert.title'), label: tx('Dialog defaults: alert - title'), controlType: FieldControlType.INPUT, dataAttributes: { globalPath: 'dialog.defaults.alert.title' } },
1409
+ { name: safeName('dialog.defaults.alert.icon'), label: tx('Dialog defaults: alert - icon'), controlType: FieldControlType.INPUT, dataAttributes: { globalPath: 'dialog.defaults.alert.icon' } },
1410
+ { name: safeName('dialog.defaults.alert.message'), label: tx('Dialog defaults: alert - message'), controlType: FieldControlType.TEXTAREA, dataAttributes: { globalPath: 'dialog.defaults.alert.message' } },
1411
+ { name: safeName('dialog.defaults.alert.themeColor'), label: tx('Dialog defaults: alert - themeColor'), controlType: FieldControlType.SELECT, selectOptions: [{ text: 'light', value: 'light' }, { text: 'primary', value: 'primary' }, { text: 'dark', value: 'dark' }], dataAttributes: { globalPath: 'dialog.defaults.alert.themeColor' } },
897
1412
  {
898
1413
  name: safeName('dialog.defaults.alert.closeOnBackdropClick'),
899
- label: 'Dialog Defaults: alert fechar ao clicar no backdrop',
1414
+ label: tx('Dialog defaults: alert - close on backdrop click'),
900
1415
  controlType: FieldControlType.TOGGLE,
901
1416
  dataAttributes: { globalPath: 'dialog.defaults.alert.closeOnBackdropClick' },
902
1417
  },
903
- { name: safeName('dialog.defaults.alert.disableClose'), label: 'Dialog Defaults: alert disableClose', controlType: FieldControlType.TOGGLE, dataAttributes: { globalPath: 'dialog.defaults.alert.disableClose' } },
904
- { name: safeName('dialog.defaults.alert.hasBackdrop'), label: 'Dialog Defaults: alert hasBackdrop', controlType: FieldControlType.TOGGLE, dataAttributes: { globalPath: 'dialog.defaults.alert.hasBackdrop' } },
905
- { name: safeName('dialog.defaults.alert.panelClass'), label: 'Dialog Defaults: alert panelClass', controlType: FieldControlType.INPUT, dataAttributes: { globalPath: 'dialog.defaults.alert.panelClass' } },
906
- { name: safeName('dialog.defaults.alert.styles'), label: 'Dialog Defaults: alert styles (JSON)', controlType: FieldControlType.TEXTAREA, dataAttributes: { globalPath: 'dialog.defaults.alert.styles', monospace: true }, hint: 'Ex.: {"containerColor":"var(--md-sys-color-surface)","containerBorderColor":"var(--md-sys-color-outline-variant)","backdropColor":"var(--md-sys-color-scrim)"}' },
907
- { name: safeName('dialog.defaults.alert.animation'), label: 'Dialog Defaults: alert animation (JSON/boolean)', controlType: FieldControlType.TEXTAREA, dataAttributes: { globalPath: 'dialog.defaults.alert.animation', monospace: true } },
1418
+ { name: safeName('dialog.defaults.alert.disableClose'), label: tx('Dialog defaults: alert - disableClose'), controlType: FieldControlType.TOGGLE, dataAttributes: { globalPath: 'dialog.defaults.alert.disableClose' } },
1419
+ { name: safeName('dialog.defaults.alert.hasBackdrop'), label: tx('Dialog defaults: alert - hasBackdrop'), controlType: FieldControlType.TOGGLE, dataAttributes: { globalPath: 'dialog.defaults.alert.hasBackdrop' } },
1420
+ { name: safeName('dialog.defaults.alert.panelClass'), label: tx('Dialog defaults: alert - panelClass'), controlType: FieldControlType.INPUT, dataAttributes: { globalPath: 'dialog.defaults.alert.panelClass' } },
1421
+ { name: safeName('dialog.defaults.alert.styles'), label: tx('Dialog defaults: alert - styles (JSON)'), controlType: FieldControlType.TEXTAREA, dataAttributes: { globalPath: 'dialog.defaults.alert.styles', monospace: true }, hint: tx('Example JSON: {"containerColor":"var(--md-sys-color-surface)","containerBorderColor":"var(--md-sys-color-outline-variant)","backdropColor":"var(--md-sys-color-scrim)"}') },
1422
+ { name: safeName('dialog.defaults.alert.animation'), label: tx('Dialog defaults: alert - animation (JSON/boolean)'), controlType: FieldControlType.TEXTAREA, dataAttributes: { globalPath: 'dialog.defaults.alert.animation', monospace: true } },
908
1423
  {
909
1424
  name: safeName('dialog.defaults.prompt.ariaRole'),
910
- label: 'Dialog Defaults: prompt ariaRole',
1425
+ label: tx('Dialog defaults: prompt - ariaRole'),
911
1426
  controlType: FieldControlType.SELECT,
912
1427
  selectOptions: [
913
1428
  { text: 'dialog', value: 'dialog' },
@@ -915,79 +1430,79 @@ function buildGlobalConfigFormConfig() {
915
1430
  ],
916
1431
  dataAttributes: { globalPath: 'dialog.defaults.prompt.ariaRole' },
917
1432
  },
918
- { name: safeName('dialog.defaults.prompt.title'), label: 'Dialog Defaults: prompt título', controlType: FieldControlType.INPUT, dataAttributes: { globalPath: 'dialog.defaults.prompt.title' } },
919
- { name: safeName('dialog.defaults.prompt.icon'), label: 'Dialog Defaults: prompt ícone', controlType: FieldControlType.INPUT, dataAttributes: { globalPath: 'dialog.defaults.prompt.icon' } },
920
- { name: safeName('dialog.defaults.prompt.message'), label: 'Dialog Defaults: prompt mensagem', controlType: FieldControlType.TEXTAREA, dataAttributes: { globalPath: 'dialog.defaults.prompt.message' } },
921
- { name: safeName('dialog.defaults.prompt.themeColor'), label: 'Dialog Defaults: prompt themeColor', controlType: FieldControlType.SELECT, selectOptions: [{ text: 'light', value: 'light' }, { text: 'primary', value: 'primary' }, { text: 'dark', value: 'dark' }], dataAttributes: { globalPath: 'dialog.defaults.prompt.themeColor' } },
1433
+ { name: safeName('dialog.defaults.prompt.title'), label: tx('Dialog defaults: prompt - title'), controlType: FieldControlType.INPUT, dataAttributes: { globalPath: 'dialog.defaults.prompt.title' } },
1434
+ { name: safeName('dialog.defaults.prompt.icon'), label: tx('Dialog defaults: prompt - icon'), controlType: FieldControlType.INPUT, dataAttributes: { globalPath: 'dialog.defaults.prompt.icon' } },
1435
+ { name: safeName('dialog.defaults.prompt.message'), label: tx('Dialog defaults: prompt - message'), controlType: FieldControlType.TEXTAREA, dataAttributes: { globalPath: 'dialog.defaults.prompt.message' } },
1436
+ { name: safeName('dialog.defaults.prompt.themeColor'), label: tx('Dialog defaults: prompt - themeColor'), controlType: FieldControlType.SELECT, selectOptions: [{ text: 'light', value: 'light' }, { text: 'primary', value: 'primary' }, { text: 'dark', value: 'dark' }], dataAttributes: { globalPath: 'dialog.defaults.prompt.themeColor' } },
922
1437
  {
923
1438
  name: safeName('dialog.defaults.prompt.closeOnBackdropClick'),
924
- label: 'Dialog Defaults: prompt fechar ao clicar no backdrop',
1439
+ label: tx('Dialog defaults: prompt - close on backdrop click'),
925
1440
  controlType: FieldControlType.TOGGLE,
926
1441
  dataAttributes: { globalPath: 'dialog.defaults.prompt.closeOnBackdropClick' },
927
1442
  },
928
- { name: safeName('dialog.defaults.prompt.disableClose'), label: 'Dialog Defaults: prompt disableClose', controlType: FieldControlType.TOGGLE, dataAttributes: { globalPath: 'dialog.defaults.prompt.disableClose' } },
929
- { name: safeName('dialog.defaults.prompt.hasBackdrop'), label: 'Dialog Defaults: prompt hasBackdrop', controlType: FieldControlType.TOGGLE, dataAttributes: { globalPath: 'dialog.defaults.prompt.hasBackdrop' } },
930
- { name: safeName('dialog.defaults.prompt.panelClass'), label: 'Dialog Defaults: prompt panelClass', controlType: FieldControlType.INPUT, dataAttributes: { globalPath: 'dialog.defaults.prompt.panelClass' } },
931
- { name: safeName('dialog.defaults.prompt.styles'), label: 'Dialog Defaults: prompt styles (JSON)', controlType: FieldControlType.TEXTAREA, dataAttributes: { globalPath: 'dialog.defaults.prompt.styles', monospace: true }, hint: 'Ex.: {"containerColor":"var(--md-sys-color-surface)","containerBorderColor":"var(--md-sys-color-outline-variant)","backdropColor":"var(--md-sys-color-scrim)"}' },
932
- { name: safeName('dialog.defaults.prompt.animation'), label: 'Dialog Defaults: prompt animation (JSON/boolean)', controlType: FieldControlType.TEXTAREA, dataAttributes: { globalPath: 'dialog.defaults.prompt.animation', monospace: true } },
933
- // Dialog Variants per profile (danger, info, success, question, error)
1443
+ { name: safeName('dialog.defaults.prompt.disableClose'), label: tx('Dialog defaults: prompt - disableClose'), controlType: FieldControlType.TOGGLE, dataAttributes: { globalPath: 'dialog.defaults.prompt.disableClose' } },
1444
+ { name: safeName('dialog.defaults.prompt.hasBackdrop'), label: tx('Dialog defaults: prompt - hasBackdrop'), controlType: FieldControlType.TOGGLE, dataAttributes: { globalPath: 'dialog.defaults.prompt.hasBackdrop' } },
1445
+ { name: safeName('dialog.defaults.prompt.panelClass'), label: tx('Dialog defaults: prompt - panelClass'), controlType: FieldControlType.INPUT, dataAttributes: { globalPath: 'dialog.defaults.prompt.panelClass' } },
1446
+ { name: safeName('dialog.defaults.prompt.styles'), label: tx('Dialog defaults: prompt - styles (JSON)'), controlType: FieldControlType.TEXTAREA, dataAttributes: { globalPath: 'dialog.defaults.prompt.styles', monospace: true }, hint: tx('Example JSON: {"containerColor":"var(--md-sys-color-surface)","containerBorderColor":"var(--md-sys-color-outline-variant)","backdropColor":"var(--md-sys-color-scrim)"}') },
1447
+ { name: safeName('dialog.defaults.prompt.animation'), label: tx('Dialog defaults: prompt - animation (JSON/boolean)'), controlType: FieldControlType.TEXTAREA, dataAttributes: { globalPath: 'dialog.defaults.prompt.animation', monospace: true } },
1448
+ // Dialog - Variants per profile (danger, info, success, question, error)
934
1449
  // Each variant exposes commonly customized fields + JSON editors for actions/styles
935
1450
  // danger
936
- { name: safeName('dialog.variants.danger.title'), label: 'Variant danger título', controlType: FieldControlType.INPUT, dataAttributes: { globalPath: 'dialog.variants.danger.title' } },
937
- { name: safeName('dialog.variants.danger.icon'), label: 'Variant danger ícone', controlType: FieldControlType.INPUT, dataAttributes: { globalPath: 'dialog.variants.danger.icon' } },
938
- { name: safeName('dialog.variants.danger.message'), label: 'Variant danger mensagem', controlType: FieldControlType.TEXTAREA, dataAttributes: { globalPath: 'dialog.variants.danger.message' } },
939
- { name: safeName('dialog.variants.danger.ariaRole'), label: 'Variant danger ariaRole', controlType: FieldControlType.SELECT, selectOptions: [{ text: 'dialog', value: 'dialog' }, { text: 'alertdialog', value: 'alertdialog' }], dataAttributes: { globalPath: 'dialog.variants.danger.ariaRole' } },
940
- { name: safeName('dialog.variants.danger.closeOnBackdropClick'), label: 'Variant danger fechar ao clicar no backdrop', controlType: FieldControlType.TOGGLE, dataAttributes: { globalPath: 'dialog.variants.danger.closeOnBackdropClick' } },
941
- { name: safeName('dialog.variants.danger.panelClass'), label: 'Variant danger panelClass', controlType: FieldControlType.INPUT, dataAttributes: { globalPath: 'dialog.variants.danger.panelClass' } },
942
- { name: safeName('dialog.variants.danger.actions'), label: 'Variant danger actions (JSON array)', controlType: FieldControlType.TEXTAREA, dataAttributes: { globalPath: 'dialog.variants.danger.actions', monospace: true }, hint: 'Ex.: [{"id":"cancel","text":"Cancelar","role":"secondary","close":true,"cssClass":"btn"},{"id":"confirm","text":"Excluir","role":"primary","close":true,"cssClass":"btn btn-danger","icon":"delete"}]' },
943
- { name: safeName('dialog.variants.danger.styles'), label: 'Variant danger styles (JSON)', controlType: FieldControlType.TEXTAREA, dataAttributes: { globalPath: 'dialog.variants.danger.styles', monospace: true }, hint: 'Ex.: {"containerColor":"var(--md-sys-color-surface)","containerBorderColor":"var(--md-sys-color-outline-variant)","backdropColor":"var(--md-sys-color-scrim)","actionButtonRadius":"8px"}' },
944
- { name: safeName('dialog.variants.danger.animation'), label: 'Variant danger animation (JSON/boolean)', controlType: FieldControlType.TEXTAREA, dataAttributes: { globalPath: 'dialog.variants.danger.animation', monospace: true } },
1451
+ { name: safeName('dialog.variants.danger.title'), label: tx('Variant danger - title'), controlType: FieldControlType.INPUT, dataAttributes: { globalPath: 'dialog.variants.danger.title' } },
1452
+ { name: safeName('dialog.variants.danger.icon'), label: tx('Variant danger - icon'), controlType: FieldControlType.INPUT, dataAttributes: { globalPath: 'dialog.variants.danger.icon' } },
1453
+ { name: safeName('dialog.variants.danger.message'), label: tx('Variant danger - message'), controlType: FieldControlType.TEXTAREA, dataAttributes: { globalPath: 'dialog.variants.danger.message' } },
1454
+ { name: safeName('dialog.variants.danger.ariaRole'), label: tx('Variant danger - ariaRole'), controlType: FieldControlType.SELECT, selectOptions: [{ text: 'dialog', value: 'dialog' }, { text: 'alertdialog', value: 'alertdialog' }], dataAttributes: { globalPath: 'dialog.variants.danger.ariaRole' } },
1455
+ { name: safeName('dialog.variants.danger.closeOnBackdropClick'), label: tx('Variant danger - close on backdrop click'), controlType: FieldControlType.TOGGLE, dataAttributes: { globalPath: 'dialog.variants.danger.closeOnBackdropClick' } },
1456
+ { name: safeName('dialog.variants.danger.panelClass'), label: tx('Variant danger - panelClass'), controlType: FieldControlType.INPUT, dataAttributes: { globalPath: 'dialog.variants.danger.panelClass' } },
1457
+ { name: safeName('dialog.variants.danger.actions'), label: tx('Variant danger - actions (JSON array)'), controlType: FieldControlType.TEXTAREA, dataAttributes: { globalPath: 'dialog.variants.danger.actions', monospace: true }, hint: tx('Example JSON array: [{"id":"cancel","text":"Cancel","role":"secondary","close":true,"cssClass":"btn"},{"id":"confirm","text":"Delete","role":"primary","close":true,"cssClass":"btn btn-danger","icon":"delete"}]') },
1458
+ { name: safeName('dialog.variants.danger.styles'), label: tx('Variant danger - styles (JSON)'), controlType: FieldControlType.TEXTAREA, dataAttributes: { globalPath: 'dialog.variants.danger.styles', monospace: true }, hint: tx('Example JSON: {"containerColor":"var(--md-sys-color-surface)","containerBorderColor":"var(--md-sys-color-outline-variant)","backdropColor":"var(--md-sys-color-scrim)","actionButtonRadius":"8px"}') },
1459
+ { name: safeName('dialog.variants.danger.animation'), label: tx('Variant danger - animation (JSON/boolean)'), controlType: FieldControlType.TEXTAREA, dataAttributes: { globalPath: 'dialog.variants.danger.animation', monospace: true } },
945
1460
  // info
946
- { name: safeName('dialog.variants.info.title'), label: 'Variant info título', controlType: FieldControlType.INPUT, dataAttributes: { globalPath: 'dialog.variants.info.title' } },
947
- { name: safeName('dialog.variants.info.icon'), label: 'Variant info ícone', controlType: FieldControlType.INPUT, dataAttributes: { globalPath: 'dialog.variants.info.icon' } },
948
- { name: safeName('dialog.variants.info.message'), label: 'Variant info mensagem', controlType: FieldControlType.TEXTAREA, dataAttributes: { globalPath: 'dialog.variants.info.message' } },
949
- { name: safeName('dialog.variants.info.ariaRole'), label: 'Variant info ariaRole', controlType: FieldControlType.SELECT, selectOptions: [{ text: 'dialog', value: 'dialog' }, { text: 'alertdialog', value: 'alertdialog' }], dataAttributes: { globalPath: 'dialog.variants.info.ariaRole' } },
950
- { name: safeName('dialog.variants.info.closeOnBackdropClick'), label: 'Variant info fechar ao clicar no backdrop', controlType: FieldControlType.TOGGLE, dataAttributes: { globalPath: 'dialog.variants.info.closeOnBackdropClick' } },
951
- { name: safeName('dialog.variants.info.panelClass'), label: 'Variant info panelClass', controlType: FieldControlType.INPUT, dataAttributes: { globalPath: 'dialog.variants.info.panelClass' } },
952
- { name: safeName('dialog.variants.info.actions'), label: 'Variant info actions (JSON array)', controlType: FieldControlType.TEXTAREA, dataAttributes: { globalPath: 'dialog.variants.info.actions', monospace: true } },
953
- { name: safeName('dialog.variants.info.styles'), label: 'Variant info styles (JSON)', controlType: FieldControlType.TEXTAREA, dataAttributes: { globalPath: 'dialog.variants.info.styles', monospace: true }, hint: 'Ex.: {"containerColor":"var(--md-sys-color-surface)","containerBorderColor":"var(--md-sys-color-outline-variant)","backdropColor":"var(--md-sys-color-scrim)","actionButtonRadius":"8px"}' },
954
- { name: safeName('dialog.variants.info.animation'), label: 'Variant info animation (JSON/boolean)', controlType: FieldControlType.TEXTAREA, dataAttributes: { globalPath: 'dialog.variants.info.animation', monospace: true } },
1461
+ { name: safeName('dialog.variants.info.title'), label: tx('Variant info - title'), controlType: FieldControlType.INPUT, dataAttributes: { globalPath: 'dialog.variants.info.title' } },
1462
+ { name: safeName('dialog.variants.info.icon'), label: tx('Variant info - icon'), controlType: FieldControlType.INPUT, dataAttributes: { globalPath: 'dialog.variants.info.icon' } },
1463
+ { name: safeName('dialog.variants.info.message'), label: tx('Variant info - message'), controlType: FieldControlType.TEXTAREA, dataAttributes: { globalPath: 'dialog.variants.info.message' } },
1464
+ { name: safeName('dialog.variants.info.ariaRole'), label: tx('Variant info - ariaRole'), controlType: FieldControlType.SELECT, selectOptions: [{ text: 'dialog', value: 'dialog' }, { text: 'alertdialog', value: 'alertdialog' }], dataAttributes: { globalPath: 'dialog.variants.info.ariaRole' } },
1465
+ { name: safeName('dialog.variants.info.closeOnBackdropClick'), label: tx('Variant info - close on backdrop click'), controlType: FieldControlType.TOGGLE, dataAttributes: { globalPath: 'dialog.variants.info.closeOnBackdropClick' } },
1466
+ { name: safeName('dialog.variants.info.panelClass'), label: tx('Variant info - panelClass'), controlType: FieldControlType.INPUT, dataAttributes: { globalPath: 'dialog.variants.info.panelClass' } },
1467
+ { name: safeName('dialog.variants.info.actions'), label: tx('Variant info - actions (JSON array)'), controlType: FieldControlType.TEXTAREA, dataAttributes: { globalPath: 'dialog.variants.info.actions', monospace: true } },
1468
+ { name: safeName('dialog.variants.info.styles'), label: tx('Variant info - styles (JSON)'), controlType: FieldControlType.TEXTAREA, dataAttributes: { globalPath: 'dialog.variants.info.styles', monospace: true }, hint: tx('Example JSON: {"containerColor":"var(--md-sys-color-surface)","containerBorderColor":"var(--md-sys-color-outline-variant)","backdropColor":"var(--md-sys-color-scrim)","actionButtonRadius":"8px"}') },
1469
+ { name: safeName('dialog.variants.info.animation'), label: tx('Variant info - animation (JSON/boolean)'), controlType: FieldControlType.TEXTAREA, dataAttributes: { globalPath: 'dialog.variants.info.animation', monospace: true } },
955
1470
  // success
956
- { name: safeName('dialog.variants.success.title'), label: 'Variant success título', controlType: FieldControlType.INPUT, dataAttributes: { globalPath: 'dialog.variants.success.title' } },
957
- { name: safeName('dialog.variants.success.icon'), label: 'Variant success ícone', controlType: FieldControlType.INPUT, dataAttributes: { globalPath: 'dialog.variants.success.icon' } },
958
- { name: safeName('dialog.variants.success.message'), label: 'Variant success mensagem', controlType: FieldControlType.TEXTAREA, dataAttributes: { globalPath: 'dialog.variants.success.message' } },
959
- { name: safeName('dialog.variants.success.ariaRole'), label: 'Variant success ariaRole', controlType: FieldControlType.SELECT, selectOptions: [{ text: 'dialog', value: 'dialog' }, { text: 'alertdialog', value: 'alertdialog' }], dataAttributes: { globalPath: 'dialog.variants.success.ariaRole' } },
960
- { name: safeName('dialog.variants.success.closeOnBackdropClick'), label: 'Variant success fechar ao clicar no backdrop', controlType: FieldControlType.TOGGLE, dataAttributes: { globalPath: 'dialog.variants.success.closeOnBackdropClick' } },
961
- { name: safeName('dialog.variants.success.panelClass'), label: 'Variant success panelClass', controlType: FieldControlType.INPUT, dataAttributes: { globalPath: 'dialog.variants.success.panelClass' } },
962
- { name: safeName('dialog.variants.success.actions'), label: 'Variant success actions (JSON array)', controlType: FieldControlType.TEXTAREA, dataAttributes: { globalPath: 'dialog.variants.success.actions', monospace: true } },
963
- { name: safeName('dialog.variants.success.styles'), label: 'Variant success styles (JSON)', controlType: FieldControlType.TEXTAREA, dataAttributes: { globalPath: 'dialog.variants.success.styles', monospace: true }, hint: 'Ex.: {"containerColor":"var(--md-sys-color-surface)","containerBorderColor":"var(--md-sys-color-outline-variant)","backdropColor":"var(--md-sys-color-scrim)","actionButtonRadius":"8px"}' },
964
- { name: safeName('dialog.variants.success.animation'), label: 'Variant success animation (JSON/boolean)', controlType: FieldControlType.TEXTAREA, dataAttributes: { globalPath: 'dialog.variants.success.animation', monospace: true } },
1471
+ { name: safeName('dialog.variants.success.title'), label: tx('Variant success - title'), controlType: FieldControlType.INPUT, dataAttributes: { globalPath: 'dialog.variants.success.title' } },
1472
+ { name: safeName('dialog.variants.success.icon'), label: tx('Variant success - icon'), controlType: FieldControlType.INPUT, dataAttributes: { globalPath: 'dialog.variants.success.icon' } },
1473
+ { name: safeName('dialog.variants.success.message'), label: tx('Variant success - message'), controlType: FieldControlType.TEXTAREA, dataAttributes: { globalPath: 'dialog.variants.success.message' } },
1474
+ { name: safeName('dialog.variants.success.ariaRole'), label: tx('Variant success - ariaRole'), controlType: FieldControlType.SELECT, selectOptions: [{ text: 'dialog', value: 'dialog' }, { text: 'alertdialog', value: 'alertdialog' }], dataAttributes: { globalPath: 'dialog.variants.success.ariaRole' } },
1475
+ { name: safeName('dialog.variants.success.closeOnBackdropClick'), label: tx('Variant success - close on backdrop click'), controlType: FieldControlType.TOGGLE, dataAttributes: { globalPath: 'dialog.variants.success.closeOnBackdropClick' } },
1476
+ { name: safeName('dialog.variants.success.panelClass'), label: tx('Variant success - panelClass'), controlType: FieldControlType.INPUT, dataAttributes: { globalPath: 'dialog.variants.success.panelClass' } },
1477
+ { name: safeName('dialog.variants.success.actions'), label: tx('Variant success - actions (JSON array)'), controlType: FieldControlType.TEXTAREA, dataAttributes: { globalPath: 'dialog.variants.success.actions', monospace: true } },
1478
+ { name: safeName('dialog.variants.success.styles'), label: tx('Variant success - styles (JSON)'), controlType: FieldControlType.TEXTAREA, dataAttributes: { globalPath: 'dialog.variants.success.styles', monospace: true }, hint: tx('Example JSON: {"containerColor":"var(--md-sys-color-surface)","containerBorderColor":"var(--md-sys-color-outline-variant)","backdropColor":"var(--md-sys-color-scrim)","actionButtonRadius":"8px"}') },
1479
+ { name: safeName('dialog.variants.success.animation'), label: tx('Variant success - animation (JSON/boolean)'), controlType: FieldControlType.TEXTAREA, dataAttributes: { globalPath: 'dialog.variants.success.animation', monospace: true } },
965
1480
  // question
966
- { name: safeName('dialog.variants.question.title'), label: 'Variant question título', controlType: FieldControlType.INPUT, dataAttributes: { globalPath: 'dialog.variants.question.title' } },
967
- { name: safeName('dialog.variants.question.icon'), label: 'Variant question ícone', controlType: FieldControlType.INPUT, dataAttributes: { globalPath: 'dialog.variants.question.icon' } },
968
- { name: safeName('dialog.variants.question.message'), label: 'Variant question mensagem', controlType: FieldControlType.TEXTAREA, dataAttributes: { globalPath: 'dialog.variants.question.message' } },
969
- { name: safeName('dialog.variants.question.ariaRole'), label: 'Variant question ariaRole', controlType: FieldControlType.SELECT, selectOptions: [{ text: 'dialog', value: 'dialog' }, { text: 'alertdialog', value: 'alertdialog' }], dataAttributes: { globalPath: 'dialog.variants.question.ariaRole' } },
970
- { name: safeName('dialog.variants.question.closeOnBackdropClick'), label: 'Variant question fechar ao clicar no backdrop', controlType: FieldControlType.TOGGLE, dataAttributes: { globalPath: 'dialog.variants.question.closeOnBackdropClick' } },
971
- { name: safeName('dialog.variants.question.panelClass'), label: 'Variant question panelClass', controlType: FieldControlType.INPUT, dataAttributes: { globalPath: 'dialog.variants.question.panelClass' } },
972
- { name: safeName('dialog.variants.question.actions'), label: 'Variant question actions (JSON array)', controlType: FieldControlType.TEXTAREA, dataAttributes: { globalPath: 'dialog.variants.question.actions', monospace: true } },
973
- { name: safeName('dialog.variants.question.styles'), label: 'Variant question styles (JSON)', controlType: FieldControlType.TEXTAREA, dataAttributes: { globalPath: 'dialog.variants.question.styles', monospace: true }, hint: 'Ex.: {"containerColor":"var(--md-sys-color-surface)","containerBorderColor":"var(--md-sys-color-outline-variant)","backdropColor":"var(--md-sys-color-scrim)","actionButtonRadius":"8px"}' },
974
- { name: safeName('dialog.variants.question.animation'), label: 'Variant question animation (JSON/boolean)', controlType: FieldControlType.TEXTAREA, dataAttributes: { globalPath: 'dialog.variants.question.animation', monospace: true } },
1481
+ { name: safeName('dialog.variants.question.title'), label: tx('Variant question - title'), controlType: FieldControlType.INPUT, dataAttributes: { globalPath: 'dialog.variants.question.title' } },
1482
+ { name: safeName('dialog.variants.question.icon'), label: tx('Variant question - icon'), controlType: FieldControlType.INPUT, dataAttributes: { globalPath: 'dialog.variants.question.icon' } },
1483
+ { name: safeName('dialog.variants.question.message'), label: tx('Variant question - message'), controlType: FieldControlType.TEXTAREA, dataAttributes: { globalPath: 'dialog.variants.question.message' } },
1484
+ { name: safeName('dialog.variants.question.ariaRole'), label: tx('Variant question - ariaRole'), controlType: FieldControlType.SELECT, selectOptions: [{ text: 'dialog', value: 'dialog' }, { text: 'alertdialog', value: 'alertdialog' }], dataAttributes: { globalPath: 'dialog.variants.question.ariaRole' } },
1485
+ { name: safeName('dialog.variants.question.closeOnBackdropClick'), label: tx('Variant question - close on backdrop click'), controlType: FieldControlType.TOGGLE, dataAttributes: { globalPath: 'dialog.variants.question.closeOnBackdropClick' } },
1486
+ { name: safeName('dialog.variants.question.panelClass'), label: tx('Variant question - panelClass'), controlType: FieldControlType.INPUT, dataAttributes: { globalPath: 'dialog.variants.question.panelClass' } },
1487
+ { name: safeName('dialog.variants.question.actions'), label: tx('Variant question - actions (JSON array)'), controlType: FieldControlType.TEXTAREA, dataAttributes: { globalPath: 'dialog.variants.question.actions', monospace: true } },
1488
+ { name: safeName('dialog.variants.question.styles'), label: tx('Variant question - styles (JSON)'), controlType: FieldControlType.TEXTAREA, dataAttributes: { globalPath: 'dialog.variants.question.styles', monospace: true }, hint: tx('Example JSON: {"containerColor":"var(--md-sys-color-surface)","containerBorderColor":"var(--md-sys-color-outline-variant)","backdropColor":"var(--md-sys-color-scrim)","actionButtonRadius":"8px"}') },
1489
+ { name: safeName('dialog.variants.question.animation'), label: tx('Variant question - animation (JSON/boolean)'), controlType: FieldControlType.TEXTAREA, dataAttributes: { globalPath: 'dialog.variants.question.animation', monospace: true } },
975
1490
  // error
976
- { name: safeName('dialog.variants.error.title'), label: 'Variant error título', controlType: FieldControlType.INPUT, dataAttributes: { globalPath: 'dialog.variants.error.title' } },
977
- { name: safeName('dialog.variants.error.icon'), label: 'Variant error ícone', controlType: FieldControlType.INPUT, dataAttributes: { globalPath: 'dialog.variants.error.icon' } },
978
- { name: safeName('dialog.variants.error.message'), label: 'Variant error mensagem', controlType: FieldControlType.TEXTAREA, dataAttributes: { globalPath: 'dialog.variants.error.message' } },
979
- { name: safeName('dialog.variants.error.ariaRole'), label: 'Variant error ariaRole', controlType: FieldControlType.SELECT, selectOptions: [{ text: 'dialog', value: 'dialog' }, { text: 'alertdialog', value: 'alertdialog' }], dataAttributes: { globalPath: 'dialog.variants.error.ariaRole' } },
980
- { name: safeName('dialog.variants.error.closeOnBackdropClick'), label: 'Variant error fechar ao clicar no backdrop', controlType: FieldControlType.TOGGLE, dataAttributes: { globalPath: 'dialog.variants.error.closeOnBackdropClick' } },
981
- { name: safeName('dialog.variants.error.panelClass'), label: 'Variant error panelClass', controlType: FieldControlType.INPUT, dataAttributes: { globalPath: 'dialog.variants.error.panelClass' } },
982
- { name: safeName('dialog.variants.error.actions'), label: 'Variant error actions (JSON array)', controlType: FieldControlType.TEXTAREA, dataAttributes: { globalPath: 'dialog.variants.error.actions', monospace: true } },
983
- { name: safeName('dialog.variants.error.styles'), label: 'Variant error styles (JSON)', controlType: FieldControlType.TEXTAREA, dataAttributes: { globalPath: 'dialog.variants.error.styles', monospace: true }, hint: 'Ex.: {"containerColor":"var(--md-sys-color-surface)","containerBorderColor":"var(--md-sys-color-outline-variant)","backdropColor":"var(--md-sys-color-scrim)","actionButtonRadius":"8px"}' },
984
- { name: safeName('dialog.variants.error.animation'), label: 'Variant error animation (JSON/boolean)', controlType: FieldControlType.TEXTAREA, dataAttributes: { globalPath: 'dialog.variants.error.animation', monospace: true } },
1491
+ { name: safeName('dialog.variants.error.title'), label: tx('Variant error - title'), controlType: FieldControlType.INPUT, dataAttributes: { globalPath: 'dialog.variants.error.title' } },
1492
+ { name: safeName('dialog.variants.error.icon'), label: tx('Variant error - icon'), controlType: FieldControlType.INPUT, dataAttributes: { globalPath: 'dialog.variants.error.icon' } },
1493
+ { name: safeName('dialog.variants.error.message'), label: tx('Variant error - message'), controlType: FieldControlType.TEXTAREA, dataAttributes: { globalPath: 'dialog.variants.error.message' } },
1494
+ { name: safeName('dialog.variants.error.ariaRole'), label: tx('Variant error - ariaRole'), controlType: FieldControlType.SELECT, selectOptions: [{ text: 'dialog', value: 'dialog' }, { text: 'alertdialog', value: 'alertdialog' }], dataAttributes: { globalPath: 'dialog.variants.error.ariaRole' } },
1495
+ { name: safeName('dialog.variants.error.closeOnBackdropClick'), label: tx('Variant error - close on backdrop click'), controlType: FieldControlType.TOGGLE, dataAttributes: { globalPath: 'dialog.variants.error.closeOnBackdropClick' } },
1496
+ { name: safeName('dialog.variants.error.panelClass'), label: tx('Variant error - panelClass'), controlType: FieldControlType.INPUT, dataAttributes: { globalPath: 'dialog.variants.error.panelClass' } },
1497
+ { name: safeName('dialog.variants.error.actions'), label: tx('Variant error - actions (JSON array)'), controlType: FieldControlType.TEXTAREA, dataAttributes: { globalPath: 'dialog.variants.error.actions', monospace: true } },
1498
+ { name: safeName('dialog.variants.error.styles'), label: tx('Variant error - styles (JSON)'), controlType: FieldControlType.TEXTAREA, dataAttributes: { globalPath: 'dialog.variants.error.styles', monospace: true }, hint: tx('Example JSON: {"containerColor":"var(--md-sys-color-surface)","containerBorderColor":"var(--md-sys-color-outline-variant)","backdropColor":"var(--md-sys-color-scrim)","actionButtonRadius":"8px"}') },
1499
+ { name: safeName('dialog.variants.error.animation'), label: tx('Variant error - animation (JSON/boolean)'), controlType: FieldControlType.TEXTAREA, dataAttributes: { globalPath: 'dialog.variants.error.animation', monospace: true } },
985
1500
  ];
986
1501
  const cfg = {
987
1502
  sections: [
988
1503
  {
989
1504
  id: 'crud',
990
- title: 'CRUD',
1505
+ title: tx('CRUD'),
991
1506
  rows: [
992
1507
  {
993
1508
  id: 'crud-row-1',
@@ -1014,7 +1529,7 @@ function buildGlobalConfigFormConfig() {
1014
1529
  },
1015
1530
  {
1016
1531
  id: 'dynamic-fields',
1017
- title: 'Dynamic Fields',
1532
+ title: tx('Dynamic Fields'),
1018
1533
  rows: [
1019
1534
  {
1020
1535
  id: 'df-row-1',
@@ -1035,7 +1550,7 @@ function buildGlobalConfigFormConfig() {
1035
1550
  },
1036
1551
  {
1037
1552
  id: 'ai-credentials',
1038
- title: 'Credenciais', // Internal title, UI might override
1553
+ title: tx('Credentials'), // Internal title, UI might override
1039
1554
  rows: [
1040
1555
  {
1041
1556
  id: 'ai-cred-row-1',
@@ -1048,7 +1563,7 @@ function buildGlobalConfigFormConfig() {
1048
1563
  },
1049
1564
  {
1050
1565
  id: 'ai-model',
1051
- title: 'Modelo & Comportamento',
1566
+ title: tx('Model & Behavior'),
1052
1567
  rows: [
1053
1568
  {
1054
1569
  id: 'ai-mod-row-1',
@@ -1061,7 +1576,7 @@ function buildGlobalConfigFormConfig() {
1061
1576
  },
1062
1577
  {
1063
1578
  id: 'ai-embedding',
1064
- title: 'Embeddings',
1579
+ title: tx('Embeddings (RAG)'),
1065
1580
  rows: [
1066
1581
  {
1067
1582
  id: 'ai-embed-row-1',
@@ -1075,7 +1590,7 @@ function buildGlobalConfigFormConfig() {
1075
1590
  },
1076
1591
  {
1077
1592
  id: 'cache',
1078
- title: 'Cache & Persistência',
1593
+ title: tx('Cache & Persistência'),
1079
1594
  rows: [
1080
1595
  {
1081
1596
  id: 'cache-row-1',
@@ -1087,7 +1602,7 @@ function buildGlobalConfigFormConfig() {
1087
1602
  },
1088
1603
  {
1089
1604
  id: 'table',
1090
- title: 'Tabela',
1605
+ title: tx('Tabela'),
1091
1606
  rows: [
1092
1607
  {
1093
1608
  id: 'tbl-row-1',
@@ -1148,7 +1663,7 @@ function buildGlobalConfigFormConfig() {
1148
1663
  },
1149
1664
  {
1150
1665
  id: 'dialog',
1151
- title: 'Dialog',
1666
+ title: tx('Dialog'),
1152
1667
  rows: [
1153
1668
  {
1154
1669
  id: 'dlg-row-defaults',
@@ -1273,9 +1788,9 @@ function buildGlobalConfigFormConfig() {
1273
1788
  actions: {
1274
1789
  placement: 'afterSections',
1275
1790
  // Hide internal form actions; Settings Panel footer handles Apply/Save
1276
- submit: { visible: false, label: 'Salvar' },
1277
- cancel: { visible: false, label: 'Cancelar' },
1278
- reset: { visible: false, label: 'Redefinir', type: 'reset' },
1791
+ submit: { visible: false, label: tx('Salvar') },
1792
+ cancel: { visible: false, label: tx('Cancelar') },
1793
+ reset: { visible: false, label: tx('Redefinir'), type: 'reset' },
1279
1794
  },
1280
1795
  fieldMetadata: fields,
1281
1796
  };
@@ -1301,10 +1816,10 @@ const TABLE_COMPACT_FONT_SIZE_PATHS = new Set([
1301
1816
  'table.appearance.typography.headerFontSize',
1302
1817
  ]);
1303
1818
  const TABLE_COMPACT_FIELD_LABELS = {
1304
- 'table.appearance.spacing.cellPadding': 'padding das células',
1305
- 'table.appearance.spacing.headerPadding': 'padding do cabeçalho',
1306
- 'table.appearance.typography.fontSize': 'fonte das células',
1307
- 'table.appearance.typography.headerFontSize': 'fonte do cabeçalho',
1819
+ 'table.appearance.spacing.cellPadding': 'cell padding',
1820
+ 'table.appearance.spacing.headerPadding': 'header padding',
1821
+ 'table.appearance.typography.fontSize': 'cell font size',
1822
+ 'table.appearance.typography.headerFontSize': 'header font size',
1308
1823
  };
1309
1824
  const TABLE_COMPACT_LENGTH_TOKEN = '(?:0|(?:\\d+|\\d*\\.\\d+)(?:px|rem|em|%|vh|vw|svh|svw|lvh|lvw|dvh|dvw|ch|ex))';
1310
1825
  const TABLE_COMPACT_SPACING_REGEX = new RegExp(`^(?:var\\(.+\\)|calc\\(.+\\)|${TABLE_COMPACT_LENGTH_TOKEN}(?:\\s+${TABLE_COMPACT_LENGTH_TOKEN}){0,3})$`, 'i');
@@ -1331,6 +1846,7 @@ class GlobalConfigEditorComponent {
1331
1846
  hostAiModel;
1332
1847
  hostAiEmbedding;
1333
1848
  destroyRef = inject(DestroyRef);
1849
+ i18n = inject(PraxisI18nService);
1334
1850
  iconPicker = inject(IconPickerService);
1335
1851
  aiApi = inject(AiBackendApiService);
1336
1852
  cdr = inject(ChangeDetectorRef);
@@ -1364,7 +1880,7 @@ class GlobalConfigEditorComponent {
1364
1880
  apiKeyLast4 = null;
1365
1881
  hasStoredApiKey = false;
1366
1882
  hasStoredGlobalConfig = false;
1367
- configSourceLabel = 'Padrões do servidor (env vars)';
1883
+ configSourceLabel = this.tx('Server defaults (env vars)');
1368
1884
  // UX: API Key monitoring
1369
1885
  apiKeyChanged$ = new Subject();
1370
1886
  hasApiKey = false;
@@ -1376,12 +1892,12 @@ class GlobalConfigEditorComponent {
1376
1892
  get apiKeyStatusLabel() {
1377
1893
  const apiKey = this.currentValues?.[this.safeName('ai.apiKey')] || '';
1378
1894
  if (apiKey)
1379
- return 'Chave informada';
1895
+ return this.tx('Key provided');
1380
1896
  if (this.apiKeyLast4)
1381
- return `Chave salva (****${this.apiKeyLast4})`;
1897
+ return this.tx('Saved key (****{{last4}})', { last4: this.apiKeyLast4 });
1382
1898
  if (this.hasStoredApiKey)
1383
- return 'Chave salva';
1384
- return 'Sem chave salva';
1899
+ return this.tx('Saved key');
1900
+ return this.tx('No saved key');
1385
1901
  }
1386
1902
  constructor(admin, snack) {
1387
1903
  this.admin = admin;
@@ -1390,7 +1906,7 @@ class GlobalConfigEditorComponent {
1390
1906
  async ngOnInit() {
1391
1907
  const cfg = this.admin.getEffectiveConfig();
1392
1908
  const flat = this.flatten(cfg);
1393
- this.formConfig = buildGlobalConfigFormConfig();
1909
+ this.formConfig = buildGlobalConfigFormConfig(this.tx.bind(this));
1394
1910
  this.applyConfigSnapshot(flat, { resetForms: false });
1395
1911
  await this.loadProviderCatalog();
1396
1912
  this.applyProviderOptions();
@@ -1535,7 +2051,7 @@ class GlobalConfigEditorComponent {
1535
2051
  const ref = g.host.createComponent(this.dynamicFormCtor);
1536
2052
  ref.setInput('config', g.cfg);
1537
2053
  ref.setInput('mode', 'edit');
1538
- // Não habilitar o modo de edição de layout (canvas) queremos apenas edição de valores
2054
+ // Não habilitar o modo de edição de layout (canvas) - queremos apenas edição de valores
1539
2055
  ref.setInput('enableCustomization', false);
1540
2056
  const inst = ref.instance;
1541
2057
  // FORÇAR estado de sucesso para renderizar o formulário sem resourcePath
@@ -1608,7 +2124,7 @@ class GlobalConfigEditorComponent {
1608
2124
  {
1609
2125
  id: 'gemini',
1610
2126
  label: 'Google Gemini',
1611
- description: 'Modelos rápidos e multimodais do Google.',
2127
+ description: this.tx('Fast multimodal models from Google.'),
1612
2128
  defaultModel: 'gemini-2.0-flash',
1613
2129
  requiresApiKey: true,
1614
2130
  supportsModels: true,
@@ -1618,7 +2134,7 @@ class GlobalConfigEditorComponent {
1618
2134
  {
1619
2135
  id: 'openai',
1620
2136
  label: 'OpenAI',
1621
- description: 'Modelos GPT para texto e chat.',
2137
+ description: this.tx('GPT models for text and chat.'),
1622
2138
  defaultModel: 'gpt-4o-mini',
1623
2139
  requiresApiKey: true,
1624
2140
  supportsModels: true,
@@ -1628,7 +2144,7 @@ class GlobalConfigEditorComponent {
1628
2144
  {
1629
2145
  id: 'xai',
1630
2146
  label: 'xAI (Grok)',
1631
- description: 'Modelos Grok focados em raciocínio.',
2147
+ description: this.tx('Grok models focused on reasoning.'),
1632
2148
  defaultModel: 'grok-2-latest',
1633
2149
  requiresApiKey: true,
1634
2150
  supportsModels: true,
@@ -1638,7 +2154,7 @@ class GlobalConfigEditorComponent {
1638
2154
  {
1639
2155
  id: 'mock',
1640
2156
  label: 'Mock (dev)',
1641
- description: 'Modo local para testes sem chave.',
2157
+ description: this.tx('Local mode for tests without a key.'),
1642
2158
  defaultModel: 'mock-default',
1643
2159
  requiresApiKey: false,
1644
2160
  supportsModels: true,
@@ -1827,8 +2343,8 @@ class GlobalConfigEditorComponent {
1827
2343
  this.hasStoredGlobalConfig = false;
1828
2344
  }
1829
2345
  this.configSourceLabel = this.hasStoredGlobalConfig
1830
- ? 'Configuração salva (UI) sobrescreve os defaults do servidor'
1831
- : 'Padrões do servidor (env vars)';
2346
+ ? this.tx('Saved configuration (UI) - overrides server defaults')
2347
+ : this.tx('Server defaults (env vars)');
1832
2348
  }
1833
2349
  async clearStoredConfig() {
1834
2350
  if (this.isClearingGlobalConfig)
@@ -1843,13 +2359,13 @@ class GlobalConfigEditorComponent {
1843
2359
  this.refreshAiStateAfterConfig();
1844
2360
  await this.refreshStoredConfigState();
1845
2361
  try {
1846
- this.snack.open('Configuração global limpa. Usando defaults do servidor.', undefined, { duration: 2500 });
2362
+ this.snack.open(this.tx('Global config cleared. Using server defaults.'), undefined, { duration: 2500 });
1847
2363
  }
1848
2364
  catch { }
1849
2365
  }
1850
2366
  catch (err) {
1851
2367
  try {
1852
- this.snack.open('Falha ao limpar a configuração global.', undefined, { duration: 4000 });
2368
+ this.snack.open(this.tx('Failed to clear global config.'), undefined, { duration: 4000 });
1853
2369
  }
1854
2370
  catch { }
1855
2371
  }
@@ -1976,10 +2492,10 @@ class GlobalConfigEditorComponent {
1976
2492
  const model = this.availableModels.find(m => m.name.endsWith(modelName));
1977
2493
  if (model) {
1978
2494
  const formatLimit = (n) => n ? (n >= 1000 ? (n / 1000).toFixed(0) + 'k' : n) : 'N/A';
1979
- this.selectedModelDetails = `Modelo: ${model.displayName || modelName} | Tokens (in/out): ${formatLimit(model.inputTokenLimit)}/${formatLimit(model.outputTokenLimit)} | Métodos: ${model.supportedGenerationMethods?.join(', ') || 'N/A'}`;
2495
+ this.selectedModelDetails = this.tx('Model: {{model}} | Tokens (in/out): {{in}}/{{out}} | Methods: {{methods}}', { model: model.displayName || modelName, in: formatLimit(model.inputTokenLimit), out: formatLimit(model.outputTokenLimit), methods: model.supportedGenerationMethods?.join(', ') || 'N/A' });
1980
2496
  }
1981
2497
  else {
1982
- this.selectedModelDetails = 'Detalhes do modelo não disponíveis.';
2498
+ this.selectedModelDetails = this.tx('No model details available.');
1983
2499
  }
1984
2500
  }
1985
2501
  // SettingsPanel expects these methods
@@ -2015,7 +2531,7 @@ class GlobalConfigEditorComponent {
2015
2531
  this.initialValues = { ...this.currentValues };
2016
2532
  this.isDirty$.next(false);
2017
2533
  try {
2018
- this.snack.open('Configurações salvas', undefined, { duration: 2000 });
2534
+ this.snack.open(this.tx('Settings saved'), undefined, { duration: 2000 });
2019
2535
  }
2020
2536
  catch { }
2021
2537
  return partial;
@@ -2038,7 +2554,7 @@ class GlobalConfigEditorComponent {
2038
2554
  const meta = this.findProvider(provider);
2039
2555
  if (meta?.supportsModels === false) {
2040
2556
  if (!silent) {
2041
- this.aiTestResult = { success: false, message: 'Este provedor não oferece catálogo de modelos.' };
2557
+ this.aiTestResult = { success: false, message: this.tx('This provider has no model catalog.') };
2042
2558
  this.cdr.detectChanges();
2043
2559
  }
2044
2560
  return;
@@ -2046,7 +2562,7 @@ class GlobalConfigEditorComponent {
2046
2562
  const requiresKey = meta?.requiresApiKey !== false;
2047
2563
  const hasKey = !!apiKey || this.hasStoredApiKey || !requiresKey;
2048
2564
  if (requiresKey && !hasKey) {
2049
- this.aiTestResult = { success: false, message: 'Insira uma chave de API para buscar modelos.' };
2565
+ this.aiTestResult = { success: false, message: this.tx('Enter an API key to fetch models.') };
2050
2566
  this.cdr.detectChanges();
2051
2567
  return;
2052
2568
  }
@@ -2061,8 +2577,7 @@ class GlobalConfigEditorComponent {
2061
2577
  request.apiKey = apiKey;
2062
2578
  const response = await firstValueFrom(this.aiApi.listModels(request));
2063
2579
  if (!response?.success) {
2064
- const msg = response?.message || 'Erro ao buscar modelos.';
2065
- throw new Error(msg);
2580
+ throw new Error(this.tx('Error fetching models.'));
2066
2581
  }
2067
2582
  const models = response.models || [];
2068
2583
  this.availableModels = models; // Store available models
@@ -2083,9 +2598,9 @@ class GlobalConfigEditorComponent {
2083
2598
  }
2084
2599
  catch (error) {
2085
2600
  this.logger.error('[GlobalConfigEditor] Error fetching models', this.buildLogOptions({ error, provider }, { context: { actionId: 'models.fetch' } }));
2086
- this.aiTestResult = { success: false, message: error.message || 'Erro ao buscar modelos.' };
2601
+ this.aiTestResult = { success: false, message: this.tx('Error fetching models.') };
2087
2602
  if (!silent) {
2088
- this.snack.open('Erro ao buscar modelos. Verifique a chave de API.', 'Fechar', { duration: 5000 });
2603
+ this.snack.open(this.tx('Error fetching models. Check your API key.'), this.tx('Close'), { duration: 5000 });
2089
2604
  }
2090
2605
  }
2091
2606
  finally {
@@ -2115,7 +2630,7 @@ class GlobalConfigEditorComponent {
2115
2630
  this.recreateAiModelForm();
2116
2631
  if (!silent) {
2117
2632
  try {
2118
- this.snack.open(`Lista de modelos atualizada (${modelOptions.length} modelos)`, undefined, { duration: 3000 });
2633
+ this.snack.open(this.tx('Model list updated ({{count}} models)', { count: modelOptions.length }), undefined, { duration: 3000 });
2119
2634
  }
2120
2635
  catch { }
2121
2636
  }
@@ -2133,7 +2648,7 @@ class GlobalConfigEditorComponent {
2133
2648
  const requiresKey = meta?.requiresApiKey !== false;
2134
2649
  const hasKey = !!apiKey || this.hasStoredApiKey || !requiresKey;
2135
2650
  if (requiresKey && !hasKey) {
2136
- this.aiTestResult = { success: false, message: 'Insira uma chave de API para testar.' };
2651
+ this.aiTestResult = { success: false, message: this.tx('Enter an API key to test.') };
2137
2652
  this.isTestingAi = false;
2138
2653
  this.cdr.detectChanges();
2139
2654
  return;
@@ -2144,17 +2659,16 @@ class GlobalConfigEditorComponent {
2144
2659
  request.apiKey = apiKey;
2145
2660
  const response = await firstValueFrom(this.aiApi.testProvider(request));
2146
2661
  if (!response?.success) {
2147
- throw new Error(response?.message || 'Falha ao testar conexao.');
2662
+ throw new Error(this.tx('Failed to test connection.'));
2148
2663
  }
2149
- this.aiTestResult = { success: true, message: response.message || 'Conexao estabelecida com sucesso!' };
2664
+ this.aiTestResult = { success: true, message: this.tx('Connection established successfully!') };
2150
2665
  this.hasApiKey = true; // Garantir desbloqueio da seção de modelo após sucesso
2151
2666
  // Após validar a chave, já buscar a lista de modelos para preencher o select
2152
2667
  await this.refreshModels(true);
2153
2668
  }
2154
2669
  catch (err) {
2155
2670
  this.logger.error('[GlobalConfigEditor] AI Connection Test Error', this.buildLogOptions({ error: err, provider, model: selectedModel }, { context: { actionId: 'provider.test-connection' } }));
2156
- const msg = err?.message || 'Erro desconhecido';
2157
- this.aiTestResult = { success: false, message: msg };
2671
+ this.aiTestResult = { success: false, message: this.tx('Failed to test connection.') };
2158
2672
  }
2159
2673
  finally {
2160
2674
  this.isTestingAi = false;
@@ -2175,6 +2689,10 @@ class GlobalConfigEditorComponent {
2175
2689
  safeName(path) {
2176
2690
  return path.replace(/[^a-zA-Z0-9_]/g, '_');
2177
2691
  }
2692
+ tx(text, params) {
2693
+ const normalized = normalizeMojibakeText(text);
2694
+ return this.i18n.t(normalized, params, normalized, PRAXIS_SETTINGS_PANEL_I18N_NAMESPACE);
2695
+ }
2178
2696
  buildChangedValues() {
2179
2697
  const out = {};
2180
2698
  for (const [safe, value] of Object.entries(this.currentValues)) {
@@ -2199,21 +2717,7 @@ class GlobalConfigEditorComponent {
2199
2717
  return initial !== current;
2200
2718
  }
2201
2719
  resolveSaveErrorMessage(err) {
2202
- const apiMessage = typeof err?.error?.message === 'string' ? err.error.message : null;
2203
- const details = err?.error?.details;
2204
- if (apiMessage && apiMessage.trim()) {
2205
- return apiMessage;
2206
- }
2207
- if (details && typeof details === 'object') {
2208
- const first = Object.values(details).find((v) => typeof v === 'string' && v.trim());
2209
- if (typeof first === 'string') {
2210
- return first;
2211
- }
2212
- }
2213
- if (typeof err?.message === 'string' && err.message.trim()) {
2214
- return err.message;
2215
- }
2216
- return 'Falha ao salvar configurações.';
2720
+ return this.tx('Save failed.');
2217
2721
  }
2218
2722
  normalizeFieldValue(path, value) {
2219
2723
  if (typeof value !== 'string')
@@ -2260,7 +2764,7 @@ class GlobalConfigEditorComponent {
2260
2764
  if (!normalized)
2261
2765
  continue;
2262
2766
  if (!check.regex.test(normalized)) {
2263
- return `Valor inválido em ${TABLE_COMPACT_FIELD_LABELS[check.path]}. Use uma string CSS simples, como ${check.example}.`;
2767
+ return `Invalid value in ${TABLE_COMPACT_FIELD_LABELS[check.path]}. Use a simple CSS string, such as ${check.example}.`;
2264
2768
  }
2265
2769
  }
2266
2770
  return null;
@@ -2370,9 +2874,9 @@ class GlobalConfigEditorComponent {
2370
2874
  <mat-expansion-panel-header>
2371
2875
  <mat-panel-title>
2372
2876
  <mat-icon class="panel-icon">construction</mat-icon>
2373
- CRUD
2877
+ {{ tx('CRUD') }}
2374
2878
  </mat-panel-title>
2375
- <mat-panel-description>Políticas globais de abertura, back e header</mat-panel-description>
2879
+ <mat-panel-description>{{ tx('Global policies for opening, back and header') }}</mat-panel-description>
2376
2880
  </mat-expansion-panel-header>
2377
2881
  <ng-template #hostCrud></ng-template>
2378
2882
  </mat-expansion-panel>
@@ -2380,9 +2884,9 @@ class GlobalConfigEditorComponent {
2380
2884
  <mat-expansion-panel-header>
2381
2885
  <mat-panel-title>
2382
2886
  <mat-icon class="panel-icon">dynamic_form</mat-icon>
2383
- Dynamic Fields
2887
+ {{ tx('Dynamic Fields') }}
2384
2888
  </mat-panel-title>
2385
- <mat-panel-description>Async Select, cascata e paginação</mat-panel-description>
2889
+ <mat-panel-description>{{ tx('Async Select, cascade and pagination') }}</mat-panel-description>
2386
2890
  </mat-expansion-panel-header>
2387
2891
  <ng-template #hostFields></ng-template>
2388
2892
  </mat-expansion-panel>
@@ -2390,9 +2894,9 @@ class GlobalConfigEditorComponent {
2390
2894
  <mat-expansion-panel-header>
2391
2895
  <mat-panel-title>
2392
2896
  <mat-icon class="panel-icon">cached</mat-icon>
2393
- Cache & Persistência
2897
+ {{ tx('Cache & Persistence') }}
2394
2898
  </mat-panel-title>
2395
- <mat-panel-description>Estratégia de cache de schema (local vs server)</mat-panel-description>
2899
+ <mat-panel-description>{{ tx('Schema cache strategy (local vs server)') }}</mat-panel-description>
2396
2900
  </mat-expansion-panel-header>
2397
2901
  <ng-template #hostCache></ng-template>
2398
2902
  </mat-expansion-panel>
@@ -2400,9 +2904,9 @@ class GlobalConfigEditorComponent {
2400
2904
  <mat-expansion-panel-header>
2401
2905
  <mat-panel-title>
2402
2906
  <mat-icon class="panel-icon">psychology</mat-icon>
2403
- Inteligência Artificial
2907
+ {{ tx('Artificial Intelligence') }}
2404
2908
  </mat-panel-title>
2405
- <mat-panel-description>Integração com LLM</mat-panel-description>
2909
+ <mat-panel-description>{{ tx('LLM integration') }}</mat-panel-description>
2406
2910
  </mat-expansion-panel-header>
2407
2911
 
2408
2912
  <div class="ai-config-container">
@@ -2411,23 +2915,23 @@ class GlobalConfigEditorComponent {
2411
2915
  <mat-icon>settings_suggest</mat-icon>
2412
2916
  <span>{{ configSourceLabel }}</span>
2413
2917
  </div>
2414
- <button
2415
- mat-stroked-button
2416
- type="button"
2417
- class="ai-action-btn ai-action-btn--clear"
2418
- *ngIf="hasStoredGlobalConfig"
2419
- [attr.aria-busy]="isClearingGlobalConfig ? 'true' : null"
2420
- [disabled]="isClearingGlobalConfig"
2421
- (click)="clearStoredConfig()"
2422
- matTooltip="Apaga o config salvo e volta aos defaults do servidor"
2918
+ <button
2919
+ mat-stroked-button
2920
+ type="button"
2921
+ class="ai-action-btn ai-action-btn--clear"
2922
+ *ngIf="hasStoredGlobalConfig"
2923
+ [attr.aria-busy]="isClearingGlobalConfig ? 'true' : null"
2924
+ [disabled]="isClearingGlobalConfig"
2925
+ (click)="clearStoredConfig()"
2926
+ [matTooltip]="tx('Clear saved config and return to server defaults')"
2423
2927
  >
2424
2928
  <ng-container *ngIf="isClearingGlobalConfig; else clearContent">
2425
2929
  <mat-spinner diameter="16" class="btn-spinner"></mat-spinner>
2426
- <span class="ai-action-label">Limpando...</span>
2930
+ <span class="ai-action-label">{{ tx('Clearing...') }}</span>
2427
2931
  </ng-container>
2428
2932
  <ng-template #clearContent>
2429
2933
  <mat-icon>delete_sweep</mat-icon>
2430
- <span class="ai-action-label">Limpar config salvo</span>
2934
+ <span class="ai-action-label">{{ tx('Clear saved config') }}</span>
2431
2935
  </ng-template>
2432
2936
  </button>
2433
2937
  </div>
@@ -2435,7 +2939,7 @@ class GlobalConfigEditorComponent {
2435
2939
  <div class="ai-group">
2436
2940
  <div class="ai-group-header">
2437
2941
  <div class="ai-group-title">
2438
- <mat-icon>vpn_key</mat-icon> Credenciais
2942
+ <mat-icon>vpn_key</mat-icon> {{ tx('Credentials') }}
2439
2943
  </div>
2440
2944
  <button mat-stroked-button
2441
2945
  type="button"
@@ -2444,15 +2948,15 @@ class GlobalConfigEditorComponent {
2444
2948
  [attr.aria-busy]="isTestingAi ? 'true' : null"
2445
2949
  (click)="testAiConnection()"
2446
2950
  [disabled]="isTestingAi || !hasApiKey"
2447
- matTooltip="Testar conexão com a chave informada">
2951
+ [matTooltip]="tx('Test connection with the provided key')">
2448
2952
  <ng-container *ngIf="isTestingAi; else btnContent">
2449
2953
  <mat-spinner diameter="16" class="btn-spinner"></mat-spinner>
2450
- <span class="ai-action-label">Conectando...</span>
2954
+ <span class="ai-action-label">{{ tx('Connecting...') }}</span>
2451
2955
  </ng-container>
2452
2956
  <ng-template #btnContent>
2453
2957
  <mat-icon>{{ aiTestResult?.success ? 'check' : 'bolt' }}</mat-icon>
2454
2958
  <span class="ai-action-label">
2455
- {{ aiTestResult?.success ? 'Conectado' : 'Testar conexão' }}
2959
+ {{ aiTestResult?.success ? tx('Connected') : tx('Test connection') }}
2456
2960
  </span>
2457
2961
  </ng-template>
2458
2962
  </button>
@@ -2494,7 +2998,7 @@ class GlobalConfigEditorComponent {
2494
2998
  </div>
2495
2999
  <div class="ai-provider-key is-unlocked" *ngIf="selectedProvider?.requiresApiKey === false">
2496
3000
  <mat-icon>check_circle</mat-icon>
2497
- <span>Sem chave necessária</span>
3001
+ <span>{{ tx('No key required') }}</span>
2498
3002
  </div>
2499
3003
  </div>
2500
3004
  <div class="ai-credentials-row">
@@ -2514,12 +3018,12 @@ class GlobalConfigEditorComponent {
2514
3018
  <div class="ai-group" [class.disabled-group]="!hasApiKey">
2515
3019
  <div class="ai-group-header">
2516
3020
  <div class="ai-group-title">
2517
- <mat-icon>smart_toy</mat-icon> Modelo & Comportamento
3021
+ <mat-icon>smart_toy</mat-icon> {{ tx('Model & Behavior') }}
2518
3022
  </div>
2519
3023
  <div class="ai-header-actions">
2520
- <span class="ai-subtext" *ngIf="hasApiKey">Escolha o modelo após validar a chave.</span>
2521
- <mat-chip-option *ngIf="!hasApiKey" disabled>Requer chave API validada</mat-chip-option>
2522
- <button mat-icon-button (click)="refreshModels(true)" [disabled]="isTestingAi || !hasApiKey" matTooltip="Atualizar lista de modelos" aria-label="Atualizar lista de modelos">
3024
+ <span class="ai-subtext" *ngIf="hasApiKey">{{ tx('Choose the model after validating the key.') }}</span>
3025
+ <mat-chip-option *ngIf="!hasApiKey" disabled>{{ tx('API key validated required') }}</mat-chip-option>
3026
+ <button mat-icon-button (click)="refreshModels(true)" [disabled]="isTestingAi || !hasApiKey" [matTooltip]="tx('Refresh model list')" [attr.aria-label]="tx('Refresh model list')">
2523
3027
  <mat-icon [class.spin]="isRefetchingModels">sync</mat-icon>
2524
3028
  </button>
2525
3029
  </div>
@@ -2538,7 +3042,7 @@ class GlobalConfigEditorComponent {
2538
3042
 
2539
3043
  <div class="ai-placeholder" *ngIf="!hasApiKey">
2540
3044
  <mat-icon>lock</mat-icon>
2541
- <span>Configure e teste sua chave de API para desbloquear a seleção de modelos.</span>
3045
+ <span>{{ tx('Configure and test your API key to unlock model selection.') }}</span>
2542
3046
  </div>
2543
3047
  </div>
2544
3048
 
@@ -2546,7 +3050,7 @@ class GlobalConfigEditorComponent {
2546
3050
  <div class="ai-group">
2547
3051
  <div class="ai-group-header">
2548
3052
  <div class="ai-group-title">
2549
- <mat-icon>scatter_plot</mat-icon> Embeddings (RAG)
3053
+ <mat-icon>scatter_plot</mat-icon> {{ tx('Embeddings (RAG)') }}
2550
3054
  </div>
2551
3055
  <div class="ai-header-actions">
2552
3056
  <button
@@ -2555,19 +3059,19 @@ class GlobalConfigEditorComponent {
2555
3059
  class="ai-action-btn"
2556
3060
  (click)="useLlmForEmbeddings()"
2557
3061
  [disabled]="!canUseLlmForEmbeddings"
2558
- matTooltip="Aplicar provedor e chave do LLM aos embeddings"
3062
+ [matTooltip]="tx('Use the LLM provider and key for embeddings')"
2559
3063
  >
2560
3064
  <mat-icon>merge_type</mat-icon>
2561
- <span class="ai-action-label">Usar mesmo LLM</span>
3065
+ <span class="ai-action-label">{{ tx('Use the LLM provider and key for embeddings') }}</span>
2562
3066
  </button>
2563
- <mat-chip-option *ngIf="!canUseLlmForEmbeddings" disabled>Provedor sem embeddings</mat-chip-option>
3067
+ <mat-chip-option *ngIf="!canUseLlmForEmbeddings" disabled>{{ tx('Provider has no embeddings') }}</mat-chip-option>
2564
3068
  </div>
2565
3069
  </div>
2566
3070
  <div class="ai-subtext">
2567
- Configure o provedor de embeddings para buscas vetoriais (templates e schemas).
3071
+ {{ tx('Configure the embeddings provider for vector search (templates and schemas).') }}
2568
3072
  </div>
2569
3073
  <div class="ai-subtext" *ngIf="embeddingUseSameAsLlm">
2570
- Sincronizado com o LLM. Os campos abaixo acompanham a credencial principal.
3074
+ {{ tx('Synchronized with the LLM. The fields below follow the primary credential.') }}
2571
3075
  </div>
2572
3076
  <div class="ai-embedding-row">
2573
3077
  <ng-template #hostAiEmbedding></ng-template>
@@ -2575,7 +3079,7 @@ class GlobalConfigEditorComponent {
2575
3079
  <div class="ai-feedback ai-feedback--warn" *ngIf="embeddingDimensionMismatch">
2576
3080
  <mat-icon>warning</mat-icon>
2577
3081
  <span class="error-text">
2578
- Dimensão de embeddings diferente do banco (768). Ajuste para 768 ou refaça a migração.
3082
+ {{ tx('Embedding dimension mismatch with database (768). Adjust to 768 or redo the migration.') }}
2579
3083
  </span>
2580
3084
  </div>
2581
3085
  </div>
@@ -2586,9 +3090,9 @@ class GlobalConfigEditorComponent {
2586
3090
  <mat-expansion-panel-header>
2587
3091
  <mat-panel-title>
2588
3092
  <mat-icon class="panel-icon">table_chart</mat-icon>
2589
- Tabela
3093
+ {{ tx('Table') }}
2590
3094
  </mat-panel-title>
2591
- <mat-panel-description>Toolbar, aparência e filtro avançado</mat-panel-description>
3095
+ <mat-panel-description>{{ tx('Toolbar, appearance and advanced filter') }}</mat-panel-description>
2592
3096
  </mat-expansion-panel-header>
2593
3097
  <ng-template #hostTable></ng-template>
2594
3098
  </mat-expansion-panel>
@@ -2596,27 +3100,27 @@ class GlobalConfigEditorComponent {
2596
3100
  <mat-expansion-panel-header>
2597
3101
  <mat-panel-title>
2598
3102
  <mat-icon class="panel-icon">forum</mat-icon>
2599
- Dialog
3103
+ {{ tx('Dialog') }}
2600
3104
  </mat-panel-title>
2601
- <mat-panel-description>Defaults e variants (danger, info, success, question, error)</mat-panel-description>
3105
+ <mat-panel-description>{{ tx('Defaults and variants (danger, info, success, question, error)') }}</mat-panel-description>
2602
3106
  </mat-expansion-panel-header>
2603
3107
  <ng-template #hostDialog></ng-template>
2604
3108
  <!-- Icon UX helpers for Dialog variants -->
2605
3109
  <div class="dlg-icon-helpers">
2606
- <div class="dlg-icon-helpers__head">Ícones por perfil (atalhos)</div>
3110
+ <div class="dlg-icon-helpers__head">{{ tx('Icons by profile (shortcuts)') }}</div>
2607
3111
  <div class="dlg-icon-helpers__row" *ngFor="let k of dialogVariantKeys">
2608
3112
  <div class="dlg-icon-helpers__label">{{ k }}</div>
2609
3113
  <mat-icon aria-hidden="true" [praxisIcon]="getVariantIcon(k) || 'mi:help_outline'" class="dlg-icon-helpers__preview"></mat-icon>
2610
- <button mat-stroked-button color="primary" type="button" (click)="pickVariantIcon(k)" matTooltip="Escolher ícone para {{k}}">
3114
+ <button mat-stroked-button color="primary" type="button" (click)="pickVariantIcon(k)" [matTooltip]="tx('Pick icon for {{key}}', { key: k })">
2611
3115
  <mat-icon>search</mat-icon>
2612
- Escolher ícone
3116
+ {{ tx('Pick icon') }}
2613
3117
  </button>
2614
- <button mat-icon-button type="button" *ngIf="getVariantIcon(k)" (click)="clearVariantIcon(k)" matTooltip="Limpar ícone de {{k}}" aria-label="Limpar ícone">
3118
+ <button mat-icon-button type="button" *ngIf="getVariantIcon(k)" (click)="clearVariantIcon(k)" [matTooltip]="tx('Clear icon for {{key}}', { key: k })" [attr.aria-label]="tx('Clear icon')">
2615
3119
  <mat-icon>backspace</mat-icon>
2616
3120
  </button>
2617
3121
  <span class="dlg-icon-helpers__value" *ngIf="getVariantIcon(k)">{{ getVariantIcon(k) }}</span>
2618
3122
  </div>
2619
- <div class="dlg-icon-helpers__hint">Dica: O campo de texto acima permanece editável. Estes botões apenas facilitam a escolha/limpeza com preview.</div>
3123
+ <div class="dlg-icon-helpers__hint">{{ tx('The text field above remains editable. These buttons only help with selection/clear preview.') }}</div>
2620
3124
  </div>
2621
3125
  </mat-expansion-panel>
2622
3126
  </mat-accordion>
@@ -2630,9 +3134,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
2630
3134
  <mat-expansion-panel-header>
2631
3135
  <mat-panel-title>
2632
3136
  <mat-icon class="panel-icon">construction</mat-icon>
2633
- CRUD
3137
+ {{ tx('CRUD') }}
2634
3138
  </mat-panel-title>
2635
- <mat-panel-description>Políticas globais de abertura, back e header</mat-panel-description>
3139
+ <mat-panel-description>{{ tx('Global policies for opening, back and header') }}</mat-panel-description>
2636
3140
  </mat-expansion-panel-header>
2637
3141
  <ng-template #hostCrud></ng-template>
2638
3142
  </mat-expansion-panel>
@@ -2640,9 +3144,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
2640
3144
  <mat-expansion-panel-header>
2641
3145
  <mat-panel-title>
2642
3146
  <mat-icon class="panel-icon">dynamic_form</mat-icon>
2643
- Dynamic Fields
3147
+ {{ tx('Dynamic Fields') }}
2644
3148
  </mat-panel-title>
2645
- <mat-panel-description>Async Select, cascata e paginação</mat-panel-description>
3149
+ <mat-panel-description>{{ tx('Async Select, cascade and pagination') }}</mat-panel-description>
2646
3150
  </mat-expansion-panel-header>
2647
3151
  <ng-template #hostFields></ng-template>
2648
3152
  </mat-expansion-panel>
@@ -2650,9 +3154,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
2650
3154
  <mat-expansion-panel-header>
2651
3155
  <mat-panel-title>
2652
3156
  <mat-icon class="panel-icon">cached</mat-icon>
2653
- Cache & Persistência
3157
+ {{ tx('Cache & Persistence') }}
2654
3158
  </mat-panel-title>
2655
- <mat-panel-description>Estratégia de cache de schema (local vs server)</mat-panel-description>
3159
+ <mat-panel-description>{{ tx('Schema cache strategy (local vs server)') }}</mat-panel-description>
2656
3160
  </mat-expansion-panel-header>
2657
3161
  <ng-template #hostCache></ng-template>
2658
3162
  </mat-expansion-panel>
@@ -2660,9 +3164,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
2660
3164
  <mat-expansion-panel-header>
2661
3165
  <mat-panel-title>
2662
3166
  <mat-icon class="panel-icon">psychology</mat-icon>
2663
- Inteligência Artificial
3167
+ {{ tx('Artificial Intelligence') }}
2664
3168
  </mat-panel-title>
2665
- <mat-panel-description>Integração com LLM</mat-panel-description>
3169
+ <mat-panel-description>{{ tx('LLM integration') }}</mat-panel-description>
2666
3170
  </mat-expansion-panel-header>
2667
3171
 
2668
3172
  <div class="ai-config-container">
@@ -2671,23 +3175,23 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
2671
3175
  <mat-icon>settings_suggest</mat-icon>
2672
3176
  <span>{{ configSourceLabel }}</span>
2673
3177
  </div>
2674
- <button
2675
- mat-stroked-button
2676
- type="button"
2677
- class="ai-action-btn ai-action-btn--clear"
2678
- *ngIf="hasStoredGlobalConfig"
2679
- [attr.aria-busy]="isClearingGlobalConfig ? 'true' : null"
2680
- [disabled]="isClearingGlobalConfig"
2681
- (click)="clearStoredConfig()"
2682
- matTooltip="Apaga o config salvo e volta aos defaults do servidor"
3178
+ <button
3179
+ mat-stroked-button
3180
+ type="button"
3181
+ class="ai-action-btn ai-action-btn--clear"
3182
+ *ngIf="hasStoredGlobalConfig"
3183
+ [attr.aria-busy]="isClearingGlobalConfig ? 'true' : null"
3184
+ [disabled]="isClearingGlobalConfig"
3185
+ (click)="clearStoredConfig()"
3186
+ [matTooltip]="tx('Clear saved config and return to server defaults')"
2683
3187
  >
2684
3188
  <ng-container *ngIf="isClearingGlobalConfig; else clearContent">
2685
3189
  <mat-spinner diameter="16" class="btn-spinner"></mat-spinner>
2686
- <span class="ai-action-label">Limpando...</span>
3190
+ <span class="ai-action-label">{{ tx('Clearing...') }}</span>
2687
3191
  </ng-container>
2688
3192
  <ng-template #clearContent>
2689
3193
  <mat-icon>delete_sweep</mat-icon>
2690
- <span class="ai-action-label">Limpar config salvo</span>
3194
+ <span class="ai-action-label">{{ tx('Clear saved config') }}</span>
2691
3195
  </ng-template>
2692
3196
  </button>
2693
3197
  </div>
@@ -2695,7 +3199,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
2695
3199
  <div class="ai-group">
2696
3200
  <div class="ai-group-header">
2697
3201
  <div class="ai-group-title">
2698
- <mat-icon>vpn_key</mat-icon> Credenciais
3202
+ <mat-icon>vpn_key</mat-icon> {{ tx('Credentials') }}
2699
3203
  </div>
2700
3204
  <button mat-stroked-button
2701
3205
  type="button"
@@ -2704,15 +3208,15 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
2704
3208
  [attr.aria-busy]="isTestingAi ? 'true' : null"
2705
3209
  (click)="testAiConnection()"
2706
3210
  [disabled]="isTestingAi || !hasApiKey"
2707
- matTooltip="Testar conexão com a chave informada">
3211
+ [matTooltip]="tx('Test connection with the provided key')">
2708
3212
  <ng-container *ngIf="isTestingAi; else btnContent">
2709
3213
  <mat-spinner diameter="16" class="btn-spinner"></mat-spinner>
2710
- <span class="ai-action-label">Conectando...</span>
3214
+ <span class="ai-action-label">{{ tx('Connecting...') }}</span>
2711
3215
  </ng-container>
2712
3216
  <ng-template #btnContent>
2713
3217
  <mat-icon>{{ aiTestResult?.success ? 'check' : 'bolt' }}</mat-icon>
2714
3218
  <span class="ai-action-label">
2715
- {{ aiTestResult?.success ? 'Conectado' : 'Testar conexão' }}
3219
+ {{ aiTestResult?.success ? tx('Connected') : tx('Test connection') }}
2716
3220
  </span>
2717
3221
  </ng-template>
2718
3222
  </button>
@@ -2754,7 +3258,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
2754
3258
  </div>
2755
3259
  <div class="ai-provider-key is-unlocked" *ngIf="selectedProvider?.requiresApiKey === false">
2756
3260
  <mat-icon>check_circle</mat-icon>
2757
- <span>Sem chave necessária</span>
3261
+ <span>{{ tx('No key required') }}</span>
2758
3262
  </div>
2759
3263
  </div>
2760
3264
  <div class="ai-credentials-row">
@@ -2774,12 +3278,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
2774
3278
  <div class="ai-group" [class.disabled-group]="!hasApiKey">
2775
3279
  <div class="ai-group-header">
2776
3280
  <div class="ai-group-title">
2777
- <mat-icon>smart_toy</mat-icon> Modelo & Comportamento
3281
+ <mat-icon>smart_toy</mat-icon> {{ tx('Model & Behavior') }}
2778
3282
  </div>
2779
3283
  <div class="ai-header-actions">
2780
- <span class="ai-subtext" *ngIf="hasApiKey">Escolha o modelo após validar a chave.</span>
2781
- <mat-chip-option *ngIf="!hasApiKey" disabled>Requer chave API validada</mat-chip-option>
2782
- <button mat-icon-button (click)="refreshModels(true)" [disabled]="isTestingAi || !hasApiKey" matTooltip="Atualizar lista de modelos" aria-label="Atualizar lista de modelos">
3284
+ <span class="ai-subtext" *ngIf="hasApiKey">{{ tx('Choose the model after validating the key.') }}</span>
3285
+ <mat-chip-option *ngIf="!hasApiKey" disabled>{{ tx('API key validated required') }}</mat-chip-option>
3286
+ <button mat-icon-button (click)="refreshModels(true)" [disabled]="isTestingAi || !hasApiKey" [matTooltip]="tx('Refresh model list')" [attr.aria-label]="tx('Refresh model list')">
2783
3287
  <mat-icon [class.spin]="isRefetchingModels">sync</mat-icon>
2784
3288
  </button>
2785
3289
  </div>
@@ -2798,7 +3302,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
2798
3302
 
2799
3303
  <div class="ai-placeholder" *ngIf="!hasApiKey">
2800
3304
  <mat-icon>lock</mat-icon>
2801
- <span>Configure e teste sua chave de API para desbloquear a seleção de modelos.</span>
3305
+ <span>{{ tx('Configure and test your API key to unlock model selection.') }}</span>
2802
3306
  </div>
2803
3307
  </div>
2804
3308
 
@@ -2806,7 +3310,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
2806
3310
  <div class="ai-group">
2807
3311
  <div class="ai-group-header">
2808
3312
  <div class="ai-group-title">
2809
- <mat-icon>scatter_plot</mat-icon> Embeddings (RAG)
3313
+ <mat-icon>scatter_plot</mat-icon> {{ tx('Embeddings (RAG)') }}
2810
3314
  </div>
2811
3315
  <div class="ai-header-actions">
2812
3316
  <button
@@ -2815,19 +3319,19 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
2815
3319
  class="ai-action-btn"
2816
3320
  (click)="useLlmForEmbeddings()"
2817
3321
  [disabled]="!canUseLlmForEmbeddings"
2818
- matTooltip="Aplicar provedor e chave do LLM aos embeddings"
3322
+ [matTooltip]="tx('Use the LLM provider and key for embeddings')"
2819
3323
  >
2820
3324
  <mat-icon>merge_type</mat-icon>
2821
- <span class="ai-action-label">Usar mesmo LLM</span>
3325
+ <span class="ai-action-label">{{ tx('Use the LLM provider and key for embeddings') }}</span>
2822
3326
  </button>
2823
- <mat-chip-option *ngIf="!canUseLlmForEmbeddings" disabled>Provedor sem embeddings</mat-chip-option>
3327
+ <mat-chip-option *ngIf="!canUseLlmForEmbeddings" disabled>{{ tx('Provider has no embeddings') }}</mat-chip-option>
2824
3328
  </div>
2825
3329
  </div>
2826
3330
  <div class="ai-subtext">
2827
- Configure o provedor de embeddings para buscas vetoriais (templates e schemas).
3331
+ {{ tx('Configure the embeddings provider for vector search (templates and schemas).') }}
2828
3332
  </div>
2829
3333
  <div class="ai-subtext" *ngIf="embeddingUseSameAsLlm">
2830
- Sincronizado com o LLM. Os campos abaixo acompanham a credencial principal.
3334
+ {{ tx('Synchronized with the LLM. The fields below follow the primary credential.') }}
2831
3335
  </div>
2832
3336
  <div class="ai-embedding-row">
2833
3337
  <ng-template #hostAiEmbedding></ng-template>
@@ -2835,7 +3339,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
2835
3339
  <div class="ai-feedback ai-feedback--warn" *ngIf="embeddingDimensionMismatch">
2836
3340
  <mat-icon>warning</mat-icon>
2837
3341
  <span class="error-text">
2838
- Dimensão de embeddings diferente do banco (768). Ajuste para 768 ou refaça a migração.
3342
+ {{ tx('Embedding dimension mismatch with database (768). Adjust to 768 or redo the migration.') }}
2839
3343
  </span>
2840
3344
  </div>
2841
3345
  </div>
@@ -2846,9 +3350,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
2846
3350
  <mat-expansion-panel-header>
2847
3351
  <mat-panel-title>
2848
3352
  <mat-icon class="panel-icon">table_chart</mat-icon>
2849
- Tabela
3353
+ {{ tx('Table') }}
2850
3354
  </mat-panel-title>
2851
- <mat-panel-description>Toolbar, aparência e filtro avançado</mat-panel-description>
3355
+ <mat-panel-description>{{ tx('Toolbar, appearance and advanced filter') }}</mat-panel-description>
2852
3356
  </mat-expansion-panel-header>
2853
3357
  <ng-template #hostTable></ng-template>
2854
3358
  </mat-expansion-panel>
@@ -2856,27 +3360,27 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
2856
3360
  <mat-expansion-panel-header>
2857
3361
  <mat-panel-title>
2858
3362
  <mat-icon class="panel-icon">forum</mat-icon>
2859
- Dialog
3363
+ {{ tx('Dialog') }}
2860
3364
  </mat-panel-title>
2861
- <mat-panel-description>Defaults e variants (danger, info, success, question, error)</mat-panel-description>
3365
+ <mat-panel-description>{{ tx('Defaults and variants (danger, info, success, question, error)') }}</mat-panel-description>
2862
3366
  </mat-expansion-panel-header>
2863
3367
  <ng-template #hostDialog></ng-template>
2864
3368
  <!-- Icon UX helpers for Dialog variants -->
2865
3369
  <div class="dlg-icon-helpers">
2866
- <div class="dlg-icon-helpers__head">Ícones por perfil (atalhos)</div>
3370
+ <div class="dlg-icon-helpers__head">{{ tx('Icons by profile (shortcuts)') }}</div>
2867
3371
  <div class="dlg-icon-helpers__row" *ngFor="let k of dialogVariantKeys">
2868
3372
  <div class="dlg-icon-helpers__label">{{ k }}</div>
2869
3373
  <mat-icon aria-hidden="true" [praxisIcon]="getVariantIcon(k) || 'mi:help_outline'" class="dlg-icon-helpers__preview"></mat-icon>
2870
- <button mat-stroked-button color="primary" type="button" (click)="pickVariantIcon(k)" matTooltip="Escolher ícone para {{k}}">
3374
+ <button mat-stroked-button color="primary" type="button" (click)="pickVariantIcon(k)" [matTooltip]="tx('Pick icon for {{key}}', { key: k })">
2871
3375
  <mat-icon>search</mat-icon>
2872
- Escolher ícone
3376
+ {{ tx('Pick icon') }}
2873
3377
  </button>
2874
- <button mat-icon-button type="button" *ngIf="getVariantIcon(k)" (click)="clearVariantIcon(k)" matTooltip="Limpar ícone de {{k}}" aria-label="Limpar ícone">
3378
+ <button mat-icon-button type="button" *ngIf="getVariantIcon(k)" (click)="clearVariantIcon(k)" [matTooltip]="tx('Clear icon for {{key}}', { key: k })" [attr.aria-label]="tx('Clear icon')">
2875
3379
  <mat-icon>backspace</mat-icon>
2876
3380
  </button>
2877
3381
  <span class="dlg-icon-helpers__value" *ngIf="getVariantIcon(k)">{{ getVariantIcon(k) }}</span>
2878
3382
  </div>
2879
- <div class="dlg-icon-helpers__hint">Dica: O campo de texto acima permanece editável. Estes botões apenas facilitam a escolha/limpeza com preview.</div>
3383
+ <div class="dlg-icon-helpers__hint">{{ tx('The text field above remains editable. These buttons only help with selection/clear preview.') }}</div>
2880
3384
  </div>
2881
3385
  </mat-expansion-panel>
2882
3386
  </mat-accordion>
@@ -2915,7 +3419,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
2915
3419
  function openGlobalConfigEditor(settings, opts) {
2916
3420
  settings.open({
2917
3421
  id: opts?.id ?? 'global-config',
2918
- title: opts?.title ?? 'Configurações Globais',
3422
+ title: opts?.title,
2919
3423
  titleIcon: opts?.titleIcon ?? 'tune',
2920
3424
  content: { component: GlobalConfigEditorComponent, inputs: {} },
2921
3425
  });
@@ -2959,5 +3463,5 @@ const SETTINGS_PANEL_AI_CAPABILITIES = {
2959
3463
  * Generated bundle index. Do not edit.
2960
3464
  */
2961
3465
 
2962
- export { GLOBAL_CONFIG_DYNAMIC_FORM_COMPONENT, GlobalConfigAdminService, GlobalConfigEditorComponent, SETTINGS_PANEL_AI_CAPABILITIES, SETTINGS_PANEL_DATA, SETTINGS_PANEL_REF, SettingsPanelComponent, SettingsPanelRef, SettingsPanelService, buildGlobalConfigFormConfig, openGlobalConfigEditor };
3466
+ export { GLOBAL_CONFIG_DYNAMIC_FORM_COMPONENT, GlobalConfigAdminService, GlobalConfigEditorComponent, SETTINGS_PANEL_AI_CAPABILITIES, SETTINGS_PANEL_DATA, SETTINGS_PANEL_REF, SettingsPanelComponent, SettingsPanelRef, SettingsPanelService, buildGlobalConfigFormConfig, openGlobalConfigEditor, providePraxisSettingsPanelBridge };
2963
3467
  //# sourceMappingURL=praxisui-settings-panel.mjs.map