@praxisui/table 5.0.0-beta.0 → 7.0.0-beta.0
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.
- package/README.md +470 -414
- package/fesm2022/praxisui-table.mjs +3071 -31
- package/index.d.ts +209 -4
- package/package.json +8 -7
|
@@ -34,6 +34,7 @@ import { moveItemInArray, DragDropModule } from '@angular/cdk/drag-drop';
|
|
|
34
34
|
import { Subject, debounceTime, takeUntil, of, firstValueFrom, BehaviorSubject, take as take$1 } from 'rxjs';
|
|
35
35
|
import * as i1 from '@praxisui/core';
|
|
36
36
|
import { LoggerService, createCorporateLoggerConfig, ConsoleLoggerSink, PraxisJsonLogicService, PraxisIconDirective, PraxisI18nService, isTableConfigV2, providePraxisI18nConfig, GLOBAL_ACTION_SPEC_CATALOG, SURFACE_OPEN_I18N_NAMESPACE, getGlobalActionUiSchema, SurfaceOpenActionEditorComponent, SURFACE_OPEN_I18N_CONFIG, INLINE_FILTER_CONTROL_TYPES, INLINE_FILTER_CONTROL_TYPE_VALUES, FieldControlType, normalizeControlTypeToken, ASYNC_CONFIG_STORAGE, resolveControlTypeAlias, mapFieldDefinitionsToMetadata, PraxisJsonLogicError, GenericCrudService, TableConfigService, createDefaultTableConfig, fillUndefined, deepMerge, INLINE_FILTER_ALIAS_TOKENS, GlobalConfigService, buildSchemaId, MemoryCacheAdapter, LocalStorageCacheAdapter, SchemaMetadataClient, resolveInlineFilterControlType, fetchWithETag, ComponentMetadataRegistry, ResourceQuickConnectComponent, translateResourceAvailabilityReason, PRAXIS_LOADING_CTX, translateResourceDiscoveryText, supportsImplicitValuePresentation, resolveValuePresentation, translateUnavailableWorkflowMessage, CONNECTION_STORAGE, PRAXIS_LOADING_RENDERER, EmptyStateCardComponent, RESOURCE_DISCOVERY_I18N_CONFIG, AnalyticsStatsRequestBuilderService, buildApiUrl, normalizePraxisDataQueryContext, API_URL } from '@praxisui/core';
|
|
37
|
+
import { PraxisRichContent } from '@praxisui/rich-content';
|
|
37
38
|
import * as i2 from '@angular/material/toolbar';
|
|
38
39
|
import { MatToolbarModule } from '@angular/material/toolbar';
|
|
39
40
|
import * as i4 from '@angular/material/tabs';
|
|
@@ -1168,7 +1169,7 @@ class PraxisTableToolbar {
|
|
|
1168
1169
|
}
|
|
1169
1170
|
</div>
|
|
1170
1171
|
</mat-toolbar>
|
|
1171
|
-
`, isInline: true, styles: [":host{display:block}.praxis-toolbar{background:transparent;box-shadow:none;padding:var(--pfx-toolbar-pad-y, 6px) var(--pfx-toolbar-pad-x, 12px);min-height:var(--pfx-filter-h, 44px);display:flex;flex-direction:row;align-items:flex-start;gap:
|
|
1172
|
+
`, isInline: true, styles: [":host{display:block}.praxis-toolbar{background:linear-gradient(180deg,color-mix(in srgb,var(--md-sys-color-surface, #fff) 96%,transparent),color-mix(in srgb,var(--md-sys-color-surface-container-low, #f6f8fc) 100%,transparent));box-shadow:none;padding:var(--pfx-toolbar-pad-y, 6px) var(--pfx-toolbar-pad-x, 12px);min-height:var(--pfx-filter-h, 44px);display:flex;flex-direction:row;align-items:flex-start;gap:6px;flex-wrap:wrap;border:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant, #d7dbe5) 78%,transparent);border-radius:10px}.praxis-toolbar.mat-toolbar-single-row,.praxis-toolbar .mat-toolbar-row{height:auto}.praxis-toolbar.mat-toolbar-multiple-rows{min-height:var(--pfx-filter-h, 44px)}.toolbar-main{display:flex;align-items:stretch;justify-content:flex-start;min-width:0;gap:6px;min-height:var(--pfx-filter-h, 44px);flex:1 1 auto}.toolbar-main>*{min-width:0}.toolbar-actions{display:flex;align-items:center;justify-content:flex-end;gap:6px;min-height:var(--pfx-filter-h, 44px);flex:0 0 auto;margin-left:auto}.actions-group{display:flex;align-items:center;gap:6px}.action-btn{height:36px;min-width:36px;border-radius:8px;font-size:12px;line-height:1.2}.action-btn--fab{width:42px;height:42px;box-shadow:none}.pfx-tonal{background:var(--md-sys-color-secondary-container);color:var(--md-sys-color-on-secondary-container)}.pfx-tonal:hover{background:var(--md-sys-color-secondary-container)}.mobile-actions{display:none;align-items:center;gap:6px}.overflow-trigger{height:36px}.action-btn .mat-icon,.action-btn--fab .mat-icon,.overflow-trigger .mat-icon{font-size:18px;width:18px;height:18px;line-height:18px}.action-btn.mat-mdc-button-base,.action-btn--fab.mat-mdc-button-base,.overflow-trigger.mat-mdc-button-base{--mdc-text-button-container-height: 36px;--mdc-protected-button-container-height: 36px;--mdc-outlined-button-container-height: 36px}.action-btn.mat-mdc-unelevated-button:not(:disabled),.action-btn.mat-mdc-outlined-button:not(:disabled),.action-btn.pfx-tonal:not(:disabled){border-color:color-mix(in srgb,var(--md-sys-color-outline-variant, #d7dbe5) 82%,transparent)}.action-btn.mat-mdc-unelevated-button:not(:disabled){box-shadow:none}.action-btn.mat-mdc-button-base:not(.mat-mdc-icon-button){padding-inline:10px}.end-actions{display:flex;align-items:center;gap:6px;margin-left:4px;padding-left:10px;border-left:1px solid color-mix(in srgb,var(--md-sys-color-outline) 68%,transparent)}@media(min-width:1024px){.toolbar-actions{justify-content:flex-end}}@media(max-width:1023px){.actions-group{display:none}.mobile-actions{display:flex}.toolbar-actions{justify-content:flex-end}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: MatToolbarModule }, { kind: "component", type: i2.MatToolbar, selector: "mat-toolbar", inputs: ["color"], exportAs: ["matToolbar"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i3.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.MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }, { kind: "component", type: i3.MatFabButton, selector: "button[mat-fab], a[mat-fab], button[matFab], a[matFab]", inputs: ["extended"], exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i5.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: MatMenuModule }, { kind: "component", type: i17.MatMenu, selector: "mat-menu", inputs: ["backdropClass", "aria-label", "aria-labelledby", "aria-describedby", "xPosition", "yPosition", "overlapTrigger", "hasBackdrop", "class", "classList"], outputs: ["closed", "close"], exportAs: ["matMenu"] }, { kind: "component", type: i17.MatMenuItem, selector: "[mat-menu-item]", inputs: ["role", "disabled", "disableRipple"], exportAs: ["matMenuItem"] }, { kind: "directive", type: i17.MatMenuTrigger, selector: "[mat-menu-trigger-for], [matMenuTriggerFor]", inputs: ["mat-menu-trigger-for", "matMenuTriggerFor", "matMenuTriggerData", "matMenuTriggerRestoreFocus"], outputs: ["menuOpened", "onMenuOpen", "menuClosed", "onMenuClose"], exportAs: ["matMenuTrigger"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i10.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }] });
|
|
1172
1173
|
}
|
|
1173
1174
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: PraxisTableToolbar, decorators: [{
|
|
1174
1175
|
type: Component,
|
|
@@ -1541,7 +1542,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
|
|
|
1541
1542
|
`, host: {
|
|
1542
1543
|
'[class.praxis-toolbar-footer]': "placement === 'footer'",
|
|
1543
1544
|
'(document:keydown)': 'onDocumentKeydown($event)',
|
|
1544
|
-
}, styles: [":host{display:block}.praxis-toolbar{background:transparent;box-shadow:none;padding:var(--pfx-toolbar-pad-y, 6px) var(--pfx-toolbar-pad-x, 12px);min-height:var(--pfx-filter-h, 44px);display:flex;flex-direction:row;align-items:flex-start;gap:
|
|
1545
|
+
}, styles: [":host{display:block}.praxis-toolbar{background:linear-gradient(180deg,color-mix(in srgb,var(--md-sys-color-surface, #fff) 96%,transparent),color-mix(in srgb,var(--md-sys-color-surface-container-low, #f6f8fc) 100%,transparent));box-shadow:none;padding:var(--pfx-toolbar-pad-y, 6px) var(--pfx-toolbar-pad-x, 12px);min-height:var(--pfx-filter-h, 44px);display:flex;flex-direction:row;align-items:flex-start;gap:6px;flex-wrap:wrap;border:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant, #d7dbe5) 78%,transparent);border-radius:10px}.praxis-toolbar.mat-toolbar-single-row,.praxis-toolbar .mat-toolbar-row{height:auto}.praxis-toolbar.mat-toolbar-multiple-rows{min-height:var(--pfx-filter-h, 44px)}.toolbar-main{display:flex;align-items:stretch;justify-content:flex-start;min-width:0;gap:6px;min-height:var(--pfx-filter-h, 44px);flex:1 1 auto}.toolbar-main>*{min-width:0}.toolbar-actions{display:flex;align-items:center;justify-content:flex-end;gap:6px;min-height:var(--pfx-filter-h, 44px);flex:0 0 auto;margin-left:auto}.actions-group{display:flex;align-items:center;gap:6px}.action-btn{height:36px;min-width:36px;border-radius:8px;font-size:12px;line-height:1.2}.action-btn--fab{width:42px;height:42px;box-shadow:none}.pfx-tonal{background:var(--md-sys-color-secondary-container);color:var(--md-sys-color-on-secondary-container)}.pfx-tonal:hover{background:var(--md-sys-color-secondary-container)}.mobile-actions{display:none;align-items:center;gap:6px}.overflow-trigger{height:36px}.action-btn .mat-icon,.action-btn--fab .mat-icon,.overflow-trigger .mat-icon{font-size:18px;width:18px;height:18px;line-height:18px}.action-btn.mat-mdc-button-base,.action-btn--fab.mat-mdc-button-base,.overflow-trigger.mat-mdc-button-base{--mdc-text-button-container-height: 36px;--mdc-protected-button-container-height: 36px;--mdc-outlined-button-container-height: 36px}.action-btn.mat-mdc-unelevated-button:not(:disabled),.action-btn.mat-mdc-outlined-button:not(:disabled),.action-btn.pfx-tonal:not(:disabled){border-color:color-mix(in srgb,var(--md-sys-color-outline-variant, #d7dbe5) 82%,transparent)}.action-btn.mat-mdc-unelevated-button:not(:disabled){box-shadow:none}.action-btn.mat-mdc-button-base:not(.mat-mdc-icon-button){padding-inline:10px}.end-actions{display:flex;align-items:center;gap:6px;margin-left:4px;padding-left:10px;border-left:1px solid color-mix(in srgb,var(--md-sys-color-outline) 68%,transparent)}@media(min-width:1024px){.toolbar-actions{justify-content:flex-end}}@media(max-width:1023px){.actions-group{display:none}.mobile-actions{display:flex}.toolbar-actions{justify-content:flex-end}}\n"] }]
|
|
1545
1546
|
}], ctorParameters: () => [{ type: i0.ElementRef }, { type: i1.LoggerService, decorators: [{
|
|
1546
1547
|
type: Optional
|
|
1547
1548
|
}] }], propDecorators: { config: [{
|
|
@@ -7031,6 +7032,38 @@ const PRAXIS_TABLE_EDITOR_I18N_CONFIG = {
|
|
|
7031
7032
|
'sections.messages': 'Mensagens e localização',
|
|
7032
7033
|
'sections.dialogs': 'Diálogos',
|
|
7033
7034
|
'sections.json': 'JSON',
|
|
7035
|
+
'inlineAuthoring.title': 'Estrutura da tabela',
|
|
7036
|
+
'inlineAuthoring.description': 'Edite o TableConfig canônico usado por esta superfície de CRUD.',
|
|
7037
|
+
'inlineAuthoring.essentialsTitle': 'Essenciais da tabela',
|
|
7038
|
+
'inlineAuthoring.essentialsDescription': 'Defina a presença da toolbar e os textos que o usuário vê primeiro.',
|
|
7039
|
+
'inlineAuthoring.advancedTitle': 'Detalhes avançados da tabela',
|
|
7040
|
+
'inlineAuthoring.advancedDescription': 'Abra os próximos painéis apenas quando precisar ajustar comportamento da lista, textos de estado ou colunas visíveis.',
|
|
7041
|
+
'inlineAuthoring.advanced.behavior': 'Comportamento',
|
|
7042
|
+
'inlineAuthoring.advanced.states': 'Textos de estado',
|
|
7043
|
+
'inlineAuthoring.advanced.columns': 'Colunas',
|
|
7044
|
+
'inlineAuthoring.toolbarTitle': 'Título da barra',
|
|
7045
|
+
'inlineAuthoring.columnsTitle': 'Colunas',
|
|
7046
|
+
'inlineAuthoring.columnsDescription': 'Abra apenas quando precisar ajustar campos visíveis, rótulos e renderizadores.',
|
|
7047
|
+
'inlineAuthoring.summary.toolbar': 'Toolbar',
|
|
7048
|
+
'inlineAuthoring.summary.density': 'Densidade',
|
|
7049
|
+
'inlineAuthoring.summary.actions': 'Ações',
|
|
7050
|
+
'inlineAuthoring.summary.behavior': 'Comportamento da lista',
|
|
7051
|
+
'inlineAuthoring.summary.states': 'Mensagens de estado',
|
|
7052
|
+
'inlineAuthoring.summary.columns': 'Estrutura visível',
|
|
7053
|
+
'inlineAuthoring.summary.toolbarHidden': 'Oculta',
|
|
7054
|
+
'inlineAuthoring.summary.toolbarDefault': 'Visível sem título customizado',
|
|
7055
|
+
'inlineAuthoring.summary.paginationOff': 'Paginação desativada',
|
|
7056
|
+
'inlineAuthoring.summary.sortingOff': 'Ordenação desativada',
|
|
7057
|
+
'inlineAuthoring.summary.statesDefault': 'Textos padrão',
|
|
7058
|
+
'inlineAuthoring.summary.statesCustom': '{count} estados customizados',
|
|
7059
|
+
'inlineAuthoring.summary.columnsEmpty': 'Nenhuma coluna configurada ainda',
|
|
7060
|
+
'inlineAuthoring.columnCount': '{count} colunas',
|
|
7061
|
+
'inlineAuthoring.behaviorTitle': 'Comportamento da lista',
|
|
7062
|
+
'inlineAuthoring.behaviorDescription': 'Controle paginação e ordenação com a mesma semântica canônica já usada pelo editor completo da tabela.',
|
|
7063
|
+
'inlineAuthoring.statesTitle': 'Mensagens de estado',
|
|
7064
|
+
'inlineAuthoring.statesDescription': 'Ajuste as primeiras mensagens que o usuário lê quando a lista está carregando, vazia, filtrada ou com erro.',
|
|
7065
|
+
'inlineAuthoring.noneOption': 'Nenhum',
|
|
7066
|
+
'inlineAuthoring.readonlyHint': 'Esta superfície de authoring está somente leitura no contexto atual.',
|
|
7034
7067
|
'connect.resource': 'Recurso',
|
|
7035
7068
|
'connect.resource.placeholder': 'ex.: employees',
|
|
7036
7069
|
'connect.primaryKey': 'Chave primária',
|
|
@@ -7606,7 +7639,9 @@ const PRAXIS_TABLE_EDITOR_I18N_CONFIG = {
|
|
|
7606
7639
|
'behavior.pagination.positionHint': 'Paginator no topo/baixo/ambos.',
|
|
7607
7640
|
'behavior.pagination.style': 'Estilo do paginator',
|
|
7608
7641
|
'behavior.pagination.style.default': 'Padrao',
|
|
7642
|
+
'behavior.pagination.style.simple': 'Simples',
|
|
7609
7643
|
'behavior.pagination.style.compact': 'Compacto',
|
|
7644
|
+
'behavior.pagination.style.advanced': 'Avancado',
|
|
7610
7645
|
'behavior.pagination.styleHint': 'Compacto para densidade alta.',
|
|
7611
7646
|
'behavior.sorting.title': 'Ordenacao',
|
|
7612
7647
|
'behavior.sorting.description': 'Controle como as colunas podem ser ordenadas',
|
|
@@ -7726,7 +7761,7 @@ const PRAXIS_TABLE_EDITOR_I18N_CONFIG = {
|
|
|
7726
7761
|
'behavior.expansion.detailSource.resourcePath': 'Resource Path',
|
|
7727
7762
|
'behavior.expansion.detailSource.hypermedia': 'Hypermedia',
|
|
7728
7763
|
'behavior.expansion.inlineSchema': 'Inline schema (JSON)',
|
|
7729
|
-
'behavior.expansion.inlineSchemaHint': 'Aceita
|
|
7764
|
+
'behavior.expansion.inlineSchemaHint': 'Aceita nós como card/mediaBlock/cardGrid/detailList/timeline/actionBar/formRef/tableRef/chartRef/diagramEmbed/richText/tabs/list, conforme schemaContract.allowedNodes.',
|
|
7730
7765
|
'behavior.expansion.inlineSchemaError': 'JSON invalido: o contrato atual nao foi aplicado para',
|
|
7731
7766
|
'behavior.expansion.allowList': 'Resource allow list',
|
|
7732
7767
|
'behavior.expansion.resourceKind': 'Tipo de recurso',
|
|
@@ -7773,8 +7808,8 @@ const PRAXIS_TABLE_EDITOR_I18N_CONFIG = {
|
|
|
7773
7808
|
'behavior.appearance.density.compact': 'Compacta',
|
|
7774
7809
|
'behavior.appearance.density.comfortable': 'Confortavel',
|
|
7775
7810
|
'behavior.appearance.density.spacious': 'Espacosa',
|
|
7776
|
-
'crud.defaults.title': '
|
|
7777
|
-
'crud.defaults.description': '
|
|
7811
|
+
'crud.defaults.title': 'Overrides de runtime do CRUD',
|
|
7812
|
+
'crud.defaults.description': 'Ajustes operacionais de abertura usados quando a tabela aciona o fluxo CRUD.',
|
|
7778
7813
|
'crud.defaults.openMode': 'Modo de abertura',
|
|
7779
7814
|
'crud.mode.modal': 'Modal',
|
|
7780
7815
|
'crud.mode.route': 'Rota',
|
|
@@ -8023,6 +8058,38 @@ const PRAXIS_TABLE_EDITOR_I18N_CONFIG = {
|
|
|
8023
8058
|
'sections.messages': 'Messages and localization',
|
|
8024
8059
|
'sections.dialogs': 'Dialogs',
|
|
8025
8060
|
'sections.json': 'JSON',
|
|
8061
|
+
'inlineAuthoring.title': 'Table structure',
|
|
8062
|
+
'inlineAuthoring.description': 'Edit the canonical TableConfig used by this CRUD surface.',
|
|
8063
|
+
'inlineAuthoring.essentialsTitle': 'Table essentials',
|
|
8064
|
+
'inlineAuthoring.essentialsDescription': 'Define the toolbar presence and the texts users see first.',
|
|
8065
|
+
'inlineAuthoring.advancedTitle': 'Advanced table details',
|
|
8066
|
+
'inlineAuthoring.advancedDescription': 'Open the next panels only when you need to tune list behavior, state copy, or visible columns.',
|
|
8067
|
+
'inlineAuthoring.advanced.behavior': 'Behavior',
|
|
8068
|
+
'inlineAuthoring.advanced.states': 'State copy',
|
|
8069
|
+
'inlineAuthoring.advanced.columns': 'Columns',
|
|
8070
|
+
'inlineAuthoring.toolbarTitle': 'Toolbar title',
|
|
8071
|
+
'inlineAuthoring.columnsTitle': 'Columns',
|
|
8072
|
+
'inlineAuthoring.columnsDescription': 'Open only when you need to adjust visible fields, labels, and renderers.',
|
|
8073
|
+
'inlineAuthoring.summary.toolbar': 'Toolbar',
|
|
8074
|
+
'inlineAuthoring.summary.density': 'Density',
|
|
8075
|
+
'inlineAuthoring.summary.actions': 'Actions',
|
|
8076
|
+
'inlineAuthoring.summary.behavior': 'List behavior',
|
|
8077
|
+
'inlineAuthoring.summary.states': 'State messages',
|
|
8078
|
+
'inlineAuthoring.summary.columns': 'Visible structure',
|
|
8079
|
+
'inlineAuthoring.summary.toolbarHidden': 'Hidden',
|
|
8080
|
+
'inlineAuthoring.summary.toolbarDefault': 'Visible without custom title',
|
|
8081
|
+
'inlineAuthoring.summary.paginationOff': 'Pagination off',
|
|
8082
|
+
'inlineAuthoring.summary.sortingOff': 'Sorting off',
|
|
8083
|
+
'inlineAuthoring.summary.statesDefault': 'Default copy',
|
|
8084
|
+
'inlineAuthoring.summary.statesCustom': '{count} customized states',
|
|
8085
|
+
'inlineAuthoring.summary.columnsEmpty': 'No columns configured yet',
|
|
8086
|
+
'inlineAuthoring.columnCount': '{count} columns',
|
|
8087
|
+
'inlineAuthoring.behaviorTitle': 'List behavior',
|
|
8088
|
+
'inlineAuthoring.behaviorDescription': 'Control pagination and sorting with the same canonical semantics already used by the full table editor.',
|
|
8089
|
+
'inlineAuthoring.statesTitle': 'State messages',
|
|
8090
|
+
'inlineAuthoring.statesDescription': 'Adjust the first messages users read when the list is loading, empty, filtered, or broken.',
|
|
8091
|
+
'inlineAuthoring.noneOption': 'None',
|
|
8092
|
+
'inlineAuthoring.readonlyHint': 'This authoring surface is read-only in the current context.',
|
|
8026
8093
|
'connect.resource': 'Resource',
|
|
8027
8094
|
'connect.resource.placeholder': 'e.g. employees',
|
|
8028
8095
|
'connect.primaryKey': 'Primary key',
|
|
@@ -8598,7 +8665,9 @@ const PRAXIS_TABLE_EDITOR_I18N_CONFIG = {
|
|
|
8598
8665
|
'behavior.pagination.positionHint': 'Paginator on top/bottom/both.',
|
|
8599
8666
|
'behavior.pagination.style': 'Paginator style',
|
|
8600
8667
|
'behavior.pagination.style.default': 'Default',
|
|
8668
|
+
'behavior.pagination.style.simple': 'Simple',
|
|
8601
8669
|
'behavior.pagination.style.compact': 'Compact',
|
|
8670
|
+
'behavior.pagination.style.advanced': 'Advanced',
|
|
8602
8671
|
'behavior.pagination.styleHint': 'Compact for high density.',
|
|
8603
8672
|
'behavior.sorting.title': 'Sorting',
|
|
8604
8673
|
'behavior.sorting.description': 'Control how columns can be sorted',
|
|
@@ -8718,7 +8787,7 @@ const PRAXIS_TABLE_EDITOR_I18N_CONFIG = {
|
|
|
8718
8787
|
'behavior.expansion.detailSource.resourcePath': 'Resource Path',
|
|
8719
8788
|
'behavior.expansion.detailSource.hypermedia': 'Hypermedia',
|
|
8720
8789
|
'behavior.expansion.inlineSchema': 'Inline schema (JSON)',
|
|
8721
|
-
'behavior.expansion.inlineSchemaHint': 'Accepts nodes such as card/formRef/tableRef/chartRef/richText/tabs/list, according to schemaContract.allowedNodes.',
|
|
8790
|
+
'behavior.expansion.inlineSchemaHint': 'Accepts nodes such as card/mediaBlock/cardGrid/detailList/timeline/actionBar/formRef/tableRef/chartRef/diagramEmbed/richText/tabs/list, according to schemaContract.allowedNodes.',
|
|
8722
8791
|
'behavior.expansion.inlineSchemaError': 'Invalid JSON: the current contract was not applied to',
|
|
8723
8792
|
'behavior.expansion.allowList': 'Resource allow list',
|
|
8724
8793
|
'behavior.expansion.resourceKind': 'Resource kind',
|
|
@@ -8765,8 +8834,8 @@ const PRAXIS_TABLE_EDITOR_I18N_CONFIG = {
|
|
|
8765
8834
|
'behavior.appearance.density.compact': 'Compact',
|
|
8766
8835
|
'behavior.appearance.density.comfortable': 'Comfortable',
|
|
8767
8836
|
'behavior.appearance.density.spacious': 'Spacious',
|
|
8768
|
-
'crud.defaults.title': 'CRUD
|
|
8769
|
-
'crud.defaults.description': '
|
|
8837
|
+
'crud.defaults.title': 'CRUD runtime overrides',
|
|
8838
|
+
'crud.defaults.description': 'Operational open-mode settings applied when the table launches the CRUD flow.',
|
|
8770
8839
|
'crud.defaults.openMode': 'Open mode',
|
|
8771
8840
|
'crud.mode.modal': 'Modal',
|
|
8772
8841
|
'crud.mode.route': 'Route',
|
|
@@ -14414,12 +14483,18 @@ const DEFAULT_EXPANSION_ALLOWED_NODES$1 = [
|
|
|
14414
14483
|
'tabs',
|
|
14415
14484
|
'tab',
|
|
14416
14485
|
'card',
|
|
14486
|
+
'mediaBlock',
|
|
14487
|
+
'cardGrid',
|
|
14488
|
+
'timeline',
|
|
14417
14489
|
'value',
|
|
14418
14490
|
'action',
|
|
14491
|
+
'actionBar',
|
|
14419
14492
|
'list',
|
|
14493
|
+
'detailList',
|
|
14420
14494
|
'formRef',
|
|
14421
14495
|
'tableRef',
|
|
14422
14496
|
'chartRef',
|
|
14497
|
+
'diagramEmbed',
|
|
14423
14498
|
'richText',
|
|
14424
14499
|
'templateRef',
|
|
14425
14500
|
];
|
|
@@ -16088,7 +16163,7 @@ class BehaviorConfigEditorComponent {
|
|
|
16088
16163
|
matSuffix
|
|
16089
16164
|
type="button"
|
|
16090
16165
|
class="help-icon-button"
|
|
16091
|
-
|
|
16166
|
+
[matTooltip]="tx('behavior.expansion.inlineSchemaHint', 'Accepts nodes such as card/mediaBlock/cardGrid/timeline/actionBar/detailList/formRef/tableRef/chartRef/templateRef/diagramEmbed/richText/tabs/list, according to schemaContract.allowedNodes.')"
|
|
16092
16167
|
>
|
|
16093
16168
|
<mat-icon>help_outline</mat-icon>
|
|
16094
16169
|
</button>
|
|
@@ -17080,7 +17155,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
|
|
|
17080
17155
|
matSuffix
|
|
17081
17156
|
type="button"
|
|
17082
17157
|
class="help-icon-button"
|
|
17083
|
-
|
|
17158
|
+
[matTooltip]="tx('behavior.expansion.inlineSchemaHint', 'Accepts nodes such as card/mediaBlock/cardGrid/timeline/actionBar/detailList/formRef/tableRef/chartRef/templateRef/diagramEmbed/richText/tabs/list, according to schemaContract.allowedNodes.')"
|
|
17084
17159
|
>
|
|
17085
17160
|
<mat-icon>help_outline</mat-icon>
|
|
17086
17161
|
</button>
|
|
@@ -36111,6 +36186,12 @@ const PRAXIS_TABLE_RUNTIME_I18N_CONFIG = {
|
|
|
36111
36186
|
namespaces: {
|
|
36112
36187
|
[PRAXIS_TABLE_RUNTIME_I18N_NAMESPACE]: {
|
|
36113
36188
|
'pt-BR': {
|
|
36189
|
+
'table.chrome.settings': 'Configurações',
|
|
36190
|
+
'table.chrome.settings.reconcile': 'Schema do servidor mudou - reconciliar',
|
|
36191
|
+
'table.chrome.disconnect': 'Desconectar',
|
|
36192
|
+
'table.chrome.disconnectTooltip': 'Desconectar da fonte de dados',
|
|
36193
|
+
'table.chrome.rowActions.more': 'Mais ações',
|
|
36194
|
+
'table.chrome.rowActions.loading': 'Carregando ações contextuais',
|
|
36114
36195
|
'table.expansion.toggle.ariaLabel.expand': 'Expandir detalhes do item',
|
|
36115
36196
|
'table.expansion.toggle.ariaLabel.collapse': 'Recolher detalhes do item',
|
|
36116
36197
|
'table.expansion.region.ariaLabel': 'Detalhes do item expandido (linha {position})',
|
|
@@ -36157,8 +36238,29 @@ const PRAXIS_TABLE_RUNTIME_I18N_CONFIG = {
|
|
|
36157
36238
|
'table.expansion.hypermedia.operations.create': 'Criar',
|
|
36158
36239
|
'table.expansion.hypermedia.operations.edit': 'Editar',
|
|
36159
36240
|
'table.expansion.hypermedia.operations.delete': 'Excluir',
|
|
36241
|
+
'table.expansion.actionBar.title': 'Ações rápidas',
|
|
36242
|
+
'table.expansion.actionBar.empty': 'Nenhuma ação disponível.',
|
|
36243
|
+
'table.expansion.timeline.title': 'Linha do tempo',
|
|
36244
|
+
'table.expansion.timeline.empty': 'Sem eventos recentes.',
|
|
36245
|
+
'table.expansion.embed.formRef.label': 'Formulário governado',
|
|
36246
|
+
'table.expansion.embed.tableRef.label': 'Tabela governada',
|
|
36247
|
+
'table.expansion.embed.chartRef.label': 'Gráfico governado',
|
|
36248
|
+
'table.expansion.embed.templateRef.label': 'Template governado',
|
|
36249
|
+
'table.expansion.embed.diagramEmbed.label': 'Diagrama governado',
|
|
36250
|
+
'table.expansion.embed.empty': 'Nenhum conteúdo de embed disponível.',
|
|
36251
|
+
'table.expansion.embed.reference': 'Referência',
|
|
36252
|
+
'table.expansion.embed.provider': 'Provedor',
|
|
36253
|
+
'table.expansion.embed.preset': 'Preset',
|
|
36254
|
+
'table.expansion.embed.inputs': 'Inputs',
|
|
36255
|
+
'table.expansion.embed.diagramSource': 'Fonte do diagrama',
|
|
36160
36256
|
},
|
|
36161
36257
|
'en-US': {
|
|
36258
|
+
'table.chrome.settings': 'Settings',
|
|
36259
|
+
'table.chrome.settings.reconcile': 'Server schema changed - reconcile',
|
|
36260
|
+
'table.chrome.disconnect': 'Disconnect',
|
|
36261
|
+
'table.chrome.disconnectTooltip': 'Disconnect from the data source',
|
|
36262
|
+
'table.chrome.rowActions.more': 'More actions',
|
|
36263
|
+
'table.chrome.rowActions.loading': 'Loading contextual actions',
|
|
36162
36264
|
'table.expansion.toggle.ariaLabel.expand': 'Expand item details',
|
|
36163
36265
|
'table.expansion.toggle.ariaLabel.collapse': 'Collapse item details',
|
|
36164
36266
|
'table.expansion.region.ariaLabel': 'Expanded item details (row {position})',
|
|
@@ -36205,6 +36307,21 @@ const PRAXIS_TABLE_RUNTIME_I18N_CONFIG = {
|
|
|
36205
36307
|
'table.expansion.hypermedia.operations.create': 'Create',
|
|
36206
36308
|
'table.expansion.hypermedia.operations.edit': 'Edit',
|
|
36207
36309
|
'table.expansion.hypermedia.operations.delete': 'Delete',
|
|
36310
|
+
'table.expansion.actionBar.title': 'Quick actions',
|
|
36311
|
+
'table.expansion.actionBar.empty': 'No actions available.',
|
|
36312
|
+
'table.expansion.timeline.title': 'Timeline',
|
|
36313
|
+
'table.expansion.timeline.empty': 'No recent events.',
|
|
36314
|
+
'table.expansion.embed.formRef.label': 'Governed form',
|
|
36315
|
+
'table.expansion.embed.tableRef.label': 'Governed table',
|
|
36316
|
+
'table.expansion.embed.chartRef.label': 'Governed chart',
|
|
36317
|
+
'table.expansion.embed.templateRef.label': 'Governed template',
|
|
36318
|
+
'table.expansion.embed.diagramEmbed.label': 'Governed diagram',
|
|
36319
|
+
'table.expansion.embed.empty': 'No embed content available.',
|
|
36320
|
+
'table.expansion.embed.reference': 'Reference',
|
|
36321
|
+
'table.expansion.embed.provider': 'Provider',
|
|
36322
|
+
'table.expansion.embed.preset': 'Preset',
|
|
36323
|
+
'table.expansion.embed.inputs': 'Inputs',
|
|
36324
|
+
'table.expansion.embed.diagramSource': 'Diagram source',
|
|
36208
36325
|
},
|
|
36209
36326
|
},
|
|
36210
36327
|
},
|
|
@@ -36251,12 +36368,18 @@ const DEFAULT_EXPANSION_ALLOWED_NODES = [
|
|
|
36251
36368
|
'tabs',
|
|
36252
36369
|
'tab',
|
|
36253
36370
|
'card',
|
|
36371
|
+
'mediaBlock',
|
|
36372
|
+
'cardGrid',
|
|
36254
36373
|
'value',
|
|
36255
36374
|
'action',
|
|
36375
|
+
'actionBar',
|
|
36256
36376
|
'list',
|
|
36377
|
+
'detailList',
|
|
36378
|
+
'timeline',
|
|
36257
36379
|
'formRef',
|
|
36258
36380
|
'tableRef',
|
|
36259
36381
|
'chartRef',
|
|
36382
|
+
'diagramEmbed',
|
|
36260
36383
|
'richText',
|
|
36261
36384
|
'templateRef',
|
|
36262
36385
|
];
|
|
@@ -36378,6 +36501,7 @@ class PraxisTable {
|
|
|
36378
36501
|
metadataChange = new EventEmitter();
|
|
36379
36502
|
loadingStateChange = new EventEmitter();
|
|
36380
36503
|
collectionLinksChange = new EventEmitter();
|
|
36504
|
+
latestLoadingState = null;
|
|
36381
36505
|
paginator;
|
|
36382
36506
|
sort;
|
|
36383
36507
|
materialTable;
|
|
@@ -36518,6 +36642,16 @@ class PraxisTable {
|
|
|
36518
36642
|
return true;
|
|
36519
36643
|
return this.selection.selected.length === 0;
|
|
36520
36644
|
}
|
|
36645
|
+
getFloatingBulkActionRichContentNodes(action) {
|
|
36646
|
+
const icon = String(action?.icon || 'done_all').trim() || 'done_all';
|
|
36647
|
+
return [
|
|
36648
|
+
{
|
|
36649
|
+
type: 'icon',
|
|
36650
|
+
icon,
|
|
36651
|
+
className: 'praxis-floating-bulk-actions__icon',
|
|
36652
|
+
},
|
|
36653
|
+
];
|
|
36654
|
+
}
|
|
36521
36655
|
shouldShowToolbarActionsTop() {
|
|
36522
36656
|
const pos = this.getToolbarActionsPosition();
|
|
36523
36657
|
return pos === 'top' || pos === 'both';
|
|
@@ -36691,6 +36825,31 @@ class PraxisTable {
|
|
|
36691
36825
|
this.cdr.markForCheck();
|
|
36692
36826
|
}
|
|
36693
36827
|
}
|
|
36828
|
+
scheduleResponsiveHorizontalScrollRefresh() {
|
|
36829
|
+
const scheduler = typeof globalThis.requestAnimationFrame === 'function'
|
|
36830
|
+
? globalThis.requestAnimationFrame.bind(globalThis)
|
|
36831
|
+
: null;
|
|
36832
|
+
if (!scheduler) {
|
|
36833
|
+
this.refreshResponsiveHorizontalScroll();
|
|
36834
|
+
return;
|
|
36835
|
+
}
|
|
36836
|
+
if (this.resizeObserverRefreshFrameId !== null) {
|
|
36837
|
+
return;
|
|
36838
|
+
}
|
|
36839
|
+
this.resizeObserverRefreshFrameId = scheduler(() => {
|
|
36840
|
+
this.resizeObserverRefreshFrameId = null;
|
|
36841
|
+
this.refreshResponsiveHorizontalScroll();
|
|
36842
|
+
});
|
|
36843
|
+
}
|
|
36844
|
+
cancelResponsiveHorizontalScrollRefresh() {
|
|
36845
|
+
if (this.resizeObserverRefreshFrameId === null) {
|
|
36846
|
+
return;
|
|
36847
|
+
}
|
|
36848
|
+
if (typeof globalThis.cancelAnimationFrame === 'function') {
|
|
36849
|
+
globalThis.cancelAnimationFrame(this.resizeObserverRefreshFrameId);
|
|
36850
|
+
}
|
|
36851
|
+
this.resizeObserverRefreshFrameId = null;
|
|
36852
|
+
}
|
|
36694
36853
|
hasBottomPaginator() {
|
|
36695
36854
|
if (!this.getPaginationEnabled())
|
|
36696
36855
|
return false;
|
|
@@ -36734,6 +36893,82 @@ class PraxisTable {
|
|
|
36734
36893
|
return true;
|
|
36735
36894
|
return this.isLocalMode() && !this.isLocalDataModeFeatureEnabled();
|
|
36736
36895
|
}
|
|
36896
|
+
shouldShowNoDataState() {
|
|
36897
|
+
if (this.shouldShowEmptyState() ||
|
|
36898
|
+
!this.shouldRenderDataSurface() ||
|
|
36899
|
+
this.schemaError ||
|
|
36900
|
+
this.dataError ||
|
|
36901
|
+
this.isTableDataLoading()) {
|
|
36902
|
+
return false;
|
|
36903
|
+
}
|
|
36904
|
+
if (this.isRemoteMode() && !this.hasResolvedRemoteDataLoad()) {
|
|
36905
|
+
return false;
|
|
36906
|
+
}
|
|
36907
|
+
return this.getRenderedRowCount() === 0;
|
|
36908
|
+
}
|
|
36909
|
+
shouldShowLoadingSurface() {
|
|
36910
|
+
if (this.shouldShowEmptyState() ||
|
|
36911
|
+
!this.shouldRenderDataSurface() ||
|
|
36912
|
+
this.schemaError ||
|
|
36913
|
+
this.dataError) {
|
|
36914
|
+
return false;
|
|
36915
|
+
}
|
|
36916
|
+
return this.isTableDataLoading() && this.getRenderedRowCount() === 0;
|
|
36917
|
+
}
|
|
36918
|
+
getLoadingSurfaceMessage() {
|
|
36919
|
+
return this.config?.messages?.states?.loading || 'Carregando dados...';
|
|
36920
|
+
}
|
|
36921
|
+
getNoDataStateTitle() {
|
|
36922
|
+
const emptyState = this.resolveNoDataStateConfig();
|
|
36923
|
+
return emptyState.message;
|
|
36924
|
+
}
|
|
36925
|
+
getNoDataStateDescription() {
|
|
36926
|
+
const emptyState = this.resolveNoDataStateConfig();
|
|
36927
|
+
const actions = emptyState.actions ?? [];
|
|
36928
|
+
if (!actions.length) {
|
|
36929
|
+
return undefined;
|
|
36930
|
+
}
|
|
36931
|
+
return this.hasActiveDataFilters()
|
|
36932
|
+
? 'Ajuste os filtros ou abra outra carteira operacional.'
|
|
36933
|
+
: 'Use a ação principal para iniciar a próxima operação.';
|
|
36934
|
+
}
|
|
36935
|
+
getTableSettingsLabel() {
|
|
36936
|
+
return translateTableRuntimeText(this.i18n, 'table.chrome.settings', 'Configurações');
|
|
36937
|
+
}
|
|
36938
|
+
getTableSettingsTooltip() {
|
|
36939
|
+
return this.schemaOutdated
|
|
36940
|
+
? translateTableRuntimeText(this.i18n, 'table.chrome.settings.reconcile', 'Schema do servidor mudou - reconciliar')
|
|
36941
|
+
: this.getTableSettingsLabel();
|
|
36942
|
+
}
|
|
36943
|
+
getDisconnectLabel() {
|
|
36944
|
+
return translateTableRuntimeText(this.i18n, 'table.chrome.disconnect', 'Desconectar');
|
|
36945
|
+
}
|
|
36946
|
+
getDisconnectTooltip() {
|
|
36947
|
+
return translateTableRuntimeText(this.i18n, 'table.chrome.disconnectTooltip', 'Desconectar da fonte de dados');
|
|
36948
|
+
}
|
|
36949
|
+
getNoDataStateIcon() {
|
|
36950
|
+
const emptyState = this.resolveNoDataStateConfig();
|
|
36951
|
+
return (emptyState.icon || '').trim();
|
|
36952
|
+
}
|
|
36953
|
+
getNoDataStatePrimaryAction() {
|
|
36954
|
+
const actions = this.resolveNoDataStateConfig().actions ?? [];
|
|
36955
|
+
const action = actions.find((entry) => entry?.primary) ?? actions[0];
|
|
36956
|
+
return action ? this.mapEmptyStateAction(action) : null;
|
|
36957
|
+
}
|
|
36958
|
+
getNoDataStateSecondaryActions() {
|
|
36959
|
+
const actions = this.resolveNoDataStateConfig().actions ?? [];
|
|
36960
|
+
const primary = this.getNoDataStatePrimaryAction();
|
|
36961
|
+
const primaryId = primary?.label ? primary.label : null;
|
|
36962
|
+
return actions
|
|
36963
|
+
.filter((entry) => {
|
|
36964
|
+
if (!entry)
|
|
36965
|
+
return false;
|
|
36966
|
+
if (entry.primary && primaryId)
|
|
36967
|
+
return false;
|
|
36968
|
+
return true;
|
|
36969
|
+
})
|
|
36970
|
+
.map((entry) => this.mapEmptyStateAction(entry));
|
|
36971
|
+
}
|
|
36737
36972
|
shouldRenderAdvancedFilter() {
|
|
36738
36973
|
if (!this.config?.behavior?.filtering?.advancedFilters?.enabled) {
|
|
36739
36974
|
return false;
|
|
@@ -36901,6 +37136,7 @@ class PraxisTable {
|
|
|
36901
37136
|
allowComparisons: true,
|
|
36902
37137
|
});
|
|
36903
37138
|
resizeObserver;
|
|
37139
|
+
resizeObserverRefreshFrameId = null;
|
|
36904
37140
|
removeViewportChangeListeners = null;
|
|
36905
37141
|
warnedUnsupportedFeatures = new Set();
|
|
36906
37142
|
warnedStrictCspStyleMode = false;
|
|
@@ -37324,7 +37560,7 @@ class PraxisTable {
|
|
|
37324
37560
|
});
|
|
37325
37561
|
}
|
|
37326
37562
|
emitLoadingState(phase, status, message, error) {
|
|
37327
|
-
this.
|
|
37563
|
+
this.latestLoadingState = {
|
|
37328
37564
|
phase,
|
|
37329
37565
|
status,
|
|
37330
37566
|
message,
|
|
@@ -37335,8 +37571,71 @@ class PraxisTable {
|
|
|
37335
37571
|
resourcePath: this.resourcePath,
|
|
37336
37572
|
},
|
|
37337
37573
|
timestamp: new Date().toISOString(),
|
|
37574
|
+
};
|
|
37575
|
+
this.loadingStateChange.emit({
|
|
37576
|
+
...this.latestLoadingState,
|
|
37338
37577
|
});
|
|
37339
37578
|
}
|
|
37579
|
+
hasResolvedRemoteDataLoad() {
|
|
37580
|
+
return this.latestLoadingState?.status === 'success';
|
|
37581
|
+
}
|
|
37582
|
+
isTableDataLoading() {
|
|
37583
|
+
return this.latestLoadingState?.status === 'loading';
|
|
37584
|
+
}
|
|
37585
|
+
getRenderedRowCount() {
|
|
37586
|
+
return Array.isArray(this.dataSource?.data) ? this.dataSource.data.length : 0;
|
|
37587
|
+
}
|
|
37588
|
+
hasActiveDataFilters() {
|
|
37589
|
+
const criteria = this.getEffectiveFilterCriteria();
|
|
37590
|
+
const values = Object.values(criteria || {});
|
|
37591
|
+
return values.some((value) => this.hasMeaningfulFilterValue(value));
|
|
37592
|
+
}
|
|
37593
|
+
hasMeaningfulFilterValue(value) {
|
|
37594
|
+
if (value == null)
|
|
37595
|
+
return false;
|
|
37596
|
+
if (typeof value === 'string')
|
|
37597
|
+
return value.trim().length > 0;
|
|
37598
|
+
if (typeof value === 'number' || typeof value === 'boolean')
|
|
37599
|
+
return true;
|
|
37600
|
+
if (Array.isArray(value)) {
|
|
37601
|
+
return value.some((entry) => this.hasMeaningfulFilterValue(entry));
|
|
37602
|
+
}
|
|
37603
|
+
if (typeof value === 'object') {
|
|
37604
|
+
return Object.values(value).some((entry) => this.hasMeaningfulFilterValue(entry));
|
|
37605
|
+
}
|
|
37606
|
+
return false;
|
|
37607
|
+
}
|
|
37608
|
+
resolveNoDataStateConfig() {
|
|
37609
|
+
const baseEmptyState = this.config?.behavior?.emptyState;
|
|
37610
|
+
const contextualEmptyState = this.hasActiveDataFilters()
|
|
37611
|
+
? (baseEmptyState?.contexts?.filtered ?? baseEmptyState?.contexts?.searched)
|
|
37612
|
+
: baseEmptyState?.contexts?.initial;
|
|
37613
|
+
const merged = {
|
|
37614
|
+
...(baseEmptyState || {}),
|
|
37615
|
+
...(contextualEmptyState || {}),
|
|
37616
|
+
};
|
|
37617
|
+
const fallbackMessage = this.hasActiveDataFilters()
|
|
37618
|
+
? this.config?.messages?.states?.noResults || 'Nenhum resultado encontrado.'
|
|
37619
|
+
: this.config?.messages?.states?.empty || 'Nenhum dado disponivel.';
|
|
37620
|
+
return {
|
|
37621
|
+
message: String(merged.message || fallbackMessage),
|
|
37622
|
+
icon: typeof merged.icon === 'string' ? merged.icon : undefined,
|
|
37623
|
+
actions: Array.isArray(merged.actions) ? merged.actions : [],
|
|
37624
|
+
};
|
|
37625
|
+
}
|
|
37626
|
+
mapEmptyStateAction(action) {
|
|
37627
|
+
return {
|
|
37628
|
+
label: action.label,
|
|
37629
|
+
icon: action.icon,
|
|
37630
|
+
action: () => this.onEmptyStateAction(action.action),
|
|
37631
|
+
};
|
|
37632
|
+
}
|
|
37633
|
+
onEmptyStateAction(actionId) {
|
|
37634
|
+
const action = String(actionId || '').trim();
|
|
37635
|
+
if (!action)
|
|
37636
|
+
return;
|
|
37637
|
+
this.onToolbarAction({ action });
|
|
37638
|
+
}
|
|
37340
37639
|
buildLoadingContext(phase, label, blocking) {
|
|
37341
37640
|
const componentId = this.tableId || this.componentInstanceId || 'table';
|
|
37342
37641
|
return {
|
|
@@ -37801,24 +38100,839 @@ class PraxisTable {
|
|
|
37801
38100
|
}
|
|
37802
38101
|
return '—';
|
|
37803
38102
|
}
|
|
38103
|
+
getExpansionDetailListEntries(row, node) {
|
|
38104
|
+
const field = String(node?.field || '').trim();
|
|
38105
|
+
const staticItems = Array.isArray(node?.items) ? node.items : null;
|
|
38106
|
+
if (field) {
|
|
38107
|
+
const resolved = this.getNestedPropertyValue(row, field);
|
|
38108
|
+
if (Array.isArray(resolved)) {
|
|
38109
|
+
return resolved;
|
|
38110
|
+
}
|
|
38111
|
+
}
|
|
38112
|
+
if (staticItems) {
|
|
38113
|
+
return staticItems;
|
|
38114
|
+
}
|
|
38115
|
+
return [];
|
|
38116
|
+
}
|
|
37804
38117
|
getExpansionDetailListItems(row, node) {
|
|
38118
|
+
return this.getExpansionDetailListEntries(row, node)
|
|
38119
|
+
.map((entry) => this.formatExpansionDetailListEntry(entry))
|
|
38120
|
+
.filter((entry) => entry.length > 0);
|
|
38121
|
+
}
|
|
38122
|
+
getExpansionDetailRichListEntries(row, node) {
|
|
38123
|
+
const field = String(node?.field || '').trim();
|
|
38124
|
+
const staticItems = Array.isArray(node?.items) ? node.items : null;
|
|
38125
|
+
if (field) {
|
|
38126
|
+
const resolved = this.getNestedPropertyValue(row, field);
|
|
38127
|
+
if (Array.isArray(resolved)) {
|
|
38128
|
+
return resolved;
|
|
38129
|
+
}
|
|
38130
|
+
}
|
|
38131
|
+
if (staticItems) {
|
|
38132
|
+
return staticItems;
|
|
38133
|
+
}
|
|
38134
|
+
return [];
|
|
38135
|
+
}
|
|
38136
|
+
getExpansionDetailRichListEmptyText(node) {
|
|
38137
|
+
return String(node?.emptyText || 'Sem itens.').trim() || 'Sem itens.';
|
|
38138
|
+
}
|
|
38139
|
+
getExpansionDetailRichListItemNodes(node) {
|
|
38140
|
+
return Array.isArray(node?.itemSchema?.nodes)
|
|
38141
|
+
? node.itemSchema.nodes
|
|
38142
|
+
: [];
|
|
38143
|
+
}
|
|
38144
|
+
getExpansionDetailCardGridHeaderNodes(node) {
|
|
38145
|
+
const title = String(node?.title || '').trim();
|
|
38146
|
+
const subtitle = String(node?.subtitle || '').trim();
|
|
38147
|
+
const items = [];
|
|
38148
|
+
if (title) {
|
|
38149
|
+
items.push({
|
|
38150
|
+
type: 'text',
|
|
38151
|
+
text: title,
|
|
38152
|
+
className: 'pfx-expansion-node-card-grid__title-text',
|
|
38153
|
+
});
|
|
38154
|
+
}
|
|
38155
|
+
if (subtitle) {
|
|
38156
|
+
items.push({
|
|
38157
|
+
type: 'text',
|
|
38158
|
+
text: subtitle,
|
|
38159
|
+
className: 'pfx-expansion-node-card-grid__subtitle-text',
|
|
38160
|
+
});
|
|
38161
|
+
}
|
|
38162
|
+
if (!items.length) {
|
|
38163
|
+
return [];
|
|
38164
|
+
}
|
|
38165
|
+
return [
|
|
38166
|
+
{
|
|
38167
|
+
type: 'compose',
|
|
38168
|
+
direction: 'column',
|
|
38169
|
+
gap: 'xs',
|
|
38170
|
+
items,
|
|
38171
|
+
},
|
|
38172
|
+
];
|
|
38173
|
+
}
|
|
38174
|
+
getExpansionDetailCardGridCards(node) {
|
|
38175
|
+
return Array.isArray(node?.cards) ? node.cards : [];
|
|
38176
|
+
}
|
|
38177
|
+
getExpansionDetailCardGridStyles(node) {
|
|
38178
|
+
const columns = node?.columns === 'auto'
|
|
38179
|
+
? 'repeat(auto-fit, minmax(var(--pfx-expansion-card-grid-min-width, 220px), 1fr))'
|
|
38180
|
+
: `repeat(${this.normalizeExpansionDetailCardGridColumns(node?.columns)}, minmax(0, 1fr))`;
|
|
38181
|
+
const minCardWidth = this.normalizeExpansionDetailCardGridMinWidth(node?.minCardWidth);
|
|
38182
|
+
return {
|
|
38183
|
+
'--pfx-expansion-card-grid-columns': columns,
|
|
38184
|
+
'--pfx-expansion-card-grid-min-width': `${minCardWidth}px`,
|
|
38185
|
+
};
|
|
38186
|
+
}
|
|
38187
|
+
getExpansionDetailCardGridCardNodes(card) {
|
|
38188
|
+
const content = this.normalizeExpansionDetailCardGridCardContent(card?.content);
|
|
38189
|
+
return [
|
|
38190
|
+
{
|
|
38191
|
+
type: 'card',
|
|
38192
|
+
id: card?.id ? String(card.id) : undefined,
|
|
38193
|
+
title: card?.title ? String(card.title) : undefined,
|
|
38194
|
+
subtitle: card?.subtitle ? String(card.subtitle) : undefined,
|
|
38195
|
+
content,
|
|
38196
|
+
className: 'pfx-expansion-node-card-grid__card',
|
|
38197
|
+
},
|
|
38198
|
+
];
|
|
38199
|
+
}
|
|
38200
|
+
getExpansionDetailTimelineEntries(row, node) {
|
|
37805
38201
|
const field = String(node?.field || '').trim();
|
|
37806
38202
|
const staticItems = Array.isArray(node?.items) ? node.items : null;
|
|
37807
38203
|
if (field) {
|
|
37808
38204
|
const resolved = this.getNestedPropertyValue(row, field);
|
|
37809
38205
|
if (Array.isArray(resolved)) {
|
|
37810
|
-
return resolved
|
|
37811
|
-
.map((entry) => this.formatExpansionDetailListEntry(entry))
|
|
37812
|
-
.filter((entry) => entry.length > 0);
|
|
38206
|
+
return resolved;
|
|
37813
38207
|
}
|
|
37814
38208
|
}
|
|
37815
38209
|
if (staticItems) {
|
|
37816
|
-
return staticItems
|
|
37817
|
-
.map((entry) => this.formatExpansionDetailListEntry(entry))
|
|
37818
|
-
.filter((entry) => entry.length > 0);
|
|
38210
|
+
return staticItems;
|
|
37819
38211
|
}
|
|
37820
38212
|
return [];
|
|
37821
38213
|
}
|
|
38214
|
+
getExpansionDetailTimelineEmptyText(node) {
|
|
38215
|
+
return (String(node?.emptyText
|
|
38216
|
+
|| this.resolveTableMessage('table.expansion.timeline.empty', 'Sem eventos recentes.')).trim()
|
|
38217
|
+
|| this.resolveTableMessage('table.expansion.timeline.empty', 'Sem eventos recentes.'));
|
|
38218
|
+
}
|
|
38219
|
+
getExpansionDetailTimelineNodes(row, node) {
|
|
38220
|
+
const timelineNode = this.buildExpansionDetailTimelineRichNode(row, node);
|
|
38221
|
+
return timelineNode ? [timelineNode] : [];
|
|
38222
|
+
}
|
|
38223
|
+
getExpansionDetailRichListItemContext(row, rowIndex, node, entry, itemIndex) {
|
|
38224
|
+
const baseContext = this.getExpansionDetailRichContentContext(row, rowIndex);
|
|
38225
|
+
const canonicalAlias = 'detailItem';
|
|
38226
|
+
const canonicalIndexAlias = 'detailIndex';
|
|
38227
|
+
const itemAlias = String(node?.itemContext?.itemAlias || canonicalAlias).trim() || canonicalAlias;
|
|
38228
|
+
const indexAlias = String(node?.itemContext?.indexAlias || canonicalIndexAlias).trim() || canonicalIndexAlias;
|
|
38229
|
+
const extendedContext = {
|
|
38230
|
+
...baseContext,
|
|
38231
|
+
[canonicalAlias]: entry,
|
|
38232
|
+
[canonicalIndexAlias]: itemIndex,
|
|
38233
|
+
};
|
|
38234
|
+
if (itemAlias !== canonicalAlias) {
|
|
38235
|
+
extendedContext[itemAlias] = entry;
|
|
38236
|
+
}
|
|
38237
|
+
if (indexAlias !== canonicalIndexAlias) {
|
|
38238
|
+
extendedContext[indexAlias] = itemIndex;
|
|
38239
|
+
}
|
|
38240
|
+
return extendedContext;
|
|
38241
|
+
}
|
|
38242
|
+
getExpansionDetailRichListItemClassName(node) {
|
|
38243
|
+
const layout = String(node?.itemSchema?.layout || 'stack').trim().toLowerCase();
|
|
38244
|
+
if (layout === 'row') {
|
|
38245
|
+
return 'pfx-expansion-node-rich-list__item pfx-expansion-node-rich-list__item--row';
|
|
38246
|
+
}
|
|
38247
|
+
if (layout === 'card-list') {
|
|
38248
|
+
return 'pfx-expansion-node-rich-list__item pfx-expansion-node-rich-list__item--card-list';
|
|
38249
|
+
}
|
|
38250
|
+
return 'pfx-expansion-node-rich-list__item pfx-expansion-node-rich-list__item--stack';
|
|
38251
|
+
}
|
|
38252
|
+
getExpansionDetailRichListItemKey(node, entry, itemIndex) {
|
|
38253
|
+
const keyField = String(node?.itemKeyField || '').trim();
|
|
38254
|
+
if (keyField && entry && typeof entry === 'object' && !Array.isArray(entry)) {
|
|
38255
|
+
const resolved = this.getNestedPropertyValue(entry, keyField);
|
|
38256
|
+
const normalized = String(resolved ?? '').trim();
|
|
38257
|
+
if (normalized) {
|
|
38258
|
+
return normalized;
|
|
38259
|
+
}
|
|
38260
|
+
}
|
|
38261
|
+
const label = this.formatExpansionDetailListEntry(entry);
|
|
38262
|
+
return label ? `${itemIndex}:${label}` : `item-${itemIndex}`;
|
|
38263
|
+
}
|
|
38264
|
+
getExpansionDetailRichListItemActions(node, row, rowIndex, entry, itemIndex) {
|
|
38265
|
+
const actions = Array.isArray(node?.itemActions) ? node.itemActions : [];
|
|
38266
|
+
const context = this.getExpansionDetailRichListItemContext(row, rowIndex, node, entry, itemIndex);
|
|
38267
|
+
return actions.filter((action) => this.isExpansionDetailRichListItemActionVisible(action, context));
|
|
38268
|
+
}
|
|
38269
|
+
normalizeExpansionDetailCardGridColumns(columns) {
|
|
38270
|
+
const normalized = Number(columns);
|
|
38271
|
+
if (normalized === 4 || normalized === 3 || normalized === 2) {
|
|
38272
|
+
return normalized;
|
|
38273
|
+
}
|
|
38274
|
+
return 1;
|
|
38275
|
+
}
|
|
38276
|
+
normalizeExpansionDetailCardGridMinWidth(minCardWidth) {
|
|
38277
|
+
const normalized = Number(minCardWidth);
|
|
38278
|
+
return Number.isFinite(normalized) && normalized >= 160 ? normalized : 220;
|
|
38279
|
+
}
|
|
38280
|
+
getExpansionDetailTimelineFieldName(node, fieldName) {
|
|
38281
|
+
const explicit = String(node?.itemSchema?.[fieldName] || '').trim();
|
|
38282
|
+
if (explicit) {
|
|
38283
|
+
return explicit;
|
|
38284
|
+
}
|
|
38285
|
+
const defaults = {
|
|
38286
|
+
titleField: 'label',
|
|
38287
|
+
subtitleField: 'secondary',
|
|
38288
|
+
metaField: 'status',
|
|
38289
|
+
iconField: 'icon',
|
|
38290
|
+
badgeField: 'badge',
|
|
38291
|
+
};
|
|
38292
|
+
return defaults[fieldName];
|
|
38293
|
+
}
|
|
38294
|
+
buildExpansionDetailTimelineRichNode(row, node) {
|
|
38295
|
+
const items = this.getExpansionDetailTimelineEntries(row, node)
|
|
38296
|
+
.map((entry, itemIndex) => this.mapExpansionDetailTimelineItem(entry, node, itemIndex))
|
|
38297
|
+
.filter((item) => item != null);
|
|
38298
|
+
return {
|
|
38299
|
+
type: 'timeline',
|
|
38300
|
+
id: node?.id ? String(node.id) : undefined,
|
|
38301
|
+
className: 'pfx-expansion-node pfx-expansion-node-timeline',
|
|
38302
|
+
title: this.getExpansionDetailNodeTitle(node, this.resolveTableMessage('table.expansion.timeline.title', 'Linha do tempo')) || undefined,
|
|
38303
|
+
emptyText: this.getExpansionDetailTimelineEmptyText(node),
|
|
38304
|
+
items,
|
|
38305
|
+
};
|
|
38306
|
+
}
|
|
38307
|
+
mapExpansionDetailTimelineItem(entry, node, itemIndex) {
|
|
38308
|
+
if (entry === null || entry === undefined) {
|
|
38309
|
+
return null;
|
|
38310
|
+
}
|
|
38311
|
+
if (typeof entry === 'string'
|
|
38312
|
+
|| typeof entry === 'number'
|
|
38313
|
+
|| typeof entry === 'boolean'
|
|
38314
|
+
|| typeof entry === 'bigint') {
|
|
38315
|
+
const title = String(entry).trim();
|
|
38316
|
+
return title
|
|
38317
|
+
? {
|
|
38318
|
+
id: `timeline-${itemIndex}`,
|
|
38319
|
+
title,
|
|
38320
|
+
}
|
|
38321
|
+
: null;
|
|
38322
|
+
}
|
|
38323
|
+
if (Array.isArray(entry)) {
|
|
38324
|
+
const title = entry
|
|
38325
|
+
.map((nested) => this.formatExpansionDetailListEntry(nested))
|
|
38326
|
+
.filter((nested) => nested.length > 0)
|
|
38327
|
+
.join(' - ');
|
|
38328
|
+
return title
|
|
38329
|
+
? {
|
|
38330
|
+
id: `timeline-${itemIndex}`,
|
|
38331
|
+
title,
|
|
38332
|
+
}
|
|
38333
|
+
: null;
|
|
38334
|
+
}
|
|
38335
|
+
if (typeof entry !== 'object') {
|
|
38336
|
+
return null;
|
|
38337
|
+
}
|
|
38338
|
+
const record = entry;
|
|
38339
|
+
const title = this.getExpansionDetailTimelineObjectValue(record, this.getExpansionDetailTimelineFieldName(node, 'titleField'), ['label', 'title', 'name', 'value', 'event']);
|
|
38340
|
+
if (!title) {
|
|
38341
|
+
return null;
|
|
38342
|
+
}
|
|
38343
|
+
return {
|
|
38344
|
+
id: this.getExpansionDetailTimelineObjectValue(record, 'id', [])
|
|
38345
|
+
|| `timeline-${itemIndex}`,
|
|
38346
|
+
title,
|
|
38347
|
+
subtitle: this.getExpansionDetailTimelineObjectValue(record, this.getExpansionDetailTimelineFieldName(node, 'subtitleField'), ['secondary', 'subtitle', 'description', 'detail']) || undefined,
|
|
38348
|
+
meta: this.getExpansionDetailTimelineObjectValue(record, this.getExpansionDetailTimelineFieldName(node, 'metaField'), ['status', 'time', 'timeAgo', 'date', 'when']) || undefined,
|
|
38349
|
+
icon: this.getExpansionDetailTimelineObjectValue(record, this.getExpansionDetailTimelineFieldName(node, 'iconField'), ['icon', 'symbol', 'kind']) || undefined,
|
|
38350
|
+
badge: this.getExpansionDetailTimelineObjectValue(record, this.getExpansionDetailTimelineFieldName(node, 'badgeField'), ['badge', 'category', 'tag', 'severity']) || undefined,
|
|
38351
|
+
};
|
|
38352
|
+
}
|
|
38353
|
+
getExpansionDetailTimelineObjectValue(entry, preferredKey, fallbackKeys) {
|
|
38354
|
+
const keys = [preferredKey, ...fallbackKeys].filter((key, index, all) => key && all.indexOf(key) === index);
|
|
38355
|
+
for (const key of keys) {
|
|
38356
|
+
const raw = entry[key];
|
|
38357
|
+
if (typeof raw === 'string'
|
|
38358
|
+
|| typeof raw === 'number'
|
|
38359
|
+
|| typeof raw === 'boolean'
|
|
38360
|
+
|| typeof raw === 'bigint') {
|
|
38361
|
+
const normalized = String(raw).trim();
|
|
38362
|
+
if (normalized) {
|
|
38363
|
+
return normalized;
|
|
38364
|
+
}
|
|
38365
|
+
}
|
|
38366
|
+
}
|
|
38367
|
+
return null;
|
|
38368
|
+
}
|
|
38369
|
+
normalizeExpansionDetailCardGridCardContent(rawContent) {
|
|
38370
|
+
const content = Array.isArray(rawContent) ? rawContent : [];
|
|
38371
|
+
return content.filter((node) => this.isExpansionDetailCardGridContentNode(node));
|
|
38372
|
+
}
|
|
38373
|
+
normalizeExpansionDetailMediaBlockAvatar(candidate) {
|
|
38374
|
+
return candidate && typeof candidate === 'object' && candidate.type === 'avatar'
|
|
38375
|
+
? candidate
|
|
38376
|
+
: null;
|
|
38377
|
+
}
|
|
38378
|
+
normalizeExpansionDetailMediaBlockText(candidate) {
|
|
38379
|
+
return candidate && typeof candidate === 'object' && candidate.type === 'text'
|
|
38380
|
+
? candidate
|
|
38381
|
+
: null;
|
|
38382
|
+
}
|
|
38383
|
+
normalizeExpansionDetailMediaBlockMeta(candidate) {
|
|
38384
|
+
if (!candidate || typeof candidate !== 'object' || candidate.type !== 'compose') {
|
|
38385
|
+
return null;
|
|
38386
|
+
}
|
|
38387
|
+
const normalizedItems = this.normalizeExpansionDetailComposeItems(candidate.items);
|
|
38388
|
+
if (!normalizedItems.length) {
|
|
38389
|
+
return null;
|
|
38390
|
+
}
|
|
38391
|
+
return {
|
|
38392
|
+
...candidate,
|
|
38393
|
+
items: normalizedItems,
|
|
38394
|
+
};
|
|
38395
|
+
}
|
|
38396
|
+
normalizeExpansionDetailMediaBlockTrailing(candidate) {
|
|
38397
|
+
return this.normalizeExpansionDetailCardGridCardContent(candidate);
|
|
38398
|
+
}
|
|
38399
|
+
normalizeExpansionDetailComposeItems(rawItems) {
|
|
38400
|
+
const items = Array.isArray(rawItems) ? rawItems : [];
|
|
38401
|
+
return items.filter((node) => this.isExpansionDetailComposeItemNode(node));
|
|
38402
|
+
}
|
|
38403
|
+
isExpansionDetailCardGridContentNode(node) {
|
|
38404
|
+
if (!node || typeof node !== 'object') {
|
|
38405
|
+
return false;
|
|
38406
|
+
}
|
|
38407
|
+
const type = String(node.type || '').trim();
|
|
38408
|
+
return (type === 'text'
|
|
38409
|
+
|| type === 'icon'
|
|
38410
|
+
|| type === 'image'
|
|
38411
|
+
|| type === 'badge'
|
|
38412
|
+
|| type === 'avatar'
|
|
38413
|
+
|| type === 'metric'
|
|
38414
|
+
|| type === 'progress'
|
|
38415
|
+
|| type === 'compose');
|
|
38416
|
+
}
|
|
38417
|
+
isExpansionDetailComposeItemNode(node) {
|
|
38418
|
+
if (!node || typeof node !== 'object') {
|
|
38419
|
+
return false;
|
|
38420
|
+
}
|
|
38421
|
+
const type = String(node.type || '').trim();
|
|
38422
|
+
return (type === 'text'
|
|
38423
|
+
|| type === 'icon'
|
|
38424
|
+
|| type === 'image'
|
|
38425
|
+
|| type === 'badge'
|
|
38426
|
+
|| type === 'avatar'
|
|
38427
|
+
|| type === 'metric'
|
|
38428
|
+
|| type === 'progress');
|
|
38429
|
+
}
|
|
38430
|
+
getExpansionDetailRichListItemActionNodes(action) {
|
|
38431
|
+
const labelNode = {
|
|
38432
|
+
type: 'text',
|
|
38433
|
+
text: String(action?.label || action?.actionId || 'Ação').trim() || 'Ação',
|
|
38434
|
+
className: 'pfx-expansion-node-rich-list__item-action-text',
|
|
38435
|
+
};
|
|
38436
|
+
const icon = String(action?.icon || '').trim();
|
|
38437
|
+
if (!icon) {
|
|
38438
|
+
return [labelNode];
|
|
38439
|
+
}
|
|
38440
|
+
return [
|
|
38441
|
+
{
|
|
38442
|
+
type: 'compose',
|
|
38443
|
+
direction: 'row',
|
|
38444
|
+
gap: 'sm',
|
|
38445
|
+
items: [
|
|
38446
|
+
{
|
|
38447
|
+
type: 'icon',
|
|
38448
|
+
icon,
|
|
38449
|
+
ariaLabel: labelNode.text,
|
|
38450
|
+
className: 'pfx-expansion-node-rich-list__item-action-icon',
|
|
38451
|
+
},
|
|
38452
|
+
labelNode,
|
|
38453
|
+
],
|
|
38454
|
+
},
|
|
38455
|
+
];
|
|
38456
|
+
}
|
|
38457
|
+
isExpansionDetailRichListItemActionDisabled(action, row, rowIndex, node, entry, itemIndex) {
|
|
38458
|
+
const disabledWhen = action?.disabledWhen;
|
|
38459
|
+
if (!this.hasConditionalExpression(disabledWhen)) {
|
|
38460
|
+
return false;
|
|
38461
|
+
}
|
|
38462
|
+
return this.evaluateExpansionDetailRichListItemCondition(disabledWhen, this.getExpansionDetailRichListItemContext(row, rowIndex, node, entry, itemIndex), true);
|
|
38463
|
+
}
|
|
38464
|
+
onExpansionDetailRichListItemAction(action, row, rowIndex, node, entry, itemIndex, event) {
|
|
38465
|
+
const actionId = String(action?.actionId || '').trim();
|
|
38466
|
+
event.stopPropagation();
|
|
38467
|
+
if (!actionId) {
|
|
38468
|
+
return;
|
|
38469
|
+
}
|
|
38470
|
+
const context = this.getExpansionDetailRichListItemContext(row, rowIndex, node, entry, itemIndex);
|
|
38471
|
+
this.onRowAction(actionId, row, event, this.resolveRowActionRuntimeOptions({
|
|
38472
|
+
actionConfig: action,
|
|
38473
|
+
payload: this.evaluateExpansionDetailRichListItemPayload(action?.payloadExpr, context, entry),
|
|
38474
|
+
}, action));
|
|
38475
|
+
}
|
|
38476
|
+
getExpansionDetailListItemRichContentNodes(entry) {
|
|
38477
|
+
if (entry === null || entry === undefined) {
|
|
38478
|
+
return null;
|
|
38479
|
+
}
|
|
38480
|
+
if (typeof entry === 'string'
|
|
38481
|
+
|| typeof entry === 'number'
|
|
38482
|
+
|| typeof entry === 'boolean'
|
|
38483
|
+
|| typeof entry === 'bigint') {
|
|
38484
|
+
const text = String(entry).trim();
|
|
38485
|
+
return text ? [{ type: 'text', text }] : null;
|
|
38486
|
+
}
|
|
38487
|
+
if (typeof entry !== 'object' || Array.isArray(entry)) {
|
|
38488
|
+
return null;
|
|
38489
|
+
}
|
|
38490
|
+
const record = entry;
|
|
38491
|
+
const label = this.getExpansionDetailObjectListLabel(record);
|
|
38492
|
+
if (!label) {
|
|
38493
|
+
return null;
|
|
38494
|
+
}
|
|
38495
|
+
const textNode = { type: 'text', text: label };
|
|
38496
|
+
const badgeLabel = this.getExpansionDetailObjectListBadgeLabel(record);
|
|
38497
|
+
if (!badgeLabel) {
|
|
38498
|
+
return [textNode];
|
|
38499
|
+
}
|
|
38500
|
+
const badgeNode = {
|
|
38501
|
+
type: 'badge',
|
|
38502
|
+
label: badgeLabel,
|
|
38503
|
+
className: 'pfx-expansion-node-list__badge',
|
|
38504
|
+
};
|
|
38505
|
+
return [
|
|
38506
|
+
{
|
|
38507
|
+
type: 'compose',
|
|
38508
|
+
direction: 'row',
|
|
38509
|
+
gap: 'sm',
|
|
38510
|
+
items: [textNode, badgeNode],
|
|
38511
|
+
},
|
|
38512
|
+
];
|
|
38513
|
+
}
|
|
38514
|
+
getExpansionDetailActionId(node) {
|
|
38515
|
+
return String(node?.actionId || node?.id || node?.action || '').trim();
|
|
38516
|
+
}
|
|
38517
|
+
getExpansionDetailActionLabel(node) {
|
|
38518
|
+
return this.getExpansionDetailNodeTitle(node, this.getExpansionDetailActionId(node) || 'Action');
|
|
38519
|
+
}
|
|
38520
|
+
getExpansionDetailActionStatusText(node) {
|
|
38521
|
+
const raw = node?.statusText ?? node?.description ?? null;
|
|
38522
|
+
const normalized = String(raw ?? '').trim();
|
|
38523
|
+
return normalized || null;
|
|
38524
|
+
}
|
|
38525
|
+
getExpansionDetailActionBarTitle(node) {
|
|
38526
|
+
return (this.getExpansionDetailNodeTitle(node, this.resolveTableMessage('table.expansion.actionBar.title', 'Ações rápidas'))
|
|
38527
|
+
|| this.resolveTableMessage('table.expansion.actionBar.title', 'Ações rápidas'));
|
|
38528
|
+
}
|
|
38529
|
+
getExpansionDetailActionBarActions(node, row, index) {
|
|
38530
|
+
const actions = Array.isArray(node?.actions) ? node.actions : [];
|
|
38531
|
+
const context = this.getExpansionDetailRichContentContext(row, index);
|
|
38532
|
+
return actions.filter((action) => this.isExpansionDetailActionBarActionVisible(action, context));
|
|
38533
|
+
}
|
|
38534
|
+
getExpansionDetailActionBarActionNodes(action) {
|
|
38535
|
+
return this.getExpansionDetailRichListItemActionNodes(action);
|
|
38536
|
+
}
|
|
38537
|
+
isExpansionDetailActionBarActionDisabled(action, row, index) {
|
|
38538
|
+
const disabledWhen = action?.disabledWhen;
|
|
38539
|
+
if (!this.hasConditionalExpression(disabledWhen)) {
|
|
38540
|
+
return false;
|
|
38541
|
+
}
|
|
38542
|
+
return this.evaluateExpansionDetailRichListItemCondition(disabledWhen, this.getExpansionDetailRichContentContext(row, index), true);
|
|
38543
|
+
}
|
|
38544
|
+
getExpansionDetailActionBarEmptyText(node) {
|
|
38545
|
+
return (String(node?.emptyText
|
|
38546
|
+
|| this.resolveTableMessage('table.expansion.actionBar.empty', 'Nenhuma ação disponível.')).trim()
|
|
38547
|
+
|| this.resolveTableMessage('table.expansion.actionBar.empty', 'Nenhuma ação disponível.'));
|
|
38548
|
+
}
|
|
38549
|
+
onExpansionDetailActionBarAction(action, row, index, event) {
|
|
38550
|
+
const actionId = String(action?.actionId || '').trim();
|
|
38551
|
+
event.stopPropagation();
|
|
38552
|
+
if (!actionId) {
|
|
38553
|
+
return;
|
|
38554
|
+
}
|
|
38555
|
+
const context = this.getExpansionDetailRichContentContext(row, index);
|
|
38556
|
+
this.onRowAction(actionId, row, event, this.resolveRowActionRuntimeOptions({
|
|
38557
|
+
actionConfig: action,
|
|
38558
|
+
payload: this.evaluateExpansionDetailRichListItemPayload(action?.payloadExpr, context, row),
|
|
38559
|
+
}, action));
|
|
38560
|
+
}
|
|
38561
|
+
getExpansionDetailEmbedHeaderNodes(node) {
|
|
38562
|
+
const items = [];
|
|
38563
|
+
const title = this.getExpansionDetailNodeTitle(node, this.getExpansionDetailEmbedLabel(node));
|
|
38564
|
+
const subtitle = String(node?.subtitle || '').trim();
|
|
38565
|
+
const description = String(node?.description || '').trim();
|
|
38566
|
+
const caption = String(node?.caption || '').trim();
|
|
38567
|
+
if (title) {
|
|
38568
|
+
items.push({ type: 'text', text: title, className: 'pfx-expansion-node-embed__title-text' });
|
|
38569
|
+
}
|
|
38570
|
+
if (subtitle) {
|
|
38571
|
+
items.push({ type: 'text', text: subtitle, className: 'pfx-expansion-node-embed__subtitle-text' });
|
|
38572
|
+
}
|
|
38573
|
+
if (description) {
|
|
38574
|
+
items.push({ type: 'text', text: description, className: 'pfx-expansion-node-embed__description-text' });
|
|
38575
|
+
}
|
|
38576
|
+
if (caption) {
|
|
38577
|
+
items.push({ type: 'text', text: caption, className: 'pfx-expansion-node-embed__caption-text' });
|
|
38578
|
+
}
|
|
38579
|
+
if (!items.length) {
|
|
38580
|
+
return [];
|
|
38581
|
+
}
|
|
38582
|
+
return [
|
|
38583
|
+
{
|
|
38584
|
+
type: 'compose',
|
|
38585
|
+
direction: 'column',
|
|
38586
|
+
gap: 'xs',
|
|
38587
|
+
items,
|
|
38588
|
+
},
|
|
38589
|
+
];
|
|
38590
|
+
}
|
|
38591
|
+
getExpansionDetailEmbedMetaNodes(node) {
|
|
38592
|
+
const items = [
|
|
38593
|
+
{
|
|
38594
|
+
type: 'badge',
|
|
38595
|
+
label: this.getExpansionDetailEmbedLabel(node),
|
|
38596
|
+
className: 'pfx-expansion-node-embed__kind-badge',
|
|
38597
|
+
},
|
|
38598
|
+
];
|
|
38599
|
+
const reference = this.getExpansionDetailEmbedReference(node);
|
|
38600
|
+
if (reference) {
|
|
38601
|
+
items.push({
|
|
38602
|
+
type: 'text',
|
|
38603
|
+
text: `${this.resolveTableMessage('table.expansion.embed.reference', 'Referência')}: ${reference}`,
|
|
38604
|
+
className: 'pfx-expansion-node-embed__meta-text',
|
|
38605
|
+
});
|
|
38606
|
+
}
|
|
38607
|
+
const provider = this.getExpansionDetailDiagramProvider(node);
|
|
38608
|
+
if (provider) {
|
|
38609
|
+
items.push({
|
|
38610
|
+
type: 'text',
|
|
38611
|
+
text: `${this.resolveTableMessage('table.expansion.embed.provider', 'Provedor')}: ${provider}`,
|
|
38612
|
+
className: 'pfx-expansion-node-embed__meta-text',
|
|
38613
|
+
});
|
|
38614
|
+
}
|
|
38615
|
+
const preset = this.getExpansionDetailEmbedPresetLabel(node);
|
|
38616
|
+
if (preset) {
|
|
38617
|
+
items.push({
|
|
38618
|
+
type: 'text',
|
|
38619
|
+
text: `${this.resolveTableMessage('table.expansion.embed.preset', 'Preset')}: ${preset}`,
|
|
38620
|
+
className: 'pfx-expansion-node-embed__meta-text',
|
|
38621
|
+
});
|
|
38622
|
+
}
|
|
38623
|
+
const inputSummary = this.getExpansionDetailEmbedInputsSummary(node);
|
|
38624
|
+
if (inputSummary) {
|
|
38625
|
+
items.push({
|
|
38626
|
+
type: 'text',
|
|
38627
|
+
text: `${this.resolveTableMessage('table.expansion.embed.inputs', 'Inputs')}: ${inputSummary}`,
|
|
38628
|
+
className: 'pfx-expansion-node-embed__meta-text',
|
|
38629
|
+
});
|
|
38630
|
+
}
|
|
38631
|
+
if (items.length === 1) {
|
|
38632
|
+
return [items[0]];
|
|
38633
|
+
}
|
|
38634
|
+
return [
|
|
38635
|
+
{
|
|
38636
|
+
type: 'compose',
|
|
38637
|
+
direction: 'row',
|
|
38638
|
+
gap: 'sm',
|
|
38639
|
+
wrap: true,
|
|
38640
|
+
items,
|
|
38641
|
+
},
|
|
38642
|
+
];
|
|
38643
|
+
}
|
|
38644
|
+
getExpansionDetailEmbedActionNodes(action) {
|
|
38645
|
+
return this.getExpansionDetailRichListItemActionNodes(action);
|
|
38646
|
+
}
|
|
38647
|
+
getExpansionDetailEmbedAction(node, row, index) {
|
|
38648
|
+
const action = node?.action;
|
|
38649
|
+
if (!action || typeof action !== 'object') {
|
|
38650
|
+
return null;
|
|
38651
|
+
}
|
|
38652
|
+
const context = this.getExpansionDetailRichContentContext(row, index);
|
|
38653
|
+
return this.isExpansionDetailEmbedActionVisible(action, context) ? action : null;
|
|
38654
|
+
}
|
|
38655
|
+
isExpansionDetailEmbedActionDisabled(action, row, index) {
|
|
38656
|
+
const disabledWhen = action?.disabledWhen;
|
|
38657
|
+
if (!this.hasConditionalExpression(disabledWhen)) {
|
|
38658
|
+
return false;
|
|
38659
|
+
}
|
|
38660
|
+
return this.evaluateExpansionDetailRichListItemCondition(disabledWhen, this.getExpansionDetailRichContentContext(row, index), true);
|
|
38661
|
+
}
|
|
38662
|
+
getExpansionDetailEmbedEmptyText(node) {
|
|
38663
|
+
return (String(node?.emptyText
|
|
38664
|
+
|| this.resolveTableMessage('table.expansion.embed.empty', 'Nenhum conteúdo de embed disponível.')).trim()
|
|
38665
|
+
|| this.resolveTableMessage('table.expansion.embed.empty', 'Nenhum conteúdo de embed disponível.'));
|
|
38666
|
+
}
|
|
38667
|
+
getExpansionDetailDiagramSource(row, node) {
|
|
38668
|
+
const staticSource = String(node?.source || '').trim();
|
|
38669
|
+
if (staticSource) {
|
|
38670
|
+
return staticSource;
|
|
38671
|
+
}
|
|
38672
|
+
const field = String(node?.sourceField || '').trim();
|
|
38673
|
+
if (!field) {
|
|
38674
|
+
return null;
|
|
38675
|
+
}
|
|
38676
|
+
const resolved = this.getNestedPropertyValue(row, field);
|
|
38677
|
+
const normalized = String(resolved ?? '').trim();
|
|
38678
|
+
return normalized || null;
|
|
38679
|
+
}
|
|
38680
|
+
getExpansionDetailDiagramSourceLabel() {
|
|
38681
|
+
return this.resolveTableMessage('table.expansion.embed.diagramSource', 'Fonte do diagrama');
|
|
38682
|
+
}
|
|
38683
|
+
onExpansionDetailEmbedAction(action, row, index, event) {
|
|
38684
|
+
const actionId = String(action?.actionId || '').trim();
|
|
38685
|
+
event.stopPropagation();
|
|
38686
|
+
if (!actionId) {
|
|
38687
|
+
return;
|
|
38688
|
+
}
|
|
38689
|
+
const context = this.getExpansionDetailRichContentContext(row, index);
|
|
38690
|
+
this.onRowAction(actionId, row, event, this.resolveRowActionRuntimeOptions({
|
|
38691
|
+
actionConfig: action,
|
|
38692
|
+
payload: this.evaluateExpansionDetailRichListItemPayload(action?.payloadExpr, context, row),
|
|
38693
|
+
}, action));
|
|
38694
|
+
}
|
|
38695
|
+
isExpansionDetailEmbedActionVisible(action, context) {
|
|
38696
|
+
const visibleWhen = action?.visibleWhen;
|
|
38697
|
+
if (!this.hasConditionalExpression(visibleWhen)) {
|
|
38698
|
+
return true;
|
|
38699
|
+
}
|
|
38700
|
+
return this.evaluateExpansionDetailRichListItemCondition(visibleWhen, context, this.resolveRowVisibleWhenFailurePolicy() === 'fail-open');
|
|
38701
|
+
}
|
|
38702
|
+
getExpansionDetailEmbedLabel(node) {
|
|
38703
|
+
const type = this.getExpansionDetailNodeType(node);
|
|
38704
|
+
switch (type) {
|
|
38705
|
+
case 'formRef':
|
|
38706
|
+
return this.resolveTableMessage('table.expansion.embed.formRef.label', 'Formulário governado');
|
|
38707
|
+
case 'tableRef':
|
|
38708
|
+
return this.resolveTableMessage('table.expansion.embed.tableRef.label', 'Tabela governada');
|
|
38709
|
+
case 'chartRef':
|
|
38710
|
+
return this.resolveTableMessage('table.expansion.embed.chartRef.label', 'Gráfico governado');
|
|
38711
|
+
case 'templateRef':
|
|
38712
|
+
return this.resolveTableMessage('table.expansion.embed.templateRef.label', 'Template governado');
|
|
38713
|
+
case 'diagramEmbed':
|
|
38714
|
+
return this.resolveTableMessage('table.expansion.embed.diagramEmbed.label', 'Diagrama governado');
|
|
38715
|
+
default:
|
|
38716
|
+
return this.resolveTableMessage('table.expansion.embed.empty', 'Nenhum conteúdo de embed disponível.');
|
|
38717
|
+
}
|
|
38718
|
+
}
|
|
38719
|
+
getExpansionDetailEmbedReference(node) {
|
|
38720
|
+
const candidates = [
|
|
38721
|
+
node?.schemaId,
|
|
38722
|
+
node?.templateId,
|
|
38723
|
+
node?.tableId,
|
|
38724
|
+
node?.chartId,
|
|
38725
|
+
node?.formId,
|
|
38726
|
+
node?.id,
|
|
38727
|
+
];
|
|
38728
|
+
for (const candidate of candidates) {
|
|
38729
|
+
const normalized = String(candidate ?? '').trim();
|
|
38730
|
+
if (normalized) {
|
|
38731
|
+
return normalized;
|
|
38732
|
+
}
|
|
38733
|
+
}
|
|
38734
|
+
return null;
|
|
38735
|
+
}
|
|
38736
|
+
getExpansionDetailDiagramProvider(node) {
|
|
38737
|
+
if (this.getExpansionDetailNodeType(node) !== 'diagramEmbed') {
|
|
38738
|
+
return null;
|
|
38739
|
+
}
|
|
38740
|
+
const normalized = String(node?.provider || '').trim();
|
|
38741
|
+
return normalized || null;
|
|
38742
|
+
}
|
|
38743
|
+
getExpansionDetailEmbedPresetLabel(node) {
|
|
38744
|
+
const presetRef = node?.presetRef;
|
|
38745
|
+
if (!presetRef || typeof presetRef !== 'object') {
|
|
38746
|
+
return null;
|
|
38747
|
+
}
|
|
38748
|
+
const namespace = String(presetRef.namespace || '').trim();
|
|
38749
|
+
const presetId = String(presetRef.presetId || '').trim();
|
|
38750
|
+
const version = String(presetRef.version || '').trim();
|
|
38751
|
+
if (!namespace || !presetId) {
|
|
38752
|
+
return null;
|
|
38753
|
+
}
|
|
38754
|
+
return version ? `${namespace}/${presetId}@${version}` : `${namespace}/${presetId}`;
|
|
38755
|
+
}
|
|
38756
|
+
getExpansionDetailEmbedInputsSummary(node) {
|
|
38757
|
+
const inputs = node?.inputs;
|
|
38758
|
+
if (!inputs || typeof inputs !== 'object' || Array.isArray(inputs)) {
|
|
38759
|
+
return null;
|
|
38760
|
+
}
|
|
38761
|
+
const keys = Object.keys(inputs).filter((key) => String(key || '').trim().length > 0);
|
|
38762
|
+
if (!keys.length) {
|
|
38763
|
+
return null;
|
|
38764
|
+
}
|
|
38765
|
+
if (keys.length <= 3) {
|
|
38766
|
+
return keys.join(', ');
|
|
38767
|
+
}
|
|
38768
|
+
return `${keys.slice(0, 3).join(', ')} +${keys.length - 3}`;
|
|
38769
|
+
}
|
|
38770
|
+
getExpansionDetailTextRichContentNodes(text, className) {
|
|
38771
|
+
const normalized = String(text ?? '').trim();
|
|
38772
|
+
if (!normalized) {
|
|
38773
|
+
return [];
|
|
38774
|
+
}
|
|
38775
|
+
return [
|
|
38776
|
+
{
|
|
38777
|
+
type: 'text',
|
|
38778
|
+
text: normalized,
|
|
38779
|
+
...(className ? { className } : {}),
|
|
38780
|
+
},
|
|
38781
|
+
];
|
|
38782
|
+
}
|
|
38783
|
+
getTableChromeTextRichContentNodes(text, className) {
|
|
38784
|
+
const normalized = String(text ?? '').trim();
|
|
38785
|
+
if (!normalized) {
|
|
38786
|
+
return [];
|
|
38787
|
+
}
|
|
38788
|
+
return [
|
|
38789
|
+
{
|
|
38790
|
+
type: 'text',
|
|
38791
|
+
text: normalized,
|
|
38792
|
+
...(className ? { className } : {}),
|
|
38793
|
+
},
|
|
38794
|
+
];
|
|
38795
|
+
}
|
|
38796
|
+
getRowActionRichContentNodes(action) {
|
|
38797
|
+
const label = String(action?.label || this.getActionId(action) || '').trim();
|
|
38798
|
+
const textNode = {
|
|
38799
|
+
type: 'text',
|
|
38800
|
+
text: label || this.getActionId(action),
|
|
38801
|
+
className: 'praxis-row-action__label',
|
|
38802
|
+
};
|
|
38803
|
+
const icon = String(action?.icon || '').trim();
|
|
38804
|
+
if (!icon) {
|
|
38805
|
+
return [textNode];
|
|
38806
|
+
}
|
|
38807
|
+
const iconNode = {
|
|
38808
|
+
type: 'icon',
|
|
38809
|
+
icon,
|
|
38810
|
+
ariaLabel: label || this.getActionId(action),
|
|
38811
|
+
className: 'praxis-row-action__icon',
|
|
38812
|
+
};
|
|
38813
|
+
return [
|
|
38814
|
+
{
|
|
38815
|
+
type: 'compose',
|
|
38816
|
+
direction: 'row',
|
|
38817
|
+
gap: 'sm',
|
|
38818
|
+
items: [iconNode, textNode],
|
|
38819
|
+
},
|
|
38820
|
+
];
|
|
38821
|
+
}
|
|
38822
|
+
getRowActionIconRichContentNodes(action) {
|
|
38823
|
+
const icon = String(action?.icon || '').trim();
|
|
38824
|
+
if (!icon) {
|
|
38825
|
+
return [];
|
|
38826
|
+
}
|
|
38827
|
+
return [
|
|
38828
|
+
{
|
|
38829
|
+
type: 'icon',
|
|
38830
|
+
icon,
|
|
38831
|
+
ariaLabel: String(action?.label || this.getActionId(action) || '').trim() || this.getActionId(action),
|
|
38832
|
+
className: 'praxis-row-action__icon',
|
|
38833
|
+
},
|
|
38834
|
+
];
|
|
38835
|
+
}
|
|
38836
|
+
getExpansionDetailActionRichContentNodes(node) {
|
|
38837
|
+
const labelNode = {
|
|
38838
|
+
type: 'text',
|
|
38839
|
+
text: this.getExpansionDetailActionLabel(node),
|
|
38840
|
+
};
|
|
38841
|
+
const icon = String(node?.icon || '').trim();
|
|
38842
|
+
if (!icon) {
|
|
38843
|
+
return [labelNode];
|
|
38844
|
+
}
|
|
38845
|
+
const iconNode = {
|
|
38846
|
+
type: 'icon',
|
|
38847
|
+
icon,
|
|
38848
|
+
ariaLabel: this.getExpansionDetailActionLabel(node),
|
|
38849
|
+
};
|
|
38850
|
+
return [
|
|
38851
|
+
{
|
|
38852
|
+
type: 'compose',
|
|
38853
|
+
direction: 'row',
|
|
38854
|
+
gap: 'sm',
|
|
38855
|
+
items: [iconNode, labelNode],
|
|
38856
|
+
},
|
|
38857
|
+
];
|
|
38858
|
+
}
|
|
38859
|
+
isExpansionDetailActionBarActionVisible(action, context) {
|
|
38860
|
+
const visibleWhen = action?.visibleWhen;
|
|
38861
|
+
if (!this.hasConditionalExpression(visibleWhen)) {
|
|
38862
|
+
return true;
|
|
38863
|
+
}
|
|
38864
|
+
return this.evaluateExpansionDetailRichListItemCondition(visibleWhen, context, this.resolveRowVisibleWhenFailurePolicy() === 'fail-open');
|
|
38865
|
+
}
|
|
38866
|
+
getExpansionDetailTabButtonRichContentNodes(tab) {
|
|
38867
|
+
const titleNode = {
|
|
38868
|
+
type: 'text',
|
|
38869
|
+
text: this.getExpansionDetailNodeTitle(tab, 'Tab'),
|
|
38870
|
+
className: 'pfx-expansion-detail-tab-btn__title',
|
|
38871
|
+
};
|
|
38872
|
+
const items = [];
|
|
38873
|
+
const icon = String(tab?.icon ?? tab?.tabIcon ?? '').trim();
|
|
38874
|
+
if (icon) {
|
|
38875
|
+
items.push({
|
|
38876
|
+
type: 'icon',
|
|
38877
|
+
icon,
|
|
38878
|
+
ariaLabel: this.getExpansionDetailNodeTitle(tab, 'Tab'),
|
|
38879
|
+
className: 'pfx-expansion-detail-tab-btn__icon',
|
|
38880
|
+
});
|
|
38881
|
+
}
|
|
38882
|
+
items.push(titleNode);
|
|
38883
|
+
const badgeLabel = this.getExpansionDetailTabBadgeLabel(tab);
|
|
38884
|
+
if (badgeLabel) {
|
|
38885
|
+
items.push({
|
|
38886
|
+
type: 'badge',
|
|
38887
|
+
label: badgeLabel,
|
|
38888
|
+
className: 'pfx-expansion-detail-tab-btn__badge',
|
|
38889
|
+
});
|
|
38890
|
+
}
|
|
38891
|
+
if (items.length === 1) {
|
|
38892
|
+
return [titleNode];
|
|
38893
|
+
}
|
|
38894
|
+
return [
|
|
38895
|
+
{
|
|
38896
|
+
type: 'compose',
|
|
38897
|
+
direction: 'row',
|
|
38898
|
+
gap: 'sm',
|
|
38899
|
+
items,
|
|
38900
|
+
},
|
|
38901
|
+
];
|
|
38902
|
+
}
|
|
38903
|
+
getExpansionDetailTabBadgeLabel(tab) {
|
|
38904
|
+
const rawBadge = tab?.badge
|
|
38905
|
+
?? tab?.badgeLabel
|
|
38906
|
+
?? tab?.badgeText
|
|
38907
|
+
?? tab?.count
|
|
38908
|
+
?? null;
|
|
38909
|
+
if (rawBadge === null || rawBadge === undefined) {
|
|
38910
|
+
return null;
|
|
38911
|
+
}
|
|
38912
|
+
if (typeof rawBadge === 'object' && !Array.isArray(rawBadge)) {
|
|
38913
|
+
const record = rawBadge;
|
|
38914
|
+
const nested = record['label']
|
|
38915
|
+
?? record['text']
|
|
38916
|
+
?? record['value']
|
|
38917
|
+
?? null;
|
|
38918
|
+
const normalizedNested = String(nested ?? '').trim();
|
|
38919
|
+
return normalizedNested || null;
|
|
38920
|
+
}
|
|
38921
|
+
const normalized = String(rawBadge).trim();
|
|
38922
|
+
return normalized || null;
|
|
38923
|
+
}
|
|
38924
|
+
isExpansionDetailActionDisabled(node) {
|
|
38925
|
+
return node?.disabled === true;
|
|
38926
|
+
}
|
|
38927
|
+
onExpansionDetailAction(node, row, event) {
|
|
38928
|
+
const actionId = this.getExpansionDetailActionId(node);
|
|
38929
|
+
if (!actionId) {
|
|
38930
|
+
event.stopPropagation();
|
|
38931
|
+
return;
|
|
38932
|
+
}
|
|
38933
|
+
const runtimeOptions = this.resolveRowActionRuntimeOptions(this.buildRendererActionRuntimeOptions(node, row), node);
|
|
38934
|
+
this.onRowAction(actionId, row, event, runtimeOptions);
|
|
38935
|
+
}
|
|
37822
38936
|
formatExpansionDetailListEntry(entry) {
|
|
37823
38937
|
if (entry === null || entry === undefined) {
|
|
37824
38938
|
return '';
|
|
@@ -37871,12 +38985,207 @@ class PraxisTable {
|
|
|
37871
38985
|
}
|
|
37872
38986
|
return null;
|
|
37873
38987
|
}
|
|
38988
|
+
getExpansionDetailObjectListBadgeLabel(entry) {
|
|
38989
|
+
const preferredKeys = ['status', 'state', 'tag', 'badge'];
|
|
38990
|
+
for (const key of preferredKeys) {
|
|
38991
|
+
const raw = entry[key];
|
|
38992
|
+
if (typeof raw === 'string'
|
|
38993
|
+
|| typeof raw === 'number'
|
|
38994
|
+
|| typeof raw === 'boolean'
|
|
38995
|
+
|| typeof raw === 'bigint') {
|
|
38996
|
+
const normalized = String(raw).trim();
|
|
38997
|
+
if (normalized)
|
|
38998
|
+
return normalized;
|
|
38999
|
+
}
|
|
39000
|
+
}
|
|
39001
|
+
return null;
|
|
39002
|
+
}
|
|
39003
|
+
evaluateExpansionDetailRichListItemPayload(raw, context, fallback) {
|
|
39004
|
+
if (raw === null || raw === undefined) {
|
|
39005
|
+
return fallback;
|
|
39006
|
+
}
|
|
39007
|
+
const normalized = String(raw).trim();
|
|
39008
|
+
if (!normalized) {
|
|
39009
|
+
return fallback;
|
|
39010
|
+
}
|
|
39011
|
+
const result = this.computedExpressionEvaluator.evaluate(normalized, context);
|
|
39012
|
+
if (result.error) {
|
|
39013
|
+
return fallback;
|
|
39014
|
+
}
|
|
39015
|
+
if (result.value === undefined && !normalized.startsWith('=')) {
|
|
39016
|
+
const nested = this.getNestedPropertyValue(context, normalized);
|
|
39017
|
+
return nested === undefined ? fallback : nested;
|
|
39018
|
+
}
|
|
39019
|
+
return result.value;
|
|
39020
|
+
}
|
|
39021
|
+
isExpansionDetailRichListItemActionVisible(action, context) {
|
|
39022
|
+
const visibleWhen = action?.visibleWhen;
|
|
39023
|
+
if (!this.hasConditionalExpression(visibleWhen)) {
|
|
39024
|
+
return true;
|
|
39025
|
+
}
|
|
39026
|
+
return this.evaluateExpansionDetailRichListItemCondition(visibleWhen, context, this.resolveRowVisibleWhenFailurePolicy() === 'fail-open');
|
|
39027
|
+
}
|
|
39028
|
+
evaluateExpansionDetailRichListItemCondition(expression, context, fallbackResult) {
|
|
39029
|
+
if (!this.isJsonLogicExpression(expression)) {
|
|
39030
|
+
return fallbackResult;
|
|
39031
|
+
}
|
|
39032
|
+
try {
|
|
39033
|
+
return this.jsonLogic.matches({
|
|
39034
|
+
condition: expression,
|
|
39035
|
+
data: context,
|
|
39036
|
+
});
|
|
39037
|
+
}
|
|
39038
|
+
catch {
|
|
39039
|
+
return fallbackResult;
|
|
39040
|
+
}
|
|
39041
|
+
}
|
|
37874
39042
|
getExpansionDetailRichText(node) {
|
|
37875
39043
|
const html = String(node?.html ?? node?.text ?? '').trim();
|
|
37876
39044
|
if (!html)
|
|
37877
39045
|
return '';
|
|
37878
39046
|
return this.sanitizeStrictHtml(html);
|
|
37879
39047
|
}
|
|
39048
|
+
getExpansionDetailRichContentContext(row, index) {
|
|
39049
|
+
return {
|
|
39050
|
+
row,
|
|
39051
|
+
computed: {
|
|
39052
|
+
rowId: this.getRowId(row),
|
|
39053
|
+
rowIndex: index,
|
|
39054
|
+
},
|
|
39055
|
+
detail: this.buildExpansionContextRecord(row, index),
|
|
39056
|
+
meta: (this.config?.meta || {}),
|
|
39057
|
+
};
|
|
39058
|
+
}
|
|
39059
|
+
getExpansionDetailRichContentNodes(node, row, index) {
|
|
39060
|
+
const mapped = this.mapExpansionDetailNodeToRichContent(node, row, index);
|
|
39061
|
+
return mapped ? [mapped] : null;
|
|
39062
|
+
}
|
|
39063
|
+
getExpansionDetailTabRichContentNodes(tab, row, index) {
|
|
39064
|
+
const mappedChildren = this.getExpansionDetailNodeChildren(tab)
|
|
39065
|
+
.map((childNode) => this.mapExpansionDetailNodeToRichContent(childNode, row, index));
|
|
39066
|
+
if (mappedChildren.some((childNode) => childNode == null)) {
|
|
39067
|
+
return null;
|
|
39068
|
+
}
|
|
39069
|
+
return mappedChildren;
|
|
39070
|
+
}
|
|
39071
|
+
mapExpansionDetailNodeToRichContent(node, row, index) {
|
|
39072
|
+
const type = this.getExpansionDetailNodeType(node);
|
|
39073
|
+
if (type === 'mediaBlock') {
|
|
39074
|
+
return this.mapExpansionDetailMediaBlockNodeToRichContent(node);
|
|
39075
|
+
}
|
|
39076
|
+
if (type === 'timeline') {
|
|
39077
|
+
return this.mapExpansionDetailTimelineNodeToRichContent(node, row);
|
|
39078
|
+
}
|
|
39079
|
+
if (type === 'card') {
|
|
39080
|
+
return this.mapExpansionDetailCardNodeToRichContent(node, row, index);
|
|
39081
|
+
}
|
|
39082
|
+
if (type === 'layout' || type === 'stack') {
|
|
39083
|
+
return this.mapExpansionDetailStackNodeToRichContent(node, row, index);
|
|
39084
|
+
}
|
|
39085
|
+
if (type === 'value') {
|
|
39086
|
+
return this.mapExpansionDetailValueNodeToRichContent(node, row);
|
|
39087
|
+
}
|
|
39088
|
+
return null;
|
|
39089
|
+
}
|
|
39090
|
+
mapExpansionDetailMediaBlockNodeToRichContent(node) {
|
|
39091
|
+
const avatar = this.normalizeExpansionDetailMediaBlockAvatar(node?.avatar);
|
|
39092
|
+
const title = this.normalizeExpansionDetailMediaBlockText(node?.title);
|
|
39093
|
+
const subtitle = this.normalizeExpansionDetailMediaBlockText(node?.subtitle);
|
|
39094
|
+
const meta = this.normalizeExpansionDetailMediaBlockMeta(node?.meta);
|
|
39095
|
+
const trailing = this.normalizeExpansionDetailMediaBlockTrailing(node?.trailing);
|
|
39096
|
+
if (!avatar && !title && !subtitle && !meta && trailing.length === 0) {
|
|
39097
|
+
return null;
|
|
39098
|
+
}
|
|
39099
|
+
return {
|
|
39100
|
+
type: 'mediaBlock',
|
|
39101
|
+
id: node?.id ? String(node.id) : undefined,
|
|
39102
|
+
className: 'pfx-expansion-node pfx-expansion-node-media-block',
|
|
39103
|
+
avatar: avatar ?? undefined,
|
|
39104
|
+
title: title ?? undefined,
|
|
39105
|
+
subtitle: subtitle ?? undefined,
|
|
39106
|
+
meta: meta ?? undefined,
|
|
39107
|
+
trailing: trailing.length ? trailing : undefined,
|
|
39108
|
+
};
|
|
39109
|
+
}
|
|
39110
|
+
mapExpansionDetailCardNodeToRichContent(node, row, index) {
|
|
39111
|
+
const mappedChildren = this.getExpansionDetailNodeChildren(node)
|
|
39112
|
+
.map((childNode) => this.mapExpansionDetailNodeToRichContent(childNode, row, index));
|
|
39113
|
+
const content = mappedChildren
|
|
39114
|
+
.filter((childNode) => childNode != null && childNode.type !== 'card' && childNode.type !== 'preset');
|
|
39115
|
+
if (content.length !== mappedChildren.length) {
|
|
39116
|
+
return null;
|
|
39117
|
+
}
|
|
39118
|
+
return {
|
|
39119
|
+
type: 'card',
|
|
39120
|
+
id: node?.id ? String(node.id) : undefined,
|
|
39121
|
+
className: 'pfx-expansion-node pfx-expansion-node-card',
|
|
39122
|
+
title: this.getExpansionDetailNodeTitle(node, 'Card'),
|
|
39123
|
+
subtitle: node?.subtitle ? String(node.subtitle) : undefined,
|
|
39124
|
+
content,
|
|
39125
|
+
};
|
|
39126
|
+
}
|
|
39127
|
+
mapExpansionDetailStackNodeToRichContent(node, row, index) {
|
|
39128
|
+
const mappedChildren = this.getExpansionDetailNodeChildren(node)
|
|
39129
|
+
.map((childNode) => this.mapExpansionDetailNodeToRichContent(childNode, row, index));
|
|
39130
|
+
const items = [];
|
|
39131
|
+
for (const childNode of mappedChildren) {
|
|
39132
|
+
if (!childNode
|
|
39133
|
+
|| childNode.type === 'card'
|
|
39134
|
+
|| childNode.type === 'preset'
|
|
39135
|
+
|| childNode.type === 'mediaBlock'
|
|
39136
|
+
|| childNode.type === 'timeline') {
|
|
39137
|
+
return null;
|
|
39138
|
+
}
|
|
39139
|
+
if (childNode.type === 'compose') {
|
|
39140
|
+
items.push(...childNode.items);
|
|
39141
|
+
continue;
|
|
39142
|
+
}
|
|
39143
|
+
if (!this.isExpansionDetailComposeItemNode(childNode)) {
|
|
39144
|
+
return null;
|
|
39145
|
+
}
|
|
39146
|
+
items.push(childNode);
|
|
39147
|
+
}
|
|
39148
|
+
if (!items.length) {
|
|
39149
|
+
return null;
|
|
39150
|
+
}
|
|
39151
|
+
return {
|
|
39152
|
+
type: 'compose',
|
|
39153
|
+
id: node?.id ? String(node.id) : undefined,
|
|
39154
|
+
className: 'pfx-expansion-node pfx-expansion-node-stack',
|
|
39155
|
+
direction: 'column',
|
|
39156
|
+
gap: 'sm',
|
|
39157
|
+
items,
|
|
39158
|
+
};
|
|
39159
|
+
}
|
|
39160
|
+
mapExpansionDetailValueNodeToRichContent(node, row) {
|
|
39161
|
+
const labelNode = {
|
|
39162
|
+
type: 'text',
|
|
39163
|
+
className: 'pfx-expansion-node-value__label',
|
|
39164
|
+
text: this.getExpansionDetailNodeTitle(node, 'Valor'),
|
|
39165
|
+
};
|
|
39166
|
+
const valueNode = {
|
|
39167
|
+
type: 'text',
|
|
39168
|
+
className: 'pfx-expansion-node-value__content',
|
|
39169
|
+
text: this.getExpansionDetailValue(row, node),
|
|
39170
|
+
};
|
|
39171
|
+
return {
|
|
39172
|
+
type: 'compose',
|
|
39173
|
+
className: 'pfx-expansion-node pfx-expansion-node-value',
|
|
39174
|
+
direction: 'column',
|
|
39175
|
+
gap: 'xs',
|
|
39176
|
+
items: [labelNode, valueNode],
|
|
39177
|
+
};
|
|
39178
|
+
}
|
|
39179
|
+
mapExpansionDetailTimelineNodeToRichContent(node, row) {
|
|
39180
|
+
const timelineNode = this.buildExpansionDetailTimelineRichNode(row, node) || {
|
|
39181
|
+
type: 'timeline',
|
|
39182
|
+
items: [],
|
|
39183
|
+
};
|
|
39184
|
+
return {
|
|
39185
|
+
...timelineNode,
|
|
39186
|
+
className: 'pfx-expansion-node pfx-expansion-node-timeline',
|
|
39187
|
+
};
|
|
39188
|
+
}
|
|
37880
39189
|
getExpansionDetailTabId(row, index, tab, tabIndex) {
|
|
37881
39190
|
const rowKey = this.resolveRowExpansionKey(row, index) || `index-${Math.max(0, index)}`;
|
|
37882
39191
|
const rawTabId = String(tab?.id || `tab-${tabIndex + 1}`).trim();
|
|
@@ -38442,6 +39751,49 @@ class PraxisTable {
|
|
|
38442
39751
|
};
|
|
38443
39752
|
}
|
|
38444
39753
|
const clone = { ...node, type };
|
|
39754
|
+
if (type === 'mediaBlock') {
|
|
39755
|
+
const sanitizedMediaBlock = this.sanitizeExpansionDetailMediaBlockNode(clone, fallbackNodePolicy, path);
|
|
39756
|
+
if (!sanitizedMediaBlock.ok) {
|
|
39757
|
+
return {
|
|
39758
|
+
ok: false,
|
|
39759
|
+
node: null,
|
|
39760
|
+
message: sanitizedMediaBlock.message,
|
|
39761
|
+
};
|
|
39762
|
+
}
|
|
39763
|
+
return {
|
|
39764
|
+
ok: true,
|
|
39765
|
+
node: sanitizedMediaBlock.node,
|
|
39766
|
+
message: null,
|
|
39767
|
+
};
|
|
39768
|
+
}
|
|
39769
|
+
if (type === 'cardGrid') {
|
|
39770
|
+
const sanitizedCards = this.sanitizeExpansionDetailCardGridCards(clone.cards, fallbackNodePolicy, `${path}.cards`);
|
|
39771
|
+
if (!sanitizedCards.ok) {
|
|
39772
|
+
return {
|
|
39773
|
+
ok: false,
|
|
39774
|
+
node: null,
|
|
39775
|
+
message: sanitizedCards.message,
|
|
39776
|
+
};
|
|
39777
|
+
}
|
|
39778
|
+
clone.cards = sanitizedCards.cards;
|
|
39779
|
+
}
|
|
39780
|
+
if (type === 'diagramEmbed') {
|
|
39781
|
+
const provider = String(clone.provider || '').trim();
|
|
39782
|
+
if (provider !== 'mermaid' && provider !== 'bpmn' && provider !== 'custom') {
|
|
39783
|
+
if (fallbackNodePolicy === 'renderPlaceholder') {
|
|
39784
|
+
return {
|
|
39785
|
+
ok: true,
|
|
39786
|
+
node: this.buildExpansionBlockedPlaceholderNode(`provider inválido para diagramEmbed`, path),
|
|
39787
|
+
message: null,
|
|
39788
|
+
};
|
|
39789
|
+
}
|
|
39790
|
+
return {
|
|
39791
|
+
ok: false,
|
|
39792
|
+
node: null,
|
|
39793
|
+
message: `provider inválido para diagramEmbed em ${path}.`,
|
|
39794
|
+
};
|
|
39795
|
+
}
|
|
39796
|
+
}
|
|
38445
39797
|
const childKeys = ['content', 'items'];
|
|
38446
39798
|
for (const childKey of childKeys) {
|
|
38447
39799
|
const rawChildren = clone[childKey];
|
|
@@ -38459,6 +39811,91 @@ class PraxisTable {
|
|
|
38459
39811
|
}
|
|
38460
39812
|
return { ok: true, node: clone, message: null };
|
|
38461
39813
|
}
|
|
39814
|
+
sanitizeExpansionDetailMediaBlockNode(candidate, fallbackNodePolicy, path) {
|
|
39815
|
+
const avatar = this.normalizeExpansionDetailMediaBlockAvatar(candidate?.avatar);
|
|
39816
|
+
const title = this.normalizeExpansionDetailMediaBlockText(candidate?.title);
|
|
39817
|
+
const subtitle = this.normalizeExpansionDetailMediaBlockText(candidate?.subtitle);
|
|
39818
|
+
const meta = this.normalizeExpansionDetailMediaBlockMeta(candidate?.meta);
|
|
39819
|
+
const trailing = this.normalizeExpansionDetailMediaBlockTrailing(candidate?.trailing);
|
|
39820
|
+
if (!avatar && !title && !subtitle && !meta && trailing.length === 0) {
|
|
39821
|
+
if (fallbackNodePolicy === 'renderPlaceholder') {
|
|
39822
|
+
return {
|
|
39823
|
+
ok: true,
|
|
39824
|
+
node: {
|
|
39825
|
+
type: 'mediaBlock',
|
|
39826
|
+
title: { type: 'text', text: 'Node bloqueado' },
|
|
39827
|
+
subtitle: { type: 'text', text: `mediaBlock inválido (${path})` },
|
|
39828
|
+
},
|
|
39829
|
+
message: null,
|
|
39830
|
+
};
|
|
39831
|
+
}
|
|
39832
|
+
return { ok: false, node: null, message: `mediaBlock inválido em ${path}.` };
|
|
39833
|
+
}
|
|
39834
|
+
return {
|
|
39835
|
+
ok: true,
|
|
39836
|
+
node: {
|
|
39837
|
+
...candidate,
|
|
39838
|
+
type: 'mediaBlock',
|
|
39839
|
+
avatar: avatar ?? undefined,
|
|
39840
|
+
title: title ?? undefined,
|
|
39841
|
+
subtitle: subtitle ?? undefined,
|
|
39842
|
+
meta: meta ?? undefined,
|
|
39843
|
+
trailing: trailing.length ? trailing : undefined,
|
|
39844
|
+
},
|
|
39845
|
+
message: null,
|
|
39846
|
+
};
|
|
39847
|
+
}
|
|
39848
|
+
sanitizeExpansionDetailCardGridCards(cards, fallbackNodePolicy, path) {
|
|
39849
|
+
if (!Array.isArray(cards)) {
|
|
39850
|
+
if (fallbackNodePolicy === 'renderPlaceholder') {
|
|
39851
|
+
return {
|
|
39852
|
+
ok: true,
|
|
39853
|
+
cards: [
|
|
39854
|
+
{
|
|
39855
|
+
title: 'Node bloqueado',
|
|
39856
|
+
subtitle: `cards inválidos (${path})`,
|
|
39857
|
+
content: [{ type: 'text', text: 'Node bloqueado' }],
|
|
39858
|
+
},
|
|
39859
|
+
],
|
|
39860
|
+
message: null,
|
|
39861
|
+
};
|
|
39862
|
+
}
|
|
39863
|
+
return { ok: false, cards: [], message: `cards inválidos em ${path}.` };
|
|
39864
|
+
}
|
|
39865
|
+
const out = [];
|
|
39866
|
+
for (let i = 0; i < cards.length; i += 1) {
|
|
39867
|
+
const candidate = cards[i];
|
|
39868
|
+
if (!candidate || typeof candidate !== 'object') {
|
|
39869
|
+
if (fallbackNodePolicy === 'renderPlaceholder') {
|
|
39870
|
+
out.push({
|
|
39871
|
+
title: 'Node bloqueado',
|
|
39872
|
+
subtitle: `card inválido (${path}[${i}])`,
|
|
39873
|
+
content: [{ type: 'text', text: 'Node bloqueado' }],
|
|
39874
|
+
});
|
|
39875
|
+
continue;
|
|
39876
|
+
}
|
|
39877
|
+
return { ok: false, cards: [], message: `card inválido em ${path}[${i}].` };
|
|
39878
|
+
}
|
|
39879
|
+
const sanitizedContent = this.normalizeExpansionDetailCardGridCardContent(candidate.content);
|
|
39880
|
+
if (!sanitizedContent.length) {
|
|
39881
|
+
if (fallbackNodePolicy === 'renderPlaceholder') {
|
|
39882
|
+
out.push({
|
|
39883
|
+
id: candidate.id,
|
|
39884
|
+
title: candidate.title || 'Node bloqueado',
|
|
39885
|
+
subtitle: `content inválido (${path}[${i}].content)`,
|
|
39886
|
+
content: [{ type: 'text', text: 'Node bloqueado' }],
|
|
39887
|
+
});
|
|
39888
|
+
continue;
|
|
39889
|
+
}
|
|
39890
|
+
return { ok: false, cards: [], message: `content inválido em ${path}[${i}].content.` };
|
|
39891
|
+
}
|
|
39892
|
+
out.push({
|
|
39893
|
+
...candidate,
|
|
39894
|
+
content: sanitizedContent,
|
|
39895
|
+
});
|
|
39896
|
+
}
|
|
39897
|
+
return { ok: true, cards: out, message: null };
|
|
39898
|
+
}
|
|
38462
39899
|
buildExpansionBlockedPlaceholderNode(reason, path) {
|
|
38463
39900
|
return {
|
|
38464
39901
|
type: 'card',
|
|
@@ -38652,12 +40089,9 @@ class PraxisTable {
|
|
|
38652
40089
|
items.push({
|
|
38653
40090
|
type: 'card',
|
|
38654
40091
|
title: this.getExpansionHypermediaMessage('table.expansion.hypermedia.actions.title', this.isEnglishLocale() ? 'Workflow actions' : 'Ações de workflow'),
|
|
38655
|
-
content:
|
|
38656
|
-
type: 'value',
|
|
38657
|
-
title: item.title,
|
|
38658
|
-
value: item.value,
|
|
38659
|
-
})),
|
|
40092
|
+
content: [],
|
|
38660
40093
|
});
|
|
40094
|
+
items.push(...workflowActionItems);
|
|
38661
40095
|
}
|
|
38662
40096
|
if (!items.length) {
|
|
38663
40097
|
return null;
|
|
@@ -38719,10 +40153,15 @@ class PraxisTable {
|
|
|
38719
40153
|
.map((action) => {
|
|
38720
40154
|
const title = action.title || action.id;
|
|
38721
40155
|
return {
|
|
40156
|
+
type: 'action',
|
|
40157
|
+
id: action.id,
|
|
38722
40158
|
title,
|
|
38723
|
-
|
|
40159
|
+
disabled: action.availability?.allowed === false,
|
|
40160
|
+
statusText: action.availability?.allowed === false
|
|
38724
40161
|
? translateResourceAvailabilityReason(this.i18n, action.availability?.reason)
|
|
38725
40162
|
: this.getExpansionHypermediaMessage('table.expansion.hypermedia.actions.status.ready', this.isEnglishLocale() ? 'Ready to use' : 'Pronta para uso'),
|
|
40163
|
+
actionId: action.id,
|
|
40164
|
+
__praxisDiscoveredAction: action,
|
|
38726
40165
|
};
|
|
38727
40166
|
});
|
|
38728
40167
|
}
|
|
@@ -40097,6 +41536,14 @@ class PraxisTable {
|
|
|
40097
41536
|
tableId: this.tableId,
|
|
40098
41537
|
config: this.config,
|
|
40099
41538
|
});
|
|
41539
|
+
if (this.crudContext && typeof this.crudContext.openAuthoring === 'function') {
|
|
41540
|
+
this.debugLog('[PraxisTable] Delegating settings entrypoint to CRUD authoring shell', {
|
|
41541
|
+
tableId: this.tableId,
|
|
41542
|
+
componentKeyId: this.componentKeyId(),
|
|
41543
|
+
});
|
|
41544
|
+
this.crudContext.openAuthoring();
|
|
41545
|
+
return;
|
|
41546
|
+
}
|
|
40100
41547
|
const configCopy = JSON.parse(JSON.stringify(this.config));
|
|
40101
41548
|
const componentKeyId = this.componentKeyId();
|
|
40102
41549
|
const panelInputs = {
|
|
@@ -41411,7 +42858,7 @@ class PraxisTable {
|
|
|
41411
42858
|
const existing = this.config?.columns ?? [];
|
|
41412
42859
|
if (existing.length === 0) {
|
|
41413
42860
|
this.config.columns = fields
|
|
41414
|
-
.filter((f) => !f.tableHidden)
|
|
42861
|
+
.filter((f) => !f.tableHidden && !f.hidden)
|
|
41415
42862
|
.map((f) => this.convertFieldToColumn(f));
|
|
41416
42863
|
}
|
|
41417
42864
|
const mountCtx = this.buildLoadingContext('mount', 'Montando colunas…', false);
|
|
@@ -41466,7 +42913,7 @@ class PraxisTable {
|
|
|
41466
42913
|
order: field.order,
|
|
41467
42914
|
width: field.width ?? undefined,
|
|
41468
42915
|
sortable: field.sortable,
|
|
41469
|
-
visible: field.tableHidden ? false : true,
|
|
42916
|
+
visible: field.tableHidden || field.hidden ? false : true,
|
|
41470
42917
|
type: apiType,
|
|
41471
42918
|
_originalApiType: apiType,
|
|
41472
42919
|
_isApiField: true,
|
|
@@ -43353,6 +44800,19 @@ class PraxisTable {
|
|
|
43353
44800
|
getIconAriaLabel(_row, column) {
|
|
43354
44801
|
return this.getEffectiveRenderer(_row, column)?.icon?.ariaLabel || null;
|
|
43355
44802
|
}
|
|
44803
|
+
getIconRichContentNodes(row, column) {
|
|
44804
|
+
const icon = this.getIconName(row, column);
|
|
44805
|
+
if (!icon)
|
|
44806
|
+
return [];
|
|
44807
|
+
return [
|
|
44808
|
+
{
|
|
44809
|
+
type: 'icon',
|
|
44810
|
+
icon,
|
|
44811
|
+
ariaLabel: this.getIconAriaLabel(row, column) || icon,
|
|
44812
|
+
className: 'pfx-icon-renderer__icon',
|
|
44813
|
+
},
|
|
44814
|
+
];
|
|
44815
|
+
}
|
|
43356
44816
|
/**
|
|
43357
44817
|
* Lightweight, controlled evaluator for string/number expressions using row context.
|
|
43358
44818
|
* Accepts values like '= row.status === "OK" ? "primary" : "warn"'.
|
|
@@ -43812,6 +45272,31 @@ class PraxisTable {
|
|
|
43812
45272
|
return null;
|
|
43813
45273
|
return (cfg.altField ? this.getNestedPropertyValue(row, cfg.altField) : cfg.alt) || null;
|
|
43814
45274
|
}
|
|
45275
|
+
getImageRichContentNodes(row, column) {
|
|
45276
|
+
const shape = this.getImageShape(row, column);
|
|
45277
|
+
const width = this.getImageWidth(row, column);
|
|
45278
|
+
const height = this.getImageHeight(row, column);
|
|
45279
|
+
const fit = this.getImageFit(row, column);
|
|
45280
|
+
const style = {};
|
|
45281
|
+
if (width != null)
|
|
45282
|
+
style['width'] = `${width}px`;
|
|
45283
|
+
if (height != null)
|
|
45284
|
+
style['height'] = `${height}px`;
|
|
45285
|
+
if (fit)
|
|
45286
|
+
style['objectFit'] = fit;
|
|
45287
|
+
const node = {
|
|
45288
|
+
type: 'image',
|
|
45289
|
+
src: this.getImageSrc(row, column) ?? undefined,
|
|
45290
|
+
alt: this.getImageAlt(row, column) ?? '',
|
|
45291
|
+
className: shape === 'rounded'
|
|
45292
|
+
? 'shape-rounded'
|
|
45293
|
+
: shape === 'circle'
|
|
45294
|
+
? 'shape-circle'
|
|
45295
|
+
: undefined,
|
|
45296
|
+
style,
|
|
45297
|
+
};
|
|
45298
|
+
return [node];
|
|
45299
|
+
}
|
|
43815
45300
|
getImageWidth(row, column) {
|
|
43816
45301
|
if (this.isStrictCspStyleModeEnabled())
|
|
43817
45302
|
return null;
|
|
@@ -43859,6 +45344,26 @@ class PraxisTable {
|
|
|
43859
45344
|
out.push(`pfx-badge--filled-${color || 'primary'}`);
|
|
43860
45345
|
return out;
|
|
43861
45346
|
}
|
|
45347
|
+
getBadgeRichContentNodes(row, column) {
|
|
45348
|
+
const nodes = [];
|
|
45349
|
+
const icon = this.getBadgeIcon(row, column);
|
|
45350
|
+
const text = this.getBadgeText(row, column);
|
|
45351
|
+
if (icon) {
|
|
45352
|
+
nodes.push({
|
|
45353
|
+
type: 'icon',
|
|
45354
|
+
icon,
|
|
45355
|
+
className: 'pfx-badge-icon',
|
|
45356
|
+
});
|
|
45357
|
+
}
|
|
45358
|
+
if (text) {
|
|
45359
|
+
nodes.push({
|
|
45360
|
+
type: 'text',
|
|
45361
|
+
text,
|
|
45362
|
+
className: 'pfx-badge-text',
|
|
45363
|
+
});
|
|
45364
|
+
}
|
|
45365
|
+
return nodes;
|
|
45366
|
+
}
|
|
43862
45367
|
// Resolve renderer type per row (supports conditional typeExpr)
|
|
43863
45368
|
getEffectiveRendererType(row, column) {
|
|
43864
45369
|
const eff = this.getEffectiveRenderer(row, column);
|
|
@@ -44115,6 +45620,39 @@ class PraxisTable {
|
|
|
44115
45620
|
const text = cfg?.textField ? this.getNestedPropertyValue(row, cfg.textField) : cfg?.text;
|
|
44116
45621
|
return (text != null ? String(text) : String(this.getCellValue(row, column) ?? '')) || '';
|
|
44117
45622
|
}
|
|
45623
|
+
getLinkRichContentNodes(row, column) {
|
|
45624
|
+
const text = this.getLinkText(row, column);
|
|
45625
|
+
if (!text)
|
|
45626
|
+
return [];
|
|
45627
|
+
return [
|
|
45628
|
+
{
|
|
45629
|
+
type: 'text',
|
|
45630
|
+
text,
|
|
45631
|
+
className: 'pfx-link-text',
|
|
45632
|
+
},
|
|
45633
|
+
];
|
|
45634
|
+
}
|
|
45635
|
+
getMenuItemRichContentNodes(item) {
|
|
45636
|
+
const nodes = [];
|
|
45637
|
+
const icon = String(item?.icon || '').trim();
|
|
45638
|
+
const label = String(item?.label || item?.id || '').trim();
|
|
45639
|
+
if (icon) {
|
|
45640
|
+
nodes.push({
|
|
45641
|
+
type: 'icon',
|
|
45642
|
+
icon,
|
|
45643
|
+
className: 'pfx-menu-item__icon',
|
|
45644
|
+
ariaLabel: label || icon,
|
|
45645
|
+
});
|
|
45646
|
+
}
|
|
45647
|
+
if (label) {
|
|
45648
|
+
nodes.push({
|
|
45649
|
+
type: 'text',
|
|
45650
|
+
text: label,
|
|
45651
|
+
className: 'pfx-menu-item__label',
|
|
45652
|
+
});
|
|
45653
|
+
}
|
|
45654
|
+
return nodes;
|
|
45655
|
+
}
|
|
44118
45656
|
getLinkTarget(row, column) {
|
|
44119
45657
|
const t = this.getEffectiveRenderer(row, column)?.link?.target || null;
|
|
44120
45658
|
return t === '_blank' || t === '_self' || t === '_parent' || t === '_top' ? t : null;
|
|
@@ -44152,6 +45690,26 @@ class PraxisTable {
|
|
|
44152
45690
|
getButtonAriaLabel(row, column) {
|
|
44153
45691
|
return this.getEffectiveRenderer(row, column)?.button?.ariaLabel || this.getButtonLabel(row, column) || null;
|
|
44154
45692
|
}
|
|
45693
|
+
getButtonRichContentNodes(row, column) {
|
|
45694
|
+
const nodes = [];
|
|
45695
|
+
const icon = this.getButtonIcon(row, column);
|
|
45696
|
+
const label = this.getButtonLabel(row, column);
|
|
45697
|
+
if (icon) {
|
|
45698
|
+
nodes.push({
|
|
45699
|
+
type: 'icon',
|
|
45700
|
+
icon,
|
|
45701
|
+
className: 'pfx-button-renderer__icon',
|
|
45702
|
+
});
|
|
45703
|
+
}
|
|
45704
|
+
if (label) {
|
|
45705
|
+
nodes.push({
|
|
45706
|
+
type: 'text',
|
|
45707
|
+
text: label,
|
|
45708
|
+
className: 'pfx-button-renderer__label',
|
|
45709
|
+
});
|
|
45710
|
+
}
|
|
45711
|
+
return nodes;
|
|
45712
|
+
}
|
|
44155
45713
|
evaluateActionPayloadExpr(raw, row) {
|
|
44156
45714
|
if (raw === undefined)
|
|
44157
45715
|
return undefined;
|
|
@@ -44196,6 +45754,26 @@ class PraxisTable {
|
|
|
44196
45754
|
const t = cfg.textField ? this.getNestedPropertyValue(row, cfg.textField) : cfg.text;
|
|
44197
45755
|
return t != null ? String(t) : null;
|
|
44198
45756
|
}
|
|
45757
|
+
getChipRichContentNodes(row, column) {
|
|
45758
|
+
const nodes = [];
|
|
45759
|
+
const icon = this.getChipIcon(row, column);
|
|
45760
|
+
const text = this.getChipText(row, column);
|
|
45761
|
+
if (icon) {
|
|
45762
|
+
nodes.push({
|
|
45763
|
+
type: 'icon',
|
|
45764
|
+
icon,
|
|
45765
|
+
className: 'pfx-chip-icon',
|
|
45766
|
+
});
|
|
45767
|
+
}
|
|
45768
|
+
if (text) {
|
|
45769
|
+
nodes.push({
|
|
45770
|
+
type: 'text',
|
|
45771
|
+
text,
|
|
45772
|
+
className: 'pfx-chip-text',
|
|
45773
|
+
});
|
|
45774
|
+
}
|
|
45775
|
+
return nodes;
|
|
45776
|
+
}
|
|
44199
45777
|
getChipIcon(row, column) {
|
|
44200
45778
|
return this.getEffectiveRenderer(row, column)?.chip?.icon || null;
|
|
44201
45779
|
}
|
|
@@ -44241,6 +45819,24 @@ class PraxisTable {
|
|
|
44241
45819
|
getProgressShowLabel(row, column) {
|
|
44242
45820
|
return !!this.getEffectiveRenderer(row, column)?.progress?.showLabel;
|
|
44243
45821
|
}
|
|
45822
|
+
getProgressRichContentContext(row, column) {
|
|
45823
|
+
const value = this.getProgressValue(row, column);
|
|
45824
|
+
return {
|
|
45825
|
+
value,
|
|
45826
|
+
label: this.getProgressShowLabel(row, column) ? `${value}%` : null,
|
|
45827
|
+
};
|
|
45828
|
+
}
|
|
45829
|
+
getProgressRichContentNodes(row, column) {
|
|
45830
|
+
return [
|
|
45831
|
+
{
|
|
45832
|
+
type: 'progress',
|
|
45833
|
+
valueExpr: 'value',
|
|
45834
|
+
labelExpr: 'label',
|
|
45835
|
+
max: 100,
|
|
45836
|
+
className: 'pfx-progress__node',
|
|
45837
|
+
},
|
|
45838
|
+
];
|
|
45839
|
+
}
|
|
44244
45840
|
// Rating
|
|
44245
45841
|
getRatingValue(row, column) {
|
|
44246
45842
|
const cfg = this.getEffectiveRenderer(row, column)?.rating;
|
|
@@ -44328,6 +45924,20 @@ class PraxisTable {
|
|
|
44328
45924
|
}
|
|
44329
45925
|
return '';
|
|
44330
45926
|
}
|
|
45927
|
+
getAvatarRichContentNodes(row, column) {
|
|
45928
|
+
const imageSrc = this.getAvatarSrc(row, column);
|
|
45929
|
+
const initials = this.getAvatarInitials(row, column);
|
|
45930
|
+
const alt = this.getAvatarAlt(row, column) || undefined;
|
|
45931
|
+
return [
|
|
45932
|
+
{
|
|
45933
|
+
type: 'avatar',
|
|
45934
|
+
imageSrc: imageSrc || undefined,
|
|
45935
|
+
initials: initials || undefined,
|
|
45936
|
+
name: alt,
|
|
45937
|
+
className: 'pfx-avatar',
|
|
45938
|
+
},
|
|
45939
|
+
];
|
|
45940
|
+
}
|
|
44331
45941
|
getAvatarShape(row, column) {
|
|
44332
45942
|
return this.getEffectiveRenderer(row, column)?.avatar?.shape || undefined;
|
|
44333
45943
|
}
|
|
@@ -44364,6 +45974,14 @@ class PraxisTable {
|
|
|
44364
45974
|
getMenuAriaLabel(row, column) {
|
|
44365
45975
|
return this.getEffectiveRenderer(row, column)?.menu?.ariaLabel || null;
|
|
44366
45976
|
}
|
|
45977
|
+
getMenuTriggerRichContentNodes() {
|
|
45978
|
+
const node = {
|
|
45979
|
+
type: 'icon',
|
|
45980
|
+
icon: 'more_vert',
|
|
45981
|
+
className: 'pfx-menu-trigger__icon',
|
|
45982
|
+
};
|
|
45983
|
+
return [node];
|
|
45984
|
+
}
|
|
44367
45985
|
evaluateArrayExpr(raw, row) {
|
|
44368
45986
|
const expr = this.extractExpression(raw, true);
|
|
44369
45987
|
if (!expr)
|
|
@@ -44958,7 +46576,7 @@ class PraxisTable {
|
|
|
44958
46576
|
this.resizeObserver = new ResizeObserver((entries) => {
|
|
44959
46577
|
for (const entry of entries) {
|
|
44960
46578
|
if (entry.target === this.hostRef.nativeElement) {
|
|
44961
|
-
this.
|
|
46579
|
+
this.scheduleResponsiveHorizontalScrollRefresh();
|
|
44962
46580
|
}
|
|
44963
46581
|
}
|
|
44964
46582
|
});
|
|
@@ -45062,6 +46680,26 @@ class PraxisTable {
|
|
|
45062
46680
|
const rowCfg = this.getRowActionsConfig();
|
|
45063
46681
|
return rowCfg?.header?.label ?? rowCfg?.headerLabel;
|
|
45064
46682
|
}
|
|
46683
|
+
getActionsHeaderRichContentNodes() {
|
|
46684
|
+
const nodes = [];
|
|
46685
|
+
const icon = this.getActionsHeaderIcon();
|
|
46686
|
+
const label = this.getActionsHeaderLabel();
|
|
46687
|
+
if (icon) {
|
|
46688
|
+
nodes.push({
|
|
46689
|
+
type: 'icon',
|
|
46690
|
+
icon,
|
|
46691
|
+
className: 'praxis-actions-header__icon',
|
|
46692
|
+
});
|
|
46693
|
+
}
|
|
46694
|
+
if (label) {
|
|
46695
|
+
nodes.push({
|
|
46696
|
+
type: 'text',
|
|
46697
|
+
text: label,
|
|
46698
|
+
className: 'praxis-actions-header__label',
|
|
46699
|
+
});
|
|
46700
|
+
}
|
|
46701
|
+
return nodes;
|
|
46702
|
+
}
|
|
45065
46703
|
getRowActionsDisplay() {
|
|
45066
46704
|
const display = this.getRowActionsConfig()?.display;
|
|
45067
46705
|
return display === 'menu' || display === 'buttons' || display === 'icons'
|
|
@@ -45393,8 +47031,8 @@ class PraxisTable {
|
|
|
45393
47031
|
}
|
|
45394
47032
|
getRowMenuTooltip(row) {
|
|
45395
47033
|
return this.isRowDiscoveryPending(row)
|
|
45396
|
-
?
|
|
45397
|
-
:
|
|
47034
|
+
? translateTableRuntimeText(this.i18n, 'table.chrome.rowActions.loading', 'Carregando ações contextuais')
|
|
47035
|
+
: translateTableRuntimeText(this.i18n, 'table.chrome.rowActions.more', 'Mais ações');
|
|
45398
47036
|
}
|
|
45399
47037
|
getRowMenuButtonColor() {
|
|
45400
47038
|
return this.config.actions?.row?.menuButtonColor ?? undefined;
|
|
@@ -45428,6 +47066,7 @@ class PraxisTable {
|
|
|
45428
47066
|
if (this.resizeObserver) {
|
|
45429
47067
|
this.resizeObserver.disconnect();
|
|
45430
47068
|
}
|
|
47069
|
+
this.cancelResponsiveHorizontalScrollRefresh();
|
|
45431
47070
|
this.removeViewportChangeListeners?.();
|
|
45432
47071
|
this.removeViewportChangeListeners = null;
|
|
45433
47072
|
}
|
|
@@ -45439,7 +47078,7 @@ class PraxisTable {
|
|
|
45439
47078
|
TableDefaultsProvider,
|
|
45440
47079
|
FilterConfigService,
|
|
45441
47080
|
DataFormattingService
|
|
45442
|
-
], queries: [{ propertyName: "toolbar", first: true, predicate: PraxisTableToolbar, descendants: true }, { propertyName: "projectedFilter", first: true, predicate: ["projectedFilter"], descendants: true }], viewQueries: [{ propertyName: "paginator", first: true, predicate: MatPaginator, descendants: true }, { propertyName: "sort", first: true, predicate: MatSort, descendants: true }, { propertyName: "materialTable", first: true, predicate: MatTable, descendants: true }, { propertyName: "internalFilter", first: true, predicate: PraxisFilter, descendants: true }], usesOnChanges: true, ngImport: i0, template: "@if (shouldShowEmptyState()) {\n <praxis-empty-state-card\n icon=\"link\"\n [title]=\"'Conecte a tabela \u00E0 fonte de dados'\"\n [description]=\"'Informe a rota do recurso da API para carregar colunas e dados automaticamente.'\"\n [primaryAction]=\"{ label: 'Conectar \u00E0 fonte de dados', icon: 'bolt', action: openQuickConnect.bind(this) }\"\n ></praxis-empty-state-card>\n}\n\n<!-- Error State with Quick Connect CTA -->\n@if (isRemoteMode() && (schemaError || dataError)) {\n<div class=\"ptable-error\" role=\"alert\" aria-live=\"assertive\">\n <mat-icon color=\"warn\" aria-hidden=\"true\">error</mat-icon>\n <div class=\"ptable-error__content\">\n <div class=\"ptable-error__title\">Erro</div>\n <div>{{ errorMessage || 'Ocorreu um erro ao carregar a tabela.' }}</div>\n </div>\n <button mat-flat-button color=\"primary\" (click)=\"openQuickConnect()\">\n <mat-icon>bolt</mat-icon>\n Conectar a recurso\n </button>\n @if (!schemaError) { <button mat-stroked-button (click)=\"retryData()\">Tentar novamente</button> }\n @if (schemaError) { <button mat-stroked-button (click)=\"reloadSchema()\">Recarregar colunas</button> }\n </div>\n}\n\n<!-- Inline banner for schema change (only in edit mode) -->\n@if (shouldShowOutdatedInline()) {\n<div class=\"ptable-info-banner\" role=\"status\" aria-live=\"polite\">\n <div class=\"text\">O schema do servidor mudou. Reconciliar agora?</div>\n <div class=\"actions\">\n <button mat-stroked-button color=\"primary\" (click)=\"onReconcileRequested()\">\n <mat-icon>sync</mat-icon>\n Reconciliar\n </button>\n <button mat-button (click)=\"onSnoozeOutdated()\">Lembrar depois</button>\n <button mat-button (click)=\"onIgnoreOutdated()\">Ignorar</button>\n </div>\n </div>\n}\n\n@if (shouldRenderDataSurface() && !schemaError && !dataError && toolbarV2) {\n <div class=\"praxis-table-header\" [class.edit-mode]=\"enableCustomization\" [class.stacked]=\"showToolbar\">\n @if (showToolbar && shouldShowToolbarTopPlacement()) {\n <praxis-table-toolbar\n [config]=\"config\"\n [backgroundColor]=\"getToolbarActionsBackgroundColor()\"\n [style.--pfx-filter-h]=\"getToolbarLayoutHeightHostStyle()\"\n [evaluationContext]=\"getToolbarEvaluationContext()\"\n [showActionsGroup]=\"shouldShowToolbarActionsTop()\"\n [showMobileActions]=\"shouldShowToolbarActionsTop()\"\n (toolbarAction)=\"onToolbarAction($event)\"\n (reset)=\"onResetPreferences()\"\n >\n @if (shouldRenderAdvancedFilter()) {\n <praxis-filter\n advancedFilter\n [resourcePath]=\"getAdvancedFilterResourcePath()\"\n [filterId]=\"tableId\"\n [formId]=\"tableId\"\n [persistenceKey]=\"getAdvancedFilterPersistenceKey()\"\n [fieldMetadata]=\"getAdvancedFilterFieldMetadata()\"\n [enableCustomization]=\"enableCustomization\"\n \n [alwaysVisibleFields]=\"config.behavior?.filtering?.advancedFilters?.settings?.alwaysVisibleFields\"\n [alwaysVisibleFieldMetadataOverrides]=\"config.behavior?.filtering?.advancedFilters?.settings?.alwaysVisibleFieldMetadataOverrides ?? {}\"\n [selectedFieldIds]=\"config.behavior?.filtering?.advancedFilters?.settings?.selectedFieldIds ?? []\"\n [allowSaveTags]=\"config.behavior?.filtering?.advancedFilters?.settings?.allowSaveTags\"\n [changeDebounceMs]=\"config.behavior?.filtering?.advancedFilters?.settings?.changeDebounceMs ?? 300\"\n [i18n]=\"getFilterI18n()\"\n [mode]=\"'filter'\"\n [showFilterSettings]=\"enableCustomization\"\n (change)=\"onAdvancedFilterChange($event)\"\n (requestSearch)=\"onAdvancedFilterSubmit($event)\"\n (clear)=\"onAdvancedFilterClear()\"\n ></praxis-filter>\n }\n <ng-content select=\"[advancedFilter]\" />\n <ng-content select=\"[toolbar]\" />\n \n <!-- AI Assistant in Toolbar -->\n @defer (on idle) {\n @if (aiAdapter) {\n <praxis-ai-assistant [adapter]=\"aiAdapter\" end-actions></praxis-ai-assistant>\n }\n }\n\n @if (enableCustomization) {\n <button end-actions mat-icon-button color=\"primary\" data-role=\"table-settings\" data-testid=\"table-settings-trigger\"\n (click)=\"openTableSettings()\" aria-label=\"Configura\u00E7\u00F5es\"\n [matBadge]=\"schemaOutdated ? '!' : ''\"\n [matBadgeHidden]=\"!schemaOutdated\"\n matBadgeColor=\"warn\" matBadgeSize=\"small\" matBadgePosition=\"above after\"\n [matTooltip]=\"schemaOutdated ? 'Schema do servidor mudou \u2014 Reconciliar' : 'Configura\u00E7\u00F5es'\"\n matTooltipPosition=\"below\">\n <mat-icon>settings</mat-icon>\n </button>\n }\n </praxis-table-toolbar>\n }\n @if (!showToolbar && enableCustomization) {\n <div class=\"ptable-header-actions\">\n @defer (on idle) {\n @if (aiAdapter) {\n <praxis-ai-assistant [adapter]=\"aiAdapter\"></praxis-ai-assistant>\n }\n }\n <button mat-icon-button color=\"primary\" data-role=\"table-settings\" data-testid=\"table-settings-trigger\" (click)=\"openTableSettings()\" aria-label=\"Configura\u00E7\u00F5es\"\n [matBadge]=\"schemaOutdated ? '!' : ''\"\n [matBadgeHidden]=\"!schemaOutdated\"\n matBadgeColor=\"warn\" matBadgeSize=\"small\" matBadgePosition=\"above after\"\n [matTooltip]=\"schemaOutdated ? 'Schema do servidor mudou \u2014 Reconciliar' : 'Configura\u00E7\u00F5es'\"\n matTooltipPosition=\"below\">\n <mat-icon>settings</mat-icon>\n </button>\n @if (isRemoteMode()) {\n <button mat-icon-button (click)=\"disconnect()\" aria-label=\"Desconectar\" matTooltip=\"Desconectar da fonte de dados\">\n <mat-icon>link_off</mat-icon>\n </button>\n }\n </div>\n }\n </div>\n} @else {\n @if (shouldRenderDataSurface() && !schemaError && !dataError) {\n @if (showToolbar && shouldShowToolbarTopPlacement()) {\n <praxis-table-toolbar\n [config]=\"config\"\n [backgroundColor]=\"getToolbarActionsBackgroundColor()\"\n [style.--pfx-filter-h]=\"getToolbarLayoutHeightHostStyle()\"\n [evaluationContext]=\"getToolbarEvaluationContext()\"\n [showActionsGroup]=\"shouldShowToolbarActionsTop()\"\n [showMobileActions]=\"shouldShowToolbarActionsTop()\"\n (toolbarAction)=\"onToolbarAction($event)\"\n (reset)=\"onResetPreferences()\"\n >\n @if (shouldRenderAdvancedFilter()) {\n <praxis-filter\n advancedFilter\n [resourcePath]=\"getAdvancedFilterResourcePath()\"\n [filterId]=\"tableId\"\n [formId]=\"tableId\"\n [persistenceKey]=\"getAdvancedFilterPersistenceKey()\"\n [fieldMetadata]=\"getAdvancedFilterFieldMetadata()\"\n [enableCustomization]=\"enableCustomization\"\n \n [alwaysVisibleFields]=\"config.behavior?.filtering?.advancedFilters?.settings?.alwaysVisibleFields\"\n [alwaysVisibleFieldMetadataOverrides]=\"config.behavior?.filtering?.advancedFilters?.settings?.alwaysVisibleFieldMetadataOverrides ?? {}\"\n [selectedFieldIds]=\"config.behavior?.filtering?.advancedFilters?.settings?.selectedFieldIds ?? []\"\n [allowSaveTags]=\"config.behavior?.filtering?.advancedFilters?.settings?.allowSaveTags\"\n [changeDebounceMs]=\"config.behavior?.filtering?.advancedFilters?.settings?.changeDebounceMs ?? 300\"\n [i18n]=\"getFilterI18n()\"\n [mode]=\"'filter'\"\n [showFilterSettings]=\"enableCustomization\"\n (change)=\"onAdvancedFilterChange($event)\"\n (requestSearch)=\"onAdvancedFilterSubmit($event)\"\n (clear)=\"onAdvancedFilterClear()\"\n ></praxis-filter>\n }\n <ng-content select=\"[advancedFilter]\" />\n <ng-content select=\"[toolbar]\" />\n @defer (on idle) {\n @if (aiAdapter) {\n <praxis-ai-assistant [adapter]=\"aiAdapter\" end-actions></praxis-ai-assistant>\n }\n }\n @if (enableCustomization) {\n <button end-actions mat-icon-button color=\"primary\" data-role=\"table-settings\" data-testid=\"table-settings-trigger\"\n (click)=\"openTableSettings()\" aria-label=\"Configura\u00E7\u00F5es\"\n [matBadge]=\"schemaOutdated ? '!' : ''\"\n [matBadgeHidden]=\"!schemaOutdated\"\n matBadgeColor=\"warn\" matBadgeSize=\"small\" matBadgePosition=\"above after\"\n [matTooltip]=\"schemaOutdated ? 'Schema do servidor mudou \u2014 Reconciliar' : 'Configura\u00E7\u00F5es'\"\n matTooltipPosition=\"below\">\n <mat-icon>settings</mat-icon>\n </button>\n }\n </praxis-table-toolbar>\n }\n @if (!showToolbar && enableCustomization) {\n <div class=\"ptable-header-actions\">\n <button mat-icon-button color=\"primary\" data-role=\"table-settings\" data-testid=\"table-settings-trigger\" (click)=\"openTableSettings()\" aria-label=\"Configura\u00E7\u00F5es\"\n [matBadge]=\"schemaOutdated ? '!' : ''\"\n [matBadgeHidden]=\"!schemaOutdated\"\n matBadgeColor=\"warn\" matBadgeSize=\"small\" matBadgePosition=\"above after\"\n [matTooltip]=\"schemaOutdated ? 'Schema do servidor mudou \u2014 Reconciliar' : 'Configura\u00E7\u00F5es'\"\n matTooltipPosition=\"below\">\n <mat-icon>settings</mat-icon>\n </button>\n </div>\n }\n }\n}\n<div class=\"px-scroll-viewport\"\n cdkScrollable\n [class.scroll-auto]=\"horizontalScroll === 'auto'\"\n [class.scroll-wrap]=\"horizontalScroll === 'wrap'\"\n [class.scroll-none]=\"horizontalScroll === 'none'\">\n\n@if (shouldRenderDataSurface() && !schemaError && !dataError) {\n<div class=\"praxis-visually-hidden-status\" role=\"status\" aria-live=\"polite\" aria-atomic=\"true\">\n {{ columnReorderStatusMessage }}\n</div>\n@if (columnReorderVisualStatusMessage) {\n <div class=\"praxis-column-reorder-status\" role=\"note\">\n {{ columnReorderVisualStatusMessage }}\n </div>\n}\n<table\n mat-table\n data-testid=\"table-column-drag-drop-list\"\n [dataSource]=\"dataSource\"\n [multiTemplateDataRows]=\"isRowExpansionRuntimeEnabled()\"\n cdkDropList\n [cdkDropListDisabled]=\"!isColumnDraggingEnabled()\"\n [cdkDropListData]=\"visibleDataColumnsForDrag\"\n cdkDropListOrientation=\"horizontal\"\n (cdkDropListDropped)=\"onColumnDrop($event)\"\n matSort\n (matSortChange)=\"onSortChange($event)\"\n [matSortDisabled]=\"!getSortingEnabled()\"\n [ngClass]=\"getTableElevationClassName()\"\n [class.table-stack-top]=\"showToolbar\"\n [class.pfx-column-drag-enabled]=\"isColumnDraggingEnabled()\"\n [class.pfx-column-drag-indicator]=\"isColumnDragIndicatorEnabled()\"\n>\n @if (config.behavior?.selection?.enabled) {\n <ng-container\n matColumnDef=\"_select\"\n >\n <th mat-header-cell *matHeaderCellDef>\n @if (canSelectAll()) {\n <mat-checkbox\n (change)=\"masterToggle()\"\n [checked]=\"isAllSelected()\"\n [indeterminate]=\"selection.hasValue() && !isAllSelected()\"\n ></mat-checkbox>\n }\n </th>\n <td mat-cell *matCellDef=\"let row\">\n <mat-checkbox\n (click)=\"$event.stopPropagation()\"\n (change)=\"toggleRow(row)\"\n [checked]=\"selection.isSelected(row)\"\n ></mat-checkbox>\n </td>\n </ng-container>\n }\n @if (isRowExpansionRuntimeEnabled()) {\n <ng-container matColumnDef=\"_expander\">\n <th mat-header-cell *matHeaderCellDef class=\"pfx-expansion-col-header\">\n <span class=\"praxis-visually-hidden-status\">Expandir detalhes da linha</span>\n </th>\n <td mat-cell *matCellDef=\"let row; let i = index\" class=\"pfx-expansion-col-cell\">\n <button\n mat-icon-button\n class=\"pfx-expansion-toggle\"\n [disabled]=\"!isRowExpandable(row, i) || !isExpansionIconTriggerEnabled()\"\n [attr.aria-expanded]=\"isRowExpanded(row, i) ? 'true' : 'false'\"\n [attr.aria-controls]=\"getRowExpansionDetailId(row, i)\"\n [attr.aria-label]=\"getRowExpansionToggleAriaLabel(row, i)\"\n (click)=\"onExpansionToggleFromIcon(row, i, $event)\"\n (keydown)=\"onExpansionToggleKeydown($event, row, i)\"\n >\n <mat-icon [praxisIcon]=\"isRowExpanded(row, i)\n ? getExpansionExpandedIcon()\n : getExpansionCollapsedIcon()\"></mat-icon>\n </button>\n </td>\n </ng-container>\n }\n @for (column of visibleColumns; track column.field) {\n <ng-container\n [matColumnDef]=\"column.field\"\n [sticky]=\"column.sticky === true || column.sticky === 'start'\"\n [stickyEnd]=\"column.sticky === 'end'\"\n >\n <th\n mat-header-cell\n *matHeaderCellDef\n mat-sort-header\n cdkDrag\n [cdkDragData]=\"column\"\n cdkDragLockAxis=\"x\"\n cdkDragPreviewClass=\"pfx-column-drag-preview\"\n (cdkDragStarted)=\"onColumnDragStarted(column)\"\n (cdkDragEnded)=\"onColumnDragEnded($event, column)\"\n (keydown)=\"onColumnDragHandleKeydown($event, column)\"\n [cdkDragDisabled]=\"!isColumnDraggingEnabled() || !isColumnDraggable(column)\"\n [class.praxis-header-draggable]=\"isColumnDraggingEnabled() && isColumnDraggable(column)\"\n [disabled]=\"!getSortingEnabled() || column.sortable === false\"\n [style.text-align]=\"getColumnTextAlignStyle(column)\"\n [style.width]=\"getColumnWidthStyle(column)\"\n [attr.style]=\"getColumnHeaderAttrStyle(column)\"\n [attr.aria-label]=\"isColumnDraggingEnabled() && isColumnDraggable(column) ? getColumnDragHandleAriaLabel(column) : null\"\n >\n <span class=\"praxis-header-label\" data-testid=\"column-header-label\">\n @if (isColumnDraggingEnabled() && isColumnDraggable(column)) {\n <span\n class=\"praxis-column-drag-handle\"\n data-testid=\"column-drag-handle\"\n [attr.data-column-field]=\"column.field\"\n aria-hidden=\"true\"\n >\n <mat-icon [praxisIcon]=\"'drag_indicator'\"></mat-icon>\n </span>\n }\n <span class=\"praxis-header-label-text\">{{ column.header }}</span>\n </span>\n </th>\n <td\n mat-cell\n *matCellDef=\"let element\"\n [style.text-align]=\"getColumnTextAlignStyle(column)\"\n [style.width]=\"getColumnWidthStyle(column)\"\n [attr.style]=\"getColumnCellAttrStyle(column)\"\n [ngClass]=\"getCellClasses(element, column)\"\n [ngStyle]=\"getCellNgStyle(element, column)\"\n >\n <div\n class=\"pfx-cell-content\"\n [ngClass]=\"getCellContentClasses(element, column)\"\n [ngStyle]=\"getCellContentNgStyle(element, column)\"\n >\n <ng-container [ngSwitch]=\"getEffectiveRendererType(element, column)\">\n <!-- Icon renderer -->\n <ng-container *ngSwitchCase=\"'icon'\">\n <mat-icon\n [color]=\"getIconColor(element, column) || null\"\n [ngStyle]=\"getIconStyle(element, column)\"\n [attr.aria-label]=\"getIconAriaLabel(element, column) || null\"\n >{{ getIconName(element, column) }}</mat-icon\n >\n </ng-container>\n\n <!-- Image renderer -->\n <ng-container *ngSwitchCase=\"'image'\">\n <img\n class=\"pfx-cell-image\"\n [src]=\"getImageSrc(element, column)\"\n [attr.alt]=\"getImageAlt(element, column) || ''\"\n [attr.loading]=\"getImageLazy(element, column) ? 'lazy' : null\"\n [style.width.px]=\"getImageWidth(element, column)\"\n [style.height.px]=\"getImageHeight(element, column)\"\n [class.shape-rounded]=\"getImageShape(element, column) === 'rounded'\"\n [class.shape-circle]=\"getImageShape(element, column) === 'circle'\"\n [style.object-fit]=\"getImageFit(element, column)\"\n />\n </ng-container>\n\n <!-- Badge renderer -->\n <ng-container *ngSwitchCase=\"'badge'\">\n <span class=\"pfx-badge\" [ngClass]=\"getBadgeClasses(element, column)\">\n @if (getBadgeIcon(element, column); as bi) { <mat-icon class=\"pfx-badge-icon\">{{ bi }}</mat-icon> }\n <span class=\"pfx-badge-text\">{{ getBadgeText(element, column) }}</span>\n </span>\n </ng-container>\n\n <!-- Link renderer -->\n <ng-container *ngSwitchCase=\"'link'\">\n <a\n class=\"pfx-link\"\n [attr.href]=\"getLinkHref(element, column) || null\"\n [attr.target]=\"getLinkTarget(element, column) || null\"\n [attr.rel]=\"getLinkRel(element, column) || null\"\n (click)=\"$event.stopPropagation()\"\n >{{ getLinkText(element, column) }}</a\n >\n </ng-container>\n\n <!-- Button renderer -->\n <ng-container *ngSwitchCase=\"'button'\">\n <ng-container [ngSwitch]=\"getButtonVariant(element, column)\">\n <button\n *ngSwitchCase=\"'outlined'\"\n mat-stroked-button\n [color]=\"getButtonColor(element, column) || null\"\n [disabled]=\"isButtonDisabled(element, column)\"\n [attr.aria-label]=\"getButtonAriaLabel(element, column) || getButtonLabel(element, column)\"\n (click)=\"onButtonClick(element, column, $event)\"\n >\n @if (getButtonIcon(element, column); as bi) { <mat-icon>{{ bi }}</mat-icon> }\n {{ getButtonLabel(element, column) }}\n </button>\n <button\n *ngSwitchCase=\"'text'\"\n mat-button\n [color]=\"getButtonColor(element, column) || null\"\n [disabled]=\"isButtonDisabled(element, column)\"\n [attr.aria-label]=\"getButtonAriaLabel(element, column) || getButtonLabel(element, column)\"\n (click)=\"onButtonClick(element, column, $event)\"\n >\n @if (getButtonIcon(element, column); as bi) { <mat-icon>{{ bi }}</mat-icon> }\n {{ getButtonLabel(element, column) }}\n </button>\n <button\n *ngSwitchDefault\n mat-flat-button\n [color]=\"getButtonColor(element, column) || null\"\n [disabled]=\"isButtonDisabled(element, column)\"\n [attr.aria-label]=\"getButtonAriaLabel(element, column) || getButtonLabel(element, column)\"\n (click)=\"onButtonClick(element, column, $event)\"\n >\n @if (getButtonIcon(element, column); as bi) { <mat-icon>{{ bi }}</mat-icon> }\n {{ getButtonLabel(element, column) }}\n </button>\n </ng-container>\n </ng-container>\n\n <!-- Chip renderer -->\n <ng-container *ngSwitchCase=\"'chip'\">\n <span class=\"pfx-chip\" [ngClass]=\"getChipClasses(element, column)\">\n @if (getChipIcon(element, column); as ci) { <mat-icon class=\"pfx-chip-icon\">{{ ci }}</mat-icon> }\n <span class=\"pfx-chip-text\">{{ getChipText(element, column) }}</span>\n </span>\n </ng-container>\n\n <!-- Progress renderer -->\n <ng-container *ngSwitchCase=\"'progress'\">\n <div class=\"pfx-progress\">\n <div class=\"pfx-progress-bar\" [style.width.%]=\"getProgressWidthPercentStyle(element, column)\" [style.background]=\"getProgressBackgroundStyle(element, column)\"></div>\n @if (getProgressShowLabel(element, column)) { <div class=\"pfx-progress-label\">{{ getProgressValue(element, column) }}%</div> }\n </div>\n </ng-container>\n\n <!-- Avatar renderer -->\n <ng-container *ngSwitchCase=\"'avatar'\">\n @if (getAvatarSrc(element, column); as asrc) {\n <img class=\"pfx-avatar\" [src]=\"asrc\" [attr.alt]=\"getAvatarAlt(element, column) || ''\" [ngStyle]=\"getAvatarStyle(element, column)\" [class.shape-rounded]=\"getAvatarShape(element, column) === 'rounded'\" [class.shape-circle]=\"getAvatarShape(element, column) === 'circle'\" loading=\"lazy\" />\n } @else {\n <span class=\"pfx-avatar pfx-avatar--initials\" [ngStyle]=\"getAvatarStyle(element, column)\" [class.shape-rounded]=\"getAvatarShape(element, column) === 'rounded'\" [class.shape-circle]=\"getAvatarShape(element, column) === 'circle'\">{{ getAvatarInitials(element, column) }}</span>\n }\n </ng-container>\n\n <!-- Toggle renderer -->\n <ng-container *ngSwitchCase=\"'toggle'\">\n <mat-slide-toggle\n [checked]=\"getToggleState(element, column)\"\n [disabled]=\"isToggleDisabled(element, column)\"\n [attr.aria-label]=\"getToggleAriaLabel(element, column) || 'Alternar'\"\n (change)=\"onToggleChange(element, column, $event)\"\n (click)=\"$event.stopPropagation()\"\n ></mat-slide-toggle>\n </ng-container>\n\n <!-- Menu renderer -->\n <ng-container *ngSwitchCase=\"'menu'\">\n <button mat-icon-button [matMenuTriggerFor]=\"menuRef\" (click)=\"$event.stopPropagation()\" [attr.aria-label]=\"getMenuAriaLabel(element, column) || 'Menu'\">\n <mat-icon>more_vert</mat-icon>\n </button>\n <mat-menu #menuRef=\"matMenu\">\n <button mat-menu-item *ngFor=\"let it of getMenuItems(element, column)\" (click)=\"onMenuItemClick(it, element, $event)\" [disabled]=\"!it.__visible\" >\n @if (it.icon) { <mat-icon>{{ it.icon }}</mat-icon> }\n <span>{{ it.label }}</span>\n </button>\n </mat-menu>\n </ng-container>\n\n <!-- Rating renderer -->\n <ng-container *ngSwitchCase=\"'rating'\">\n <praxis-table-rating\n class=\"pfx-rating-cell\"\n [itemsCount]=\"getRatingMax(element, column)\"\n [value]=\"getRatingValue(element, column)\"\n [size]=\"getRatingSize(element, column)\"\n [ratingColor]=\"getRatingColor(element, column)\"\n [outlineColor]=\"getRatingOutlineColor(element, column)\"\n [ariaLabel]=\"getRatingAriaLabel(element, column) || column.header\">\n </praxis-table-rating>\n </ng-container>\n\n <!-- HTML renderer (sanitizado) -->\n <ng-container *ngSwitchCase=\"'html'\">\n <span [innerHTML]=\"getSafeHtml(element, column)\"></span>\n </ng-container>\n\n <!-- Compose renderer -->\n <ng-container *ngSwitchCase=\"'compose'\">\n <span class=\"pfx-cell-compose\" [ngClass]=\"getComposeClasses(element, column)\" [ngStyle]=\"getComposeGapStyle(element, column)\">\n <ng-container *ngFor=\"let it of getComposeItems(element, column)\">\n <ng-container [ngSwitch]=\"getItemEffectiveType(element, column, it)\">\n <!-- Reuse helpers by projecting item as faux column -->\n <ng-container *ngSwitchCase=\"'icon'\">\n <mat-icon [color]=\"getIconColor(element, asItemColumn(column, it)) || null\" [ngStyle]=\"getIconStyle(element, asItemColumn(column, it))\" [attr.aria-label]=\"getIconAriaLabel(element, asItemColumn(column, it)) || null\">{{ getIconName(element, asItemColumn(column, it)) }}</mat-icon>\n </ng-container>\n <ng-container *ngSwitchCase=\"'image'\">\n <img class=\"pfx-cell-image\" [src]=\"getImageSrc(element, asItemColumn(column, it))\" [attr.alt]=\"getImageAlt(element, asItemColumn(column, it)) || ''\" [attr.loading]=\"getImageLazy(element, asItemColumn(column, it)) ? 'lazy' : null\" [style.width.px]=\"getImageWidth(element, asItemColumn(column, it))\" [style.height.px]=\"getImageHeight(element, asItemColumn(column, it))\" [class.shape-rounded]=\"getImageShape(element, asItemColumn(column, it)) === 'rounded'\" [class.shape-circle]=\"getImageShape(element, asItemColumn(column, it)) === 'circle'\" [style.object-fit]=\"getImageFit(element, asItemColumn(column, it))\" />\n </ng-container>\n <ng-container *ngSwitchCase=\"'badge'\">\n <span class=\"pfx-badge\" [ngClass]=\"getBadgeClasses(element, asItemColumn(column, it))\">@if (getBadgeIcon(element, asItemColumn(column, it)); as bi) { <mat-icon class=\"pfx-badge-icon\">{{ bi }}</mat-icon> }<span class=\"pfx-badge-text\">{{ getBadgeText(element, asItemColumn(column, it)) }}</span></span>\n </ng-container>\n <ng-container *ngSwitchCase=\"'link'\">\n <a class=\"pfx-link\" [attr.href]=\"getLinkHref(element, asItemColumn(column, it)) || null\" [attr.target]=\"getLinkTarget(element, asItemColumn(column, it)) || null\" [attr.rel]=\"getLinkRel(element, asItemColumn(column, it)) || null\" (click)=\"$event.stopPropagation()\">{{ getLinkText(element, asItemColumn(column, it)) }}</a>\n </ng-container>\n <ng-container *ngSwitchCase=\"'button'\">\n <ng-container [ngSwitch]=\"getButtonVariant(element, asItemColumn(column, it))\">\n <button *ngSwitchCase=\"'outlined'\" mat-stroked-button [color]=\"getButtonColor(element, asItemColumn(column, it)) || null\" [disabled]=\"isButtonDisabled(element, asItemColumn(column, it))\" [attr.aria-label]=\"getButtonAriaLabel(element, asItemColumn(column, it)) || getButtonLabel(element, asItemColumn(column, it))\" (click)=\"onButtonClick(element, asItemColumn(column, it), $event)\">@if (getButtonIcon(element, asItemColumn(column, it)); as bi) { <mat-icon>{{ bi }}</mat-icon> }{{ getButtonLabel(element, asItemColumn(column, it)) }}</button>\n <button *ngSwitchCase=\"'text'\" mat-button [color]=\"getButtonColor(element, asItemColumn(column, it)) || null\" [disabled]=\"isButtonDisabled(element, asItemColumn(column, it))\" [attr.aria-label]=\"getButtonAriaLabel(element, asItemColumn(column, it)) || getButtonLabel(element, asItemColumn(column, it))\" (click)=\"onButtonClick(element, asItemColumn(column, it), $event)\">@if (getButtonIcon(element, asItemColumn(column, it)); as bi) { <mat-icon>{{ bi }}</mat-icon> }{{ getButtonLabel(element, asItemColumn(column, it)) }}</button>\n <button *ngSwitchDefault mat-flat-button [color]=\"getButtonColor(element, asItemColumn(column, it)) || null\" [disabled]=\"isButtonDisabled(element, asItemColumn(column, it))\" [attr.aria-label]=\"getButtonAriaLabel(element, asItemColumn(column, it)) || getButtonLabel(element, asItemColumn(column, it))\" (click)=\"onButtonClick(element, asItemColumn(column, it), $event)\">@if (getButtonIcon(element, asItemColumn(column, it)); as bi) { <mat-icon>{{ bi }}</mat-icon> }{{ getButtonLabel(element, asItemColumn(column, it)) }}</button>\n </ng-container>\n </ng-container>\n <ng-container *ngSwitchCase=\"'chip'\">\n <span class=\"pfx-chip\" [ngClass]=\"getChipClasses(element, asItemColumn(column, it))\">@if (getChipIcon(element, asItemColumn(column, it)); as ci) { <mat-icon class=\"pfx-chip-icon\">{{ ci }}</mat-icon> }<span class=\"pfx-chip-text\">{{ getChipText(element, asItemColumn(column, it)) }}</span></span>\n </ng-container>\n <ng-container *ngSwitchCase=\"'progress'\">\n <div class=\"pfx-progress\"><div class=\"pfx-progress-bar\" [style.width.%]=\"getProgressWidthPercentStyle(element, asItemColumn(column, it))\" [style.background]=\"getProgressBackgroundStyle(element, asItemColumn(column, it))\"></div>@if (getProgressShowLabel(element, asItemColumn(column, it))) { <div class=\"pfx-progress-label\">{{ getProgressValue(element, asItemColumn(column, it)) }}%</div> }</div>\n </ng-container>\n <ng-container *ngSwitchCase=\"'avatar'\">\n @if (getAvatarSrc(element, asItemColumn(column, it)); as asrc) {\n <img class=\"pfx-avatar\" [src]=\"asrc\" [attr.alt]=\"getAvatarAlt(element, asItemColumn(column, it)) || ''\" [ngStyle]=\"getAvatarStyle(element, asItemColumn(column, it))\" [class.shape-rounded]=\"getAvatarShape(element, asItemColumn(column, it)) === 'rounded'\" [class.shape-circle]=\"getAvatarShape(element, asItemColumn(column, it)) === 'circle'\" loading=\"lazy\" />\n } @else {\n <span class=\"pfx-avatar pfx-avatar--initials\" [ngStyle]=\"getAvatarStyle(element, asItemColumn(column, it))\" [class.shape-rounded]=\"getAvatarShape(element, asItemColumn(column, it)) === 'rounded'\" [class.shape-circle]=\"getAvatarShape(element, asItemColumn(column, it)) === 'circle'\">{{ getAvatarInitials(element, asItemColumn(column, it)) }}</span>\n }\n </ng-container>\n <ng-container *ngSwitchCase=\"'toggle'\">\n <mat-slide-toggle [checked]=\"getToggleState(element, asItemColumn(column, it))\" [disabled]=\"isToggleDisabled(element, asItemColumn(column, it))\" [attr.aria-label]=\"getToggleAriaLabel(element, asItemColumn(column, it)) || 'Alternar'\" (change)=\"onToggleChange(element, asItemColumn(column, it), $event)\" (click)=\"$event.stopPropagation()\"></mat-slide-toggle>\n </ng-container>\n <ng-container *ngSwitchCase=\"'menu'\">\n <button mat-icon-button [matMenuTriggerFor]=\"menuRef\" (click)=\"$event.stopPropagation()\" [attr.aria-label]=\"getMenuAriaLabel(element, asItemColumn(column, it)) || 'Menu'\"><mat-icon>more_vert</mat-icon></button>\n <mat-menu #menuRef=\"matMenu\">\n <button mat-menu-item *ngFor=\"let mi of getMenuItems(element, asItemColumn(column, it))\" (click)=\"onMenuItemClick(mi, element, $event)\" [disabled]=\"!mi.__visible\">\n @if (mi.icon) { <mat-icon>{{ mi.icon }}</mat-icon> }\n <span>{{ mi.label }}</span>\n </button>\n </mat-menu>\n </ng-container>\n <ng-container *ngSwitchCase=\"'rating'\">\n <praxis-table-rating\n class=\"pfx-rating-cell\"\n [itemsCount]=\"getRatingMax(element, asItemColumn(column, it))\"\n [value]=\"getRatingValue(element, asItemColumn(column, it))\"\n [size]=\"getRatingSize(element, asItemColumn(column, it))\"\n [ratingColor]=\"getRatingColor(element, asItemColumn(column, it))\"\n [outlineColor]=\"getRatingOutlineColor(element, asItemColumn(column, it))\"\n [ariaLabel]=\"getRatingAriaLabel(element, asItemColumn(column, it)) || column.header\">\n </praxis-table-rating>\n </ng-container>\n <ng-container *ngSwitchCase=\"'html'\">\n <span [innerHTML]=\"getSafeHtml(element, asItemColumn(column, it))\"></span>\n </ng-container>\n <!-- Value item: render base cell text alongside visuals -->\n <ng-container *ngSwitchCase=\"'value'\">\n <span class=\"pfx-cell-value\">{{ getComposeItemValue(element, column, it) }}</span>\n </ng-container>\n </ng-container>\n </ng-container>\n </span>\n </ng-container>\n\n <!-- Default text rendering -->\n <ng-container *ngSwitchDefault>\n {{ getCellValue(element, column) }}\n </ng-container>\n </ng-container>\n </div>\n </td>\n </ng-container>\n }\n @if (config.actions?.row?.enabled) {\n <ng-container matColumnDef=\"_actions\" [sticky]=\"config.actions?.row?.sticky === true || config.actions?.row?.sticky === 'start'\" [stickyEnd]=\"config.actions?.row?.sticky === 'end'\">\n <th mat-header-cell *matHeaderCellDef #actionsHeaderCell [style.width]=\"getRowActionsWidthStyle()\" class=\"praxis-actions-header\" [class.align-start]=\"getActionsHeaderAlign() === 'start'\" [class.align-center]=\"getActionsHeaderAlign() === 'center'\" [class.align-end]=\"getActionsHeaderAlign() === 'end'\">\n <div class=\"praxis-actions-header__content\" [matTooltip]=\"getActionsHeaderTooltip() || ''\" [matTooltipDisabled]=\"!getActionsHeaderTooltip()\">\n @if (getActionsHeaderIcon(); as hi) { <mat-icon [praxisIcon]=\"hi\"></mat-icon> }\n @if (getActionsHeaderLabel(); as hl) { <span class=\"label\">{{ hl }}</span> }\n </div>\n </th>\n <td\n mat-cell\n *matCellDef=\"let row\"\n class=\"praxis-actions-cell\"\n [class.dense]=\"dense\"\n [style.width]=\"getRowActionsWidthStyle()\"\n >\n <div\n class=\"praxis-actions-cell__content\"\n [class.praxis-actions-cell__content--discovering]=\"isRowDiscoveryPending(row)\"\n [attr.aria-busy]=\"isRowDiscoveryPending(row) ? 'true' : null\"\n >\n <!-- A\u00E7\u00F5es inline -->\n <!-- Inline actions: icons mode -->\n @if (config.actions?.row?.display === 'icons' || !config.actions?.row?.display) {\n <ng-container *ngFor=\"let a of getInlineRowActions(row); trackBy: trackAction\">\n <span\n class=\"praxis-row-action-anchor\"\n [class.praxis-row-action-anchor--workflow]=\"isWorkflowRowAction(a)\"\n [class.praxis-row-action-anchor--blocked]=\"isBlockedWorkflowRowAction(a, row)\"\n [matTooltip]=\"getActionTooltip(a, row)\"\n [matTooltipDisabled]=\"!getActionTooltip(a, row)\"\n matTooltipPosition=\"above\"\n matTooltipClass=\"praxis-tooltip\"\n >\n <button\n mat-icon-button\n class=\"praxis-icon-btn\"\n [class.praxis-icon-btn--workflow]=\"isWorkflowRowAction(a)\"\n [class.praxis-icon-btn--blocked]=\"isBlockedWorkflowRowAction(a, row)\"\n [disabled]=\"isActionDisabled(a, row)\"\n (click)=\"onRowAction(getActionId(a), row, $event, getRowActionRuntimeOptions(a, row))\"\n [attr.aria-label]=\"a.label || getActionId(a)\"\n [color]=\"a.color || null\"\n >\n <mat-icon [praxisIcon]=\"a.icon\"></mat-icon>\n </button>\n </span>\n </ng-container>\n }\n\n <!-- Inline actions: buttons mode (show label + icon) -->\n @if (config.actions?.row?.display === 'buttons') {\n <ng-container *ngFor=\"let a of getInlineRowActions(row); trackBy: trackAction\">\n <span\n class=\"praxis-row-action-anchor\"\n [class.praxis-row-action-anchor--workflow]=\"isWorkflowRowAction(a)\"\n [class.praxis-row-action-anchor--blocked]=\"isBlockedWorkflowRowAction(a, row)\"\n [matTooltip]=\"getActionTooltip(a, row)\"\n [matTooltipDisabled]=\"!getActionTooltip(a, row)\"\n matTooltipPosition=\"above\"\n matTooltipClass=\"praxis-tooltip\"\n >\n <button\n mat-flat-button\n class=\"praxis-row-btn\"\n [class.praxis-row-btn--workflow]=\"isWorkflowRowAction(a)\"\n [class.praxis-row-btn--blocked]=\"isBlockedWorkflowRowAction(a, row)\"\n [disabled]=\"isActionDisabled(a, row)\"\n (click)=\"onRowAction(getActionId(a), row, $event, getRowActionRuntimeOptions(a, row))\"\n [attr.aria-label]=\"a.label || getActionId(a)\"\n [color]=\"a.color || null\"\n >\n <mat-icon [praxisIcon]=\"a.icon\"></mat-icon>\n <span>{{ a.label || getActionId(a) }}</span>\n </button>\n </span>\n </ng-container>\n }\n\n <!-- Menu de overflow -->\n @if (hasOverflowRowActions(row)) {\n <button\n mat-icon-button\n class=\"praxis-icon-btn praxis-more-btn\"\n [matMenuTriggerFor]=\"rowMoreMenu\"\n (menuOpened)=\"onRowOverflowMenuOpened(row)\"\n [color]=\"getRowMenuButtonColor() || null\"\n aria-label=\"Mais a\u00E7\u00F5es\"\n [matTooltip]=\"getRowMenuTooltip(row)\"\n matTooltipPosition=\"above\"\n >\n <mat-icon [praxisIcon]=\"getRowMenuIcon()\"></mat-icon>\n </button>\n }\n <mat-menu #rowMoreMenu=\"matMenu\" xPosition=\"before\">\n @if (hasRowOverflowMenuLoadingState(row)) {\n <button mat-menu-item disabled>\n <mat-icon>hourglass_empty</mat-icon>\n <span>{{ getRowOverflowMenuLoadingLabel() }}</span>\n </button>\n }\n <ng-container\n *ngFor=\"let a of getOverflowRowActions(row); trackBy: trackAction\"\n >\n <button\n mat-menu-item\n (click)=\"onRowAction(getActionId(a), row, $event, getRowActionRuntimeOptions(a, row))\"\n [disabled]=\"isActionDisabled(a, row)\"\n >\n <mat-icon [color]=\"a.color || null\" [praxisIcon]=\"a.icon\"></mat-icon>\n <span>{{ a.label || getActionId(a) }}</span>\n </button>\n </ng-container>\n @if (hasRowOverflowMenuEmptyState(row)) {\n <button mat-menu-item disabled>\n <mat-icon>info</mat-icon>\n <span>{{ getRowOverflowMenuEmptyLabel(row) }}</span>\n </button>\n }\n </mat-menu>\n </div>\n </td>\n </ng-container>\n }\n\n <tr\n mat-header-row\n *matHeaderRowDef=\"displayedColumns\"\n ></tr>\n @if (!isVirtualized()) {\n <tr\n mat-row\n *matRowDef=\"let row; let i = index; columns: displayedColumns\"\n [class.pfx-row-selected]=\"selection.isSelected(row)\"\n [class.pfx-row-expanded]=\"isRowExpansionRuntimeEnabled() && isRowExpanded(row, i)\"\n [attr.aria-selected]=\"config.behavior?.selection?.enabled ? (selection.isSelected(row) ? 'true' : 'false') : null\"\n [attr.aria-expanded]=\"isRowExpansionRuntimeEnabled() ? (isRowExpanded(row, i) ? 'true' : 'false') : null\"\n [ngClass]=\"getRowClasses(row)\"\n [ngStyle]=\"getRowNgStyle(row)\"\n [matTooltip]=\"getRowTooltip(row) || null\"\n [matTooltipDisabled]=\"!getRowTooltip(row)\"\n [matTooltipPosition]=\"getRowTooltipPosition(row)\"\n [matTooltipShowDelay]=\"getRowTooltipShowDelay(row)\"\n (click)=\"onRowClicked(row, i, $event)\"\n (dblclick)=\"onRowDoubleClicked(row, i)\"\n ></tr>\n @if (isRowExpansionRuntimeEnabled()) {\n <ng-container matColumnDef=\"_detail\">\n <td\n mat-cell\n *matCellDef=\"let row; let i = index\"\n class=\"pfx-expansion-detail-cell\"\n [attr.colspan]=\"displayedColumns.length\"\n >\n <section\n class=\"pfx-expansion-detail-panel\"\n [ngClass]=\"getExpansionMotionPresetClass()\"\n [ngStyle]=\"getExpansionMotionStyle()\"\n [attr.id]=\"getRowExpansionDetailId(row, i)\"\n role=\"region\"\n [attr.aria-label]=\"getRowExpansionRegionAriaLabel(row, i)\"\n [attr.aria-busy]=\"getExpansionDetailViewState(row, i).status === 'loading' ? 'true' : 'false'\"\n >\n @let detailState = getExpansionDetailViewState(row, i);\n @if (detailState.status === 'loading') {\n <div class=\"pfx-expansion-detail-message\" role=\"status\" aria-live=\"polite\">\n Carregando detail schema...\n </div>\n } @else if (detailState.status !== 'ready') {\n <div\n class=\"pfx-expansion-detail-message pfx-expansion-detail-message--error\"\n role=\"alert\"\n aria-live=\"assertive\"\n aria-atomic=\"true\"\n >\n {{ detailState.message || 'Detail indispon\u00EDvel para esta linha.' }}\n </div>\n } @else {\n @if (getExpansionDetailLayout(detailState.schema) === 'tabs') {\n @let detailTabs = getExpansionDetailTabs(detailState.schema);\n @if (detailTabs.length) {\n <div class=\"pfx-expansion-detail-tabs\" role=\"tablist\" aria-label=\"Se\u00E7\u00F5es do detail\">\n @for (tab of detailTabs; track $index; let tabIndex = $index) {\n <button\n type=\"button\"\n class=\"pfx-expansion-detail-tab-btn\"\n role=\"tab\"\n [attr.id]=\"getExpansionDetailTabId(row, i, tab, tabIndex)\"\n [attr.aria-controls]=\"getExpansionDetailPanelId(row, i, tab, tabIndex)\"\n [attr.aria-selected]=\"isExpansionDetailTabActive(row, i, tab, tabIndex, detailTabs) ? 'true' : 'false'\"\n [attr.tabindex]=\"isExpansionDetailTabActive(row, i, tab, tabIndex, detailTabs) ? '0' : '-1'\"\n [class.is-active]=\"isExpansionDetailTabActive(row, i, tab, tabIndex, detailTabs)\"\n (click)=\"onExpansionDetailTabSelect(row, i, tab, tabIndex, $event)\"\n (keydown)=\"onExpansionDetailTabKeydown($event, row, i, tabIndex, detailTabs)\"\n >\n {{ getExpansionDetailNodeTitle(tab, 'Tab') }}\n </button>\n }\n </div>\n @for (tab of detailTabs; track $index; let tabIndex = $index) {\n @if (isExpansionDetailTabActive(row, i, tab, tabIndex, detailTabs)) {\n <div\n class=\"pfx-expansion-detail-tab-panel\"\n role=\"tabpanel\"\n [attr.id]=\"getExpansionDetailPanelId(row, i, tab, tabIndex)\"\n [attr.aria-labelledby]=\"getExpansionDetailTabId(row, i, tab, tabIndex)\"\n >\n @for (childNode of getExpansionDetailNodeChildren(tab); track $index) {\n <ng-container\n *ngTemplateOutlet=\"\n expansionDetailNodeTemplate;\n context: { $implicit: childNode, row: row, index: i }\n \"\n ></ng-container>\n }\n </div>\n }\n }\n } @else {\n <div class=\"pfx-expansion-detail-message\">\n Schema em layout tabs sem abas v\u00E1lidas.\n </div>\n }\n } @else {\n <div class=\"pfx-expansion-detail-stack\">\n @for (node of getExpansionDetailItems(detailState.schema); track $index) {\n <ng-container\n *ngTemplateOutlet=\"\n expansionDetailNodeTemplate;\n context: { $implicit: node, row: row, index: i }\n \"\n ></ng-container>\n }\n </div>\n }\n }\n\n <ng-template #expansionDetailNodeTemplate let-node let-row=\"row\" let-index=\"index\">\n @switch (getExpansionDetailNodeType(node)) {\n @case ('card') {\n <article class=\"pfx-expansion-node pfx-expansion-node-card\">\n <header class=\"pfx-expansion-node-card__header\">\n <h5 class=\"pfx-expansion-node-card__title\">\n {{ getExpansionDetailNodeTitle(node, 'Card') }}\n </h5>\n @if (node?.subtitle) {\n <p class=\"pfx-expansion-node-card__subtitle\">{{ node?.subtitle }}</p>\n }\n </header>\n @for (childNode of getExpansionDetailNodeChildren(node); track $index) {\n <ng-container\n *ngTemplateOutlet=\"\n expansionDetailNodeTemplate;\n context: { $implicit: childNode, row: row, index: index }\n \"\n ></ng-container>\n }\n </article>\n }\n @case ('value') {\n <div class=\"pfx-expansion-node pfx-expansion-node-value\">\n <span class=\"pfx-expansion-node-value__label\">\n {{ getExpansionDetailNodeTitle(node, 'Valor') }}\n </span>\n <strong class=\"pfx-expansion-node-value__content\">\n {{ getExpansionDetailValue(row, node) }}\n </strong>\n </div>\n }\n @case ('list') {\n <section class=\"pfx-expansion-node pfx-expansion-node-list\">\n <h6 class=\"pfx-expansion-node-list__title\">\n {{ getExpansionDetailNodeTitle(node, 'Lista') }}\n </h6>\n @let listItems = getExpansionDetailListItems(row, node);\n @if (listItems.length) {\n <ul>\n @for (entry of listItems; track $index) {\n <li>{{ entry }}</li>\n }\n </ul>\n } @else {\n <p class=\"pfx-expansion-node-placeholder\">Sem itens.</p>\n }\n </section>\n }\n @case ('richText') {\n <div\n class=\"pfx-expansion-node pfx-expansion-node-richtext\"\n [innerHTML]=\"getExpansionDetailRichText(node)\"\n ></div>\n }\n @case ('formRef') {\n <div class=\"pfx-expansion-node pfx-expansion-node-placeholder\">\n Formul\u00E1rio referenciado: <code>{{ node?.schemaId || node?.id || 'sem-id' }}</code>\n </div>\n }\n @case ('tableRef') {\n <div class=\"pfx-expansion-node pfx-expansion-node-placeholder\">\n Tabela referenciada: <code>{{ node?.schemaId || node?.id || 'sem-id' }}</code>\n </div>\n }\n @case ('chartRef') {\n <div class=\"pfx-expansion-node pfx-expansion-node-placeholder\">\n Gr\u00E1fico referenciado: <code>{{ node?.schemaId || node?.id || 'sem-id' }}</code>\n </div>\n }\n @case ('templateRef') {\n <div class=\"pfx-expansion-node pfx-expansion-node-placeholder\">\n Template referenciado: <code>{{ node?.id || node?.templateId || 'sem-id' }}</code>\n </div>\n }\n @case ('action') {\n <div class=\"pfx-expansion-node pfx-expansion-node-placeholder\">\n A\u00E7\u00E3o declarada: <code>{{ node?.id || node?.actionId || 'sem-id' }}</code>\n </div>\n }\n @case ('tab') {\n <div class=\"pfx-expansion-node pfx-expansion-node-placeholder\">\n Node <code>tab</code> fora de contexto de tabs.\n </div>\n }\n @default {\n <div class=\"pfx-expansion-node pfx-expansion-node-placeholder\">\n Node n\u00E3o suportado: <code>{{ getExpansionDetailNodeType(node) }}</code>\n </div>\n }\n }\n </ng-template>\n </section>\n </td>\n </ng-container>\n <tr\n mat-row\n *matRowDef=\"let row; columns: expansionDetailRowColumns; when: isExpansionDetailRow\"\n class=\"pfx-expansion-detail-row\"\n ></tr>\n }\n }\n</table>\n}\n\n<!-- Virtual rows path (header preserved above) -->\n@if (shouldRenderDataSurface() && !schemaError && !dataError && isVirtualized()) {\n <cdk-virtual-scroll-viewport\n class=\"ptable-viewport\"\n [itemSize]=\"getVirtItemHeight()\"\n [minBufferPx]=\"getVirtBufferSize() * getVirtItemHeight()\"\n [maxBufferPx]=\"getVirtBufferSize() * getVirtItemHeight() * 2\"\n [style.minHeight]=\"getVirtMinHeightHostStyle()\"\n >\n <table\n class=\"mat-mdc-table\"\n [ngClass]=\"getTableElevationClassName()\"\n [style.width]=\"getVirtualTableWidthStyle()\"\n >\n <tbody>\n <tr class=\"mat-mdc-row\"\n *cdkVirtualFor=\"let row of dataSource.data; let i = index; trackBy: trackByRow\"\n [class.pfx-row-selected]=\"selection.isSelected(row)\"\n [attr.aria-selected]=\"config.behavior?.selection?.enabled ? (selection.isSelected(row) ? 'true' : 'false') : null\"\n [ngClass]=\"getRowClasses(row)\"\n [ngStyle]=\"getRowNgStyle(row)\"\n [matTooltip]=\"getRowTooltip(row) || null\"\n [matTooltipDisabled]=\"!getRowTooltip(row)\"\n [matTooltipPosition]=\"getRowTooltipPosition(row)\"\n [matTooltipShowDelay]=\"getRowTooltipShowDelay(row)\"\n (click)=\"onRowClicked(row, i, $event)\"\n (dblclick)=\"onRowDoubleClicked(row, i)\">\n <!-- Selection column -->\n @if (config.behavior?.selection?.enabled) { <td class=\"mat-mdc-cell\">\n <mat-checkbox\n (click)=\"$event.stopPropagation()\"\n (change)=\"toggleRow(row)\"\n [checked]=\"selection.isSelected(row)\">\n </mat-checkbox>\n </td> }\n <!-- Data columns -->\n @for (column of visibleColumns; track column.field) {\n <td class=\"mat-mdc-cell\"\n [style.text-align]=\"getColumnTextAlignStyle(column)\"\n [style.width]=\"getColumnWidthStyle(column)\"\n [attr.style]=\"getColumnCellAttrStyle(column)\"\n [ngClass]=\"getCellClasses(row, column)\"\n [ngStyle]=\"getCellNgStyle(row, column)\">\n <div\n class=\"pfx-cell-content\"\n [ngClass]=\"getCellContentClasses(row, column)\"\n [ngStyle]=\"getCellContentNgStyle(row, column)\"\n >\n <ng-container [ngSwitch]=\"getEffectiveRendererType(row, column)\">\n <ng-container *ngSwitchCase=\"'icon'\">\n <mat-icon [color]=\"getIconColor(row, column) || null\"\n [ngStyle]=\"getIconStyle(row, column)\"\n [attr.aria-label]=\"getIconAriaLabel(row, column) || null\">\n {{ getIconName(row, column) }}\n </mat-icon>\n </ng-container>\n <ng-container *ngSwitchCase=\"'image'\">\n <img class=\"pfx-cell-image\"\n [src]=\"getImageSrc(row, column)\"\n [attr.alt]=\"getImageAlt(row, column) || ''\"\n [attr.loading]=\"getImageLazy(row, column) ? 'lazy' : null\"\n [style.width.px]=\"getImageWidth(row, column)\"\n [style.height.px]=\"getImageHeight(row, column)\"\n [class.shape-rounded]=\"getImageShape(row, column) === 'rounded'\"\n [class.shape-circle]=\"getImageShape(row, column) === 'circle'\"\n [style.object-fit]=\"getImageFit(row, column)\" />\n </ng-container>\n <ng-container *ngSwitchCase=\"'badge'\">\n <span class=\"pfx-badge\" [ngClass]=\"getBadgeClasses(row, column)\">\n @if (getBadgeIcon(row, column); as bi) { <mat-icon class=\"pfx-badge-icon\">{{ bi }}</mat-icon> }\n <span class=\"pfx-badge-text\">{{ getBadgeText(row, column) }}</span>\n </span>\n </ng-container>\n <ng-container *ngSwitchDefault>\n {{ getCellValue(row, column) }}\n </ng-container>\n </ng-container>\n </div>\n </td>\n }\n\n <!-- Actions column -->\n @if (config.actions?.row?.enabled) {\n <td class=\"mat-mdc-cell praxis-actions-cell\" [class.dense]=\"dense\" [style.width]=\"getRowActionsWidthStyle()\">\n <div\n class=\"praxis-actions-cell__content\"\n [class.praxis-actions-cell__content--discovering]=\"isRowDiscoveryPending(row)\"\n [attr.aria-busy]=\"isRowDiscoveryPending(row) ? 'true' : null\"\n >\n @if (config.actions?.row?.display === 'icons' || !config.actions?.row?.display) {\n <ng-container *ngFor=\"let a of getInlineRowActions(row); trackBy: trackAction\">\n <span\n class=\"praxis-row-action-anchor\"\n [class.praxis-row-action-anchor--workflow]=\"isWorkflowRowAction(a)\"\n [class.praxis-row-action-anchor--blocked]=\"isBlockedWorkflowRowAction(a, row)\"\n [matTooltip]=\"getActionTooltip(a, row)\"\n [matTooltipDisabled]=\"!getActionTooltip(a, row)\"\n matTooltipPosition=\"above\"\n matTooltipClass=\"praxis-tooltip\"\n >\n <button mat-icon-button class=\"praxis-icon-btn\"\n [class.praxis-icon-btn--workflow]=\"isWorkflowRowAction(a)\"\n [class.praxis-icon-btn--blocked]=\"isBlockedWorkflowRowAction(a, row)\"\n [disabled]=\"isActionDisabled(a, row)\"\n (click)=\"onRowAction(getActionId(a), row, $event, getRowActionRuntimeOptions(a, row))\"\n [attr.aria-label]=\"a.label || getActionId(a)\"\n [color]=\"a.color || null\">\n <mat-icon [praxisIcon]=\"a.icon\"></mat-icon>\n </button>\n </span>\n </ng-container>\n }\n @if (config.actions?.row?.display === 'buttons') {\n <ng-container *ngFor=\"let a of getInlineRowActions(row); trackBy: trackAction\">\n <span\n class=\"praxis-row-action-anchor\"\n [class.praxis-row-action-anchor--workflow]=\"isWorkflowRowAction(a)\"\n [class.praxis-row-action-anchor--blocked]=\"isBlockedWorkflowRowAction(a, row)\"\n [matTooltip]=\"getActionTooltip(a, row)\"\n [matTooltipDisabled]=\"!getActionTooltip(a, row)\"\n matTooltipPosition=\"above\"\n matTooltipClass=\"praxis-tooltip\"\n >\n <button mat-flat-button class=\"praxis-row-btn\"\n [class.praxis-row-btn--workflow]=\"isWorkflowRowAction(a)\"\n [class.praxis-row-btn--blocked]=\"isBlockedWorkflowRowAction(a, row)\"\n [disabled]=\"isActionDisabled(a, row)\"\n (click)=\"onRowAction(getActionId(a), row, $event, getRowActionRuntimeOptions(a, row))\"\n [attr.aria-label]=\"a.label || getActionId(a)\"\n [color]=\"a.color || null\">\n <mat-icon [praxisIcon]=\"a.icon\"></mat-icon>\n <span>{{ a.label || getActionId(a) }}</span>\n </button>\n </span>\n </ng-container>\n }\n @if (hasOverflowRowActions(row)) {\n <button mat-icon-button class=\"praxis-icon-btn praxis-more-btn\"\n [matMenuTriggerFor]=\"rowMoreMenuV\"\n (menuOpened)=\"onRowOverflowMenuOpened(row)\"\n [color]=\"getRowMenuButtonColor() || null\"\n aria-label=\"Mais a\u00E7\u00F5es\"\n [matTooltip]=\"getRowMenuTooltip(row)\"\n matTooltipPosition=\"above\">\n <mat-icon [praxisIcon]=\"getRowMenuIcon()\"></mat-icon>\n </button>\n }\n <mat-menu #rowMoreMenuV=\"matMenu\" xPosition=\"before\">\n @if (hasRowOverflowMenuLoadingState(row)) {\n <button mat-menu-item disabled>\n <mat-icon>hourglass_empty</mat-icon>\n <span>{{ getRowOverflowMenuLoadingLabel() }}</span>\n </button>\n }\n <ng-container *ngFor=\"let a of getOverflowRowActions(row); trackBy: trackAction\">\n <button mat-menu-item (click)=\"onRowAction(getActionId(a), row, $event, getRowActionRuntimeOptions(a, row))\" [disabled]=\"isActionDisabled(a, row)\">\n <mat-icon [color]=\"a.color || null\" [praxisIcon]=\"a.icon\"></mat-icon>\n <span>{{ a.label || getActionId(a) }}</span>\n </button>\n </ng-container>\n @if (hasRowOverflowMenuEmptyState(row)) {\n <button mat-menu-item disabled>\n <mat-icon>info</mat-icon>\n <span>{{ getRowOverflowMenuEmptyLabel(row) }}</span>\n </button>\n }\n </mat-menu>\n </div>\n </td>\n }\n </tr>\n </tbody>\n </table>\n </cdk-virtual-scroll-viewport>\n}\n\n</div>\n@if (\n shouldRenderDataSurface()\n && !schemaError\n && !dataError\n && shouldRenderFloatingBulkActions()\n && getFloatingBulkActions().length\n && !shouldHideFloatingBulkActions()\n) {\n <div [class]=\"'praxis-floating-bulk-actions ' + getFloatingBulkPositionClass()\">\n @for (action of getFloatingBulkActions(); track getActionId(action)) {\n <button\n mat-mini-fab\n [color]=\"action.color || 'primary'\"\n [disabled]=\"isFloatingBulkActionDisabled(action)\"\n (click)=\"onToolbarAction({ action: getActionId(action), actionConfig: action })\"\n [attr.aria-label]=\"action.label || getActionId(action)\"\n [matTooltip]=\"action.label || getActionId(action)\"\n matTooltipPosition=\"left\"\n >\n <mat-icon [praxisIcon]=\"action.icon || 'done_all'\"></mat-icon>\n </button>\n }\n </div>\n}\n<!-- Barra de a\u00E7\u00F5es no rodap\u00E9 (opcional) -->\n@if (shouldRenderDataSurface() && !schemaError && !dataError && showToolbar && shouldRenderFooterToolbar()) {\n <praxis-table-toolbar\n [config]=\"config\"\n [backgroundColor]=\"getToolbarActionsBackgroundColor()\"\n [style.--pfx-filter-h]=\"getToolbarLayoutHeightHostStyle()\"\n [class.footer-flat]=\"hasBottomPaginator()\"\n class=\"praxis-toolbar-footer\"\n placement=\"footer\"\n [showMain]=\"shouldShowFooterToolbarMain()\"\n [showEndActions]=\"shouldShowFooterToolbarEndActions()\"\n [showReset]=\"shouldShowFooterToolbarReset()\"\n [showActionsGroup]=\"shouldShowToolbarActionsBottom()\"\n [showMobileActions]=\"shouldShowToolbarActionsBottom()\"\n [evaluationContext]=\"getToolbarEvaluationContext()\"\n (toolbarAction)=\"onToolbarAction($event)\"\n >\n <praxis-filter\n *ngIf=\"shouldShowFooterToolbarMain() && shouldRenderAdvancedFilter()\"\n advancedFilter\n [resourcePath]=\"getAdvancedFilterResourcePath()\"\n [filterId]=\"tableId\"\n [formId]=\"tableId\"\n [persistenceKey]=\"getAdvancedFilterPersistenceKey()\"\n [fieldMetadata]=\"getAdvancedFilterFieldMetadata()\"\n [enableCustomization]=\"enableCustomization\"\n [alwaysVisibleFields]=\"config.behavior?.filtering?.advancedFilters?.settings?.alwaysVisibleFields\"\n [alwaysVisibleFieldMetadataOverrides]=\"config.behavior?.filtering?.advancedFilters?.settings?.alwaysVisibleFieldMetadataOverrides ?? {}\"\n [selectedFieldIds]=\"config.behavior?.filtering?.advancedFilters?.settings?.selectedFieldIds ?? []\"\n [allowSaveTags]=\"config.behavior?.filtering?.advancedFilters?.settings?.allowSaveTags\"\n [changeDebounceMs]=\"config.behavior?.filtering?.advancedFilters?.settings?.changeDebounceMs ?? 300\"\n [i18n]=\"getFilterI18n()\"\n [mode]=\"'filter'\"\n [showFilterSettings]=\"enableCustomization\"\n (change)=\"onAdvancedFilterChange($event)\"\n (requestSearch)=\"onAdvancedFilterSubmit($event)\"\n (clear)=\"onAdvancedFilterClear()\"\n ></praxis-filter>\n <ng-container *ngIf=\"shouldShowFooterToolbarMain() && shouldRenderAdvancedFilter()\">\n <ng-content select=\"[advancedFilter]\"></ng-content>\n </ng-container>\n <ng-container *ngIf=\"shouldShowFooterToolbarMain() && shouldRenderAdvancedFilter()\">\n <ng-content select=\"[toolbar]\"></ng-content>\n </ng-container>\n @if (shouldShowFooterToolbarMain() && shouldRenderAdvancedFilter()) {\n @defer (on idle) {\n @if (aiAdapter) {\n <praxis-ai-assistant\n [adapter]=\"aiAdapter\"\n end-actions\n ></praxis-ai-assistant>\n }\n }\n }\n <button\n *ngIf=\"shouldShowFooterToolbarMain() && shouldRenderAdvancedFilter() && enableCustomization\"\n end-actions\n mat-icon-button\n color=\"primary\"\n data-role=\"table-settings\"\n data-testid=\"table-settings-trigger\"\n (click)=\"openTableSettings()\"\n aria-label=\"Configura\u00E7\u00F5es\"\n [matBadge]=\"schemaOutdated ? '!' : ''\"\n [matBadgeHidden]=\"!schemaOutdated\"\n matBadgeColor=\"warn\"\n matBadgeSize=\"small\"\n matBadgePosition=\"above after\"\n [matTooltip]=\"schemaOutdated ? 'Schema do servidor mudou \u2014 Reconciliar' : 'Configura\u00E7\u00F5es'\"\n matTooltipPosition=\"below\"\n >\n <mat-icon>settings</mat-icon>\n </button>\n </praxis-table-toolbar>\n}\n<!-- Paginadores (top/bottom) -->\n@if (shouldRenderDataSurface() && !schemaError && !dataError && getPaginationEnabled() && (config.behavior?.pagination?.position === 'top' || config.behavior?.pagination?.position === 'both')) {\n <mat-paginator\n [length]=\"getPaginationLength()\"\n [pageSize]=\"getPaginationPageSize()\"\n [pageSizeOptions]=\"getPaginationPageSizeOptions()\"\n [showFirstLastButtons]=\"getPaginationShowFirstLast()\"\n (page)=\"onPageChange($event)\"\n [class.compact]=\"config.behavior?.pagination?.style === 'compact'\"\n >\n </mat-paginator>\n}\n\n@if (shouldRenderDataSurface() && !schemaError && !dataError && getPaginationEnabled() && (config.behavior?.pagination?.position === 'bottom' || config.behavior?.pagination?.position === 'both' || !config.behavior?.pagination?.position)) {\n <mat-paginator\n [length]=\"getPaginationLength()\"\n [pageSize]=\"getPaginationPageSize()\"\n [pageSizeOptions]=\"getPaginationPageSizeOptions()\"\n [showFirstLastButtons]=\"getPaginationShowFirstLast()\"\n (page)=\"onPageChange($event)\"\n [class.compact]=\"config.behavior?.pagination?.style === 'compact'\"\n [class.footer-stack]=\"shouldShowToolbarActionsBottom()\"\n >\n </mat-paginator>\n}\n", styles: ["@charset \"UTF-8\";table{width:100%}.praxis-visually-hidden-status{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0}.praxis-column-reorder-status{margin:8px 0;padding:10px 12px;border-radius:8px;border:1px solid var(--p-table-border-color);background:var(--p-table-row-hover-bg);color:var(--p-table-header-fg);font-size:12px;line-height:1.4;box-shadow:0 4px 12px #00000014;animation:pfx-column-reorder-status-in var(--p-table-drag-status-enter-duration, .18s) var(--p-table-motion-easing, cubic-bezier(0, 0, .2, 1))}@keyframes pfx-column-reorder-status-in{0%{opacity:0;transform:translateY(-4px)}to{opacity:1;transform:translateY(0)}}.praxis-actions-cell{height:100%;padding-inline:12px;white-space:nowrap}.pfx-expansion-col-header,.pfx-expansion-col-cell{width:52px;min-width:52px;text-align:center}.pfx-expansion-toggle:focus-visible{outline:2px solid var(--md-sys-color-primary);outline-offset:2px}.pfx-expansion-detail-row{background:var(--md-sys-color-surface-container-low)}.pfx-expansion-detail-cell{padding:0!important;border-bottom:1px solid var(--p-table-border-color)}.pfx-expansion-detail-panel{padding:12px 16px;border-left:3px solid var(--md-sys-color-primary)}.pfx-expansion-detail-panel.pfx-expansion-motion-none{animation:none;transition:none}.pfx-expansion-detail-panel.pfx-expansion-motion-subtle-slide{animation:pfx-expansion-subtle-slide-in var(--pfx-expansion-motion-duration, .16s) var(--pfx-expansion-motion-easing, cubic-bezier(.2, 0, 0, 1))}.pfx-expansion-detail-panel.pfx-expansion-motion-accordion{animation:pfx-expansion-accordion-in var(--pfx-expansion-motion-duration, .18s) var(--pfx-expansion-motion-easing, cubic-bezier(.2, 0, 0, 1));transform-origin:top center}.pfx-expansion-detail-panel.pfx-expansion-motion-fade-scale{animation:pfx-expansion-fade-scale-in var(--pfx-expansion-motion-duration, .16s) var(--pfx-expansion-motion-easing, cubic-bezier(.2, 0, 0, 1));transform-origin:top center}@keyframes pfx-expansion-subtle-slide-in{0%{opacity:0;transform:translateY(-4px)}to{opacity:1;transform:translateY(0)}}@keyframes pfx-expansion-accordion-in{0%{opacity:0;transform:scaleY(.96)}to{opacity:1;transform:scaleY(1)}}@keyframes pfx-expansion-fade-scale-in{0%{opacity:0;transform:translateY(-2px) scale(.985)}to{opacity:1;transform:translateY(0) scale(1)}}.pfx-expansion-detail-schema{margin:0;font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-size:12px;line-height:1.4;white-space:pre-wrap;word-break:break-word;color:var(--md-sys-color-on-surface-variant)}.pfx-expansion-detail-message{font-size:13px;color:var(--md-sys-color-on-surface-variant)}.pfx-expansion-detail-message--error{color:var(--md-sys-color-error)}.pfx-expansion-detail-stack{display:grid;gap:10px}.pfx-expansion-detail-tabs{display:flex;flex-wrap:wrap;gap:8px;margin-bottom:10px}.pfx-expansion-detail-tab-btn{border:1px solid var(--p-table-border-color);background:var(--md-sys-color-surface);color:var(--md-sys-color-on-surface);border-radius:999px;padding:6px 12px;font-size:12px;line-height:1.2;cursor:pointer}.pfx-expansion-detail-tab-btn.is-active{border-color:var(--md-sys-color-primary);color:var(--md-sys-color-primary);font-weight:600}.pfx-expansion-detail-tab-btn:focus-visible{outline:2px solid var(--md-sys-color-primary);outline-offset:2px}.pfx-expansion-detail-tab-panel{display:grid;gap:10px}.pfx-expansion-node{border:1px solid var(--p-table-border-color);border-radius:8px;padding:10px 12px;background:var(--md-sys-color-surface)}.pfx-expansion-node-card__header{margin-bottom:8px}.pfx-expansion-node-card__title{margin:0;font-size:14px;line-height:1.3}.pfx-expansion-node-card__subtitle{margin:4px 0 0;font-size:12px;color:var(--md-sys-color-on-surface-variant)}.pfx-expansion-node-value{display:flex;align-items:baseline;gap:8px}.pfx-expansion-node-value__label{color:var(--md-sys-color-on-surface-variant);font-size:12px}.pfx-expansion-node-value__content{font-size:14px}.pfx-expansion-node-list__title{margin:0 0 6px;font-size:13px}.pfx-expansion-node-list ul{margin:0;padding-left:18px}.pfx-expansion-node-richtext :where(p,ul,ol,h1,h2,h3,h4,h5,h6){margin-top:0;margin-bottom:8px}.pfx-expansion-node-placeholder{font-size:12px;color:var(--md-sys-color-on-surface-variant)}:host.density-compact{--p-header-padding: 8px 12px;--p-cell-padding: 8px 12px;--p-actions-btn-size: 32px;--p-actions-icon-size: 18px}:host.density-comfortable{--p-header-padding: 12px 16px;--p-cell-padding: 12px 16px;--p-actions-btn-size: 40px;--p-actions-icon-size: 22px}:host.density-spacious{--p-header-padding: 16px 20px;--p-cell-padding: 16px 20px;--p-actions-btn-size: 44px;--p-actions-icon-size: 24px}:host.density-compact ::ng-deep .mat-mdc-cell{padding:var(--p-cell-padding, 8px 12px)}:host.density-comfortable ::ng-deep .mat-mdc-cell{padding:var(--p-cell-padding, 12px 16px)}:host.density-spacious ::ng-deep .mat-mdc-cell{padding:var(--p-cell-padding, 16px 20px)}:host.density-compact .praxis-actions-cell{padding-inline:8px}:host.density-spacious .praxis-actions-cell{padding-inline:16px}.praxis-actions-cell__content{display:flex;align-items:center;justify-content:flex-end;gap:8px;width:100%;transition:opacity .12s ease}.praxis-actions-cell.dense .praxis-actions-cell__content{gap:6px}.praxis-actions-cell__content--discovering{opacity:.78}.praxis-row-action-anchor{display:inline-flex;align-items:center}.praxis-row-action-anchor--workflow{position:relative}.praxis-row-action-anchor--workflow:after{content:\"\";position:absolute;right:4px;top:4px;width:6px;height:6px;border-radius:999px;background:var(--md-sys-color-secondary);opacity:.9;pointer-events:none}.praxis-row-action-anchor--blocked:after{background:var(--md-sys-color-error)}.praxis-icon-btn{width:var(--p-actions-btn-size, 40px);height:var(--p-actions-btn-size, 40px);border:0;background:transparent;padding:0;display:inline-flex;align-items:center;justify-content:center;border-radius:9999px;cursor:pointer;--mat-icon-button-state-layer-size: var(--p-actions-btn-size, 40px)}.praxis-icon-btn:hover{background:var(--md-sys-color-surface-variant)}.praxis-icon-btn:focus-visible{outline:2px solid var(--md-sys-color-primary);outline-offset:2px}.praxis-icon-btn mat-icon,.praxis-icon-btn .mat-icon{font-size:var(--p-actions-icon-size, 22px);width:var(--p-actions-icon-size, 22px);height:var(--p-actions-icon-size, 22px);line-height:var(--p-actions-icon-size, 22px)}.praxis-icon-btn--workflow{background:color-mix(in srgb,var(--md-sys-color-secondary-container) 36%,transparent)}.praxis-icon-btn--blocked{background:color-mix(in srgb,var(--md-sys-color-error-container) 42%,transparent)}.praxis-more-btn{width:var(--p-actions-more-btn-size, var(--p-actions-btn-size, 40px));height:var(--p-actions-more-btn-size, var(--p-actions-btn-size, 40px));--mat-icon-button-state-layer-size: var(--p-actions-more-btn-size, var(--p-actions-btn-size, 40px));background-image:var(--p-actions-more-btn-gradient, none);background-size:100% 100%;background-repeat:no-repeat}.praxis-more-btn mat-icon,.praxis-more-btn .mat-icon{font-size:var(--p-actions-more-icon-size, var(--p-actions-icon-size, 22px));width:var(--p-actions-more-icon-size, var(--p-actions-icon-size, 22px));height:var(--p-actions-more-icon-size, var(--p-actions-icon-size, 22px));line-height:var(--p-actions-more-icon-size, var(--p-actions-icon-size, 22px));color:var(--p-actions-more-icon-color);background-image:var(--p-actions-more-icon-gradient, none);-webkit-background-clip:text;background-clip:text}.praxis-row-btn--workflow{box-shadow:inset 0 0 0 1px color-mix(in srgb,var(--md-sys-color-secondary) 28%,transparent)}.praxis-row-btn--blocked{box-shadow:inset 0 0 0 1px color-mix(in srgb,var(--md-sys-color-error) 28%,transparent)}.praxis-icon-btn.destructive mat-icon{color:var(--md-sys-color-error)}.mat-mdc-tooltip.praxis-tooltip{margin-top:-8px;margin-bottom:8px}.spacer{flex:1 1 auto}.praxis-table-header{display:flex;flex-wrap:wrap;align-items:flex-start;gap:8px;margin:16px 0 12px;width:100%;clear:both;position:relative}.praxis-table-header.stacked{margin:0}.praxis-table-header>praxis-table-toolbar{flex:1 0 100%}.praxis-floating-bulk-actions{position:fixed;z-index:var(--praxis-layer-floating-local, 200);display:inline-flex;align-items:center;gap:8px;padding:8px;border-radius:999px;background:var(--md-sys-color-surface-container-highest);box-shadow:0 8px 20px #00000029}.praxis-floating-bulk-actions.pos-bottom-right{right:20px;bottom:20px}.praxis-floating-bulk-actions.pos-bottom-left{left:20px;bottom:20px}.praxis-floating-bulk-actions.pos-top-right{right:20px;top:20px}.praxis-floating-bulk-actions.pos-top-left{left:20px;top:20px}@media(max-width:768px){.praxis-floating-bulk-actions{gap:6px;padding:6px}.praxis-floating-bulk-actions.pos-bottom-right{right:12px;left:auto;bottom:12px}.praxis-floating-bulk-actions.pos-bottom-left{left:12px;right:auto;bottom:12px}.praxis-floating-bulk-actions.pos-top-right{right:12px;left:auto;top:12px}.praxis-floating-bulk-actions.pos-top-left{left:12px;right:auto;top:12px}}:host{display:block;width:100%;min-width:0;max-width:100%;--pfx-toolbar-pad-y: 6px;--pfx-toolbar-pad-x: 12px;--p-table-bg: var(--md-sys-color-surface-container-highest);--p-table-text-color: var(--md-sys-color-on-surface);--p-table-header-bg: var(--md-sys-color-surface-container-highest);--p-table-header-fg: var(--md-sys-color-on-surface);--p-table-border-color: var(--md-sys-color-outline-variant);--p-table-row-even-bg: var(--md-sys-color-surface-container);--p-table-row-hover-bg: var(--md-sys-color-surface-container-high);--p-table-row-selected-bg: var(--md-sys-color-primary-container);--p-table-badge-soft-primary-bg: var(--md-sys-color-primary-container);--p-table-badge-soft-primary-fg: var(--md-sys-color-on-primary-container);--p-table-badge-soft-accent-bg: var(--md-sys-color-secondary-container);--p-table-badge-soft-accent-fg: var(--md-sys-color-on-secondary-container);--p-table-badge-soft-warn-bg: var(--md-sys-color-error-container);--p-table-badge-soft-warn-fg: var(--md-sys-color-on-error-container);--p-table-state-success-bg: var(--md-sys-color-tertiary-container);--p-table-state-success-fg: var(--md-sys-color-on-tertiary-container);--p-table-state-warning-bg: var(--md-sys-color-secondary-container);--p-table-state-warning-fg: var(--md-sys-color-on-secondary-container);--p-table-state-danger-bg: var(--md-sys-color-error-container);--p-table-state-danger-fg: var(--md-sys-color-on-error-container);--p-table-state-highlight-bg: var(--md-sys-color-primary-container);--p-table-state-highlight-fg: var(--md-sys-color-on-primary-container);--p-table-drag-handle-size: 14px;--p-table-drag-handle-color: var(--md-sys-color-on-surface-variant);--p-table-drag-handle-hover-color: var(--md-sys-color-on-surface);--p-table-drag-handle-base-opacity: 0;--p-table-drag-handle-visible-opacity: .72;--p-table-drag-handle-active-opacity: 1;--p-table-drag-handle-transition-duration: .16s;--p-table-reorder-transition-duration: .16s;--p-table-drag-preview-scale: 1.01;--p-table-drag-status-enter-duration: .18s;--p-table-drag-preview-shadow: 0 14px 32px rgba(0, 0, 0, .28), 0 0 0 1px var(--p-table-border-color)}:host ::ng-deep .mat-mdc-table{background:var(--p-table-bg);color:var(--p-table-text-color);border-radius:12px 12px 0 0;width:100%;box-shadow:var(--p-table-surface-shadow);transition:box-shadow var(--p-table-selection-transition-duration, .18s) var(--p-table-motion-easing, cubic-bezier(0, 0, .2, 1))}:host ::ng-deep .mat-mdc-table:hover{box-shadow:var(--p-table-surface-shadow-hover, var(--p-table-surface-shadow))}:host ::ng-deep .mat-mdc-table.table-stack-top{border-top-left-radius:0;border-top-right-radius:0}:host ::ng-deep .praxis-toolbar-footer{border:0 solid var(--p-table-border-color);border-top:0;border-radius:0;background:var(--p-table-bg)}:host ::ng-deep .mat-mdc-paginator.footer-stack{border-top-left-radius:0;border-top-right-radius:0;border-top:0}:host ::ng-deep .mat-mdc-paginator.footer-stack .mat-mdc-paginator-container{padding:8px 12px}:host [data-role=table-settings].mat-mdc-icon-button{--mdc-icon-button-icon-color: var(--md-sys-color-primary);color:var(--md-sys-color-primary)}.pfx-link{color:var(--md-sys-color-primary);text-decoration:underline;cursor:pointer}.pfx-chip{display:inline-flex;align-items:center;gap:4px;padding:2px 8px;border-radius:10px;font-size:12px;line-height:1;border:1px solid transparent}.pfx-chip-icon{font-size:14px;width:14px;height:14px}.pfx-chip--outlined{background:transparent;border-color:var(--md-sys-color-outline-variant);color:var(--md-sys-color-on-surface)}.pfx-chip--filled-primary{background:var(--md-sys-color-primary);color:var(--md-sys-color-on-primary)}.pfx-chip--filled-accent{background:var(--md-sys-color-secondary);color:var(--md-sys-color-on-secondary)}.pfx-chip--filled-warn{background:var(--md-sys-color-error);color:var(--md-sys-color-on-error)}.pfx-chip--soft-primary{background:var(--p-table-badge-soft-primary-bg);color:var(--p-table-badge-soft-primary-fg)}.pfx-chip--soft-accent{background:var(--p-table-badge-soft-accent-bg);color:var(--p-table-badge-soft-accent-fg)}.pfx-chip--soft-warn{background:var(--p-table-badge-soft-warn-bg);color:var(--p-table-badge-soft-warn-fg)}.pfx-progress{position:relative;width:100%;max-width:140px;height:8px;background:var(--md-sys-color-surface-container-highest);border-radius:4px;overflow:hidden;display:inline-block;vertical-align:middle}.pfx-progress-bar{height:100%;background:var(--md-sys-color-primary);transition:width .2s ease}.pfx-progress-label{margin-left:8px;font-size:12px;opacity:.8;display:inline-block;vertical-align:middle}.pfx-avatar{display:inline-flex;align-items:center;justify-content:center;background:var(--md-sys-color-surface-container);color:var(--md-sys-color-on-surface);border-radius:4px;overflow:hidden;font-weight:600}.pfx-avatar.shape-rounded{border-radius:8px}.pfx-avatar.shape-circle{border-radius:999px}.pfx-avatar--initials{text-transform:uppercase;font-size:12px}.pfx-cell-compose{display:inline-flex;align-items:center;gap:6px}.pfx-cell-compose.dir-col{flex-direction:column;align-items:stretch}.pfx-cell-compose.align-start{justify-content:flex-start}.pfx-cell-compose.align-center{justify-content:center}.pfx-cell-compose.align-end{justify-content:flex-end}.pfx-cell-compose.wrap{flex-wrap:wrap}.pfx-cell-compose.ellipsis{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.px-scroll-viewport{width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch;overscroll-behavior-x:contain}.px-scroll-viewport.scroll-none{overflow-x:visible}.px-scroll-viewport.scroll-auto ::ng-deep .mat-mdc-table{width:max-content;min-width:100%}.px-scroll-viewport.scroll-wrap ::ng-deep .mat-mdc-header-cell,.px-scroll-viewport.scroll-wrap ::ng-deep .mat-mdc-cell{white-space:normal;text-overflow:initial}.px-scroll-viewport.scroll-wrap ::ng-deep .mat-mdc-table{width:100%}:host ::ng-deep .mat-mdc-header-row{position:sticky;top:0;z-index:var(--praxis-layer-sticky-local, 100);background:var(--p-table-header-bg);color:var(--p-table-header-fg);box-shadow:var(--p-table-header-shadow, 0 1px 0 var(--p-table-border-color));border-bottom:1px solid var(--p-table-border-color)}:host ::ng-deep .mat-mdc-header-cell,:host ::ng-deep .mat-sort-header-content,:host ::ng-deep .mat-mdc-header-row .mat-icon{color:var(--p-table-header-fg)!important;font-weight:600}:host ::ng-deep .mat-mdc-header-cell.mat-sort-header-sorted .mat-sort-header-arrow,:host ::ng-deep .mat-mdc-header-cell:hover .mat-sort-header-arrow{color:var(--p-table-header-fg)!important}:host ::ng-deep .mat-mdc-header-cell.mat-sort-header-sorted .mat-sort-header-arrow .mat-sort-header-indicator,:host ::ng-deep .mat-mdc-header-cell.mat-sort-header-sorted .mat-sort-header-arrow .mat-sort-header-stem,:host ::ng-deep .mat-mdc-header-cell.mat-sort-header-sorted .mat-sort-header-arrow .mat-sort-header-pointer,:host ::ng-deep .mat-mdc-header-cell.mat-sort-header-sorted .mat-sort-header-arrow .mat-sort-header-pointer-left,:host ::ng-deep .mat-mdc-header-cell.mat-sort-header-sorted .mat-sort-header-arrow .mat-sort-header-pointer-right{border-color:var(--p-table-header-fg)!important;background:var(--p-table-header-fg)!important}:host ::ng-deep .mat-mdc-header-cell{padding:var(--p-header-padding, 12px 16px)!important;font-size:var(--p-header-font-size, inherit);font-weight:var(--p-header-font-weight, 600);letter-spacing:var(--p-header-letter-spacing, normal);text-transform:var(--p-header-text-transform, none);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}:host ::ng-deep .pfx-column-drag-enabled .mat-mdc-header-cell.praxis-header-draggable .mat-sort-header-container{display:flex;align-items:center;width:100%;gap:4px;cursor:inherit}:host ::ng-deep .pfx-column-drag-enabled .mat-mdc-header-cell.praxis-header-draggable{-webkit-user-select:none;user-select:none;cursor:grab;padding-left:0!important}:host ::ng-deep .pfx-column-drag-enabled .mat-mdc-header-cell.praxis-header-draggable.cdk-drag-dragging{cursor:grabbing}:host ::ng-deep .pfx-column-drag-enabled .mat-mdc-header-cell.praxis-header-draggable .mat-sort-header-content{display:inline-flex;align-items:center;gap:4px;flex:1 1 auto;min-width:0}:host ::ng-deep .pfx-column-drag-enabled .mat-mdc-header-cell .praxis-header-label{display:inline-flex;align-items:center;gap:4px;flex:1 1 auto;min-width:0}:host ::ng-deep .pfx-column-drag-enabled .mat-mdc-header-cell .praxis-header-label-text{flex:1 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}:host ::ng-deep .pfx-column-drag-enabled .mat-mdc-header-cell .praxis-column-drag-handle{-webkit-appearance:none;appearance:none;border:0;background:transparent;color:var(--p-table-drag-handle-color);width:var(--p-table-drag-handle-size);min-width:var(--p-table-drag-handle-size);flex:0 0 var(--p-table-drag-handle-size);height:var(--p-table-drag-handle-size);padding:0;display:inline-flex;align-items:center;justify-content:center;border-radius:0;cursor:inherit;pointer-events:none;touch-action:none;opacity:var(--p-table-drag-handle-base-opacity, .42);transform:none;order:-1;margin-inline-end:0;transition:opacity var(--p-table-drag-handle-transition-duration, .16s) var(--p-table-motion-easing, cubic-bezier(0, 0, .2, 1)),color var(--p-table-drag-handle-transition-duration, .16s) var(--p-table-motion-easing, cubic-bezier(0, 0, .2, 1))}:host ::ng-deep .pfx-column-drag-enabled .mat-mdc-header-cell.praxis-header-draggable:hover .praxis-column-drag-handle,:host ::ng-deep .pfx-column-drag-enabled .mat-mdc-header-cell.praxis-header-draggable:focus-within .praxis-column-drag-handle{opacity:var(--p-table-drag-handle-visible-opacity, .72);color:var(--p-table-drag-handle-hover-color, var(--p-table-drag-handle-color))}:host ::ng-deep .pfx-column-drag-enabled .mat-mdc-header-cell .praxis-column-drag-handle:active{opacity:var(--p-table-drag-handle-active-opacity, 1);cursor:grabbing}:host ::ng-deep .pfx-column-drag-enabled .mat-mdc-header-cell .praxis-column-drag-handle .mat-icon{font-size:14px;width:14px;height:14px;line-height:14px;transition:transform .18s var(--p-table-motion-easing, cubic-bezier(0, 0, .2, 1))}:host ::ng-deep .pfx-column-drag-enabled .mat-mdc-header-cell.praxis-header-draggable:hover .praxis-column-drag-handle .mat-icon{transform:none}:host ::ng-deep .pfx-column-drag-indicator .cdk-drop-list-dragging .mat-mdc-header-cell:not(.cdk-drag-placeholder){transition:transform var(--p-table-reorder-transition-duration, .18s) var(--p-table-motion-easing, cubic-bezier(0, 0, .2, 1))}:host ::ng-deep .pfx-column-drag-indicator .mat-mdc-header-cell.cdk-drag-animating{transition:transform var(--p-table-reorder-transition-duration, .16s) var(--p-table-motion-easing, cubic-bezier(0, 0, .2, 1))}.pfx-column-drag-preview{box-sizing:border-box;display:flex;align-items:center;border-radius:10px;border:1px solid var(--p-table-border-color);background:linear-gradient(135deg,var(--p-table-header-bg) 0%,var(--p-table-row-hover-bg) 100%);color:var(--p-table-header-fg);box-shadow:var(--p-table-drag-preview-shadow);transform:scale(var(--p-table-drag-preview-scale, 1.01));pointer-events:none;z-index:var(--praxis-layer-authoring-hover, 300)}.pfx-column-drag-preview .praxis-column-drag-handle,.pfx-column-drag-preview .mat-sort-header-arrow,.pfx-column-drag-preview .mat-sort-header-indicator,.pfx-column-drag-preview .mat-sort-header-stem,.pfx-column-drag-preview .mat-sort-header-pointer,.pfx-column-drag-preview .mat-sort-header-pointer-left,.pfx-column-drag-preview .mat-sort-header-pointer-right{display:none!important}.pfx-column-drag-preview .mat-sort-header-container{display:flex;align-items:center;width:100%;min-height:100%;padding-right:0!important}.pfx-column-drag-preview .mat-sort-header-content,.pfx-column-drag-preview .praxis-header-label{display:inline-flex;align-items:center;min-width:0;width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}:host ::ng-deep .pfx-column-drag-indicator .cdk-drag-placeholder{opacity:1;border:1px dashed var(--p-table-border-color);background:var(--p-table-row-hover-bg)}:host ::ng-deep .pfx-column-drag-indicator .cdk-drag-placeholder *{opacity:0}:host ::ng-deep .pfx-column-drag-indicator .mat-mdc-header-cell.cdk-drag-dragging{opacity:.58}@media(prefers-reduced-motion:reduce){:host ::ng-deep .pfx-column-drag-indicator .cdk-drop-list-dragging .mat-mdc-header-cell:not(.cdk-drag-placeholder){transition:none}:host ::ng-deep .pfx-column-drag-enabled .mat-mdc-header-cell .praxis-column-drag-handle,:host ::ng-deep .pfx-column-drag-enabled .mat-mdc-header-cell .praxis-column-drag-handle .mat-icon,.pfx-column-drag-preview{transition:none;transform:none}.praxis-column-reorder-status{animation:none}.pfx-expansion-detail-panel{animation:none!important;transition:none!important;transform:none!important}:host ::ng-deep .mat-mdc-row{transition:none}:host ::ng-deep .mat-mdc-table{transition:none}}.praxis-actions-header{text-align:right}.praxis-actions-header.align-start{text-align:left}.praxis-actions-header.align-center{text-align:center}.praxis-actions-header.align-end{text-align:right}.praxis-actions-header .praxis-actions-header__content{display:inline-flex;align-items:center;gap:var(--p-actions-header-gap, 6px);color:var(--p-actions-header-color, inherit)}.praxis-actions-header .praxis-actions-header__content .mat-icon{font-size:18px;width:18px;height:18px;line-height:18px}:host ::ng-deep .mat-mdc-header-cell .mat-sort-header-container{padding-right:20px}:host ::ng-deep .pfx-column-drag-enabled .mat-mdc-header-cell.praxis-header-draggable .mat-sort-header-container{padding-right:12px}@media(pointer:coarse){:host{--p-table-drag-handle-size: 18px;--p-table-drag-handle-base-opacity: .56;--p-table-drag-handle-visible-opacity: .92}}:host ::ng-deep .mat-mdc-cell{color:var(--p-table-text-color);font-size:var(--p-cell-font-size, inherit);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}:host ::ng-deep .mat-mdc-cell .pfx-cell-content,:host ::ng-deep .mat-cell .pfx-cell-content{display:inline-flex;align-items:center;gap:6px;width:100%;min-width:0;overflow:hidden}:host ::ng-deep .mat-mdc-row:hover{background:var(--p-table-row-hover-bg)}:host ::ng-deep .mat-mdc-row{transition:background-color var(--p-table-hover-transition-duration, .18s) var(--p-table-motion-easing, cubic-bezier(0, 0, .2, 1)),box-shadow var(--p-table-selection-transition-duration, .18s) var(--p-table-motion-easing, cubic-bezier(0, 0, .2, 1))}:host ::ng-deep .mat-mdc-row:nth-child(2n){background:var(--p-table-row-even-bg)}:host ::ng-deep .mat-mdc-row:nth-child(2n):hover{background:var(--p-table-row-hover-bg)}:host ::ng-deep .mat-mdc-row.pfx-row-selected,:host ::ng-deep .mat-mdc-row.pfx-row-selected:hover{background:var(--p-table-row-selected-bg)}:host.row-borders ::ng-deep .mat-mdc-row .mat-mdc-cell{border-bottom:1px solid var(--p-table-border-color)}:host.row-borders ::ng-deep .mat-mdc-header-row .mat-mdc-header-cell{border-bottom:none}:host.col-borders ::ng-deep .mat-mdc-header-row .mat-mdc-header-cell,:host.col-borders ::ng-deep .mat-mdc-row .mat-mdc-cell{border-right:1px solid var(--p-table-border-color)}:host.col-borders ::ng-deep .mat-mdc-header-row .mat-mdc-header-cell:last-child,:host.col-borders ::ng-deep .mat-mdc-row .mat-mdc-cell:last-child{border-right:none}.ptable-error{display:flex;align-items:center;gap:12px;padding:12px;margin:8px 0;border:1px solid var(--md-sys-color-error);border-radius:8px}.ptable-error__content{flex:1}.ptable-error__title{font-weight:600}.ptable-info-banner{display:flex;gap:12px;align-items:center;padding:8px 12px;margin:8px 0;border-radius:8px;border:1px solid var(--md-sys-color-primary);background:var(--md-sys-color-primary-container);color:var(--md-sys-color-on-primary-container)}.ptable-info-banner .text{flex:1;font-weight:600}.ptable-info-banner .actions{display:flex;gap:8px}.pfx-cell-image{display:inline-block;vertical-align:middle;background:var(--md-sys-color-surface-variant);border:1px solid var(--md-sys-color-outline-variant)}.pfx-cell-image.shape-rounded{border-radius:8px}.pfx-cell-image.shape-circle{border-radius:9999px}.pfx-badge{display:inline-flex;align-items:center;gap:6px;line-height:1;padding:4px 8px;border-radius:9999px;font-size:12px;font-weight:600;border:1px solid transparent}.pfx-badge .pfx-badge-icon{font-size:16px;width:16px;height:16px}.pfx-badge--filled-primary{background:var(--md-sys-color-primary);color:var(--md-sys-color-on-primary)}.pfx-badge--filled-accent{background:var(--md-sys-color-secondary);color:var(--md-sys-color-on-secondary)}.pfx-badge--filled-warn{background:var(--md-sys-color-error);color:var(--md-sys-color-on-error)}.pfx-badge--outlined{background:transparent;border-color:var(--md-sys-color-outline-variant);color:inherit}.pfx-badge--soft-primary{background:var(--p-table-badge-soft-primary-bg);color:var(--p-table-badge-soft-primary-fg)}.pfx-badge--soft-accent{background:var(--p-table-badge-soft-accent-bg);color:var(--p-table-badge-soft-accent-fg)}.pfx-badge--soft-warn{background:var(--p-table-badge-soft-warn-bg);color:var(--p-table-badge-soft-warn-fg)}.row--success,.row--success td,td.row--success{background-color:var(--p-table-state-success-bg)!important;color:var(--p-table-state-success-fg)!important}.row--warning,.row--warning td,td.row--warning{background-color:var(--p-table-state-warning-bg)!important;color:var(--p-table-state-warning-fg)!important}.row--danger,.row--danger td,td.row--danger{background-color:var(--p-table-state-danger-bg)!important;color:var(--p-table-state-danger-fg)!important}.row--highlight,.row--highlight td,td.row--highlight{background-color:var(--p-table-state-highlight-bg)!important;color:var(--p-table-state-highlight-fg)!important;font-weight:600}.row--muted,.row--muted td,td.row--muted{opacity:.7;filter:saturate(.6)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i2$1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i2$1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i2$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i2$1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i2$1.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "directive", type: i2$1.NgSwitch, selector: "[ngSwitch]", inputs: ["ngSwitch"] }, { kind: "directive", type: i2$1.NgSwitchCase, selector: "[ngSwitchCase]", inputs: ["ngSwitchCase"] }, { kind: "directive", type: i2$1.NgSwitchDefault, selector: "[ngSwitchDefault]" }, { kind: "ngmodule", type: FormsModule }, { kind: "ngmodule", type: ScrollingModule }, { kind: "directive", type: i10$3.CdkScrollable, selector: "[cdk-scrollable], [cdkScrollable]" }, { kind: "directive", type: i11$1.ɵɵCdkFixedSizeVirtualScroll, selector: "cdk-virtual-scroll-viewport[itemSize]", inputs: ["itemSize", "minBufferPx", "maxBufferPx"] }, { kind: "directive", type: i11$1.ɵɵCdkVirtualForOf, selector: "[cdkVirtualFor][cdkVirtualForOf]", inputs: ["cdkVirtualForOf", "cdkVirtualForTrackBy", "cdkVirtualForTemplate", "cdkVirtualForTemplateCacheSize"] }, { kind: "component", type: i11$1.ɵɵCdkVirtualScrollViewport, selector: "cdk-virtual-scroll-viewport", inputs: ["orientation", "appendOnly"], outputs: ["scrolledIndexChange"] }, { kind: "ngmodule", type: DragDropModule }, { kind: "directive", type: i12.CdkDropList, selector: "[cdkDropList], cdk-drop-list", inputs: ["cdkDropListConnectedTo", "cdkDropListData", "cdkDropListOrientation", "id", "cdkDropListLockAxis", "cdkDropListDisabled", "cdkDropListSortingDisabled", "cdkDropListEnterPredicate", "cdkDropListSortPredicate", "cdkDropListAutoScrollDisabled", "cdkDropListAutoScrollStep", "cdkDropListElementContainer", "cdkDropListHasAnchor"], outputs: ["cdkDropListDropped", "cdkDropListEntered", "cdkDropListExited", "cdkDropListSorted"], exportAs: ["cdkDropList"] }, { kind: "directive", type: i12.CdkDrag, selector: "[cdkDrag]", inputs: ["cdkDragData", "cdkDragLockAxis", "cdkDragRootElement", "cdkDragBoundary", "cdkDragStartDelay", "cdkDragFreeDragPosition", "cdkDragDisabled", "cdkDragConstrainPosition", "cdkDragPreviewClass", "cdkDragPreviewContainer", "cdkDragScale"], outputs: ["cdkDragStarted", "cdkDragReleased", "cdkDragEnded", "cdkDragEntered", "cdkDragExited", "cdkDragDropped", "cdkDragMoved"], exportAs: ["cdkDrag"] }, { kind: "ngmodule", type: MatBadgeModule }, { kind: "directive", type: i15$2.MatBadge, selector: "[matBadge]", inputs: ["matBadgeColor", "matBadgeOverlap", "matBadgeDisabled", "matBadgePosition", "matBadge", "matBadgeDescription", "matBadgeSize", "matBadgeHidden"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i3.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.MatMiniFabButton, selector: "button[mat-mini-fab], a[mat-mini-fab], button[matMiniFab], a[matMiniFab]", exportAs: ["matButton", "matAnchor"] }, { kind: "component", type: i3.MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatCheckboxModule }, { kind: "component", type: i9.MatCheckbox, selector: "mat-checkbox", inputs: ["aria-label", "aria-labelledby", "aria-describedby", "aria-expanded", "aria-controls", "aria-owns", "id", "required", "labelPosition", "name", "value", "disableRipple", "tabIndex", "color", "disabledInteractive", "checked", "disabled", "indeterminate"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i5.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatMenuModule }, { kind: "component", type: i17.MatMenu, selector: "mat-menu", inputs: ["backdropClass", "aria-label", "aria-labelledby", "aria-describedby", "xPosition", "yPosition", "overlapTrigger", "hasBackdrop", "class", "classList"], outputs: ["closed", "close"], exportAs: ["matMenu"] }, { kind: "component", type: i17.MatMenuItem, selector: "[mat-menu-item]", inputs: ["role", "disabled", "disableRipple"], exportAs: ["matMenuItem"] }, { kind: "directive", type: i17.MatMenuTrigger, selector: "[mat-menu-trigger-for], [matMenuTriggerFor]", inputs: ["mat-menu-trigger-for", "matMenuTriggerFor", "matMenuTriggerData", "matMenuTriggerRestoreFocus"], outputs: ["menuOpened", "onMenuOpen", "menuClosed", "onMenuClose"], exportAs: ["matMenuTrigger"] }, { kind: "ngmodule", type: MatPaginatorModule }, { kind: "component", type: i18.MatPaginator, selector: "mat-paginator", inputs: ["color", "pageIndex", "length", "pageSize", "pageSizeOptions", "hidePageSize", "showFirstLastButtons", "selectConfig", "disabled"], outputs: ["page"], exportAs: ["matPaginator"] }, { kind: "ngmodule", type: MatSlideToggleModule }, { kind: "component", type: i6$1.MatSlideToggle, selector: "mat-slide-toggle", inputs: ["name", "id", "labelPosition", "aria-label", "aria-labelledby", "aria-describedby", "required", "color", "disabled", "disableRipple", "tabIndex", "checked", "hideIcon", "disabledInteractive"], outputs: ["change", "toggleChange"], exportAs: ["matSlideToggle"] }, { kind: "ngmodule", type: MatSnackBarModule }, { kind: "ngmodule", type: MatSortModule }, { kind: "directive", type: i20.MatSort, selector: "[matSort]", inputs: ["matSortActive", "matSortStart", "matSortDirection", "matSortDisableClear", "matSortDisabled"], outputs: ["matSortChange"], exportAs: ["matSort"] }, { kind: "component", type: i20.MatSortHeader, selector: "[mat-sort-header]", inputs: ["mat-sort-header", "arrowPosition", "start", "disabled", "sortActionDescription", "disableClear"], exportAs: ["matSortHeader"] }, { kind: "ngmodule", type: MatTableModule }, { kind: "component", type: i8.MatTable, selector: "mat-table, table[mat-table]", exportAs: ["matTable"] }, { kind: "directive", type: i8.MatHeaderCellDef, selector: "[matHeaderCellDef]" }, { kind: "directive", type: i8.MatHeaderRowDef, selector: "[matHeaderRowDef]", inputs: ["matHeaderRowDef", "matHeaderRowDefSticky"] }, { kind: "directive", type: i8.MatColumnDef, selector: "[matColumnDef]", inputs: ["matColumnDef"] }, { kind: "directive", type: i8.MatCellDef, selector: "[matCellDef]" }, { kind: "directive", type: i8.MatRowDef, selector: "[matRowDef]", inputs: ["matRowDefColumns", "matRowDefWhen"] }, { kind: "directive", type: i8.MatHeaderCell, selector: "mat-header-cell, th[mat-header-cell]" }, { kind: "directive", type: i8.MatCell, selector: "mat-cell, td[mat-cell]" }, { kind: "component", type: i8.MatHeaderRow, selector: "mat-header-row, tr[mat-header-row]", exportAs: ["matHeaderRow"] }, { kind: "component", type: i8.MatRow, selector: "mat-row, tr[mat-row]", exportAs: ["matRow"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i10.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "component", type: PraxisFilter, selector: "praxis-filter", inputs: ["resourcePath", "fieldMetadata", "filterId", "formId", "componentInstanceId", "mode", "notifyIfOutdated", "snoozeMs", "autoOpenSettingsOnOutdated", "enableCustomization", "value", "alwaysVisibleFields", "alwaysVisibleFieldMetadataOverrides", "selectedFieldIds", "tags", "allowSaveTags", "persistenceKey", "disablePersistence", "i18n", "changeDebounceMs", "showFilterSettings", "showAdvancedButton", "showAddButton", "showClearButton", "showSearchButton", "confirmTagDelete", "placeBooleansInActions", "showToggleLabels", "useInlineSelectVariant", "useInlineSearchableSelectVariant", "useInlineMultiSelectVariant", "useInlineInputVariant", "useInlineToggleVariant", "useInlineRangeVariant", "useInlineDateVariant", "useInlineDateRangeVariant", "useInlineTimeVariant", "useInlineTimeRangeVariant", "useInlineTreeSelectVariant", "alwaysMinWidth", "alwaysColsMd", "alwaysColsLg", "tagColor", "tagVariant", "tagButtonColor", "actionsButtonColor", "actionsVariant", "overlayVariant", "overlayBackdrop", "advancedOpenMode", "advancedClearButtonsEnabled"], outputs: ["submit", "change", "clear", "modeChange", "requestSearch", "tagsChange", "selectedFieldIdsChange", "metaChanged", "schemaStatusChange"] }, { kind: "directive", type: PraxisIconDirective, selector: "mat-icon[praxisIcon]", inputs: ["praxisIcon"] }, { kind: "component", type: PraxisTableToolbar, selector: "praxis-table-toolbar", inputs: ["config", "backgroundColor", "placement", "showMain", "showActionsGroup", "showEndActions", "showMobileActions", "showReset", "evaluationContext"], outputs: ["toolbarAction", "reset"] }, { kind: "component", type: EmptyStateCardComponent, selector: "praxis-empty-state-card", inputs: ["icon", "title", "description", "primaryAction", "secondaryActions", "inline", "tone"] }, { kind: "component", type: TableRatingCellComponent, selector: "praxis-table-rating", inputs: ["itemsCount", "value", "size", "ratingColor", "outlineColor", "ariaLabel"] }], deferBlockDependencies: [() => [import('@praxisui/ai').then(m => m.PraxisAiAssistantComponent)], () => [import('@praxisui/ai').then(m => m.PraxisAiAssistantComponent)], () => [import('@praxisui/ai').then(m => m.PraxisAiAssistantComponent)], () => [import('@praxisui/ai').then(m => m.PraxisAiAssistantComponent)]] });
|
|
47081
|
+
], queries: [{ propertyName: "toolbar", first: true, predicate: PraxisTableToolbar, descendants: true }, { propertyName: "projectedFilter", first: true, predicate: ["projectedFilter"], descendants: true }], viewQueries: [{ propertyName: "paginator", first: true, predicate: MatPaginator, descendants: true }, { propertyName: "sort", first: true, predicate: MatSort, descendants: true }, { propertyName: "materialTable", first: true, predicate: MatTable, descendants: true }, { propertyName: "internalFilter", first: true, predicate: PraxisFilter, descendants: true }], usesOnChanges: true, ngImport: i0, template: "@if (shouldShowEmptyState()) {\n <praxis-empty-state-card\n icon=\"link\"\n [title]=\"'Conecte a tabela \u00C3\u00A0 fonte de dados'\"\n [description]=\"'Informe a rota do recurso da API para carregar colunas e dados automaticamente.'\"\n [primaryAction]=\"{ label: 'Conectar \u00C3\u00A0 fonte de dados', icon: 'bolt', action: openQuickConnect.bind(this) }\"\n ></praxis-empty-state-card>\n}\n\n<!-- Error State with Quick Connect CTA -->\n@if (isRemoteMode() && (schemaError || dataError)) {\n<div class=\"ptable-error\" role=\"alert\" aria-live=\"assertive\">\n <mat-icon color=\"warn\" aria-hidden=\"true\">error</mat-icon>\n <div class=\"ptable-error__content\">\n <praxis-rich-content\n rootClassName=\"ptable-error__title\"\n [nodes]=\"getTableChromeTextRichContentNodes('Erro', 'ptable-error__title-text')\"\n ></praxis-rich-content>\n <praxis-rich-content\n rootClassName=\"ptable-error__message\"\n [nodes]=\"getTableChromeTextRichContentNodes(errorMessage || 'Ocorreu um erro ao carregar a tabela.', 'ptable-error__message-text')\"\n ></praxis-rich-content>\n </div>\n <button mat-flat-button color=\"primary\" (click)=\"openQuickConnect()\">\n <mat-icon>bolt</mat-icon>\n <praxis-rich-content\n rootClassName=\"ptable-error__action-label\"\n [nodes]=\"getTableChromeTextRichContentNodes('Conectar a recurso', 'ptable-error__action-label-text')\"\n ></praxis-rich-content>\n </button>\n @if (enableCustomization) {\n <button\n mat-icon-button\n color=\"primary\"\n data-role=\"table-settings\"\n data-testid=\"table-settings-trigger\"\n (click)=\"openTableSettings()\"\n [attr.aria-label]=\"getTableSettingsLabel()\"\n [matTooltip]=\"getTableSettingsLabel()\"\n matTooltipPosition=\"below\"\n >\n <mat-icon>settings</mat-icon>\n </button>\n }\n @if (!schemaError) {\n <button mat-stroked-button (click)=\"retryData()\">\n <praxis-rich-content\n rootClassName=\"ptable-error__action-label\"\n [nodes]=\"getTableChromeTextRichContentNodes('Tentar novamente', 'ptable-error__action-label-text')\"\n ></praxis-rich-content>\n </button>\n }\n @if (schemaError) {\n <button mat-stroked-button (click)=\"reloadSchema()\">\n <praxis-rich-content\n rootClassName=\"ptable-error__action-label\"\n [nodes]=\"getTableChromeTextRichContentNodes('Recarregar colunas', 'ptable-error__action-label-text')\"\n ></praxis-rich-content>\n </button>\n }\n </div>\n}\n\n<!-- Inline banner for schema change (only in edit mode) -->\n@if (shouldShowOutdatedInline()) {\n<div class=\"ptable-info-banner\" role=\"status\" aria-live=\"polite\">\n <praxis-rich-content\n rootClassName=\"text\"\n [nodes]=\"getTableChromeTextRichContentNodes('O schema do servidor mudou. Reconciliar agora?', 'ptable-info-banner__text')\"\n ></praxis-rich-content>\n <div class=\"actions\">\n <button mat-stroked-button color=\"primary\" (click)=\"onReconcileRequested()\">\n <mat-icon>sync</mat-icon>\n <praxis-rich-content\n rootClassName=\"ptable-info-banner__action-label\"\n [nodes]=\"getTableChromeTextRichContentNodes('Reconciliar', 'ptable-info-banner__action-label-text')\"\n ></praxis-rich-content>\n </button>\n <button mat-button (click)=\"onSnoozeOutdated()\">\n <praxis-rich-content\n rootClassName=\"ptable-info-banner__action-label\"\n [nodes]=\"getTableChromeTextRichContentNodes('Lembrar depois', 'ptable-info-banner__action-label-text')\"\n ></praxis-rich-content>\n </button>\n <button mat-button (click)=\"onIgnoreOutdated()\">\n <praxis-rich-content\n rootClassName=\"ptable-info-banner__action-label\"\n [nodes]=\"getTableChromeTextRichContentNodes('Ignorar', 'ptable-info-banner__action-label-text')\"\n ></praxis-rich-content>\n </button>\n </div>\n </div>\n}\n\n@if (shouldRenderDataSurface() && !schemaError && !dataError && toolbarV2) {\n <div class=\"praxis-table-header\" [class.edit-mode]=\"enableCustomization\" [class.stacked]=\"showToolbar\">\n @if (showToolbar && shouldShowToolbarTopPlacement()) {\n <praxis-table-toolbar\n [config]=\"config\"\n [backgroundColor]=\"getToolbarActionsBackgroundColor()\"\n [style.--pfx-filter-h]=\"getToolbarLayoutHeightHostStyle()\"\n [evaluationContext]=\"getToolbarEvaluationContext()\"\n [showActionsGroup]=\"shouldShowToolbarActionsTop()\"\n [showMobileActions]=\"shouldShowToolbarActionsTop()\"\n (toolbarAction)=\"onToolbarAction($event)\"\n (reset)=\"onResetPreferences()\"\n >\n @if (shouldRenderAdvancedFilter()) {\n <praxis-filter\n advancedFilter\n [resourcePath]=\"getAdvancedFilterResourcePath()\"\n [filterId]=\"tableId\"\n [formId]=\"tableId\"\n [persistenceKey]=\"getAdvancedFilterPersistenceKey()\"\n [fieldMetadata]=\"getAdvancedFilterFieldMetadata()\"\n [enableCustomization]=\"enableCustomization\"\n \n [alwaysVisibleFields]=\"config.behavior?.filtering?.advancedFilters?.settings?.alwaysVisibleFields\"\n [alwaysVisibleFieldMetadataOverrides]=\"config.behavior?.filtering?.advancedFilters?.settings?.alwaysVisibleFieldMetadataOverrides ?? {}\"\n [selectedFieldIds]=\"config.behavior?.filtering?.advancedFilters?.settings?.selectedFieldIds ?? []\"\n [allowSaveTags]=\"config.behavior?.filtering?.advancedFilters?.settings?.allowSaveTags\"\n [changeDebounceMs]=\"config.behavior?.filtering?.advancedFilters?.settings?.changeDebounceMs ?? 300\"\n [i18n]=\"getFilterI18n()\"\n [mode]=\"'filter'\"\n [showFilterSettings]=\"enableCustomization\"\n (change)=\"onAdvancedFilterChange($event)\"\n (requestSearch)=\"onAdvancedFilterSubmit($event)\"\n (clear)=\"onAdvancedFilterClear()\"\n ></praxis-filter>\n }\n <ng-content select=\"[advancedFilter]\" />\n <ng-content select=\"[toolbar]\" />\n \n <!-- AI Assistant in Toolbar -->\n @defer (on idle) {\n @if (aiAdapter) {\n <praxis-ai-assistant [adapter]=\"aiAdapter\" end-actions></praxis-ai-assistant>\n }\n }\n\n @if (enableCustomization) {\n <button end-actions mat-icon-button color=\"primary\" data-role=\"table-settings\" data-testid=\"table-settings-trigger\"\n (click)=\"openTableSettings()\" [attr.aria-label]=\"getTableSettingsLabel()\"\n [matBadge]=\"schemaOutdated ? '!' : ''\"\n [matBadgeHidden]=\"!schemaOutdated\"\n matBadgeColor=\"warn\" matBadgeSize=\"small\" matBadgePosition=\"above after\"\n [matTooltip]=\"getTableSettingsTooltip()\"\n matTooltipPosition=\"below\">\n <mat-icon>settings</mat-icon>\n </button>\n }\n </praxis-table-toolbar>\n }\n @if (!showToolbar && enableCustomization) {\n <div class=\"ptable-header-actions\">\n @defer (on idle) {\n @if (aiAdapter) {\n <praxis-ai-assistant [adapter]=\"aiAdapter\"></praxis-ai-assistant>\n }\n }\n <button mat-icon-button color=\"primary\" data-role=\"table-settings\" data-testid=\"table-settings-trigger\" (click)=\"openTableSettings()\" [attr.aria-label]=\"getTableSettingsLabel()\"\n [matBadge]=\"schemaOutdated ? '!' : ''\"\n [matBadgeHidden]=\"!schemaOutdated\"\n matBadgeColor=\"warn\" matBadgeSize=\"small\" matBadgePosition=\"above after\"\n [matTooltip]=\"getTableSettingsTooltip()\"\n matTooltipPosition=\"below\">\n <mat-icon>settings</mat-icon>\n </button>\n @if (isRemoteMode()) {\n <button mat-icon-button (click)=\"disconnect()\" [attr.aria-label]=\"getDisconnectLabel()\" [matTooltip]=\"getDisconnectTooltip()\">\n <mat-icon>link_off</mat-icon>\n </button>\n }\n </div>\n }\n </div>\n} @else {\n @if (shouldRenderDataSurface() && !schemaError && !dataError) {\n @if (showToolbar && shouldShowToolbarTopPlacement()) {\n <praxis-table-toolbar\n [config]=\"config\"\n [backgroundColor]=\"getToolbarActionsBackgroundColor()\"\n [style.--pfx-filter-h]=\"getToolbarLayoutHeightHostStyle()\"\n [evaluationContext]=\"getToolbarEvaluationContext()\"\n [showActionsGroup]=\"shouldShowToolbarActionsTop()\"\n [showMobileActions]=\"shouldShowToolbarActionsTop()\"\n (toolbarAction)=\"onToolbarAction($event)\"\n (reset)=\"onResetPreferences()\"\n >\n @if (shouldRenderAdvancedFilter()) {\n <praxis-filter\n advancedFilter\n [resourcePath]=\"getAdvancedFilterResourcePath()\"\n [filterId]=\"tableId\"\n [formId]=\"tableId\"\n [persistenceKey]=\"getAdvancedFilterPersistenceKey()\"\n [fieldMetadata]=\"getAdvancedFilterFieldMetadata()\"\n [enableCustomization]=\"enableCustomization\"\n \n [alwaysVisibleFields]=\"config.behavior?.filtering?.advancedFilters?.settings?.alwaysVisibleFields\"\n [alwaysVisibleFieldMetadataOverrides]=\"config.behavior?.filtering?.advancedFilters?.settings?.alwaysVisibleFieldMetadataOverrides ?? {}\"\n [selectedFieldIds]=\"config.behavior?.filtering?.advancedFilters?.settings?.selectedFieldIds ?? []\"\n [allowSaveTags]=\"config.behavior?.filtering?.advancedFilters?.settings?.allowSaveTags\"\n [changeDebounceMs]=\"config.behavior?.filtering?.advancedFilters?.settings?.changeDebounceMs ?? 300\"\n [i18n]=\"getFilterI18n()\"\n [mode]=\"'filter'\"\n [showFilterSettings]=\"enableCustomization\"\n (change)=\"onAdvancedFilterChange($event)\"\n (requestSearch)=\"onAdvancedFilterSubmit($event)\"\n (clear)=\"onAdvancedFilterClear()\"\n ></praxis-filter>\n }\n <ng-content select=\"[advancedFilter]\" />\n <ng-content select=\"[toolbar]\" />\n @defer (on idle) {\n @if (aiAdapter) {\n <praxis-ai-assistant [adapter]=\"aiAdapter\" end-actions></praxis-ai-assistant>\n }\n }\n @if (enableCustomization) {\n <button end-actions mat-icon-button color=\"primary\" data-role=\"table-settings\" data-testid=\"table-settings-trigger\"\n (click)=\"openTableSettings()\" [attr.aria-label]=\"getTableSettingsLabel()\"\n [matBadge]=\"schemaOutdated ? '!' : ''\"\n [matBadgeHidden]=\"!schemaOutdated\"\n matBadgeColor=\"warn\" matBadgeSize=\"small\" matBadgePosition=\"above after\"\n [matTooltip]=\"getTableSettingsTooltip()\"\n matTooltipPosition=\"below\">\n <mat-icon>settings</mat-icon>\n </button>\n }\n </praxis-table-toolbar>\n }\n @if (!showToolbar && enableCustomization) {\n <div class=\"ptable-header-actions\">\n <button mat-icon-button color=\"primary\" data-role=\"table-settings\" data-testid=\"table-settings-trigger\" (click)=\"openTableSettings()\" [attr.aria-label]=\"getTableSettingsLabel()\"\n [matBadge]=\"schemaOutdated ? '!' : ''\"\n [matBadgeHidden]=\"!schemaOutdated\"\n matBadgeColor=\"warn\" matBadgeSize=\"small\" matBadgePosition=\"above after\"\n [matTooltip]=\"getTableSettingsTooltip()\"\n matTooltipPosition=\"below\">\n <mat-icon>settings</mat-icon>\n </button>\n </div>\n }\n }\n}\n<div class=\"px-scroll-viewport\"\n cdkScrollable\n [class.scroll-auto]=\"horizontalScroll === 'auto'\"\n [class.scroll-wrap]=\"horizontalScroll === 'wrap'\"\n [class.scroll-none]=\"horizontalScroll === 'none'\">\n\n@if (shouldRenderDataSurface() && !schemaError && !dataError) {\n<div class=\"praxis-visually-hidden-status\" role=\"status\" aria-live=\"polite\" aria-atomic=\"true\">\n {{ columnReorderStatusMessage }}\n</div>\n@if (columnReorderVisualStatusMessage) {\n <div class=\"praxis-column-reorder-status\" role=\"note\">\n {{ columnReorderVisualStatusMessage }}\n </div>\n}\n<table\n mat-table\n data-testid=\"table-column-drag-drop-list\"\n [dataSource]=\"dataSource\"\n [multiTemplateDataRows]=\"isRowExpansionRuntimeEnabled()\"\n cdkDropList\n [cdkDropListDisabled]=\"!isColumnDraggingEnabled()\"\n [cdkDropListData]=\"visibleDataColumnsForDrag\"\n cdkDropListOrientation=\"horizontal\"\n (cdkDropListDropped)=\"onColumnDrop($event)\"\n matSort\n (matSortChange)=\"onSortChange($event)\"\n [matSortDisabled]=\"!getSortingEnabled()\"\n [ngClass]=\"getTableElevationClassName()\"\n [class.table-stack-top]=\"showToolbar\"\n [class.pfx-column-drag-enabled]=\"isColumnDraggingEnabled()\"\n [class.pfx-column-drag-indicator]=\"isColumnDragIndicatorEnabled()\"\n>\n @if (config.behavior?.selection?.enabled) {\n <ng-container\n matColumnDef=\"_select\"\n >\n <th mat-header-cell *matHeaderCellDef>\n @if (canSelectAll()) {\n <mat-checkbox\n (change)=\"masterToggle()\"\n [checked]=\"isAllSelected()\"\n [indeterminate]=\"selection.hasValue() && !isAllSelected()\"\n ></mat-checkbox>\n }\n </th>\n <td mat-cell *matCellDef=\"let row\">\n <mat-checkbox\n (click)=\"$event.stopPropagation()\"\n (change)=\"toggleRow(row)\"\n [checked]=\"selection.isSelected(row)\"\n ></mat-checkbox>\n </td>\n </ng-container>\n }\n @if (isRowExpansionRuntimeEnabled()) {\n <ng-container matColumnDef=\"_expander\">\n <th mat-header-cell *matHeaderCellDef class=\"pfx-expansion-col-header\">\n <span class=\"praxis-visually-hidden-status\">Expandir detalhes da linha</span>\n </th>\n <td mat-cell *matCellDef=\"let row; let i = index\" class=\"pfx-expansion-col-cell\">\n <button\n mat-icon-button\n class=\"pfx-expansion-toggle\"\n [disabled]=\"!isRowExpandable(row, i) || !isExpansionIconTriggerEnabled()\"\n [attr.aria-expanded]=\"isRowExpanded(row, i) ? 'true' : 'false'\"\n [attr.aria-controls]=\"getRowExpansionDetailId(row, i)\"\n [attr.aria-label]=\"getRowExpansionToggleAriaLabel(row, i)\"\n (click)=\"onExpansionToggleFromIcon(row, i, $event)\"\n (keydown)=\"onExpansionToggleKeydown($event, row, i)\"\n >\n <mat-icon [praxisIcon]=\"isRowExpanded(row, i)\n ? getExpansionExpandedIcon()\n : getExpansionCollapsedIcon()\"></mat-icon>\n </button>\n </td>\n </ng-container>\n }\n @for (column of visibleColumns; track column.field) {\n <ng-container\n [matColumnDef]=\"column.field\"\n [sticky]=\"column.sticky === true || column.sticky === 'start'\"\n [stickyEnd]=\"column.sticky === 'end'\"\n >\n <th\n mat-header-cell\n *matHeaderCellDef\n mat-sort-header\n cdkDrag\n [cdkDragData]=\"column\"\n cdkDragLockAxis=\"x\"\n cdkDragPreviewClass=\"pfx-column-drag-preview\"\n (cdkDragStarted)=\"onColumnDragStarted(column)\"\n (cdkDragEnded)=\"onColumnDragEnded($event, column)\"\n (keydown)=\"onColumnDragHandleKeydown($event, column)\"\n [cdkDragDisabled]=\"!isColumnDraggingEnabled() || !isColumnDraggable(column)\"\n [class.praxis-header-draggable]=\"isColumnDraggingEnabled() && isColumnDraggable(column)\"\n [disabled]=\"!getSortingEnabled() || column.sortable === false\"\n [style.text-align]=\"getColumnTextAlignStyle(column)\"\n [style.width]=\"getColumnWidthStyle(column)\"\n [attr.style]=\"getColumnHeaderAttrStyle(column)\"\n [attr.aria-label]=\"isColumnDraggingEnabled() && isColumnDraggable(column) ? getColumnDragHandleAriaLabel(column) : null\"\n >\n <span class=\"praxis-header-label\" data-testid=\"column-header-label\">\n @if (isColumnDraggingEnabled() && isColumnDraggable(column)) {\n <span\n class=\"praxis-column-drag-handle\"\n data-testid=\"column-drag-handle\"\n [attr.data-column-field]=\"column.field\"\n aria-hidden=\"true\"\n >\n <mat-icon [praxisIcon]=\"'drag_indicator'\"></mat-icon>\n </span>\n }\n <span class=\"praxis-header-label-text\">{{ column.header }}</span>\n </span>\n </th>\n <td\n mat-cell\n *matCellDef=\"let element\"\n [style.text-align]=\"getColumnTextAlignStyle(column)\"\n [style.width]=\"getColumnWidthStyle(column)\"\n [attr.style]=\"getColumnCellAttrStyle(column)\"\n [ngClass]=\"getCellClasses(element, column)\"\n [ngStyle]=\"getCellNgStyle(element, column)\"\n >\n <div\n class=\"pfx-cell-content\"\n [ngClass]=\"getCellContentClasses(element, column)\"\n [ngStyle]=\"getCellContentNgStyle(element, column)\"\n >\n <ng-container [ngSwitch]=\"getEffectiveRendererType(element, column)\">\n <!-- Icon renderer -->\n <ng-container *ngSwitchCase=\"'icon'\">\n <span\n class=\"pfx-icon-renderer\"\n [style.color]=\"getIconColor(element, column) || null\"\n [ngStyle]=\"getIconStyle(element, column)\"\n [attr.aria-label]=\"getIconAriaLabel(element, column) || null\"\n >\n <praxis-rich-content\n rootClassName=\"pfx-icon-renderer__content\"\n [nodes]=\"getIconRichContentNodes(element, column)\"\n ></praxis-rich-content>\n </span>\n </ng-container>\n\n <!-- Image renderer -->\n <ng-container *ngSwitchCase=\"'image'\">\n <span class=\"pfx-cell-image\">\n <praxis-rich-content\n rootClassName=\"pfx-cell-image__content\"\n [nodes]=\"getImageRichContentNodes(element, column)\"\n ></praxis-rich-content>\n </span>\n </ng-container>\n\n <!-- Badge renderer -->\n <ng-container *ngSwitchCase=\"'badge'\">\n <span class=\"pfx-badge\" [ngClass]=\"getBadgeClasses(element, column)\">\n <praxis-rich-content\n rootClassName=\"pfx-badge__content\"\n [nodes]=\"getBadgeRichContentNodes(element, column)\"\n ></praxis-rich-content>\n </span>\n </ng-container>\n\n <!-- Link renderer -->\n <ng-container *ngSwitchCase=\"'link'\">\n <a\n class=\"pfx-link\"\n [attr.href]=\"getLinkHref(element, column) || null\"\n [attr.target]=\"getLinkTarget(element, column) || null\"\n [attr.rel]=\"getLinkRel(element, column) || null\"\n (click)=\"$event.stopPropagation()\"\n ><praxis-rich-content\n rootClassName=\"pfx-link__content\"\n [nodes]=\"getLinkRichContentNodes(element, column)\"\n ></praxis-rich-content></a\n >\n </ng-container>\n\n <!-- Button renderer -->\n <ng-container *ngSwitchCase=\"'button'\">\n <ng-container [ngSwitch]=\"getButtonVariant(element, column)\">\n <button\n *ngSwitchCase=\"'outlined'\"\n mat-stroked-button\n [color]=\"getButtonColor(element, column) || null\"\n [disabled]=\"isButtonDisabled(element, column)\"\n [attr.aria-label]=\"getButtonAriaLabel(element, column) || getButtonLabel(element, column)\"\n (click)=\"onButtonClick(element, column, $event)\"\n >\n <praxis-rich-content\n rootClassName=\"pfx-button-renderer__content\"\n [nodes]=\"getButtonRichContentNodes(element, column)\"\n ></praxis-rich-content>\n </button>\n <button\n *ngSwitchCase=\"'text'\"\n mat-button\n [color]=\"getButtonColor(element, column) || null\"\n [disabled]=\"isButtonDisabled(element, column)\"\n [attr.aria-label]=\"getButtonAriaLabel(element, column) || getButtonLabel(element, column)\"\n (click)=\"onButtonClick(element, column, $event)\"\n >\n <praxis-rich-content\n rootClassName=\"pfx-button-renderer__content\"\n [nodes]=\"getButtonRichContentNodes(element, column)\"\n ></praxis-rich-content>\n </button>\n <button\n *ngSwitchDefault\n mat-flat-button\n [color]=\"getButtonColor(element, column) || null\"\n [disabled]=\"isButtonDisabled(element, column)\"\n [attr.aria-label]=\"getButtonAriaLabel(element, column) || getButtonLabel(element, column)\"\n (click)=\"onButtonClick(element, column, $event)\"\n >\n <praxis-rich-content\n rootClassName=\"pfx-button-renderer__content\"\n [nodes]=\"getButtonRichContentNodes(element, column)\"\n ></praxis-rich-content>\n </button>\n </ng-container>\n </ng-container>\n\n <!-- Chip renderer -->\n <ng-container *ngSwitchCase=\"'chip'\">\n <span class=\"pfx-chip\" [ngClass]=\"getChipClasses(element, column)\">\n <praxis-rich-content\n rootClassName=\"pfx-chip__content\"\n [nodes]=\"getChipRichContentNodes(element, column)\"\n ></praxis-rich-content>\n </span>\n </ng-container>\n\n <!-- Progress renderer -->\n <ng-container *ngSwitchCase=\"'progress'\">\n <div class=\"pfx-progress\">\n <praxis-rich-content\n rootClassName=\"pfx-progress__content\"\n [context]=\"getProgressRichContentContext(element, column)\"\n [nodes]=\"getProgressRichContentNodes(element, column)\"\n ></praxis-rich-content>\n </div>\n </ng-container>\n\n <!-- Avatar renderer -->\n <ng-container *ngSwitchCase=\"'avatar'\">\n <span class=\"pfx-avatar-renderer\"\n [ngStyle]=\"getAvatarStyle(element, column)\"\n [class.shape-rounded]=\"getAvatarShape(element, column) === 'rounded'\"\n [class.shape-circle]=\"getAvatarShape(element, column) === 'circle'\">\n <praxis-rich-content\n rootClassName=\"pfx-avatar-renderer__content\"\n [nodes]=\"getAvatarRichContentNodes(element, column)\"\n ></praxis-rich-content>\n </span>\n </ng-container>\n\n <!-- Toggle renderer -->\n <ng-container *ngSwitchCase=\"'toggle'\">\n <mat-slide-toggle\n [checked]=\"getToggleState(element, column)\"\n [disabled]=\"isToggleDisabled(element, column)\"\n [attr.aria-label]=\"getToggleAriaLabel(element, column) || 'Alternar'\"\n (change)=\"onToggleChange(element, column, $event)\"\n (click)=\"$event.stopPropagation()\"\n ></mat-slide-toggle>\n </ng-container>\n\n <!-- Menu renderer -->\n <ng-container *ngSwitchCase=\"'menu'\">\n <button mat-icon-button [matMenuTriggerFor]=\"menuRef\" (click)=\"$event.stopPropagation()\" [attr.aria-label]=\"getMenuAriaLabel(element, column) || 'Menu'\">\n <praxis-rich-content rootClassName=\"pfx-menu-trigger__content\" [nodes]=\"getMenuTriggerRichContentNodes()\"></praxis-rich-content>\n </button>\n <mat-menu #menuRef=\"matMenu\">\n <button mat-menu-item *ngFor=\"let it of getMenuItems(element, column)\" (click)=\"onMenuItemClick(it, element, $event)\" [disabled]=\"!it.__visible\" >\n <praxis-rich-content\n rootClassName=\"pfx-menu-item__content\"\n [nodes]=\"getMenuItemRichContentNodes(it)\"\n ></praxis-rich-content>\n </button>\n </mat-menu>\n </ng-container>\n\n <!-- Rating renderer -->\n <ng-container *ngSwitchCase=\"'rating'\">\n <praxis-table-rating\n class=\"pfx-rating-cell\"\n [itemsCount]=\"getRatingMax(element, column)\"\n [value]=\"getRatingValue(element, column)\"\n [size]=\"getRatingSize(element, column)\"\n [ratingColor]=\"getRatingColor(element, column)\"\n [outlineColor]=\"getRatingOutlineColor(element, column)\"\n [ariaLabel]=\"getRatingAriaLabel(element, column) || column.header\">\n </praxis-table-rating>\n </ng-container>\n\n <!-- HTML renderer (sanitizado) -->\n <ng-container *ngSwitchCase=\"'html'\">\n <span [innerHTML]=\"getSafeHtml(element, column)\"></span>\n </ng-container>\n\n <!-- Compose renderer -->\n <ng-container *ngSwitchCase=\"'compose'\">\n <span class=\"pfx-cell-compose\" [ngClass]=\"getComposeClasses(element, column)\" [ngStyle]=\"getComposeGapStyle(element, column)\">\n <ng-container *ngFor=\"let it of getComposeItems(element, column)\">\n <ng-container [ngSwitch]=\"getItemEffectiveType(element, column, it)\">\n <!-- Reuse helpers by projecting item as faux column -->\n <ng-container *ngSwitchCase=\"'icon'\">\n <span class=\"pfx-icon-renderer\" [style.color]=\"getIconColor(element, asItemColumn(column, it)) || null\" [ngStyle]=\"getIconStyle(element, asItemColumn(column, it))\" [attr.aria-label]=\"getIconAriaLabel(element, asItemColumn(column, it)) || null\"><praxis-rich-content rootClassName=\"pfx-icon-renderer__content\" [nodes]=\"getIconRichContentNodes(element, asItemColumn(column, it))\"></praxis-rich-content></span>\n </ng-container>\n <ng-container *ngSwitchCase=\"'image'\">\n <span class=\"pfx-cell-image\"><praxis-rich-content rootClassName=\"pfx-cell-image__content\" [nodes]=\"getImageRichContentNodes(element, asItemColumn(column, it))\"></praxis-rich-content></span>\n </ng-container>\n <ng-container *ngSwitchCase=\"'badge'\">\n <span class=\"pfx-badge\" [ngClass]=\"getBadgeClasses(element, asItemColumn(column, it))\"><praxis-rich-content rootClassName=\"pfx-badge__content\" [nodes]=\"getBadgeRichContentNodes(element, asItemColumn(column, it))\"></praxis-rich-content></span>\n </ng-container>\n <ng-container *ngSwitchCase=\"'link'\">\n <a class=\"pfx-link\" [attr.href]=\"getLinkHref(element, asItemColumn(column, it)) || null\" [attr.target]=\"getLinkTarget(element, asItemColumn(column, it)) || null\" [attr.rel]=\"getLinkRel(element, asItemColumn(column, it)) || null\" (click)=\"$event.stopPropagation()\"><praxis-rich-content rootClassName=\"pfx-link__content\" [nodes]=\"getLinkRichContentNodes(element, asItemColumn(column, it))\"></praxis-rich-content></a>\n </ng-container>\n <ng-container *ngSwitchCase=\"'button'\">\n <ng-container [ngSwitch]=\"getButtonVariant(element, asItemColumn(column, it))\">\n <button *ngSwitchCase=\"'outlined'\" mat-stroked-button [color]=\"getButtonColor(element, asItemColumn(column, it)) || null\" [disabled]=\"isButtonDisabled(element, asItemColumn(column, it))\" [attr.aria-label]=\"getButtonAriaLabel(element, asItemColumn(column, it)) || getButtonLabel(element, asItemColumn(column, it))\" (click)=\"onButtonClick(element, asItemColumn(column, it), $event)\"><praxis-rich-content rootClassName=\"pfx-button-renderer__content\" [nodes]=\"getButtonRichContentNodes(element, asItemColumn(column, it))\"></praxis-rich-content></button>\n <button *ngSwitchCase=\"'text'\" mat-button [color]=\"getButtonColor(element, asItemColumn(column, it)) || null\" [disabled]=\"isButtonDisabled(element, asItemColumn(column, it))\" [attr.aria-label]=\"getButtonAriaLabel(element, asItemColumn(column, it)) || getButtonLabel(element, asItemColumn(column, it))\" (click)=\"onButtonClick(element, asItemColumn(column, it), $event)\"><praxis-rich-content rootClassName=\"pfx-button-renderer__content\" [nodes]=\"getButtonRichContentNodes(element, asItemColumn(column, it))\"></praxis-rich-content></button>\n <button *ngSwitchDefault mat-flat-button [color]=\"getButtonColor(element, asItemColumn(column, it)) || null\" [disabled]=\"isButtonDisabled(element, asItemColumn(column, it))\" [attr.aria-label]=\"getButtonAriaLabel(element, asItemColumn(column, it)) || getButtonLabel(element, asItemColumn(column, it))\" (click)=\"onButtonClick(element, asItemColumn(column, it), $event)\"><praxis-rich-content rootClassName=\"pfx-button-renderer__content\" [nodes]=\"getButtonRichContentNodes(element, asItemColumn(column, it))\"></praxis-rich-content></button>\n </ng-container>\n </ng-container>\n <ng-container *ngSwitchCase=\"'chip'\">\n <span class=\"pfx-chip\" [ngClass]=\"getChipClasses(element, asItemColumn(column, it))\"><praxis-rich-content rootClassName=\"pfx-chip__content\" [nodes]=\"getChipRichContentNodes(element, asItemColumn(column, it))\"></praxis-rich-content></span>\n </ng-container>\n <ng-container *ngSwitchCase=\"'progress'\">\n <div class=\"pfx-progress\">\n <praxis-rich-content\n rootClassName=\"pfx-progress__content\"\n [context]=\"getProgressRichContentContext(element, asItemColumn(column, it))\"\n [nodes]=\"getProgressRichContentNodes(element, asItemColumn(column, it))\"\n ></praxis-rich-content>\n </div>\n </ng-container>\n <ng-container *ngSwitchCase=\"'avatar'\">\n <span class=\"pfx-avatar-renderer\" [ngStyle]=\"getAvatarStyle(element, asItemColumn(column, it))\" [class.shape-rounded]=\"getAvatarShape(element, asItemColumn(column, it)) === 'rounded'\" [class.shape-circle]=\"getAvatarShape(element, asItemColumn(column, it)) === 'circle'\"><praxis-rich-content rootClassName=\"pfx-avatar-renderer__content\" [nodes]=\"getAvatarRichContentNodes(element, asItemColumn(column, it))\"></praxis-rich-content></span>\n </ng-container>\n <ng-container *ngSwitchCase=\"'toggle'\">\n <mat-slide-toggle [checked]=\"getToggleState(element, asItemColumn(column, it))\" [disabled]=\"isToggleDisabled(element, asItemColumn(column, it))\" [attr.aria-label]=\"getToggleAriaLabel(element, asItemColumn(column, it)) || 'Alternar'\" (change)=\"onToggleChange(element, asItemColumn(column, it), $event)\" (click)=\"$event.stopPropagation()\"></mat-slide-toggle>\n </ng-container>\n <ng-container *ngSwitchCase=\"'menu'\">\n <button mat-icon-button [matMenuTriggerFor]=\"menuRef\" (click)=\"$event.stopPropagation()\" [attr.aria-label]=\"getMenuAriaLabel(element, asItemColumn(column, it)) || 'Menu'\"><praxis-rich-content rootClassName=\"pfx-menu-trigger__content\" [nodes]=\"getMenuTriggerRichContentNodes()\"></praxis-rich-content></button>\n <mat-menu #menuRef=\"matMenu\">\n <button mat-menu-item *ngFor=\"let mi of getMenuItems(element, asItemColumn(column, it))\" (click)=\"onMenuItemClick(mi, element, $event)\" [disabled]=\"!mi.__visible\">\n <praxis-rich-content\n rootClassName=\"pfx-menu-item__content\"\n [nodes]=\"getMenuItemRichContentNodes(mi)\"\n ></praxis-rich-content>\n </button>\n </mat-menu>\n </ng-container>\n <ng-container *ngSwitchCase=\"'rating'\">\n <praxis-table-rating\n class=\"pfx-rating-cell\"\n [itemsCount]=\"getRatingMax(element, asItemColumn(column, it))\"\n [value]=\"getRatingValue(element, asItemColumn(column, it))\"\n [size]=\"getRatingSize(element, asItemColumn(column, it))\"\n [ratingColor]=\"getRatingColor(element, asItemColumn(column, it))\"\n [outlineColor]=\"getRatingOutlineColor(element, asItemColumn(column, it))\"\n [ariaLabel]=\"getRatingAriaLabel(element, asItemColumn(column, it)) || column.header\">\n </praxis-table-rating>\n </ng-container>\n <ng-container *ngSwitchCase=\"'html'\">\n <span [innerHTML]=\"getSafeHtml(element, asItemColumn(column, it))\"></span>\n </ng-container>\n <!-- Value item: render base cell text alongside visuals -->\n <ng-container *ngSwitchCase=\"'value'\">\n <span class=\"pfx-cell-value\">{{ getComposeItemValue(element, column, it) }}</span>\n </ng-container>\n </ng-container>\n </ng-container>\n </span>\n </ng-container>\n\n <!-- Default text rendering -->\n <ng-container *ngSwitchDefault>\n {{ getCellValue(element, column) }}\n </ng-container>\n </ng-container>\n </div>\n </td>\n </ng-container>\n }\n @if (config.actions?.row?.enabled) {\n <ng-container matColumnDef=\"_actions\" [sticky]=\"config.actions?.row?.sticky === true || config.actions?.row?.sticky === 'start'\" [stickyEnd]=\"config.actions?.row?.sticky === 'end'\">\n <th mat-header-cell *matHeaderCellDef #actionsHeaderCell [style.width]=\"getRowActionsWidthStyle()\" class=\"praxis-actions-header\" [class.align-start]=\"getActionsHeaderAlign() === 'start'\" [class.align-center]=\"getActionsHeaderAlign() === 'center'\" [class.align-end]=\"getActionsHeaderAlign() === 'end'\">\n <div class=\"praxis-actions-header__content\" [matTooltip]=\"getActionsHeaderTooltip() || ''\" [matTooltipDisabled]=\"!getActionsHeaderTooltip()\">\n <praxis-rich-content\n rootClassName=\"praxis-actions-header__nodes\"\n [nodes]=\"getActionsHeaderRichContentNodes()\"\n ></praxis-rich-content>\n </div>\n </th>\n <td\n mat-cell\n *matCellDef=\"let row\"\n class=\"praxis-actions-cell\"\n [class.dense]=\"dense\"\n [style.width]=\"getRowActionsWidthStyle()\"\n >\n <div\n class=\"praxis-actions-cell__content\"\n [class.praxis-actions-cell__content--discovering]=\"isRowDiscoveryPending(row)\"\n [attr.aria-busy]=\"isRowDiscoveryPending(row) ? 'true' : null\"\n >\n <!-- A\u00C3\u00A7\u00C3\u00B5es inline -->\n <!-- Inline actions: icons mode -->\n @if (config.actions?.row?.display === 'icons' || !config.actions?.row?.display) {\n <ng-container *ngFor=\"let a of getInlineRowActions(row); trackBy: trackAction\">\n <span\n class=\"praxis-row-action-anchor\"\n [class.praxis-row-action-anchor--workflow]=\"isWorkflowRowAction(a)\"\n [class.praxis-row-action-anchor--blocked]=\"isBlockedWorkflowRowAction(a, row)\"\n [matTooltip]=\"getActionTooltip(a, row)\"\n [matTooltipDisabled]=\"!getActionTooltip(a, row)\"\n matTooltipPosition=\"above\"\n matTooltipClass=\"praxis-tooltip\"\n >\n <button\n mat-icon-button\n class=\"praxis-icon-btn\"\n [class.praxis-icon-btn--workflow]=\"isWorkflowRowAction(a)\"\n [class.praxis-icon-btn--blocked]=\"isBlockedWorkflowRowAction(a, row)\"\n [disabled]=\"isActionDisabled(a, row)\"\n (click)=\"onRowAction(getActionId(a), row, $event, getRowActionRuntimeOptions(a, row))\"\n [attr.aria-label]=\"a.label || getActionId(a)\"\n [color]=\"a.color || null\"\n >\n <praxis-rich-content\n rootClassName=\"praxis-row-action__content\"\n [nodes]=\"getRowActionIconRichContentNodes(a)\"\n ></praxis-rich-content>\n </button>\n </span>\n </ng-container>\n }\n\n <!-- Inline actions: buttons mode (show label + icon) -->\n @if (config.actions?.row?.display === 'buttons') {\n <ng-container *ngFor=\"let a of getInlineRowActions(row); trackBy: trackAction\">\n <span\n class=\"praxis-row-action-anchor\"\n [class.praxis-row-action-anchor--workflow]=\"isWorkflowRowAction(a)\"\n [class.praxis-row-action-anchor--blocked]=\"isBlockedWorkflowRowAction(a, row)\"\n [matTooltip]=\"getActionTooltip(a, row)\"\n [matTooltipDisabled]=\"!getActionTooltip(a, row)\"\n matTooltipPosition=\"above\"\n matTooltipClass=\"praxis-tooltip\"\n >\n <button\n mat-flat-button\n class=\"praxis-row-btn\"\n [class.praxis-row-btn--workflow]=\"isWorkflowRowAction(a)\"\n [class.praxis-row-btn--blocked]=\"isBlockedWorkflowRowAction(a, row)\"\n [disabled]=\"isActionDisabled(a, row)\"\n (click)=\"onRowAction(getActionId(a), row, $event, getRowActionRuntimeOptions(a, row))\"\n [attr.aria-label]=\"a.label || getActionId(a)\"\n [color]=\"a.color || null\"\n >\n <praxis-rich-content\n rootClassName=\"praxis-row-action__content\"\n [nodes]=\"getRowActionRichContentNodes(a)\"\n ></praxis-rich-content>\n </button>\n </span>\n </ng-container>\n }\n\n <!-- Menu de overflow -->\n @if (hasOverflowRowActions(row)) {\n <button\n mat-icon-button\n class=\"praxis-icon-btn praxis-more-btn\"\n [matMenuTriggerFor]=\"rowMoreMenu\"\n (menuOpened)=\"onRowOverflowMenuOpened(row)\"\n [color]=\"getRowMenuButtonColor() || null\"\n [attr.aria-label]=\"getRowMenuTooltip(row)\"\n [matTooltip]=\"getRowMenuTooltip(row)\"\n matTooltipPosition=\"above\"\n >\n <mat-icon [praxisIcon]=\"getRowMenuIcon()\"></mat-icon>\n </button>\n }\n <mat-menu #rowMoreMenu=\"matMenu\" xPosition=\"before\">\n @if (hasRowOverflowMenuLoadingState(row)) {\n <button mat-menu-item disabled>\n <mat-icon>hourglass_empty</mat-icon>\n <praxis-rich-content\n rootClassName=\"praxis-row-overflow-menu__label\"\n [nodes]=\"getTableChromeTextRichContentNodes(getRowOverflowMenuLoadingLabel(), 'praxis-row-overflow-menu__label-text')\"\n ></praxis-rich-content>\n </button>\n }\n <ng-container\n *ngFor=\"let a of getOverflowRowActions(row); trackBy: trackAction\"\n >\n <button\n mat-menu-item\n (click)=\"onRowAction(getActionId(a), row, $event, getRowActionRuntimeOptions(a, row))\"\n [disabled]=\"isActionDisabled(a, row)\"\n >\n <mat-icon [color]=\"a.color || null\" [praxisIcon]=\"a.icon\"></mat-icon>\n <praxis-rich-content\n rootClassName=\"praxis-row-overflow-menu__label\"\n [nodes]=\"getTableChromeTextRichContentNodes(a.label || getActionId(a), 'praxis-row-overflow-menu__label-text')\"\n ></praxis-rich-content>\n </button>\n </ng-container>\n @if (hasRowOverflowMenuEmptyState(row)) {\n <button mat-menu-item disabled>\n <mat-icon>info</mat-icon>\n <praxis-rich-content\n rootClassName=\"praxis-row-overflow-menu__label\"\n [nodes]=\"getTableChromeTextRichContentNodes(getRowOverflowMenuEmptyLabel(row), 'praxis-row-overflow-menu__label-text')\"\n ></praxis-rich-content>\n </button>\n }\n </mat-menu>\n </div>\n </td>\n </ng-container>\n }\n\n <tr\n mat-header-row\n *matHeaderRowDef=\"displayedColumns\"\n ></tr>\n @if (!isVirtualized()) {\n <tr\n mat-row\n *matRowDef=\"let row; let i = index; columns: displayedColumns\"\n [class.pfx-row-selected]=\"selection.isSelected(row)\"\n [class.pfx-row-expanded]=\"isRowExpansionRuntimeEnabled() && isRowExpanded(row, i)\"\n [attr.aria-selected]=\"config.behavior?.selection?.enabled ? (selection.isSelected(row) ? 'true' : 'false') : null\"\n [attr.aria-expanded]=\"isRowExpansionRuntimeEnabled() ? (isRowExpanded(row, i) ? 'true' : 'false') : null\"\n [ngClass]=\"getRowClasses(row)\"\n [ngStyle]=\"getRowNgStyle(row)\"\n [matTooltip]=\"getRowTooltip(row) || null\"\n [matTooltipDisabled]=\"!getRowTooltip(row)\"\n [matTooltipPosition]=\"getRowTooltipPosition(row)\"\n [matTooltipShowDelay]=\"getRowTooltipShowDelay(row)\"\n (click)=\"onRowClicked(row, i, $event)\"\n (dblclick)=\"onRowDoubleClicked(row, i)\"\n ></tr>\n @if (isRowExpansionRuntimeEnabled()) {\n <ng-container matColumnDef=\"_detail\">\n <td\n mat-cell\n *matCellDef=\"let row; let i = index\"\n class=\"pfx-expansion-detail-cell\"\n [attr.colspan]=\"displayedColumns.length\"\n >\n <section\n class=\"pfx-expansion-detail-panel\"\n [ngClass]=\"getExpansionMotionPresetClass()\"\n [ngStyle]=\"getExpansionMotionStyle()\"\n [attr.id]=\"getRowExpansionDetailId(row, i)\"\n role=\"region\"\n [attr.aria-label]=\"getRowExpansionRegionAriaLabel(row, i)\"\n [attr.aria-busy]=\"getExpansionDetailViewState(row, i).status === 'loading' ? 'true' : 'false'\"\n >\n @let detailState = getExpansionDetailViewState(row, i);\n @if (detailState.status === 'loading') {\n <div class=\"pfx-expansion-detail-message\" role=\"status\" aria-live=\"polite\">\n <praxis-rich-content\n rootClassName=\"pfx-expansion-detail-message__content\"\n [nodes]=\"getExpansionDetailTextRichContentNodes('Carregando detail schema...', 'pfx-expansion-detail-message__text')\"\n [context]=\"getExpansionDetailRichContentContext(row, i)\"\n ></praxis-rich-content>\n </div>\n } @else if (detailState.status !== 'ready') {\n <div\n class=\"pfx-expansion-detail-message pfx-expansion-detail-message--error\"\n role=\"alert\"\n aria-live=\"assertive\"\n aria-atomic=\"true\"\n >\n <praxis-rich-content\n rootClassName=\"pfx-expansion-detail-message__content\"\n [nodes]=\"getExpansionDetailTextRichContentNodes(detailState.message || 'Detail indispon\u00EDvel para esta linha.', 'pfx-expansion-detail-message__text')\"\n [context]=\"getExpansionDetailRichContentContext(row, i)\"\n ></praxis-rich-content>\n </div>\n } @else {\n @if (getExpansionDetailLayout(detailState.schema) === 'tabs') {\n @let detailTabs = getExpansionDetailTabs(detailState.schema);\n @if (detailTabs.length) {\n <div class=\"pfx-expansion-detail-tabs\" role=\"tablist\" aria-label=\"Se\u00C3\u00A7\u00C3\u00B5es do detail\">\n @for (tab of detailTabs; track $index; let tabIndex = $index) {\n <button\n type=\"button\"\n class=\"pfx-expansion-detail-tab-btn\"\n role=\"tab\"\n [attr.id]=\"getExpansionDetailTabId(row, i, tab, tabIndex)\"\n [attr.aria-controls]=\"getExpansionDetailPanelId(row, i, tab, tabIndex)\"\n [attr.aria-selected]=\"isExpansionDetailTabActive(row, i, tab, tabIndex, detailTabs) ? 'true' : 'false'\"\n [attr.tabindex]=\"isExpansionDetailTabActive(row, i, tab, tabIndex, detailTabs) ? '0' : '-1'\"\n [class.is-active]=\"isExpansionDetailTabActive(row, i, tab, tabIndex, detailTabs)\"\n (click)=\"onExpansionDetailTabSelect(row, i, tab, tabIndex, $event)\"\n (keydown)=\"onExpansionDetailTabKeydown($event, row, i, tabIndex, detailTabs)\"\n >\n <praxis-rich-content\n rootClassName=\"pfx-expansion-detail-tab-btn__content\"\n [nodes]=\"getExpansionDetailTabButtonRichContentNodes(tab)\"\n [context]=\"getExpansionDetailRichContentContext(row, i)\"\n ></praxis-rich-content>\n </button>\n }\n </div>\n @for (tab of detailTabs; track $index; let tabIndex = $index) {\n @if (isExpansionDetailTabActive(row, i, tab, tabIndex, detailTabs)) {\n <div\n class=\"pfx-expansion-detail-tab-panel\"\n role=\"tabpanel\"\n [attr.id]=\"getExpansionDetailPanelId(row, i, tab, tabIndex)\"\n [attr.aria-labelledby]=\"getExpansionDetailTabId(row, i, tab, tabIndex)\"\n >\n @if (getExpansionDetailTabRichContentNodes(tab, row, i); as richNodes) {\n <praxis-rich-content\n class=\"pfx-expansion-node-host pfx-expansion-node-host--tab\"\n [nodes]=\"richNodes\"\n [context]=\"getExpansionDetailRichContentContext(row, i)\"\n ></praxis-rich-content>\n } @else {\n @for (childNode of getExpansionDetailNodeChildren(tab); track $index) {\n <ng-container\n *ngTemplateOutlet=\"\n expansionDetailNodeTemplate;\n context: { $implicit: childNode, row: row, index: i }\n \"\n ></ng-container>\n }\n }\n </div>\n }\n }\n } @else {\n <div class=\"pfx-expansion-detail-message\">\n <praxis-rich-content\n rootClassName=\"pfx-expansion-detail-message__content\"\n [nodes]=\"getExpansionDetailTextRichContentNodes('Schema em layout tabs sem abas v\u00E1lidas.', 'pfx-expansion-detail-message__text')\"\n [context]=\"getExpansionDetailRichContentContext(row, i)\"\n ></praxis-rich-content>\n </div>\n }\n } @else {\n <div class=\"pfx-expansion-detail-stack\">\n @for (node of getExpansionDetailItems(detailState.schema); track $index) {\n <ng-container\n *ngTemplateOutlet=\"\n expansionDetailNodeTemplate;\n context: { $implicit: node, row: row, index: i }\n \"\n ></ng-container>\n }\n </div>\n }\n }\n\n <ng-template #expansionDetailNodeTemplate let-node let-row=\"row\" let-index=\"index\">\n @if (getExpansionDetailRichContentNodes(node, row, index); as richNodes) {\n <praxis-rich-content\n class=\"pfx-expansion-node-host\"\n [nodes]=\"richNodes\"\n [context]=\"getExpansionDetailRichContentContext(row, index)\"\n ></praxis-rich-content>\n } @else {\n @switch (getExpansionDetailNodeType(node)) {\n @case ('list') {\n <section class=\"pfx-expansion-node pfx-expansion-node-list\">\n <praxis-rich-content\n rootClassName=\"pfx-expansion-node-list__title\"\n [nodes]=\"getExpansionDetailTextRichContentNodes(getExpansionDetailNodeTitle(node, 'Lista'), 'pfx-expansion-node-list__title-text')\"\n [context]=\"getExpansionDetailRichContentContext(row, index)\"\n ></praxis-rich-content>\n @let listItems = getExpansionDetailListItems(row, node);\n @let listEntries = getExpansionDetailListEntries(row, node);\n @if (listItems.length) {\n <ul>\n @for (entry of listEntries; track $index) {\n <li>\n @if (getExpansionDetailListItemRichContentNodes(entry); as richNodes) {\n <praxis-rich-content\n class=\"pfx-expansion-node-list__item-host\"\n [nodes]=\"richNodes\"\n [context]=\"getExpansionDetailRichContentContext(row, index)\"\n ></praxis-rich-content>\n } @else {\n {{ formatExpansionDetailListEntry(entry) }}\n }\n </li>\n }\n </ul>\n } @else {\n <praxis-rich-content\n rootClassName=\"pfx-expansion-node-placeholder\"\n [nodes]=\"getExpansionDetailTextRichContentNodes('Sem itens.', 'pfx-expansion-node-placeholder__text')\"\n [context]=\"getExpansionDetailRichContentContext(row, index)\"\n ></praxis-rich-content>\n }\n </section>\n }\n @case ('detailList') {\n <section class=\"pfx-expansion-node pfx-expansion-node-rich-list\">\n <praxis-rich-content\n rootClassName=\"pfx-expansion-node-rich-list__title\"\n [nodes]=\"getExpansionDetailTextRichContentNodes(getExpansionDetailNodeTitle(node, 'Cole\u00E7\u00E3o rica'), 'pfx-expansion-node-rich-list__title-text')\"\n [context]=\"getExpansionDetailRichContentContext(row, index)\"\n ></praxis-rich-content>\n @let richListEntries = getExpansionDetailRichListEntries(row, node);\n @if (richListEntries.length) {\n <div class=\"pfx-expansion-node-rich-list__items\">\n @for (entry of richListEntries; track $index) {\n <article [class]=\"getExpansionDetailRichListItemClassName(node)\">\n <praxis-rich-content\n class=\"pfx-expansion-node-rich-list__item-host\"\n [nodes]=\"getExpansionDetailRichListItemNodes(node)\"\n [context]=\"getExpansionDetailRichListItemContext(row, index, node, entry, $index)\"\n ></praxis-rich-content>\n @let itemActions = getExpansionDetailRichListItemActions(node, row, index, entry, $index);\n @if (itemActions.length) {\n <div class=\"pfx-expansion-node-rich-list__item-actions\">\n @for (action of itemActions; track action.actionId) {\n <button\n type=\"button\"\n mat-stroked-button\n class=\"pfx-expansion-node-rich-list__item-action-btn\"\n [disabled]=\"isExpansionDetailRichListItemActionDisabled(action, row, index, node, entry, $index)\"\n (click)=\"onExpansionDetailRichListItemAction(action, row, index, node, entry, $index, $event)\"\n >\n <praxis-rich-content\n class=\"pfx-expansion-node-rich-list__item-action-host\"\n [nodes]=\"getExpansionDetailRichListItemActionNodes(action)\"\n [context]=\"getExpansionDetailRichListItemContext(row, index, node, entry, $index)\"\n ></praxis-rich-content>\n </button>\n }\n </div>\n }\n </article>\n }\n </div>\n } @else {\n <praxis-rich-content\n rootClassName=\"pfx-expansion-node-placeholder\"\n [nodes]=\"getExpansionDetailTextRichContentNodes(getExpansionDetailRichListEmptyText(node), 'pfx-expansion-node-placeholder__text')\"\n [context]=\"getExpansionDetailRichContentContext(row, index)\"\n ></praxis-rich-content>\n }\n </section>\n }\n @case ('cardGrid') {\n <section class=\"pfx-expansion-node pfx-expansion-node-card-grid\">\n @if (getExpansionDetailCardGridHeaderNodes(node); as cardGridHeaderNodes) {\n @if (cardGridHeaderNodes.length) {\n <praxis-rich-content\n rootClassName=\"pfx-expansion-node-card-grid__header\"\n [nodes]=\"cardGridHeaderNodes\"\n [context]=\"getExpansionDetailRichContentContext(row, index)\"\n ></praxis-rich-content>\n }\n }\n @let gridCards = getExpansionDetailCardGridCards(node);\n @if (gridCards.length) {\n <div\n class=\"pfx-expansion-node-card-grid__cards\"\n [ngStyle]=\"getExpansionDetailCardGridStyles(node)\"\n >\n @for (card of gridCards; track $index) {\n <praxis-rich-content\n class=\"pfx-expansion-node-card-grid__card-host\"\n [nodes]=\"getExpansionDetailCardGridCardNodes(card)\"\n [context]=\"getExpansionDetailRichContentContext(row, index)\"\n ></praxis-rich-content>\n }\n </div>\n } @else {\n <praxis-rich-content\n rootClassName=\"pfx-expansion-node-placeholder\"\n [nodes]=\"getExpansionDetailTextRichContentNodes('Sem itens.', 'pfx-expansion-node-placeholder__text')\"\n [context]=\"getExpansionDetailRichContentContext(row, index)\"\n ></praxis-rich-content>\n }\n </section>\n }\n @case ('richText') {\n <div\n class=\"pfx-expansion-node pfx-expansion-node-richtext\"\n [innerHTML]=\"getExpansionDetailRichText(node)\"\n ></div>\n }\n @case ('formRef') {\n <section class=\"pfx-expansion-node pfx-expansion-node-embed\">\n <praxis-rich-content\n rootClassName=\"pfx-expansion-node-embed__header\"\n [nodes]=\"getExpansionDetailEmbedHeaderNodes(node)\"\n [context]=\"getExpansionDetailRichContentContext(row, index)\"\n ></praxis-rich-content>\n <praxis-rich-content\n rootClassName=\"pfx-expansion-node-embed__meta\"\n [nodes]=\"getExpansionDetailEmbedMetaNodes(node)\"\n [context]=\"getExpansionDetailRichContentContext(row, index)\"\n ></praxis-rich-content>\n <praxis-rich-content\n rootClassName=\"pfx-expansion-node-embed__empty\"\n [nodes]=\"getExpansionDetailTextRichContentNodes(getExpansionDetailEmbedEmptyText(node), 'pfx-expansion-node-embed__empty-text')\"\n [context]=\"getExpansionDetailRichContentContext(row, index)\"\n ></praxis-rich-content>\n @if (getExpansionDetailEmbedAction(node, row, index); as embedAction) {\n <button\n type=\"button\"\n mat-stroked-button\n class=\"pfx-expansion-node-embed__action-btn\"\n [disabled]=\"isExpansionDetailEmbedActionDisabled(embedAction, row, index)\"\n (click)=\"onExpansionDetailEmbedAction(embedAction, row, index, $event)\"\n >\n <praxis-rich-content\n class=\"pfx-expansion-node-embed__action-host\"\n [nodes]=\"getExpansionDetailEmbedActionNodes(embedAction)\"\n [context]=\"getExpansionDetailRichContentContext(row, index)\"\n ></praxis-rich-content>\n </button>\n }\n </section>\n }\n @case ('tableRef') {\n <section class=\"pfx-expansion-node pfx-expansion-node-embed\">\n <praxis-rich-content\n rootClassName=\"pfx-expansion-node-embed__header\"\n [nodes]=\"getExpansionDetailEmbedHeaderNodes(node)\"\n [context]=\"getExpansionDetailRichContentContext(row, index)\"\n ></praxis-rich-content>\n <praxis-rich-content\n rootClassName=\"pfx-expansion-node-embed__meta\"\n [nodes]=\"getExpansionDetailEmbedMetaNodes(node)\"\n [context]=\"getExpansionDetailRichContentContext(row, index)\"\n ></praxis-rich-content>\n <praxis-rich-content\n rootClassName=\"pfx-expansion-node-embed__empty\"\n [nodes]=\"getExpansionDetailTextRichContentNodes(getExpansionDetailEmbedEmptyText(node), 'pfx-expansion-node-embed__empty-text')\"\n [context]=\"getExpansionDetailRichContentContext(row, index)\"\n ></praxis-rich-content>\n @if (getExpansionDetailEmbedAction(node, row, index); as embedAction) {\n <button\n type=\"button\"\n mat-stroked-button\n class=\"pfx-expansion-node-embed__action-btn\"\n [disabled]=\"isExpansionDetailEmbedActionDisabled(embedAction, row, index)\"\n (click)=\"onExpansionDetailEmbedAction(embedAction, row, index, $event)\"\n >\n <praxis-rich-content\n class=\"pfx-expansion-node-embed__action-host\"\n [nodes]=\"getExpansionDetailEmbedActionNodes(embedAction)\"\n [context]=\"getExpansionDetailRichContentContext(row, index)\"\n ></praxis-rich-content>\n </button>\n }\n </section>\n }\n @case ('chartRef') {\n <section class=\"pfx-expansion-node pfx-expansion-node-embed\">\n <praxis-rich-content\n rootClassName=\"pfx-expansion-node-embed__header\"\n [nodes]=\"getExpansionDetailEmbedHeaderNodes(node)\"\n [context]=\"getExpansionDetailRichContentContext(row, index)\"\n ></praxis-rich-content>\n <praxis-rich-content\n rootClassName=\"pfx-expansion-node-embed__meta\"\n [nodes]=\"getExpansionDetailEmbedMetaNodes(node)\"\n [context]=\"getExpansionDetailRichContentContext(row, index)\"\n ></praxis-rich-content>\n <praxis-rich-content\n rootClassName=\"pfx-expansion-node-embed__empty\"\n [nodes]=\"getExpansionDetailTextRichContentNodes(getExpansionDetailEmbedEmptyText(node), 'pfx-expansion-node-embed__empty-text')\"\n [context]=\"getExpansionDetailRichContentContext(row, index)\"\n ></praxis-rich-content>\n @if (getExpansionDetailEmbedAction(node, row, index); as embedAction) {\n <button\n type=\"button\"\n mat-stroked-button\n class=\"pfx-expansion-node-embed__action-btn\"\n [disabled]=\"isExpansionDetailEmbedActionDisabled(embedAction, row, index)\"\n (click)=\"onExpansionDetailEmbedAction(embedAction, row, index, $event)\"\n >\n <praxis-rich-content\n class=\"pfx-expansion-node-embed__action-host\"\n [nodes]=\"getExpansionDetailEmbedActionNodes(embedAction)\"\n [context]=\"getExpansionDetailRichContentContext(row, index)\"\n ></praxis-rich-content>\n </button>\n }\n </section>\n }\n @case ('templateRef') {\n <section class=\"pfx-expansion-node pfx-expansion-node-embed\">\n <praxis-rich-content\n rootClassName=\"pfx-expansion-node-embed__header\"\n [nodes]=\"getExpansionDetailEmbedHeaderNodes(node)\"\n [context]=\"getExpansionDetailRichContentContext(row, index)\"\n ></praxis-rich-content>\n <praxis-rich-content\n rootClassName=\"pfx-expansion-node-embed__meta\"\n [nodes]=\"getExpansionDetailEmbedMetaNodes(node)\"\n [context]=\"getExpansionDetailRichContentContext(row, index)\"\n ></praxis-rich-content>\n <praxis-rich-content\n rootClassName=\"pfx-expansion-node-embed__empty\"\n [nodes]=\"getExpansionDetailTextRichContentNodes(getExpansionDetailEmbedEmptyText(node), 'pfx-expansion-node-embed__empty-text')\"\n [context]=\"getExpansionDetailRichContentContext(row, index)\"\n ></praxis-rich-content>\n @if (getExpansionDetailEmbedAction(node, row, index); as embedAction) {\n <button\n type=\"button\"\n mat-stroked-button\n class=\"pfx-expansion-node-embed__action-btn\"\n [disabled]=\"isExpansionDetailEmbedActionDisabled(embedAction, row, index)\"\n (click)=\"onExpansionDetailEmbedAction(embedAction, row, index, $event)\"\n >\n <praxis-rich-content\n class=\"pfx-expansion-node-embed__action-host\"\n [nodes]=\"getExpansionDetailEmbedActionNodes(embedAction)\"\n [context]=\"getExpansionDetailRichContentContext(row, index)\"\n ></praxis-rich-content>\n </button>\n }\n </section>\n }\n @case ('diagramEmbed') {\n <section class=\"pfx-expansion-node pfx-expansion-node-embed\">\n <praxis-rich-content\n rootClassName=\"pfx-expansion-node-embed__header\"\n [nodes]=\"getExpansionDetailEmbedHeaderNodes(node)\"\n [context]=\"getExpansionDetailRichContentContext(row, index)\"\n ></praxis-rich-content>\n <praxis-rich-content\n rootClassName=\"pfx-expansion-node-embed__meta\"\n [nodes]=\"getExpansionDetailEmbedMetaNodes(node)\"\n [context]=\"getExpansionDetailRichContentContext(row, index)\"\n ></praxis-rich-content>\n @if (getExpansionDetailDiagramSource(row, node); as diagramSource) {\n <div class=\"pfx-expansion-node-embed__diagram\">\n <praxis-rich-content\n rootClassName=\"pfx-expansion-node-embed__diagram-label\"\n [nodes]=\"getExpansionDetailTextRichContentNodes(getExpansionDetailDiagramSourceLabel(), 'pfx-expansion-node-embed__diagram-label-text')\"\n [context]=\"getExpansionDetailRichContentContext(row, index)\"\n ></praxis-rich-content>\n <pre class=\"pfx-expansion-node-embed__diagram-source\">{{ diagramSource }}</pre>\n </div>\n } @else {\n <praxis-rich-content\n rootClassName=\"pfx-expansion-node-embed__empty\"\n [nodes]=\"getExpansionDetailTextRichContentNodes(getExpansionDetailEmbedEmptyText(node), 'pfx-expansion-node-embed__empty-text')\"\n [context]=\"getExpansionDetailRichContentContext(row, index)\"\n ></praxis-rich-content>\n }\n @if (getExpansionDetailEmbedAction(node, row, index); as embedAction) {\n <button\n type=\"button\"\n mat-stroked-button\n class=\"pfx-expansion-node-embed__action-btn\"\n [disabled]=\"isExpansionDetailEmbedActionDisabled(embedAction, row, index)\"\n (click)=\"onExpansionDetailEmbedAction(embedAction, row, index, $event)\"\n >\n <praxis-rich-content\n class=\"pfx-expansion-node-embed__action-host\"\n [nodes]=\"getExpansionDetailEmbedActionNodes(embedAction)\"\n [context]=\"getExpansionDetailRichContentContext(row, index)\"\n ></praxis-rich-content>\n </button>\n }\n </section>\n }\n @case ('action') {\n <div class=\"pfx-expansion-node pfx-expansion-node-action\">\n <button\n type=\"button\"\n mat-stroked-button\n [disabled]=\"isExpansionDetailActionDisabled(node)\"\n (click)=\"onExpansionDetailAction(node, row, $event)\"\n >\n <praxis-rich-content\n class=\"pfx-expansion-node-action__content\"\n [nodes]=\"getExpansionDetailActionRichContentNodes(node)\"\n [context]=\"getExpansionDetailRichContentContext(row, index)\"\n ></praxis-rich-content>\n </button>\n @if (getExpansionDetailActionStatusText(node); as actionStatusText) {\n <praxis-rich-content\n rootClassName=\"pfx-expansion-node-action__status\"\n [nodes]=\"getExpansionDetailTextRichContentNodes(actionStatusText, 'pfx-expansion-node-action__status-text')\"\n [context]=\"getExpansionDetailRichContentContext(row, index)\"\n ></praxis-rich-content>\n }\n </div>\n }\n @case ('actionBar') {\n <section class=\"pfx-expansion-node pfx-expansion-node-action-bar\">\n <praxis-rich-content\n rootClassName=\"pfx-expansion-node-action-bar__title\"\n [nodes]=\"getExpansionDetailTextRichContentNodes(getExpansionDetailActionBarTitle(node), 'pfx-expansion-node-action-bar__title-text')\"\n [context]=\"getExpansionDetailRichContentContext(row, index)\"\n ></praxis-rich-content>\n @let actionBarActions = getExpansionDetailActionBarActions(node, row, index);\n @if (actionBarActions.length) {\n <div class=\"pfx-expansion-node-action-bar__actions\">\n @for (action of actionBarActions; track action.actionId) {\n <button\n type=\"button\"\n mat-stroked-button\n class=\"pfx-expansion-node-action-bar__action-btn\"\n [disabled]=\"isExpansionDetailActionBarActionDisabled(action, row, index)\"\n (click)=\"onExpansionDetailActionBarAction(action, row, index, $event)\"\n >\n <praxis-rich-content\n class=\"pfx-expansion-node-action-bar__action-host\"\n [nodes]=\"getExpansionDetailActionBarActionNodes(action)\"\n [context]=\"getExpansionDetailRichContentContext(row, index)\"\n ></praxis-rich-content>\n </button>\n }\n </div>\n } @else {\n <praxis-rich-content\n rootClassName=\"pfx-expansion-node-placeholder\"\n [nodes]=\"getExpansionDetailTextRichContentNodes(getExpansionDetailActionBarEmptyText(node), 'pfx-expansion-node-placeholder__text')\"\n [context]=\"getExpansionDetailRichContentContext(row, index)\"\n ></praxis-rich-content>\n }\n </section>\n }\n @case ('tab') {\n <div class=\"pfx-expansion-node pfx-expansion-node-placeholder\">\n <praxis-rich-content\n rootClassName=\"pfx-expansion-node-placeholder__content\"\n [nodes]=\"getExpansionDetailTextRichContentNodes('Node', 'pfx-expansion-node-placeholder__text')\"\n [context]=\"getExpansionDetailRichContentContext(row, index)\"\n ></praxis-rich-content>\n <code>tab</code>\n <praxis-rich-content\n rootClassName=\"pfx-expansion-node-placeholder__content\"\n [nodes]=\"getExpansionDetailTextRichContentNodes('fora de contexto de tabs.', 'pfx-expansion-node-placeholder__text')\"\n [context]=\"getExpansionDetailRichContentContext(row, index)\"\n ></praxis-rich-content>\n </div>\n }\n @default {\n <div class=\"pfx-expansion-node pfx-expansion-node-placeholder\">\n <praxis-rich-content\n rootClassName=\"pfx-expansion-node-placeholder__content\"\n [nodes]=\"getExpansionDetailTextRichContentNodes('Node n\u00E3o suportado:', 'pfx-expansion-node-placeholder__text')\"\n [context]=\"getExpansionDetailRichContentContext(row, index)\"\n ></praxis-rich-content>\n <code>{{ getExpansionDetailNodeType(node) }}</code>\n </div>\n }\n }\n }\n </ng-template>\n </section>\n </td>\n </ng-container>\n <tr\n mat-row\n *matRowDef=\"let row; columns: expansionDetailRowColumns; when: isExpansionDetailRow\"\n class=\"pfx-expansion-detail-row\"\n ></tr>\n }\n }\n</table>\n}\n\n<!-- Virtual rows path (header preserved above) -->\n@if (shouldRenderDataSurface() && !schemaError && !dataError && isVirtualized()) {\n <cdk-virtual-scroll-viewport\n class=\"ptable-viewport\"\n [itemSize]=\"getVirtItemHeight()\"\n [minBufferPx]=\"getVirtBufferSize() * getVirtItemHeight()\"\n [maxBufferPx]=\"getVirtBufferSize() * getVirtItemHeight() * 2\"\n [style.minHeight]=\"getVirtMinHeightHostStyle()\"\n >\n <table\n class=\"mat-mdc-table\"\n [ngClass]=\"getTableElevationClassName()\"\n [style.width]=\"getVirtualTableWidthStyle()\"\n >\n <tbody>\n <tr class=\"mat-mdc-row\"\n *cdkVirtualFor=\"let row of dataSource.data; let i = index; trackBy: trackByRow\"\n [class.pfx-row-selected]=\"selection.isSelected(row)\"\n [attr.aria-selected]=\"config.behavior?.selection?.enabled ? (selection.isSelected(row) ? 'true' : 'false') : null\"\n [ngClass]=\"getRowClasses(row)\"\n [ngStyle]=\"getRowNgStyle(row)\"\n [matTooltip]=\"getRowTooltip(row) || null\"\n [matTooltipDisabled]=\"!getRowTooltip(row)\"\n [matTooltipPosition]=\"getRowTooltipPosition(row)\"\n [matTooltipShowDelay]=\"getRowTooltipShowDelay(row)\"\n (click)=\"onRowClicked(row, i, $event)\"\n (dblclick)=\"onRowDoubleClicked(row, i)\">\n <!-- Selection column -->\n @if (config.behavior?.selection?.enabled) { <td class=\"mat-mdc-cell\">\n <mat-checkbox\n (click)=\"$event.stopPropagation()\"\n (change)=\"toggleRow(row)\"\n [checked]=\"selection.isSelected(row)\">\n </mat-checkbox>\n </td> }\n <!-- Data columns -->\n @for (column of visibleColumns; track column.field) {\n <td class=\"mat-mdc-cell\"\n [style.text-align]=\"getColumnTextAlignStyle(column)\"\n [style.width]=\"getColumnWidthStyle(column)\"\n [attr.style]=\"getColumnCellAttrStyle(column)\"\n [ngClass]=\"getCellClasses(row, column)\"\n [ngStyle]=\"getCellNgStyle(row, column)\">\n <div\n class=\"pfx-cell-content\"\n [ngClass]=\"getCellContentClasses(row, column)\"\n [ngStyle]=\"getCellContentNgStyle(row, column)\"\n >\n <ng-container [ngSwitch]=\"getEffectiveRendererType(row, column)\">\n <ng-container *ngSwitchCase=\"'icon'\">\n <span class=\"pfx-icon-renderer\"\n [style.color]=\"getIconColor(row, column) || null\"\n [ngStyle]=\"getIconStyle(row, column)\"\n [attr.aria-label]=\"getIconAriaLabel(row, column) || null\">\n <praxis-rich-content\n rootClassName=\"pfx-icon-renderer__content\"\n [nodes]=\"getIconRichContentNodes(row, column)\"\n ></praxis-rich-content>\n </span>\n </ng-container>\n <ng-container *ngSwitchCase=\"'image'\">\n <span class=\"pfx-cell-image\">\n <praxis-rich-content\n rootClassName=\"pfx-cell-image__content\"\n [nodes]=\"getImageRichContentNodes(row, column)\"\n ></praxis-rich-content>\n </span>\n </ng-container>\n <ng-container *ngSwitchCase=\"'badge'\">\n <span class=\"pfx-badge\" [ngClass]=\"getBadgeClasses(row, column)\">\n <praxis-rich-content\n rootClassName=\"pfx-badge__content\"\n [nodes]=\"getBadgeRichContentNodes(row, column)\"\n ></praxis-rich-content>\n </span>\n </ng-container>\n <ng-container *ngSwitchCase=\"'chip'\">\n <span class=\"pfx-chip\" [ngClass]=\"getChipClasses(row, column)\">\n <praxis-rich-content\n rootClassName=\"pfx-chip__content\"\n [nodes]=\"getChipRichContentNodes(row, column)\"\n ></praxis-rich-content>\n </span>\n </ng-container>\n <ng-container *ngSwitchCase=\"'progress'\">\n <div class=\"pfx-progress\">\n <praxis-rich-content\n rootClassName=\"pfx-progress__content\"\n [context]=\"getProgressRichContentContext(row, column)\"\n [nodes]=\"getProgressRichContentNodes(row, column)\"\n ></praxis-rich-content>\n </div>\n </ng-container>\n <ng-container *ngSwitchCase=\"'avatar'\">\n <span\n class=\"pfx-avatar-renderer\"\n [ngStyle]=\"getAvatarStyle(row, column)\"\n [class.shape-rounded]=\"getAvatarShape(row, column) === 'rounded'\"\n [class.shape-circle]=\"getAvatarShape(row, column) === 'circle'\"\n >\n <praxis-rich-content\n rootClassName=\"pfx-avatar-renderer__content\"\n [nodes]=\"getAvatarRichContentNodes(row, column)\"\n ></praxis-rich-content>\n </span>\n </ng-container>\n <ng-container *ngSwitchCase=\"'link'\">\n <a\n class=\"pfx-link\"\n [attr.href]=\"getLinkHref(row, column) || null\"\n [attr.target]=\"getLinkTarget(row, column) || null\"\n [attr.rel]=\"getLinkRel(row, column) || null\"\n (click)=\"$event.stopPropagation()\"\n >\n <praxis-rich-content\n rootClassName=\"pfx-link__content\"\n [nodes]=\"getLinkRichContentNodes(row, column)\"\n ></praxis-rich-content>\n </a>\n </ng-container>\n <ng-container *ngSwitchCase=\"'button'\">\n <ng-container [ngSwitch]=\"getButtonVariant(row, column)\">\n <button\n *ngSwitchCase=\"'outlined'\"\n mat-stroked-button\n [color]=\"getButtonColor(row, column) || null\"\n [disabled]=\"isButtonDisabled(row, column)\"\n [attr.aria-label]=\"getButtonAriaLabel(row, column) || getButtonLabel(row, column)\"\n (click)=\"onButtonClick(row, column, $event)\"\n >\n <praxis-rich-content\n rootClassName=\"pfx-button-renderer__content\"\n [nodes]=\"getButtonRichContentNodes(row, column)\"\n ></praxis-rich-content>\n </button>\n <button\n *ngSwitchCase=\"'text'\"\n mat-button\n [color]=\"getButtonColor(row, column) || null\"\n [disabled]=\"isButtonDisabled(row, column)\"\n [attr.aria-label]=\"getButtonAriaLabel(row, column) || getButtonLabel(row, column)\"\n (click)=\"onButtonClick(row, column, $event)\"\n >\n <praxis-rich-content\n rootClassName=\"pfx-button-renderer__content\"\n [nodes]=\"getButtonRichContentNodes(row, column)\"\n ></praxis-rich-content>\n </button>\n <button\n *ngSwitchDefault\n mat-flat-button\n [color]=\"getButtonColor(row, column) || null\"\n [disabled]=\"isButtonDisabled(row, column)\"\n [attr.aria-label]=\"getButtonAriaLabel(row, column) || getButtonLabel(row, column)\"\n (click)=\"onButtonClick(row, column, $event)\"\n >\n <praxis-rich-content\n rootClassName=\"pfx-button-renderer__content\"\n [nodes]=\"getButtonRichContentNodes(row, column)\"\n ></praxis-rich-content>\n </button>\n </ng-container>\n </ng-container>\n <ng-container *ngSwitchCase=\"'menu'\">\n <button\n mat-icon-button\n [matMenuTriggerFor]=\"menuRef\"\n (click)=\"$event.stopPropagation()\"\n [attr.aria-label]=\"getMenuAriaLabel(row, column) || 'Menu'\"\n >\n <praxis-rich-content\n rootClassName=\"pfx-menu-trigger__content\"\n [nodes]=\"getMenuTriggerRichContentNodes()\"\n ></praxis-rich-content>\n </button>\n <mat-menu #menuRef=\"matMenu\">\n <button\n mat-menu-item\n *ngFor=\"let it of getMenuItems(row, column)\"\n (click)=\"onMenuItemClick(it, row, $event)\"\n [disabled]=\"!it.__visible\"\n >\n <praxis-rich-content\n rootClassName=\"pfx-menu-item__content\"\n [nodes]=\"getMenuItemRichContentNodes(it)\"\n ></praxis-rich-content>\n </button>\n </mat-menu>\n </ng-container>\n <ng-container *ngSwitchDefault>\n {{ getCellValue(row, column) }}\n </ng-container>\n </ng-container>\n </div>\n </td>\n }\n\n <!-- Actions column -->\n @if (config.actions?.row?.enabled) {\n <td class=\"mat-mdc-cell praxis-actions-cell\" [class.dense]=\"dense\" [style.width]=\"getRowActionsWidthStyle()\">\n <div\n class=\"praxis-actions-cell__content\"\n [class.praxis-actions-cell__content--discovering]=\"isRowDiscoveryPending(row)\"\n [attr.aria-busy]=\"isRowDiscoveryPending(row) ? 'true' : null\"\n >\n @if (config.actions?.row?.display === 'icons' || !config.actions?.row?.display) {\n <ng-container *ngFor=\"let a of getInlineRowActions(row); trackBy: trackAction\">\n <span\n class=\"praxis-row-action-anchor\"\n [class.praxis-row-action-anchor--workflow]=\"isWorkflowRowAction(a)\"\n [class.praxis-row-action-anchor--blocked]=\"isBlockedWorkflowRowAction(a, row)\"\n [matTooltip]=\"getActionTooltip(a, row)\"\n [matTooltipDisabled]=\"!getActionTooltip(a, row)\"\n matTooltipPosition=\"above\"\n matTooltipClass=\"praxis-tooltip\"\n >\n <button mat-icon-button class=\"praxis-icon-btn\"\n [class.praxis-icon-btn--workflow]=\"isWorkflowRowAction(a)\"\n [class.praxis-icon-btn--blocked]=\"isBlockedWorkflowRowAction(a, row)\"\n [disabled]=\"isActionDisabled(a, row)\"\n (click)=\"onRowAction(getActionId(a), row, $event, getRowActionRuntimeOptions(a, row))\"\n [attr.aria-label]=\"a.label || getActionId(a)\"\n [color]=\"a.color || null\">\n <praxis-rich-content\n rootClassName=\"praxis-row-action__content\"\n [nodes]=\"getRowActionIconRichContentNodes(a)\"\n ></praxis-rich-content>\n </button>\n </span>\n </ng-container>\n }\n @if (config.actions?.row?.display === 'buttons') {\n <ng-container *ngFor=\"let a of getInlineRowActions(row); trackBy: trackAction\">\n <span\n class=\"praxis-row-action-anchor\"\n [class.praxis-row-action-anchor--workflow]=\"isWorkflowRowAction(a)\"\n [class.praxis-row-action-anchor--blocked]=\"isBlockedWorkflowRowAction(a, row)\"\n [matTooltip]=\"getActionTooltip(a, row)\"\n [matTooltipDisabled]=\"!getActionTooltip(a, row)\"\n matTooltipPosition=\"above\"\n matTooltipClass=\"praxis-tooltip\"\n >\n <button mat-flat-button class=\"praxis-row-btn\"\n [class.praxis-row-btn--workflow]=\"isWorkflowRowAction(a)\"\n [class.praxis-row-btn--blocked]=\"isBlockedWorkflowRowAction(a, row)\"\n [disabled]=\"isActionDisabled(a, row)\"\n (click)=\"onRowAction(getActionId(a), row, $event, getRowActionRuntimeOptions(a, row))\"\n [attr.aria-label]=\"a.label || getActionId(a)\"\n [color]=\"a.color || null\">\n <praxis-rich-content\n rootClassName=\"praxis-row-action__content\"\n [nodes]=\"getRowActionRichContentNodes(a)\"\n ></praxis-rich-content>\n </button>\n </span>\n </ng-container>\n }\n @if (hasOverflowRowActions(row)) {\n <button mat-icon-button class=\"praxis-icon-btn praxis-more-btn\"\n [matMenuTriggerFor]=\"rowMoreMenuV\"\n (menuOpened)=\"onRowOverflowMenuOpened(row)\"\n [color]=\"getRowMenuButtonColor() || null\"\n [attr.aria-label]=\"getRowMenuTooltip(row)\"\n [matTooltip]=\"getRowMenuTooltip(row)\"\n matTooltipPosition=\"above\">\n <mat-icon [praxisIcon]=\"getRowMenuIcon()\"></mat-icon>\n </button>\n }\n <mat-menu #rowMoreMenuV=\"matMenu\" xPosition=\"before\">\n @if (hasRowOverflowMenuLoadingState(row)) {\n <button mat-menu-item disabled>\n <mat-icon>hourglass_empty</mat-icon>\n <praxis-rich-content\n rootClassName=\"praxis-row-overflow-menu__label\"\n [nodes]=\"getTableChromeTextRichContentNodes(getRowOverflowMenuLoadingLabel(), 'praxis-row-overflow-menu__label-text')\"\n ></praxis-rich-content>\n </button>\n }\n <ng-container *ngFor=\"let a of getOverflowRowActions(row); trackBy: trackAction\">\n <button mat-menu-item (click)=\"onRowAction(getActionId(a), row, $event, getRowActionRuntimeOptions(a, row))\" [disabled]=\"isActionDisabled(a, row)\">\n <mat-icon [color]=\"a.color || null\" [praxisIcon]=\"a.icon\"></mat-icon>\n <praxis-rich-content\n rootClassName=\"praxis-row-overflow-menu__label\"\n [nodes]=\"getTableChromeTextRichContentNodes(a.label || getActionId(a), 'praxis-row-overflow-menu__label-text')\"\n ></praxis-rich-content>\n </button>\n </ng-container>\n @if (hasRowOverflowMenuEmptyState(row)) {\n <button mat-menu-item disabled>\n <mat-icon>info</mat-icon>\n <praxis-rich-content\n rootClassName=\"praxis-row-overflow-menu__label\"\n [nodes]=\"getTableChromeTextRichContentNodes(getRowOverflowMenuEmptyLabel(row), 'praxis-row-overflow-menu__label-text')\"\n ></praxis-rich-content>\n </button>\n }\n </mat-menu>\n </div>\n </td>\n }\n </tr>\n </tbody>\n </table>\n </cdk-virtual-scroll-viewport>\n}\n\n</div>\n@if (shouldShowLoadingSurface()) {\n <div class=\"ptable-loading-state\" role=\"status\" aria-live=\"polite\">\n <div class=\"ptable-loading-state__hero\" aria-hidden=\"true\">\n <span class=\"ptable-loading-state__line ptable-loading-state__line--wide\"></span>\n <span class=\"ptable-loading-state__line ptable-loading-state__line--short\"></span>\n <div class=\"ptable-loading-state__rows\">\n @for (placeholder of [1, 2, 3]; track placeholder) {\n <div class=\"ptable-loading-state__row\">\n <span class=\"ptable-loading-state__cell ptable-loading-state__cell--short\"></span>\n <span class=\"ptable-loading-state__cell\"></span>\n <span class=\"ptable-loading-state__cell ptable-loading-state__cell--wide\"></span>\n </div>\n }\n </div>\n </div>\n <div class=\"ptable-loading-state__message\">\n {{ getLoadingSurfaceMessage() }}\n </div>\n </div>\n}\n@if (shouldShowNoDataState()) {\n <div class=\"ptable-no-data-state\" role=\"status\" aria-live=\"polite\">\n <praxis-empty-state-card\n [icon]=\"getNoDataStateIcon()\"\n [title]=\"getNoDataStateTitle()\"\n [description]=\"getNoDataStateDescription()\"\n [primaryAction]=\"getNoDataStatePrimaryAction()\"\n [secondaryActions]=\"getNoDataStateSecondaryActions()\"\n [inline]=\"true\"\n ></praxis-empty-state-card>\n </div>\n}\n@if (\n shouldRenderDataSurface()\n && !schemaError\n && !dataError\n && shouldRenderFloatingBulkActions()\n && getFloatingBulkActions().length\n && !shouldHideFloatingBulkActions()\n) {\n <div [class]=\"'praxis-floating-bulk-actions ' + getFloatingBulkPositionClass()\">\n @for (action of getFloatingBulkActions(); track getActionId(action)) {\n <button\n mat-mini-fab\n [color]=\"action.color || 'primary'\"\n [disabled]=\"isFloatingBulkActionDisabled(action)\"\n (click)=\"onToolbarAction({ action: getActionId(action), actionConfig: action })\"\n [attr.aria-label]=\"action.label || getActionId(action)\"\n [matTooltip]=\"action.label || getActionId(action)\"\n matTooltipPosition=\"left\"\n >\n <praxis-rich-content\n rootClassName=\"praxis-floating-bulk-actions__content\"\n [nodes]=\"getFloatingBulkActionRichContentNodes(action)\"\n ></praxis-rich-content>\n </button>\n }\n </div>\n}\n<!-- Barra de a\u00C3\u00A7\u00C3\u00B5es no rodap\u00C3\u00A9 (opcional) -->\n@if (shouldRenderDataSurface() && !schemaError && !dataError && showToolbar && shouldRenderFooterToolbar()) {\n <praxis-table-toolbar\n [config]=\"config\"\n [backgroundColor]=\"getToolbarActionsBackgroundColor()\"\n [style.--pfx-filter-h]=\"getToolbarLayoutHeightHostStyle()\"\n [class.footer-flat]=\"hasBottomPaginator()\"\n class=\"praxis-toolbar-footer\"\n placement=\"footer\"\n [showMain]=\"shouldShowFooterToolbarMain()\"\n [showEndActions]=\"shouldShowFooterToolbarEndActions()\"\n [showReset]=\"shouldShowFooterToolbarReset()\"\n [showActionsGroup]=\"shouldShowToolbarActionsBottom()\"\n [showMobileActions]=\"shouldShowToolbarActionsBottom()\"\n [evaluationContext]=\"getToolbarEvaluationContext()\"\n (toolbarAction)=\"onToolbarAction($event)\"\n >\n <praxis-filter\n *ngIf=\"shouldShowFooterToolbarMain() && shouldRenderAdvancedFilter()\"\n advancedFilter\n [resourcePath]=\"getAdvancedFilterResourcePath()\"\n [filterId]=\"tableId\"\n [formId]=\"tableId\"\n [persistenceKey]=\"getAdvancedFilterPersistenceKey()\"\n [fieldMetadata]=\"getAdvancedFilterFieldMetadata()\"\n [enableCustomization]=\"enableCustomization\"\n [alwaysVisibleFields]=\"config.behavior?.filtering?.advancedFilters?.settings?.alwaysVisibleFields\"\n [alwaysVisibleFieldMetadataOverrides]=\"config.behavior?.filtering?.advancedFilters?.settings?.alwaysVisibleFieldMetadataOverrides ?? {}\"\n [selectedFieldIds]=\"config.behavior?.filtering?.advancedFilters?.settings?.selectedFieldIds ?? []\"\n [allowSaveTags]=\"config.behavior?.filtering?.advancedFilters?.settings?.allowSaveTags\"\n [changeDebounceMs]=\"config.behavior?.filtering?.advancedFilters?.settings?.changeDebounceMs ?? 300\"\n [i18n]=\"getFilterI18n()\"\n [mode]=\"'filter'\"\n [showFilterSettings]=\"enableCustomization\"\n (change)=\"onAdvancedFilterChange($event)\"\n (requestSearch)=\"onAdvancedFilterSubmit($event)\"\n (clear)=\"onAdvancedFilterClear()\"\n ></praxis-filter>\n <ng-container *ngIf=\"shouldShowFooterToolbarMain() && shouldRenderAdvancedFilter()\">\n <ng-content select=\"[advancedFilter]\"></ng-content>\n </ng-container>\n <ng-container *ngIf=\"shouldShowFooterToolbarMain() && shouldRenderAdvancedFilter()\">\n <ng-content select=\"[toolbar]\"></ng-content>\n </ng-container>\n @if (shouldShowFooterToolbarMain() && shouldRenderAdvancedFilter()) {\n @defer (on idle) {\n @if (aiAdapter) {\n <praxis-ai-assistant\n [adapter]=\"aiAdapter\"\n end-actions\n ></praxis-ai-assistant>\n }\n }\n }\n <button\n *ngIf=\"shouldShowFooterToolbarMain() && shouldRenderAdvancedFilter() && enableCustomization\"\n end-actions\n mat-icon-button\n color=\"primary\"\n data-role=\"table-settings\"\n data-testid=\"table-settings-trigger\"\n (click)=\"openTableSettings()\"\n [attr.aria-label]=\"getTableSettingsLabel()\"\n [matBadge]=\"schemaOutdated ? '!' : ''\"\n [matBadgeHidden]=\"!schemaOutdated\"\n matBadgeColor=\"warn\"\n matBadgeSize=\"small\"\n matBadgePosition=\"above after\"\n [matTooltip]=\"getTableSettingsTooltip()\"\n matTooltipPosition=\"below\"\n >\n <mat-icon>settings</mat-icon>\n </button>\n </praxis-table-toolbar>\n}\n<!-- Paginadores (top/bottom) -->\n@if (shouldRenderDataSurface() && !schemaError && !dataError && getPaginationEnabled() && (config.behavior?.pagination?.position === 'top' || config.behavior?.pagination?.position === 'both')) {\n <mat-paginator\n [length]=\"getPaginationLength()\"\n [pageSize]=\"getPaginationPageSize()\"\n [pageSizeOptions]=\"getPaginationPageSizeOptions()\"\n [showFirstLastButtons]=\"getPaginationShowFirstLast()\"\n (page)=\"onPageChange($event)\"\n [class.compact]=\"config.behavior?.pagination?.style === 'compact'\"\n >\n </mat-paginator>\n}\n\n@if (shouldRenderDataSurface() && !schemaError && !dataError && getPaginationEnabled() && (config.behavior?.pagination?.position === 'bottom' || config.behavior?.pagination?.position === 'both' || !config.behavior?.pagination?.position)) {\n <mat-paginator\n [length]=\"getPaginationLength()\"\n [pageSize]=\"getPaginationPageSize()\"\n [pageSizeOptions]=\"getPaginationPageSizeOptions()\"\n [showFirstLastButtons]=\"getPaginationShowFirstLast()\"\n (page)=\"onPageChange($event)\"\n [class.compact]=\"config.behavior?.pagination?.style === 'compact'\"\n [class.footer-stack]=\"shouldShowToolbarActionsBottom()\"\n >\n </mat-paginator>\n}\n", styles: ["@charset \"UTF-8\";table{width:100%}.praxis-visually-hidden-status{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0}.praxis-column-reorder-status{margin:8px 0;padding:10px 12px;border-radius:8px;border:1px solid var(--p-table-border-color);background:var(--p-table-row-hover-bg);color:var(--p-table-header-fg);font-size:12px;line-height:1.4;box-shadow:0 4px 12px #00000014;animation:pfx-column-reorder-status-in var(--p-table-drag-status-enter-duration, .18s) var(--p-table-motion-easing, cubic-bezier(0, 0, .2, 1))}@keyframes pfx-column-reorder-status-in{0%{opacity:0;transform:translateY(-4px)}to{opacity:1;transform:translateY(0)}}.praxis-actions-cell{height:100%;padding-inline:12px;white-space:nowrap}.pfx-expansion-col-header,.pfx-expansion-col-cell{width:52px;min-width:52px;text-align:center}.pfx-expansion-toggle:focus-visible{outline:2px solid var(--md-sys-color-primary);outline-offset:2px}.pfx-expansion-detail-row{background:var(--md-sys-color-surface-container-low)}.pfx-expansion-detail-cell{padding:0!important;border-bottom:1px solid var(--p-table-border-color)}.pfx-expansion-detail-panel{padding:12px 16px;border-left:3px solid var(--md-sys-color-primary)}.pfx-expansion-detail-panel.pfx-expansion-motion-none{animation:none;transition:none}.pfx-expansion-detail-panel.pfx-expansion-motion-subtle-slide{animation:pfx-expansion-subtle-slide-in var(--pfx-expansion-motion-duration, .16s) var(--pfx-expansion-motion-easing, cubic-bezier(.2, 0, 0, 1))}.pfx-expansion-detail-panel.pfx-expansion-motion-accordion{animation:pfx-expansion-accordion-in var(--pfx-expansion-motion-duration, .18s) var(--pfx-expansion-motion-easing, cubic-bezier(.2, 0, 0, 1));transform-origin:top center}.pfx-expansion-detail-panel.pfx-expansion-motion-fade-scale{animation:pfx-expansion-fade-scale-in var(--pfx-expansion-motion-duration, .16s) var(--pfx-expansion-motion-easing, cubic-bezier(.2, 0, 0, 1));transform-origin:top center}@keyframes pfx-expansion-subtle-slide-in{0%{opacity:0;transform:translateY(-4px)}to{opacity:1;transform:translateY(0)}}@keyframes pfx-expansion-accordion-in{0%{opacity:0;transform:scaleY(.96)}to{opacity:1;transform:scaleY(1)}}@keyframes pfx-expansion-fade-scale-in{0%{opacity:0;transform:translateY(-2px) scale(.985)}to{opacity:1;transform:translateY(0) scale(1)}}.pfx-expansion-detail-schema{margin:0;font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-size:12px;line-height:1.4;white-space:pre-wrap;word-break:break-word;color:var(--md-sys-color-on-surface-variant)}.pfx-expansion-detail-message{font-size:13px;color:var(--md-sys-color-on-surface-variant)}.pfx-expansion-detail-message--error{color:var(--md-sys-color-error)}.pfx-expansion-detail-stack{display:grid;gap:10px}.pfx-expansion-detail-tabs{display:flex;flex-wrap:wrap;gap:8px;margin-bottom:10px}.pfx-expansion-detail-tab-btn{border:1px solid var(--p-table-border-color);background:var(--md-sys-color-surface);color:var(--md-sys-color-on-surface);border-radius:999px;padding:6px 12px;font-size:12px;line-height:1.2;cursor:pointer}.pfx-expansion-detail-tab-btn__content{display:inline-flex;align-items:center;gap:6px;min-width:0}.pfx-expansion-detail-tab-btn__icon .prx-rich-icon{font-size:16px;line-height:1}.pfx-expansion-detail-tab-btn__title{white-space:nowrap}.pfx-expansion-detail-tab-btn__badge .prx-rich-badge{padding:0 8px;min-height:18px;background:color-mix(in srgb,currentColor 12%,transparent);color:inherit}.pfx-expansion-detail-tab-btn.is-active{border-color:var(--md-sys-color-primary);color:var(--md-sys-color-primary);font-weight:600}.pfx-expansion-detail-tab-btn:focus-visible{outline:2px solid var(--md-sys-color-primary);outline-offset:2px}.pfx-expansion-detail-tab-panel{display:grid;gap:10px}.pfx-expansion-node{border:1px solid var(--p-table-border-color);border-radius:8px;padding:10px 12px;background:var(--md-sys-color-surface)}.pfx-expansion-node-card__header{margin-bottom:8px}.pfx-expansion-node-card__title{margin:0;font-size:14px;line-height:1.3}.pfx-expansion-node-card__subtitle{margin:4px 0 0;font-size:12px;color:var(--md-sys-color-on-surface-variant)}.pfx-expansion-node-value{display:flex;align-items:baseline;gap:8px}.pfx-expansion-node-value__label{color:var(--md-sys-color-on-surface-variant);font-size:12px}.pfx-expansion-node-value__content{font-size:14px}.pfx-expansion-node-list__title{margin:0 0 6px;font-size:13px}.pfx-expansion-node-list ul{margin:0;padding-left:18px}.pfx-expansion-node-rich-list__title{margin:0 0 8px;font-size:13px}.pfx-expansion-node-rich-list__items{display:grid;gap:12px}.pfx-expansion-node-rich-list__item{display:grid;gap:10px;padding:12px;border:1px solid var(--md-sys-color-outline-variant, #d7dbe5);border-radius:14px;background:var(--md-sys-color-surface-container-lowest, #fff)}.pfx-expansion-node-rich-list__item--row{grid-template-columns:minmax(0,1fr) auto;align-items:center}.pfx-expansion-node-rich-list__item--stack{grid-template-columns:minmax(0,1fr)}.pfx-expansion-node-rich-list__item--card-list{grid-template-columns:minmax(0,1fr);box-shadow:0 4px 14px #0f172a0a}.pfx-expansion-node-rich-list__item-host{min-width:0}.pfx-expansion-node-rich-list__item-actions{display:flex;flex-wrap:wrap;gap:8px;align-items:center}.pfx-expansion-node-rich-list__item-action-btn{min-width:0}.pfx-expansion-node-rich-list__item-action-host{display:inline-flex;align-items:center}.pfx-expansion-node-action-bar__title{margin:0 0 12px}.pfx-expansion-node-action-bar__actions{display:flex;flex-wrap:wrap;gap:8px;align-items:center}.pfx-expansion-node-action-bar__action-btn{min-width:0}.pfx-expansion-node-action-bar__action-host{display:inline-flex;align-items:center}.pfx-expansion-node-card-grid__header{margin:0 0 12px}.pfx-expansion-node-card-grid__cards{display:grid;gap:12px;grid-template-columns:var(--pfx-expansion-card-grid-columns, repeat(auto-fit, minmax(var(--pfx-expansion-card-grid-min-width, 220px), 1fr)))}.pfx-expansion-node-card-grid__card-host{min-width:0}.pfx-expansion-node-card-grid__card-host [data-rich-node-type=card]{height:100%}.pfx-expansion-node-richtext :where(p,ul,ol,h1,h2,h3,h4,h5,h6){margin-top:0;margin-bottom:8px}.pfx-expansion-node-placeholder{font-size:12px;color:var(--md-sys-color-on-surface-variant)}:host.density-compact{--p-header-padding: 6px 10px;--p-cell-padding: 6px 10px;--p-actions-btn-size: 30px;--p-actions-icon-size: 16px}:host.density-comfortable{--p-header-padding: 10px 14px;--p-cell-padding: 10px 14px;--p-actions-btn-size: 36px;--p-actions-icon-size: 18px}:host.density-spacious{--p-header-padding: 16px 20px;--p-cell-padding: 16px 20px;--p-actions-btn-size: 44px;--p-actions-icon-size: 24px}:host.density-compact ::ng-deep .mat-mdc-cell{padding:var(--p-cell-padding, 8px 12px)}:host.density-comfortable ::ng-deep .mat-mdc-cell{padding:var(--p-cell-padding, 12px 16px)}:host.density-spacious ::ng-deep .mat-mdc-cell{padding:var(--p-cell-padding, 16px 20px)}:host.density-compact .praxis-actions-cell{padding-inline:8px}:host.density-spacious .praxis-actions-cell{padding-inline:16px}.praxis-actions-cell__content{display:flex;align-items:center;justify-content:flex-end;gap:6px;width:100%;transition:opacity .12s ease}.praxis-actions-cell.dense .praxis-actions-cell__content{gap:6px}.praxis-actions-cell__content--discovering{opacity:.78}.praxis-row-action-anchor{display:inline-flex;align-items:center}.praxis-row-action-anchor--workflow{position:relative}.praxis-row-action-anchor--workflow:after{content:\"\";position:absolute;right:4px;top:4px;width:6px;height:6px;border-radius:999px;background:var(--md-sys-color-secondary);opacity:.9;pointer-events:none}.praxis-row-action-anchor--blocked:after{background:var(--md-sys-color-error)}.praxis-icon-btn{width:var(--p-actions-btn-size, 40px);height:var(--p-actions-btn-size, 40px);border:0;background:transparent;padding:0;display:inline-flex;align-items:center;justify-content:center;border-radius:9999px;cursor:pointer;--mat-icon-button-state-layer-size: var(--p-actions-btn-size, 40px)}.praxis-icon-btn:hover{background:var(--md-sys-color-surface-variant)}.praxis-icon-btn:focus-visible{outline:2px solid var(--md-sys-color-primary);outline-offset:2px}.praxis-icon-btn mat-icon,.praxis-icon-btn .mat-icon{font-size:var(--p-actions-icon-size, 22px);width:var(--p-actions-icon-size, 22px);height:var(--p-actions-icon-size, 22px);line-height:var(--p-actions-icon-size, 22px)}.praxis-icon-btn--workflow{background:color-mix(in srgb,var(--md-sys-color-secondary-container) 36%,transparent)}.praxis-icon-btn--blocked{background:color-mix(in srgb,var(--md-sys-color-error-container) 42%,transparent)}.praxis-more-btn{width:var(--p-actions-more-btn-size, var(--p-actions-btn-size, 40px));height:var(--p-actions-more-btn-size, var(--p-actions-btn-size, 40px));--mat-icon-button-state-layer-size: var(--p-actions-more-btn-size, var(--p-actions-btn-size, 40px));background-image:var(--p-actions-more-btn-gradient, none);background-size:100% 100%;background-repeat:no-repeat}.praxis-more-btn mat-icon,.praxis-more-btn .mat-icon{font-size:var(--p-actions-more-icon-size, var(--p-actions-icon-size, 22px));width:var(--p-actions-more-icon-size, var(--p-actions-icon-size, 22px));height:var(--p-actions-more-icon-size, var(--p-actions-icon-size, 22px));line-height:var(--p-actions-more-icon-size, var(--p-actions-icon-size, 22px));color:var(--p-actions-more-icon-color);background-image:var(--p-actions-more-icon-gradient, none);-webkit-background-clip:text;background-clip:text}.praxis-row-btn--workflow{box-shadow:inset 0 0 0 1px color-mix(in srgb,var(--md-sys-color-secondary) 28%,transparent)}.praxis-row-btn--blocked{box-shadow:inset 0 0 0 1px color-mix(in srgb,var(--md-sys-color-error) 28%,transparent)}.praxis-icon-btn.destructive mat-icon{color:var(--md-sys-color-error)}.mat-mdc-tooltip.praxis-tooltip{margin-top:-8px;margin-bottom:8px}.spacer{flex:1 1 auto}.praxis-table-header{display:flex;flex-wrap:wrap;align-items:flex-start;gap:6px;margin:10px 0 8px;width:100%;clear:both;position:relative}.praxis-table-header.stacked{margin:0}.praxis-table-header>praxis-table-toolbar{flex:1 0 100%}.praxis-floating-bulk-actions{position:fixed;z-index:var(--praxis-layer-floating-local, 200);display:inline-flex;align-items:center;gap:8px;padding:8px;border-radius:999px;background:var(--md-sys-color-surface-container-highest);box-shadow:0 8px 20px #00000029}.praxis-floating-bulk-actions.pos-bottom-right{right:20px;bottom:20px}.praxis-floating-bulk-actions.pos-bottom-left{left:20px;bottom:20px}.praxis-floating-bulk-actions.pos-top-right{right:20px;top:20px}.praxis-floating-bulk-actions.pos-top-left{left:20px;top:20px}@media(max-width:768px){.praxis-floating-bulk-actions{gap:6px;padding:6px}.praxis-floating-bulk-actions.pos-bottom-right{right:12px;left:auto;bottom:12px}.praxis-floating-bulk-actions.pos-bottom-left{left:12px;right:auto;bottom:12px}.praxis-floating-bulk-actions.pos-top-right{right:12px;left:auto;top:12px}.praxis-floating-bulk-actions.pos-top-left{left:12px;right:auto;top:12px}}:host{display:block;width:100%;min-width:0;max-width:100%;--pfx-toolbar-pad-y: 6px;--pfx-toolbar-pad-x: 12px;--p-table-bg: var(--md-sys-color-surface-container-highest);--p-table-text-color: var(--md-sys-color-on-surface);--p-table-header-bg: var(--md-sys-color-surface-container-highest);--p-table-header-fg: var(--md-sys-color-on-surface);--p-table-border-color: var(--md-sys-color-outline-variant);--p-table-row-even-bg: var(--md-sys-color-surface-container);--p-table-row-hover-bg: var(--md-sys-color-surface-container-high);--p-table-row-selected-bg: var(--md-sys-color-primary-container);--p-table-badge-soft-primary-bg: var(--md-sys-color-primary-container);--p-table-badge-soft-primary-fg: var(--md-sys-color-on-primary-container);--p-table-badge-soft-accent-bg: var(--md-sys-color-secondary-container);--p-table-badge-soft-accent-fg: var(--md-sys-color-on-secondary-container);--p-table-badge-soft-warn-bg: var(--md-sys-color-error-container);--p-table-badge-soft-warn-fg: var(--md-sys-color-on-error-container);--p-table-state-success-bg: var(--md-sys-color-tertiary-container);--p-table-state-success-fg: var(--md-sys-color-on-tertiary-container);--p-table-state-warning-bg: var(--md-sys-color-secondary-container);--p-table-state-warning-fg: var(--md-sys-color-on-secondary-container);--p-table-state-danger-bg: var(--md-sys-color-error-container);--p-table-state-danger-fg: var(--md-sys-color-on-error-container);--p-table-state-highlight-bg: var(--md-sys-color-primary-container);--p-table-state-highlight-fg: var(--md-sys-color-on-primary-container);--p-table-drag-handle-size: 14px;--p-table-drag-handle-color: var(--md-sys-color-on-surface-variant);--p-table-drag-handle-hover-color: var(--md-sys-color-on-surface);--p-table-drag-handle-base-opacity: 0;--p-table-drag-handle-visible-opacity: .72;--p-table-drag-handle-active-opacity: 1;--p-table-drag-handle-transition-duration: .16s;--p-table-reorder-transition-duration: .16s;--p-table-drag-preview-scale: 1.01;--p-table-drag-status-enter-duration: .18s;--p-table-drag-preview-shadow: 0 14px 32px rgba(0, 0, 0, .28), 0 0 0 1px var(--p-table-border-color)}:host ::ng-deep .mat-mdc-table{background:var(--p-table-bg);color:var(--p-table-text-color);border-radius:12px 12px 0 0;width:100%;box-shadow:var(--p-table-surface-shadow);transition:box-shadow var(--p-table-selection-transition-duration, .18s) var(--p-table-motion-easing, cubic-bezier(0, 0, .2, 1))}:host ::ng-deep .mat-mdc-table:hover{box-shadow:var(--p-table-surface-shadow-hover, var(--p-table-surface-shadow))}:host ::ng-deep .mat-mdc-table.table-stack-top{border-top-left-radius:0;border-top-right-radius:0}:host ::ng-deep .praxis-toolbar-footer{border:0 solid var(--p-table-border-color);border-top:0;border-radius:0;background:var(--p-table-bg)}:host ::ng-deep .mat-mdc-paginator.footer-stack{border-top-left-radius:0;border-top-right-radius:0;border-top:0}:host ::ng-deep .mat-mdc-paginator.footer-stack .mat-mdc-paginator-container{padding:6px 10px}:host ::ng-deep .mat-mdc-paginator{border-top:1px solid color-mix(in srgb,var(--p-table-border-color) 82%,transparent);background:color-mix(in srgb,var(--p-table-bg) 94%,white)}:host ::ng-deep .mat-mdc-paginator .mat-mdc-paginator-container{min-height:40px;padding:4px 8px;gap:6px}:host ::ng-deep .mat-mdc-paginator .mat-mdc-paginator-range-label,:host ::ng-deep .mat-mdc-paginator .mat-mdc-select-value-text{font-size:12px;color:color-mix(in srgb,var(--p-table-text-color) 76%,white)}:host [data-role=table-settings].mat-mdc-icon-button{--mdc-icon-button-icon-color: var(--md-sys-color-primary);color:var(--md-sys-color-primary)}.pfx-link{color:var(--md-sys-color-primary);text-decoration:underline;cursor:pointer}.pfx-chip{display:inline-flex;align-items:center;gap:4px;padding:2px 8px;border-radius:10px;font-size:12px;line-height:1;border:1px solid transparent}.pfx-chip-icon{font-size:14px;width:14px;height:14px}.pfx-chip--outlined{background:transparent;border-color:var(--md-sys-color-outline-variant);color:var(--md-sys-color-on-surface)}.pfx-chip--filled-primary{background:var(--md-sys-color-primary);color:var(--md-sys-color-on-primary)}.pfx-chip--filled-accent{background:var(--md-sys-color-secondary);color:var(--md-sys-color-on-secondary)}.pfx-chip--filled-warn{background:var(--md-sys-color-error);color:var(--md-sys-color-on-error)}.pfx-chip--soft-primary{background:var(--p-table-badge-soft-primary-bg);color:var(--p-table-badge-soft-primary-fg)}.pfx-chip--soft-accent{background:var(--p-table-badge-soft-accent-bg);color:var(--p-table-badge-soft-accent-fg)}.pfx-chip--soft-warn{background:var(--p-table-badge-soft-warn-bg);color:var(--p-table-badge-soft-warn-fg)}.pfx-progress{position:relative;width:100%;max-width:140px;height:8px;background:var(--md-sys-color-surface-container-highest);border-radius:4px;overflow:hidden;display:inline-block;vertical-align:middle}.pfx-progress-bar{height:100%;background:var(--md-sys-color-primary);transition:width .2s ease}.pfx-progress-label{margin-left:8px;font-size:12px;opacity:.8;display:inline-block;vertical-align:middle}.pfx-avatar{display:inline-flex;align-items:center;justify-content:center;background:var(--md-sys-color-surface-container);color:var(--md-sys-color-on-surface);border-radius:4px;overflow:hidden;font-weight:600}.pfx-avatar.shape-rounded{border-radius:8px}.pfx-avatar.shape-circle{border-radius:999px}.pfx-avatar--initials{text-transform:uppercase;font-size:12px}.pfx-cell-compose{display:inline-flex;align-items:center;gap:6px}.pfx-cell-compose.dir-col{flex-direction:column;align-items:stretch}.pfx-cell-compose.align-start{justify-content:flex-start}.pfx-cell-compose.align-center{justify-content:center}.pfx-cell-compose.align-end{justify-content:flex-end}.pfx-cell-compose.wrap{flex-wrap:wrap}.pfx-cell-compose.ellipsis{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.px-scroll-viewport{width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch;overscroll-behavior-x:contain}.px-scroll-viewport.scroll-none{overflow-x:visible}.px-scroll-viewport.scroll-auto ::ng-deep .mat-mdc-table{width:max-content;min-width:100%}.px-scroll-viewport.scroll-wrap ::ng-deep .mat-mdc-header-cell,.px-scroll-viewport.scroll-wrap ::ng-deep .mat-mdc-cell{white-space:normal;text-overflow:initial}.px-scroll-viewport.scroll-wrap ::ng-deep .mat-mdc-table{width:100%}:host ::ng-deep .mat-mdc-header-row{position:sticky;top:0;z-index:var(--praxis-layer-sticky-local, 100);background:var(--p-table-header-bg);color:var(--p-table-header-fg);box-shadow:var(--p-table-header-shadow, 0 1px 0 var(--p-table-border-color));border-bottom:1px solid var(--p-table-border-color)}:host ::ng-deep .mat-mdc-header-cell,:host ::ng-deep .mat-sort-header-content,:host ::ng-deep .mat-mdc-header-row .mat-icon{color:var(--p-table-header-fg)!important;font-weight:600}:host ::ng-deep .mat-mdc-header-cell.mat-sort-header-sorted .mat-sort-header-arrow,:host ::ng-deep .mat-mdc-header-cell:hover .mat-sort-header-arrow{color:var(--p-table-header-fg)!important}:host ::ng-deep .mat-mdc-header-cell.mat-sort-header-sorted .mat-sort-header-arrow .mat-sort-header-indicator,:host ::ng-deep .mat-mdc-header-cell.mat-sort-header-sorted .mat-sort-header-arrow .mat-sort-header-stem,:host ::ng-deep .mat-mdc-header-cell.mat-sort-header-sorted .mat-sort-header-arrow .mat-sort-header-pointer,:host ::ng-deep .mat-mdc-header-cell.mat-sort-header-sorted .mat-sort-header-arrow .mat-sort-header-pointer-left,:host ::ng-deep .mat-mdc-header-cell.mat-sort-header-sorted .mat-sort-header-arrow .mat-sort-header-pointer-right{border-color:var(--p-table-header-fg)!important;background:var(--p-table-header-fg)!important}:host ::ng-deep .mat-mdc-header-cell{padding:var(--p-header-padding, 12px 16px)!important;font-size:var(--p-header-font-size, inherit);font-weight:var(--p-header-font-weight, 600);letter-spacing:var(--p-header-letter-spacing, normal);text-transform:var(--p-header-text-transform, none);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}:host ::ng-deep .pfx-column-drag-enabled .mat-mdc-header-cell.praxis-header-draggable .mat-sort-header-container{display:flex;align-items:center;width:100%;gap:4px;cursor:inherit}:host ::ng-deep .pfx-column-drag-enabled .mat-mdc-header-cell.praxis-header-draggable{-webkit-user-select:none;user-select:none;cursor:grab;padding-left:0!important}:host ::ng-deep .pfx-column-drag-enabled .mat-mdc-header-cell.praxis-header-draggable.cdk-drag-dragging{cursor:grabbing}:host ::ng-deep .pfx-column-drag-enabled .mat-mdc-header-cell.praxis-header-draggable .mat-sort-header-content{display:inline-flex;align-items:center;gap:4px;flex:1 1 auto;min-width:0}:host ::ng-deep .pfx-column-drag-enabled .mat-mdc-header-cell .praxis-header-label{display:inline-flex;align-items:center;gap:4px;flex:1 1 auto;min-width:0}:host ::ng-deep .pfx-column-drag-enabled .mat-mdc-header-cell .praxis-header-label-text{flex:1 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}:host ::ng-deep .pfx-column-drag-enabled .mat-mdc-header-cell .praxis-column-drag-handle{-webkit-appearance:none;appearance:none;border:0;background:transparent;color:var(--p-table-drag-handle-color);width:var(--p-table-drag-handle-size);min-width:var(--p-table-drag-handle-size);flex:0 0 var(--p-table-drag-handle-size);height:var(--p-table-drag-handle-size);padding:0;display:inline-flex;align-items:center;justify-content:center;border-radius:0;cursor:inherit;pointer-events:none;touch-action:none;opacity:var(--p-table-drag-handle-base-opacity, .42);transform:none;order:-1;margin-inline-end:0;transition:opacity var(--p-table-drag-handle-transition-duration, .16s) var(--p-table-motion-easing, cubic-bezier(0, 0, .2, 1)),color var(--p-table-drag-handle-transition-duration, .16s) var(--p-table-motion-easing, cubic-bezier(0, 0, .2, 1))}:host ::ng-deep .pfx-column-drag-enabled .mat-mdc-header-cell.praxis-header-draggable:hover .praxis-column-drag-handle,:host ::ng-deep .pfx-column-drag-enabled .mat-mdc-header-cell.praxis-header-draggable:focus-within .praxis-column-drag-handle{opacity:var(--p-table-drag-handle-visible-opacity, .72);color:var(--p-table-drag-handle-hover-color, var(--p-table-drag-handle-color))}:host ::ng-deep .pfx-column-drag-enabled .mat-mdc-header-cell .praxis-column-drag-handle:active{opacity:var(--p-table-drag-handle-active-opacity, 1);cursor:grabbing}:host ::ng-deep .pfx-column-drag-enabled .mat-mdc-header-cell .praxis-column-drag-handle .mat-icon{font-size:14px;width:14px;height:14px;line-height:14px;transition:transform .18s var(--p-table-motion-easing, cubic-bezier(0, 0, .2, 1))}:host ::ng-deep .pfx-column-drag-enabled .mat-mdc-header-cell.praxis-header-draggable:hover .praxis-column-drag-handle .mat-icon{transform:none}:host ::ng-deep .pfx-column-drag-indicator .cdk-drop-list-dragging .mat-mdc-header-cell:not(.cdk-drag-placeholder){transition:transform var(--p-table-reorder-transition-duration, .18s) var(--p-table-motion-easing, cubic-bezier(0, 0, .2, 1))}:host ::ng-deep .pfx-column-drag-indicator .mat-mdc-header-cell.cdk-drag-animating{transition:transform var(--p-table-reorder-transition-duration, .16s) var(--p-table-motion-easing, cubic-bezier(0, 0, .2, 1))}.pfx-column-drag-preview{box-sizing:border-box;display:flex;align-items:center;border-radius:10px;border:1px solid var(--p-table-border-color);background:linear-gradient(135deg,var(--p-table-header-bg) 0%,var(--p-table-row-hover-bg) 100%);color:var(--p-table-header-fg);box-shadow:var(--p-table-drag-preview-shadow);transform:scale(var(--p-table-drag-preview-scale, 1.01));pointer-events:none;z-index:var(--praxis-layer-authoring-hover, 300)}.pfx-column-drag-preview .praxis-column-drag-handle,.pfx-column-drag-preview .mat-sort-header-arrow,.pfx-column-drag-preview .mat-sort-header-indicator,.pfx-column-drag-preview .mat-sort-header-stem,.pfx-column-drag-preview .mat-sort-header-pointer,.pfx-column-drag-preview .mat-sort-header-pointer-left,.pfx-column-drag-preview .mat-sort-header-pointer-right{display:none!important}.pfx-column-drag-preview .mat-sort-header-container{display:flex;align-items:center;width:100%;min-height:100%;padding-right:0!important}.pfx-column-drag-preview .mat-sort-header-content,.pfx-column-drag-preview .praxis-header-label{display:inline-flex;align-items:center;min-width:0;width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}:host ::ng-deep .pfx-column-drag-indicator .cdk-drag-placeholder{opacity:1;border:1px dashed var(--p-table-border-color);background:var(--p-table-row-hover-bg)}:host ::ng-deep .pfx-column-drag-indicator .cdk-drag-placeholder *{opacity:0}:host ::ng-deep .pfx-column-drag-indicator .mat-mdc-header-cell.cdk-drag-dragging{opacity:.58}@media(prefers-reduced-motion:reduce){:host ::ng-deep .pfx-column-drag-indicator .cdk-drop-list-dragging .mat-mdc-header-cell:not(.cdk-drag-placeholder){transition:none}:host ::ng-deep .pfx-column-drag-enabled .mat-mdc-header-cell .praxis-column-drag-handle,:host ::ng-deep .pfx-column-drag-enabled .mat-mdc-header-cell .praxis-column-drag-handle .mat-icon,.pfx-column-drag-preview{transition:none;transform:none}.praxis-column-reorder-status{animation:none}.pfx-expansion-detail-panel{animation:none!important;transition:none!important;transform:none!important}:host ::ng-deep .mat-mdc-row{transition:none}:host ::ng-deep .mat-mdc-table{transition:none}}.praxis-actions-header{text-align:right}.praxis-actions-header.align-start{text-align:left}.praxis-actions-header.align-center{text-align:center}.praxis-actions-header.align-end{text-align:right}.praxis-actions-header .praxis-actions-header__content{display:inline-flex;align-items:center;gap:var(--p-actions-header-gap, 6px);color:var(--p-actions-header-color, inherit)}.praxis-actions-header .praxis-actions-header__content .mat-icon{font-size:18px;width:18px;height:18px;line-height:18px}:host ::ng-deep .mat-mdc-header-cell .mat-sort-header-container{padding-right:20px}:host ::ng-deep .pfx-column-drag-enabled .mat-mdc-header-cell.praxis-header-draggable .mat-sort-header-container{padding-right:12px}@media(pointer:coarse){:host{--p-table-drag-handle-size: 18px;--p-table-drag-handle-base-opacity: .56;--p-table-drag-handle-visible-opacity: .92}}:host ::ng-deep .mat-mdc-cell{color:var(--p-table-text-color);font-size:var(--p-cell-font-size, inherit);line-height:1.25;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}:host ::ng-deep .mat-mdc-cell .pfx-cell-content,:host ::ng-deep .mat-cell .pfx-cell-content{display:inline-flex;align-items:center;gap:6px;width:100%;min-width:0;overflow:hidden}:host ::ng-deep .mat-mdc-row:hover{background:var(--p-table-row-hover-bg)}:host ::ng-deep .mat-mdc-row{transition:background-color var(--p-table-hover-transition-duration, .18s) var(--p-table-motion-easing, cubic-bezier(0, 0, .2, 1)),box-shadow var(--p-table-selection-transition-duration, .18s) var(--p-table-motion-easing, cubic-bezier(0, 0, .2, 1))}:host ::ng-deep .mat-mdc-row:nth-child(2n){background:var(--p-table-row-even-bg)}:host ::ng-deep .mat-mdc-row:nth-child(2n):hover{background:var(--p-table-row-hover-bg)}:host ::ng-deep .mat-mdc-row.pfx-row-selected,:host ::ng-deep .mat-mdc-row.pfx-row-selected:hover{background:var(--p-table-row-selected-bg)}:host.row-borders ::ng-deep .mat-mdc-row .mat-mdc-cell{border-bottom:1px solid var(--p-table-border-color)}:host.row-borders ::ng-deep .mat-mdc-header-row .mat-mdc-header-cell{border-bottom:none}:host.col-borders ::ng-deep .mat-mdc-header-row .mat-mdc-header-cell,:host.col-borders ::ng-deep .mat-mdc-row .mat-mdc-cell{border-right:1px solid var(--p-table-border-color)}:host.col-borders ::ng-deep .mat-mdc-header-row .mat-mdc-header-cell:last-child,:host.col-borders ::ng-deep .mat-mdc-row .mat-mdc-cell:last-child{border-right:none}.ptable-error{display:flex;align-items:center;gap:12px;padding:12px;margin:8px 0;border:1px solid var(--md-sys-color-error);border-radius:8px}.ptable-error__content{flex:1}.ptable-error__title{font-weight:600}.ptable-info-banner{display:flex;gap:12px;align-items:center;padding:8px 12px;margin:8px 0;border-radius:8px;border:1px solid var(--md-sys-color-primary);background:var(--md-sys-color-primary-container);color:var(--md-sys-color-on-primary-container)}.ptable-info-banner .text{flex:1;font-weight:600}.ptable-info-banner .actions{display:flex;gap:8px}.pfx-cell-image{display:inline-block;vertical-align:middle;background:var(--md-sys-color-surface-variant);border:1px solid var(--md-sys-color-outline-variant)}.pfx-cell-image.shape-rounded{border-radius:8px}.pfx-cell-image.shape-circle{border-radius:9999px}.pfx-badge{display:inline-flex;align-items:center;gap:6px;line-height:1;padding:4px 8px;border-radius:9999px;font-size:12px;font-weight:600;border:1px solid transparent}.pfx-badge .pfx-badge-icon{font-size:16px;width:16px;height:16px}.pfx-badge--filled-primary{background:var(--md-sys-color-primary);color:var(--md-sys-color-on-primary)}.pfx-badge--filled-accent{background:var(--md-sys-color-secondary);color:var(--md-sys-color-on-secondary)}.pfx-badge--filled-warn{background:var(--md-sys-color-error);color:var(--md-sys-color-on-error)}.pfx-badge--outlined{background:transparent;border-color:var(--md-sys-color-outline-variant);color:inherit}.pfx-badge--soft-primary{background:var(--p-table-badge-soft-primary-bg);color:var(--p-table-badge-soft-primary-fg)}.pfx-badge--soft-accent{background:var(--p-table-badge-soft-accent-bg);color:var(--p-table-badge-soft-accent-fg)}.pfx-badge--soft-warn{background:var(--p-table-badge-soft-warn-bg);color:var(--p-table-badge-soft-warn-fg)}.row--success,.row--success td,td.row--success{background-color:var(--p-table-state-success-bg)!important;color:var(--p-table-state-success-fg)!important}.row--warning,.row--warning td,td.row--warning{background-color:var(--p-table-state-warning-bg)!important;color:var(--p-table-state-warning-fg)!important}.row--danger,.row--danger td,td.row--danger{background-color:var(--p-table-state-danger-bg)!important;color:var(--p-table-state-danger-fg)!important}.row--highlight,.row--highlight td,td.row--highlight{background-color:var(--p-table-state-highlight-bg)!important;color:var(--p-table-state-highlight-fg)!important;font-weight:600}.row--muted,.row--muted td,td.row--muted{opacity:.7;filter:saturate(.6)}.pfx-expansion-node-embed{display:flex;flex-direction:column;gap:12px;padding:16px;border:1px solid var(--md-sys-color-outline-variant);border-radius:16px;background:var(--md-sys-color-surface-container-low, var(--md-sys-color-surface))}.ptable-loading-state{padding:8px 12px 4px;display:grid;gap:10px}.ptable-loading-state__hero{display:grid;gap:10px;padding:14px;border-radius:8px;border:1px solid rgba(18,99,180,.08);background:linear-gradient(180deg,#ffffffa6,#ffffff47),linear-gradient(0deg,#1263b408,#1263b400)}.ptable-loading-state__rows{display:grid;gap:8px}.ptable-loading-state__row{display:grid;grid-template-columns:96px minmax(0,1fr) minmax(140px,1.2fr);gap:8px}.ptable-loading-state__line,.ptable-loading-state__cell{display:block;height:12px;border-radius:999px;background:linear-gradient(90deg,#1263b414,#1263b42e,#1263b414);background-size:200% 100%;animation:ptable-loading-wave 1.2s ease-in-out infinite}.ptable-loading-state__line--wide{width:180px}.ptable-loading-state__line--short{width:96px}.ptable-loading-state__cell--short{width:100%;max-width:84px}.ptable-loading-state__cell--wide{width:100%}.ptable-loading-state__message{font-size:.85rem;color:var(--md-sys-color-on-surface-variant, #5a5d67);padding-inline:4px}.pfx-expansion-node-embed__header,.pfx-expansion-node-embed__meta,.pfx-expansion-node-embed__empty,.pfx-expansion-node-embed__diagram-label{display:block}.ptable-no-data-state{padding:8px 12px 4px}.ptable-no-data-state ::ng-deep .empty-card{margin:0;border-radius:8px}@keyframes ptable-loading-wave{0%{background-position:100% 0}to{background-position:-100% 0}}.pfx-expansion-node-embed__diagram{display:flex;flex-direction:column;gap:8px}.pfx-expansion-node-embed__diagram-source{margin:0;padding:12px;overflow:auto;border-radius:12px;border:1px solid var(--md-sys-color-outline-variant);background:var(--md-sys-color-surface-container-highest, var(--md-sys-color-surface));color:var(--md-sys-color-on-surface);font-family:Consolas,Courier New,monospace;font-size:12px;line-height:1.4;white-space:pre-wrap}.pfx-expansion-node-embed__action-btn{align-self:flex-start}.pfx-expansion-node-embed__action-host{display:inline-flex}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i2$1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i2$1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i2$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i2$1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i2$1.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "directive", type: i2$1.NgSwitch, selector: "[ngSwitch]", inputs: ["ngSwitch"] }, { kind: "directive", type: i2$1.NgSwitchCase, selector: "[ngSwitchCase]", inputs: ["ngSwitchCase"] }, { kind: "directive", type: i2$1.NgSwitchDefault, selector: "[ngSwitchDefault]" }, { kind: "ngmodule", type: FormsModule }, { kind: "ngmodule", type: ScrollingModule }, { kind: "directive", type: i10$3.CdkScrollable, selector: "[cdk-scrollable], [cdkScrollable]" }, { kind: "directive", type: i11$1.ɵɵCdkFixedSizeVirtualScroll, selector: "cdk-virtual-scroll-viewport[itemSize]", inputs: ["itemSize", "minBufferPx", "maxBufferPx"] }, { kind: "directive", type: i11$1.ɵɵCdkVirtualForOf, selector: "[cdkVirtualFor][cdkVirtualForOf]", inputs: ["cdkVirtualForOf", "cdkVirtualForTrackBy", "cdkVirtualForTemplate", "cdkVirtualForTemplateCacheSize"] }, { kind: "component", type: i11$1.ɵɵCdkVirtualScrollViewport, selector: "cdk-virtual-scroll-viewport", inputs: ["orientation", "appendOnly"], outputs: ["scrolledIndexChange"] }, { kind: "ngmodule", type: DragDropModule }, { kind: "directive", type: i12.CdkDropList, selector: "[cdkDropList], cdk-drop-list", inputs: ["cdkDropListConnectedTo", "cdkDropListData", "cdkDropListOrientation", "id", "cdkDropListLockAxis", "cdkDropListDisabled", "cdkDropListSortingDisabled", "cdkDropListEnterPredicate", "cdkDropListSortPredicate", "cdkDropListAutoScrollDisabled", "cdkDropListAutoScrollStep", "cdkDropListElementContainer", "cdkDropListHasAnchor"], outputs: ["cdkDropListDropped", "cdkDropListEntered", "cdkDropListExited", "cdkDropListSorted"], exportAs: ["cdkDropList"] }, { kind: "directive", type: i12.CdkDrag, selector: "[cdkDrag]", inputs: ["cdkDragData", "cdkDragLockAxis", "cdkDragRootElement", "cdkDragBoundary", "cdkDragStartDelay", "cdkDragFreeDragPosition", "cdkDragDisabled", "cdkDragConstrainPosition", "cdkDragPreviewClass", "cdkDragPreviewContainer", "cdkDragScale"], outputs: ["cdkDragStarted", "cdkDragReleased", "cdkDragEnded", "cdkDragEntered", "cdkDragExited", "cdkDragDropped", "cdkDragMoved"], exportAs: ["cdkDrag"] }, { kind: "ngmodule", type: MatBadgeModule }, { kind: "directive", type: i15$2.MatBadge, selector: "[matBadge]", inputs: ["matBadgeColor", "matBadgeOverlap", "matBadgeDisabled", "matBadgePosition", "matBadge", "matBadgeDescription", "matBadgeSize", "matBadgeHidden"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i3.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.MatMiniFabButton, selector: "button[mat-mini-fab], a[mat-mini-fab], button[matMiniFab], a[matMiniFab]", exportAs: ["matButton", "matAnchor"] }, { kind: "component", type: i3.MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatCheckboxModule }, { kind: "component", type: i9.MatCheckbox, selector: "mat-checkbox", inputs: ["aria-label", "aria-labelledby", "aria-describedby", "aria-expanded", "aria-controls", "aria-owns", "id", "required", "labelPosition", "name", "value", "disableRipple", "tabIndex", "color", "disabledInteractive", "checked", "disabled", "indeterminate"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i5.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatMenuModule }, { kind: "component", type: i17.MatMenu, selector: "mat-menu", inputs: ["backdropClass", "aria-label", "aria-labelledby", "aria-describedby", "xPosition", "yPosition", "overlapTrigger", "hasBackdrop", "class", "classList"], outputs: ["closed", "close"], exportAs: ["matMenu"] }, { kind: "component", type: i17.MatMenuItem, selector: "[mat-menu-item]", inputs: ["role", "disabled", "disableRipple"], exportAs: ["matMenuItem"] }, { kind: "directive", type: i17.MatMenuTrigger, selector: "[mat-menu-trigger-for], [matMenuTriggerFor]", inputs: ["mat-menu-trigger-for", "matMenuTriggerFor", "matMenuTriggerData", "matMenuTriggerRestoreFocus"], outputs: ["menuOpened", "onMenuOpen", "menuClosed", "onMenuClose"], exportAs: ["matMenuTrigger"] }, { kind: "ngmodule", type: MatPaginatorModule }, { kind: "component", type: i18.MatPaginator, selector: "mat-paginator", inputs: ["color", "pageIndex", "length", "pageSize", "pageSizeOptions", "hidePageSize", "showFirstLastButtons", "selectConfig", "disabled"], outputs: ["page"], exportAs: ["matPaginator"] }, { kind: "ngmodule", type: MatSlideToggleModule }, { kind: "component", type: i6$1.MatSlideToggle, selector: "mat-slide-toggle", inputs: ["name", "id", "labelPosition", "aria-label", "aria-labelledby", "aria-describedby", "required", "color", "disabled", "disableRipple", "tabIndex", "checked", "hideIcon", "disabledInteractive"], outputs: ["change", "toggleChange"], exportAs: ["matSlideToggle"] }, { kind: "ngmodule", type: MatSnackBarModule }, { kind: "ngmodule", type: MatSortModule }, { kind: "directive", type: i20.MatSort, selector: "[matSort]", inputs: ["matSortActive", "matSortStart", "matSortDirection", "matSortDisableClear", "matSortDisabled"], outputs: ["matSortChange"], exportAs: ["matSort"] }, { kind: "component", type: i20.MatSortHeader, selector: "[mat-sort-header]", inputs: ["mat-sort-header", "arrowPosition", "start", "disabled", "sortActionDescription", "disableClear"], exportAs: ["matSortHeader"] }, { kind: "ngmodule", type: MatTableModule }, { kind: "component", type: i8.MatTable, selector: "mat-table, table[mat-table]", exportAs: ["matTable"] }, { kind: "directive", type: i8.MatHeaderCellDef, selector: "[matHeaderCellDef]" }, { kind: "directive", type: i8.MatHeaderRowDef, selector: "[matHeaderRowDef]", inputs: ["matHeaderRowDef", "matHeaderRowDefSticky"] }, { kind: "directive", type: i8.MatColumnDef, selector: "[matColumnDef]", inputs: ["matColumnDef"] }, { kind: "directive", type: i8.MatCellDef, selector: "[matCellDef]" }, { kind: "directive", type: i8.MatRowDef, selector: "[matRowDef]", inputs: ["matRowDefColumns", "matRowDefWhen"] }, { kind: "directive", type: i8.MatHeaderCell, selector: "mat-header-cell, th[mat-header-cell]" }, { kind: "directive", type: i8.MatCell, selector: "mat-cell, td[mat-cell]" }, { kind: "component", type: i8.MatHeaderRow, selector: "mat-header-row, tr[mat-header-row]", exportAs: ["matHeaderRow"] }, { kind: "component", type: i8.MatRow, selector: "mat-row, tr[mat-row]", exportAs: ["matRow"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i10.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "component", type: PraxisFilter, selector: "praxis-filter", inputs: ["resourcePath", "fieldMetadata", "filterId", "formId", "componentInstanceId", "mode", "notifyIfOutdated", "snoozeMs", "autoOpenSettingsOnOutdated", "enableCustomization", "value", "alwaysVisibleFields", "alwaysVisibleFieldMetadataOverrides", "selectedFieldIds", "tags", "allowSaveTags", "persistenceKey", "disablePersistence", "i18n", "changeDebounceMs", "showFilterSettings", "showAdvancedButton", "showAddButton", "showClearButton", "showSearchButton", "confirmTagDelete", "placeBooleansInActions", "showToggleLabels", "useInlineSelectVariant", "useInlineSearchableSelectVariant", "useInlineMultiSelectVariant", "useInlineInputVariant", "useInlineToggleVariant", "useInlineRangeVariant", "useInlineDateVariant", "useInlineDateRangeVariant", "useInlineTimeVariant", "useInlineTimeRangeVariant", "useInlineTreeSelectVariant", "alwaysMinWidth", "alwaysColsMd", "alwaysColsLg", "tagColor", "tagVariant", "tagButtonColor", "actionsButtonColor", "actionsVariant", "overlayVariant", "overlayBackdrop", "advancedOpenMode", "advancedClearButtonsEnabled"], outputs: ["submit", "change", "clear", "modeChange", "requestSearch", "tagsChange", "selectedFieldIdsChange", "metaChanged", "schemaStatusChange"] }, { kind: "directive", type: PraxisIconDirective, selector: "mat-icon[praxisIcon]", inputs: ["praxisIcon"] }, { kind: "component", type: PraxisTableToolbar, selector: "praxis-table-toolbar", inputs: ["config", "backgroundColor", "placement", "showMain", "showActionsGroup", "showEndActions", "showMobileActions", "showReset", "evaluationContext"], outputs: ["toolbarAction", "reset"] }, { kind: "component", type: PraxisRichContent, selector: "praxis-rich-content", inputs: ["document", "nodes", "context", "hostCapabilities", "rootClassName"] }, { kind: "component", type: EmptyStateCardComponent, selector: "praxis-empty-state-card", inputs: ["icon", "title", "description", "primaryAction", "secondaryActions", "inline", "tone"] }, { kind: "component", type: TableRatingCellComponent, selector: "praxis-table-rating", inputs: ["itemsCount", "value", "size", "ratingColor", "outlineColor", "ariaLabel"] }], deferBlockDependencies: [() => [import('@praxisui/ai').then(m => m.PraxisAiAssistantComponent)], () => [import('@praxisui/ai').then(m => m.PraxisAiAssistantComponent)], () => [import('@praxisui/ai').then(m => m.PraxisAiAssistantComponent)], () => [import('@praxisui/ai').then(m => m.PraxisAiAssistantComponent)]] });
|
|
45443
47082
|
}
|
|
45444
47083
|
i0.ɵɵngDeclareClassMetadataAsync({ minVersion: "18.0.0", version: "20.3.17", ngImport: i0, type: PraxisTable, resolveDeferredDeps: () => [import('@praxisui/ai').then(m => m.PraxisAiAssistantComponent)], resolveMetadata: PraxisAiAssistantComponent => ({ decorators: [{
|
|
45445
47084
|
type: Component,
|
|
@@ -45463,6 +47102,7 @@ i0.ɵɵngDeclareClassMetadataAsync({ minVersion: "18.0.0", version: "20.3.17", n
|
|
|
45463
47102
|
PraxisFilter,
|
|
45464
47103
|
PraxisIconDirective,
|
|
45465
47104
|
PraxisTableToolbar,
|
|
47105
|
+
PraxisRichContent,
|
|
45466
47106
|
EmptyStateCardComponent,
|
|
45467
47107
|
TableRatingCellComponent,
|
|
45468
47108
|
], providers: [
|
|
@@ -45472,7 +47112,7 @@ i0.ɵɵngDeclareClassMetadataAsync({ minVersion: "18.0.0", version: "20.3.17", n
|
|
|
45472
47112
|
TableDefaultsProvider,
|
|
45473
47113
|
FilterConfigService,
|
|
45474
47114
|
DataFormattingService
|
|
45475
|
-
], template: "@if (shouldShowEmptyState()) {\n <praxis-empty-state-card\n icon=\"link\"\n [title]=\"'Conecte a tabela \u00E0 fonte de dados'\"\n [description]=\"'Informe a rota do recurso da API para carregar colunas e dados automaticamente.'\"\n [primaryAction]=\"{ label: 'Conectar \u00E0 fonte de dados', icon: 'bolt', action: openQuickConnect.bind(this) }\"\n ></praxis-empty-state-card>\n}\n\n<!-- Error State with Quick Connect CTA -->\n@if (isRemoteMode() && (schemaError || dataError)) {\n<div class=\"ptable-error\" role=\"alert\" aria-live=\"assertive\">\n <mat-icon color=\"warn\" aria-hidden=\"true\">error</mat-icon>\n <div class=\"ptable-error__content\">\n <div class=\"ptable-error__title\">Erro</div>\n <div>{{ errorMessage || 'Ocorreu um erro ao carregar a tabela.' }}</div>\n </div>\n <button mat-flat-button color=\"primary\" (click)=\"openQuickConnect()\">\n <mat-icon>bolt</mat-icon>\n Conectar a recurso\n </button>\n @if (!schemaError) { <button mat-stroked-button (click)=\"retryData()\">Tentar novamente</button> }\n @if (schemaError) { <button mat-stroked-button (click)=\"reloadSchema()\">Recarregar colunas</button> }\n </div>\n}\n\n<!-- Inline banner for schema change (only in edit mode) -->\n@if (shouldShowOutdatedInline()) {\n<div class=\"ptable-info-banner\" role=\"status\" aria-live=\"polite\">\n <div class=\"text\">O schema do servidor mudou. Reconciliar agora?</div>\n <div class=\"actions\">\n <button mat-stroked-button color=\"primary\" (click)=\"onReconcileRequested()\">\n <mat-icon>sync</mat-icon>\n Reconciliar\n </button>\n <button mat-button (click)=\"onSnoozeOutdated()\">Lembrar depois</button>\n <button mat-button (click)=\"onIgnoreOutdated()\">Ignorar</button>\n </div>\n </div>\n}\n\n@if (shouldRenderDataSurface() && !schemaError && !dataError && toolbarV2) {\n <div class=\"praxis-table-header\" [class.edit-mode]=\"enableCustomization\" [class.stacked]=\"showToolbar\">\n @if (showToolbar && shouldShowToolbarTopPlacement()) {\n <praxis-table-toolbar\n [config]=\"config\"\n [backgroundColor]=\"getToolbarActionsBackgroundColor()\"\n [style.--pfx-filter-h]=\"getToolbarLayoutHeightHostStyle()\"\n [evaluationContext]=\"getToolbarEvaluationContext()\"\n [showActionsGroup]=\"shouldShowToolbarActionsTop()\"\n [showMobileActions]=\"shouldShowToolbarActionsTop()\"\n (toolbarAction)=\"onToolbarAction($event)\"\n (reset)=\"onResetPreferences()\"\n >\n @if (shouldRenderAdvancedFilter()) {\n <praxis-filter\n advancedFilter\n [resourcePath]=\"getAdvancedFilterResourcePath()\"\n [filterId]=\"tableId\"\n [formId]=\"tableId\"\n [persistenceKey]=\"getAdvancedFilterPersistenceKey()\"\n [fieldMetadata]=\"getAdvancedFilterFieldMetadata()\"\n [enableCustomization]=\"enableCustomization\"\n \n [alwaysVisibleFields]=\"config.behavior?.filtering?.advancedFilters?.settings?.alwaysVisibleFields\"\n [alwaysVisibleFieldMetadataOverrides]=\"config.behavior?.filtering?.advancedFilters?.settings?.alwaysVisibleFieldMetadataOverrides ?? {}\"\n [selectedFieldIds]=\"config.behavior?.filtering?.advancedFilters?.settings?.selectedFieldIds ?? []\"\n [allowSaveTags]=\"config.behavior?.filtering?.advancedFilters?.settings?.allowSaveTags\"\n [changeDebounceMs]=\"config.behavior?.filtering?.advancedFilters?.settings?.changeDebounceMs ?? 300\"\n [i18n]=\"getFilterI18n()\"\n [mode]=\"'filter'\"\n [showFilterSettings]=\"enableCustomization\"\n (change)=\"onAdvancedFilterChange($event)\"\n (requestSearch)=\"onAdvancedFilterSubmit($event)\"\n (clear)=\"onAdvancedFilterClear()\"\n ></praxis-filter>\n }\n <ng-content select=\"[advancedFilter]\" />\n <ng-content select=\"[toolbar]\" />\n \n <!-- AI Assistant in Toolbar -->\n @defer (on idle) {\n @if (aiAdapter) {\n <praxis-ai-assistant [adapter]=\"aiAdapter\" end-actions></praxis-ai-assistant>\n }\n }\n\n @if (enableCustomization) {\n <button end-actions mat-icon-button color=\"primary\" data-role=\"table-settings\" data-testid=\"table-settings-trigger\"\n (click)=\"openTableSettings()\" aria-label=\"Configura\u00E7\u00F5es\"\n [matBadge]=\"schemaOutdated ? '!' : ''\"\n [matBadgeHidden]=\"!schemaOutdated\"\n matBadgeColor=\"warn\" matBadgeSize=\"small\" matBadgePosition=\"above after\"\n [matTooltip]=\"schemaOutdated ? 'Schema do servidor mudou \u2014 Reconciliar' : 'Configura\u00E7\u00F5es'\"\n matTooltipPosition=\"below\">\n <mat-icon>settings</mat-icon>\n </button>\n }\n </praxis-table-toolbar>\n }\n @if (!showToolbar && enableCustomization) {\n <div class=\"ptable-header-actions\">\n @defer (on idle) {\n @if (aiAdapter) {\n <praxis-ai-assistant [adapter]=\"aiAdapter\"></praxis-ai-assistant>\n }\n }\n <button mat-icon-button color=\"primary\" data-role=\"table-settings\" data-testid=\"table-settings-trigger\" (click)=\"openTableSettings()\" aria-label=\"Configura\u00E7\u00F5es\"\n [matBadge]=\"schemaOutdated ? '!' : ''\"\n [matBadgeHidden]=\"!schemaOutdated\"\n matBadgeColor=\"warn\" matBadgeSize=\"small\" matBadgePosition=\"above after\"\n [matTooltip]=\"schemaOutdated ? 'Schema do servidor mudou \u2014 Reconciliar' : 'Configura\u00E7\u00F5es'\"\n matTooltipPosition=\"below\">\n <mat-icon>settings</mat-icon>\n </button>\n @if (isRemoteMode()) {\n <button mat-icon-button (click)=\"disconnect()\" aria-label=\"Desconectar\" matTooltip=\"Desconectar da fonte de dados\">\n <mat-icon>link_off</mat-icon>\n </button>\n }\n </div>\n }\n </div>\n} @else {\n @if (shouldRenderDataSurface() && !schemaError && !dataError) {\n @if (showToolbar && shouldShowToolbarTopPlacement()) {\n <praxis-table-toolbar\n [config]=\"config\"\n [backgroundColor]=\"getToolbarActionsBackgroundColor()\"\n [style.--pfx-filter-h]=\"getToolbarLayoutHeightHostStyle()\"\n [evaluationContext]=\"getToolbarEvaluationContext()\"\n [showActionsGroup]=\"shouldShowToolbarActionsTop()\"\n [showMobileActions]=\"shouldShowToolbarActionsTop()\"\n (toolbarAction)=\"onToolbarAction($event)\"\n (reset)=\"onResetPreferences()\"\n >\n @if (shouldRenderAdvancedFilter()) {\n <praxis-filter\n advancedFilter\n [resourcePath]=\"getAdvancedFilterResourcePath()\"\n [filterId]=\"tableId\"\n [formId]=\"tableId\"\n [persistenceKey]=\"getAdvancedFilterPersistenceKey()\"\n [fieldMetadata]=\"getAdvancedFilterFieldMetadata()\"\n [enableCustomization]=\"enableCustomization\"\n \n [alwaysVisibleFields]=\"config.behavior?.filtering?.advancedFilters?.settings?.alwaysVisibleFields\"\n [alwaysVisibleFieldMetadataOverrides]=\"config.behavior?.filtering?.advancedFilters?.settings?.alwaysVisibleFieldMetadataOverrides ?? {}\"\n [selectedFieldIds]=\"config.behavior?.filtering?.advancedFilters?.settings?.selectedFieldIds ?? []\"\n [allowSaveTags]=\"config.behavior?.filtering?.advancedFilters?.settings?.allowSaveTags\"\n [changeDebounceMs]=\"config.behavior?.filtering?.advancedFilters?.settings?.changeDebounceMs ?? 300\"\n [i18n]=\"getFilterI18n()\"\n [mode]=\"'filter'\"\n [showFilterSettings]=\"enableCustomization\"\n (change)=\"onAdvancedFilterChange($event)\"\n (requestSearch)=\"onAdvancedFilterSubmit($event)\"\n (clear)=\"onAdvancedFilterClear()\"\n ></praxis-filter>\n }\n <ng-content select=\"[advancedFilter]\" />\n <ng-content select=\"[toolbar]\" />\n @defer (on idle) {\n @if (aiAdapter) {\n <praxis-ai-assistant [adapter]=\"aiAdapter\" end-actions></praxis-ai-assistant>\n }\n }\n @if (enableCustomization) {\n <button end-actions mat-icon-button color=\"primary\" data-role=\"table-settings\" data-testid=\"table-settings-trigger\"\n (click)=\"openTableSettings()\" aria-label=\"Configura\u00E7\u00F5es\"\n [matBadge]=\"schemaOutdated ? '!' : ''\"\n [matBadgeHidden]=\"!schemaOutdated\"\n matBadgeColor=\"warn\" matBadgeSize=\"small\" matBadgePosition=\"above after\"\n [matTooltip]=\"schemaOutdated ? 'Schema do servidor mudou \u2014 Reconciliar' : 'Configura\u00E7\u00F5es'\"\n matTooltipPosition=\"below\">\n <mat-icon>settings</mat-icon>\n </button>\n }\n </praxis-table-toolbar>\n }\n @if (!showToolbar && enableCustomization) {\n <div class=\"ptable-header-actions\">\n <button mat-icon-button color=\"primary\" data-role=\"table-settings\" data-testid=\"table-settings-trigger\" (click)=\"openTableSettings()\" aria-label=\"Configura\u00E7\u00F5es\"\n [matBadge]=\"schemaOutdated ? '!' : ''\"\n [matBadgeHidden]=\"!schemaOutdated\"\n matBadgeColor=\"warn\" matBadgeSize=\"small\" matBadgePosition=\"above after\"\n [matTooltip]=\"schemaOutdated ? 'Schema do servidor mudou \u2014 Reconciliar' : 'Configura\u00E7\u00F5es'\"\n matTooltipPosition=\"below\">\n <mat-icon>settings</mat-icon>\n </button>\n </div>\n }\n }\n}\n<div class=\"px-scroll-viewport\"\n cdkScrollable\n [class.scroll-auto]=\"horizontalScroll === 'auto'\"\n [class.scroll-wrap]=\"horizontalScroll === 'wrap'\"\n [class.scroll-none]=\"horizontalScroll === 'none'\">\n\n@if (shouldRenderDataSurface() && !schemaError && !dataError) {\n<div class=\"praxis-visually-hidden-status\" role=\"status\" aria-live=\"polite\" aria-atomic=\"true\">\n {{ columnReorderStatusMessage }}\n</div>\n@if (columnReorderVisualStatusMessage) {\n <div class=\"praxis-column-reorder-status\" role=\"note\">\n {{ columnReorderVisualStatusMessage }}\n </div>\n}\n<table\n mat-table\n data-testid=\"table-column-drag-drop-list\"\n [dataSource]=\"dataSource\"\n [multiTemplateDataRows]=\"isRowExpansionRuntimeEnabled()\"\n cdkDropList\n [cdkDropListDisabled]=\"!isColumnDraggingEnabled()\"\n [cdkDropListData]=\"visibleDataColumnsForDrag\"\n cdkDropListOrientation=\"horizontal\"\n (cdkDropListDropped)=\"onColumnDrop($event)\"\n matSort\n (matSortChange)=\"onSortChange($event)\"\n [matSortDisabled]=\"!getSortingEnabled()\"\n [ngClass]=\"getTableElevationClassName()\"\n [class.table-stack-top]=\"showToolbar\"\n [class.pfx-column-drag-enabled]=\"isColumnDraggingEnabled()\"\n [class.pfx-column-drag-indicator]=\"isColumnDragIndicatorEnabled()\"\n>\n @if (config.behavior?.selection?.enabled) {\n <ng-container\n matColumnDef=\"_select\"\n >\n <th mat-header-cell *matHeaderCellDef>\n @if (canSelectAll()) {\n <mat-checkbox\n (change)=\"masterToggle()\"\n [checked]=\"isAllSelected()\"\n [indeterminate]=\"selection.hasValue() && !isAllSelected()\"\n ></mat-checkbox>\n }\n </th>\n <td mat-cell *matCellDef=\"let row\">\n <mat-checkbox\n (click)=\"$event.stopPropagation()\"\n (change)=\"toggleRow(row)\"\n [checked]=\"selection.isSelected(row)\"\n ></mat-checkbox>\n </td>\n </ng-container>\n }\n @if (isRowExpansionRuntimeEnabled()) {\n <ng-container matColumnDef=\"_expander\">\n <th mat-header-cell *matHeaderCellDef class=\"pfx-expansion-col-header\">\n <span class=\"praxis-visually-hidden-status\">Expandir detalhes da linha</span>\n </th>\n <td mat-cell *matCellDef=\"let row; let i = index\" class=\"pfx-expansion-col-cell\">\n <button\n mat-icon-button\n class=\"pfx-expansion-toggle\"\n [disabled]=\"!isRowExpandable(row, i) || !isExpansionIconTriggerEnabled()\"\n [attr.aria-expanded]=\"isRowExpanded(row, i) ? 'true' : 'false'\"\n [attr.aria-controls]=\"getRowExpansionDetailId(row, i)\"\n [attr.aria-label]=\"getRowExpansionToggleAriaLabel(row, i)\"\n (click)=\"onExpansionToggleFromIcon(row, i, $event)\"\n (keydown)=\"onExpansionToggleKeydown($event, row, i)\"\n >\n <mat-icon [praxisIcon]=\"isRowExpanded(row, i)\n ? getExpansionExpandedIcon()\n : getExpansionCollapsedIcon()\"></mat-icon>\n </button>\n </td>\n </ng-container>\n }\n @for (column of visibleColumns; track column.field) {\n <ng-container\n [matColumnDef]=\"column.field\"\n [sticky]=\"column.sticky === true || column.sticky === 'start'\"\n [stickyEnd]=\"column.sticky === 'end'\"\n >\n <th\n mat-header-cell\n *matHeaderCellDef\n mat-sort-header\n cdkDrag\n [cdkDragData]=\"column\"\n cdkDragLockAxis=\"x\"\n cdkDragPreviewClass=\"pfx-column-drag-preview\"\n (cdkDragStarted)=\"onColumnDragStarted(column)\"\n (cdkDragEnded)=\"onColumnDragEnded($event, column)\"\n (keydown)=\"onColumnDragHandleKeydown($event, column)\"\n [cdkDragDisabled]=\"!isColumnDraggingEnabled() || !isColumnDraggable(column)\"\n [class.praxis-header-draggable]=\"isColumnDraggingEnabled() && isColumnDraggable(column)\"\n [disabled]=\"!getSortingEnabled() || column.sortable === false\"\n [style.text-align]=\"getColumnTextAlignStyle(column)\"\n [style.width]=\"getColumnWidthStyle(column)\"\n [attr.style]=\"getColumnHeaderAttrStyle(column)\"\n [attr.aria-label]=\"isColumnDraggingEnabled() && isColumnDraggable(column) ? getColumnDragHandleAriaLabel(column) : null\"\n >\n <span class=\"praxis-header-label\" data-testid=\"column-header-label\">\n @if (isColumnDraggingEnabled() && isColumnDraggable(column)) {\n <span\n class=\"praxis-column-drag-handle\"\n data-testid=\"column-drag-handle\"\n [attr.data-column-field]=\"column.field\"\n aria-hidden=\"true\"\n >\n <mat-icon [praxisIcon]=\"'drag_indicator'\"></mat-icon>\n </span>\n }\n <span class=\"praxis-header-label-text\">{{ column.header }}</span>\n </span>\n </th>\n <td\n mat-cell\n *matCellDef=\"let element\"\n [style.text-align]=\"getColumnTextAlignStyle(column)\"\n [style.width]=\"getColumnWidthStyle(column)\"\n [attr.style]=\"getColumnCellAttrStyle(column)\"\n [ngClass]=\"getCellClasses(element, column)\"\n [ngStyle]=\"getCellNgStyle(element, column)\"\n >\n <div\n class=\"pfx-cell-content\"\n [ngClass]=\"getCellContentClasses(element, column)\"\n [ngStyle]=\"getCellContentNgStyle(element, column)\"\n >\n <ng-container [ngSwitch]=\"getEffectiveRendererType(element, column)\">\n <!-- Icon renderer -->\n <ng-container *ngSwitchCase=\"'icon'\">\n <mat-icon\n [color]=\"getIconColor(element, column) || null\"\n [ngStyle]=\"getIconStyle(element, column)\"\n [attr.aria-label]=\"getIconAriaLabel(element, column) || null\"\n >{{ getIconName(element, column) }}</mat-icon\n >\n </ng-container>\n\n <!-- Image renderer -->\n <ng-container *ngSwitchCase=\"'image'\">\n <img\n class=\"pfx-cell-image\"\n [src]=\"getImageSrc(element, column)\"\n [attr.alt]=\"getImageAlt(element, column) || ''\"\n [attr.loading]=\"getImageLazy(element, column) ? 'lazy' : null\"\n [style.width.px]=\"getImageWidth(element, column)\"\n [style.height.px]=\"getImageHeight(element, column)\"\n [class.shape-rounded]=\"getImageShape(element, column) === 'rounded'\"\n [class.shape-circle]=\"getImageShape(element, column) === 'circle'\"\n [style.object-fit]=\"getImageFit(element, column)\"\n />\n </ng-container>\n\n <!-- Badge renderer -->\n <ng-container *ngSwitchCase=\"'badge'\">\n <span class=\"pfx-badge\" [ngClass]=\"getBadgeClasses(element, column)\">\n @if (getBadgeIcon(element, column); as bi) { <mat-icon class=\"pfx-badge-icon\">{{ bi }}</mat-icon> }\n <span class=\"pfx-badge-text\">{{ getBadgeText(element, column) }}</span>\n </span>\n </ng-container>\n\n <!-- Link renderer -->\n <ng-container *ngSwitchCase=\"'link'\">\n <a\n class=\"pfx-link\"\n [attr.href]=\"getLinkHref(element, column) || null\"\n [attr.target]=\"getLinkTarget(element, column) || null\"\n [attr.rel]=\"getLinkRel(element, column) || null\"\n (click)=\"$event.stopPropagation()\"\n >{{ getLinkText(element, column) }}</a\n >\n </ng-container>\n\n <!-- Button renderer -->\n <ng-container *ngSwitchCase=\"'button'\">\n <ng-container [ngSwitch]=\"getButtonVariant(element, column)\">\n <button\n *ngSwitchCase=\"'outlined'\"\n mat-stroked-button\n [color]=\"getButtonColor(element, column) || null\"\n [disabled]=\"isButtonDisabled(element, column)\"\n [attr.aria-label]=\"getButtonAriaLabel(element, column) || getButtonLabel(element, column)\"\n (click)=\"onButtonClick(element, column, $event)\"\n >\n @if (getButtonIcon(element, column); as bi) { <mat-icon>{{ bi }}</mat-icon> }\n {{ getButtonLabel(element, column) }}\n </button>\n <button\n *ngSwitchCase=\"'text'\"\n mat-button\n [color]=\"getButtonColor(element, column) || null\"\n [disabled]=\"isButtonDisabled(element, column)\"\n [attr.aria-label]=\"getButtonAriaLabel(element, column) || getButtonLabel(element, column)\"\n (click)=\"onButtonClick(element, column, $event)\"\n >\n @if (getButtonIcon(element, column); as bi) { <mat-icon>{{ bi }}</mat-icon> }\n {{ getButtonLabel(element, column) }}\n </button>\n <button\n *ngSwitchDefault\n mat-flat-button\n [color]=\"getButtonColor(element, column) || null\"\n [disabled]=\"isButtonDisabled(element, column)\"\n [attr.aria-label]=\"getButtonAriaLabel(element, column) || getButtonLabel(element, column)\"\n (click)=\"onButtonClick(element, column, $event)\"\n >\n @if (getButtonIcon(element, column); as bi) { <mat-icon>{{ bi }}</mat-icon> }\n {{ getButtonLabel(element, column) }}\n </button>\n </ng-container>\n </ng-container>\n\n <!-- Chip renderer -->\n <ng-container *ngSwitchCase=\"'chip'\">\n <span class=\"pfx-chip\" [ngClass]=\"getChipClasses(element, column)\">\n @if (getChipIcon(element, column); as ci) { <mat-icon class=\"pfx-chip-icon\">{{ ci }}</mat-icon> }\n <span class=\"pfx-chip-text\">{{ getChipText(element, column) }}</span>\n </span>\n </ng-container>\n\n <!-- Progress renderer -->\n <ng-container *ngSwitchCase=\"'progress'\">\n <div class=\"pfx-progress\">\n <div class=\"pfx-progress-bar\" [style.width.%]=\"getProgressWidthPercentStyle(element, column)\" [style.background]=\"getProgressBackgroundStyle(element, column)\"></div>\n @if (getProgressShowLabel(element, column)) { <div class=\"pfx-progress-label\">{{ getProgressValue(element, column) }}%</div> }\n </div>\n </ng-container>\n\n <!-- Avatar renderer -->\n <ng-container *ngSwitchCase=\"'avatar'\">\n @if (getAvatarSrc(element, column); as asrc) {\n <img class=\"pfx-avatar\" [src]=\"asrc\" [attr.alt]=\"getAvatarAlt(element, column) || ''\" [ngStyle]=\"getAvatarStyle(element, column)\" [class.shape-rounded]=\"getAvatarShape(element, column) === 'rounded'\" [class.shape-circle]=\"getAvatarShape(element, column) === 'circle'\" loading=\"lazy\" />\n } @else {\n <span class=\"pfx-avatar pfx-avatar--initials\" [ngStyle]=\"getAvatarStyle(element, column)\" [class.shape-rounded]=\"getAvatarShape(element, column) === 'rounded'\" [class.shape-circle]=\"getAvatarShape(element, column) === 'circle'\">{{ getAvatarInitials(element, column) }}</span>\n }\n </ng-container>\n\n <!-- Toggle renderer -->\n <ng-container *ngSwitchCase=\"'toggle'\">\n <mat-slide-toggle\n [checked]=\"getToggleState(element, column)\"\n [disabled]=\"isToggleDisabled(element, column)\"\n [attr.aria-label]=\"getToggleAriaLabel(element, column) || 'Alternar'\"\n (change)=\"onToggleChange(element, column, $event)\"\n (click)=\"$event.stopPropagation()\"\n ></mat-slide-toggle>\n </ng-container>\n\n <!-- Menu renderer -->\n <ng-container *ngSwitchCase=\"'menu'\">\n <button mat-icon-button [matMenuTriggerFor]=\"menuRef\" (click)=\"$event.stopPropagation()\" [attr.aria-label]=\"getMenuAriaLabel(element, column) || 'Menu'\">\n <mat-icon>more_vert</mat-icon>\n </button>\n <mat-menu #menuRef=\"matMenu\">\n <button mat-menu-item *ngFor=\"let it of getMenuItems(element, column)\" (click)=\"onMenuItemClick(it, element, $event)\" [disabled]=\"!it.__visible\" >\n @if (it.icon) { <mat-icon>{{ it.icon }}</mat-icon> }\n <span>{{ it.label }}</span>\n </button>\n </mat-menu>\n </ng-container>\n\n <!-- Rating renderer -->\n <ng-container *ngSwitchCase=\"'rating'\">\n <praxis-table-rating\n class=\"pfx-rating-cell\"\n [itemsCount]=\"getRatingMax(element, column)\"\n [value]=\"getRatingValue(element, column)\"\n [size]=\"getRatingSize(element, column)\"\n [ratingColor]=\"getRatingColor(element, column)\"\n [outlineColor]=\"getRatingOutlineColor(element, column)\"\n [ariaLabel]=\"getRatingAriaLabel(element, column) || column.header\">\n </praxis-table-rating>\n </ng-container>\n\n <!-- HTML renderer (sanitizado) -->\n <ng-container *ngSwitchCase=\"'html'\">\n <span [innerHTML]=\"getSafeHtml(element, column)\"></span>\n </ng-container>\n\n <!-- Compose renderer -->\n <ng-container *ngSwitchCase=\"'compose'\">\n <span class=\"pfx-cell-compose\" [ngClass]=\"getComposeClasses(element, column)\" [ngStyle]=\"getComposeGapStyle(element, column)\">\n <ng-container *ngFor=\"let it of getComposeItems(element, column)\">\n <ng-container [ngSwitch]=\"getItemEffectiveType(element, column, it)\">\n <!-- Reuse helpers by projecting item as faux column -->\n <ng-container *ngSwitchCase=\"'icon'\">\n <mat-icon [color]=\"getIconColor(element, asItemColumn(column, it)) || null\" [ngStyle]=\"getIconStyle(element, asItemColumn(column, it))\" [attr.aria-label]=\"getIconAriaLabel(element, asItemColumn(column, it)) || null\">{{ getIconName(element, asItemColumn(column, it)) }}</mat-icon>\n </ng-container>\n <ng-container *ngSwitchCase=\"'image'\">\n <img class=\"pfx-cell-image\" [src]=\"getImageSrc(element, asItemColumn(column, it))\" [attr.alt]=\"getImageAlt(element, asItemColumn(column, it)) || ''\" [attr.loading]=\"getImageLazy(element, asItemColumn(column, it)) ? 'lazy' : null\" [style.width.px]=\"getImageWidth(element, asItemColumn(column, it))\" [style.height.px]=\"getImageHeight(element, asItemColumn(column, it))\" [class.shape-rounded]=\"getImageShape(element, asItemColumn(column, it)) === 'rounded'\" [class.shape-circle]=\"getImageShape(element, asItemColumn(column, it)) === 'circle'\" [style.object-fit]=\"getImageFit(element, asItemColumn(column, it))\" />\n </ng-container>\n <ng-container *ngSwitchCase=\"'badge'\">\n <span class=\"pfx-badge\" [ngClass]=\"getBadgeClasses(element, asItemColumn(column, it))\">@if (getBadgeIcon(element, asItemColumn(column, it)); as bi) { <mat-icon class=\"pfx-badge-icon\">{{ bi }}</mat-icon> }<span class=\"pfx-badge-text\">{{ getBadgeText(element, asItemColumn(column, it)) }}</span></span>\n </ng-container>\n <ng-container *ngSwitchCase=\"'link'\">\n <a class=\"pfx-link\" [attr.href]=\"getLinkHref(element, asItemColumn(column, it)) || null\" [attr.target]=\"getLinkTarget(element, asItemColumn(column, it)) || null\" [attr.rel]=\"getLinkRel(element, asItemColumn(column, it)) || null\" (click)=\"$event.stopPropagation()\">{{ getLinkText(element, asItemColumn(column, it)) }}</a>\n </ng-container>\n <ng-container *ngSwitchCase=\"'button'\">\n <ng-container [ngSwitch]=\"getButtonVariant(element, asItemColumn(column, it))\">\n <button *ngSwitchCase=\"'outlined'\" mat-stroked-button [color]=\"getButtonColor(element, asItemColumn(column, it)) || null\" [disabled]=\"isButtonDisabled(element, asItemColumn(column, it))\" [attr.aria-label]=\"getButtonAriaLabel(element, asItemColumn(column, it)) || getButtonLabel(element, asItemColumn(column, it))\" (click)=\"onButtonClick(element, asItemColumn(column, it), $event)\">@if (getButtonIcon(element, asItemColumn(column, it)); as bi) { <mat-icon>{{ bi }}</mat-icon> }{{ getButtonLabel(element, asItemColumn(column, it)) }}</button>\n <button *ngSwitchCase=\"'text'\" mat-button [color]=\"getButtonColor(element, asItemColumn(column, it)) || null\" [disabled]=\"isButtonDisabled(element, asItemColumn(column, it))\" [attr.aria-label]=\"getButtonAriaLabel(element, asItemColumn(column, it)) || getButtonLabel(element, asItemColumn(column, it))\" (click)=\"onButtonClick(element, asItemColumn(column, it), $event)\">@if (getButtonIcon(element, asItemColumn(column, it)); as bi) { <mat-icon>{{ bi }}</mat-icon> }{{ getButtonLabel(element, asItemColumn(column, it)) }}</button>\n <button *ngSwitchDefault mat-flat-button [color]=\"getButtonColor(element, asItemColumn(column, it)) || null\" [disabled]=\"isButtonDisabled(element, asItemColumn(column, it))\" [attr.aria-label]=\"getButtonAriaLabel(element, asItemColumn(column, it)) || getButtonLabel(element, asItemColumn(column, it))\" (click)=\"onButtonClick(element, asItemColumn(column, it), $event)\">@if (getButtonIcon(element, asItemColumn(column, it)); as bi) { <mat-icon>{{ bi }}</mat-icon> }{{ getButtonLabel(element, asItemColumn(column, it)) }}</button>\n </ng-container>\n </ng-container>\n <ng-container *ngSwitchCase=\"'chip'\">\n <span class=\"pfx-chip\" [ngClass]=\"getChipClasses(element, asItemColumn(column, it))\">@if (getChipIcon(element, asItemColumn(column, it)); as ci) { <mat-icon class=\"pfx-chip-icon\">{{ ci }}</mat-icon> }<span class=\"pfx-chip-text\">{{ getChipText(element, asItemColumn(column, it)) }}</span></span>\n </ng-container>\n <ng-container *ngSwitchCase=\"'progress'\">\n <div class=\"pfx-progress\"><div class=\"pfx-progress-bar\" [style.width.%]=\"getProgressWidthPercentStyle(element, asItemColumn(column, it))\" [style.background]=\"getProgressBackgroundStyle(element, asItemColumn(column, it))\"></div>@if (getProgressShowLabel(element, asItemColumn(column, it))) { <div class=\"pfx-progress-label\">{{ getProgressValue(element, asItemColumn(column, it)) }}%</div> }</div>\n </ng-container>\n <ng-container *ngSwitchCase=\"'avatar'\">\n @if (getAvatarSrc(element, asItemColumn(column, it)); as asrc) {\n <img class=\"pfx-avatar\" [src]=\"asrc\" [attr.alt]=\"getAvatarAlt(element, asItemColumn(column, it)) || ''\" [ngStyle]=\"getAvatarStyle(element, asItemColumn(column, it))\" [class.shape-rounded]=\"getAvatarShape(element, asItemColumn(column, it)) === 'rounded'\" [class.shape-circle]=\"getAvatarShape(element, asItemColumn(column, it)) === 'circle'\" loading=\"lazy\" />\n } @else {\n <span class=\"pfx-avatar pfx-avatar--initials\" [ngStyle]=\"getAvatarStyle(element, asItemColumn(column, it))\" [class.shape-rounded]=\"getAvatarShape(element, asItemColumn(column, it)) === 'rounded'\" [class.shape-circle]=\"getAvatarShape(element, asItemColumn(column, it)) === 'circle'\">{{ getAvatarInitials(element, asItemColumn(column, it)) }}</span>\n }\n </ng-container>\n <ng-container *ngSwitchCase=\"'toggle'\">\n <mat-slide-toggle [checked]=\"getToggleState(element, asItemColumn(column, it))\" [disabled]=\"isToggleDisabled(element, asItemColumn(column, it))\" [attr.aria-label]=\"getToggleAriaLabel(element, asItemColumn(column, it)) || 'Alternar'\" (change)=\"onToggleChange(element, asItemColumn(column, it), $event)\" (click)=\"$event.stopPropagation()\"></mat-slide-toggle>\n </ng-container>\n <ng-container *ngSwitchCase=\"'menu'\">\n <button mat-icon-button [matMenuTriggerFor]=\"menuRef\" (click)=\"$event.stopPropagation()\" [attr.aria-label]=\"getMenuAriaLabel(element, asItemColumn(column, it)) || 'Menu'\"><mat-icon>more_vert</mat-icon></button>\n <mat-menu #menuRef=\"matMenu\">\n <button mat-menu-item *ngFor=\"let mi of getMenuItems(element, asItemColumn(column, it))\" (click)=\"onMenuItemClick(mi, element, $event)\" [disabled]=\"!mi.__visible\">\n @if (mi.icon) { <mat-icon>{{ mi.icon }}</mat-icon> }\n <span>{{ mi.label }}</span>\n </button>\n </mat-menu>\n </ng-container>\n <ng-container *ngSwitchCase=\"'rating'\">\n <praxis-table-rating\n class=\"pfx-rating-cell\"\n [itemsCount]=\"getRatingMax(element, asItemColumn(column, it))\"\n [value]=\"getRatingValue(element, asItemColumn(column, it))\"\n [size]=\"getRatingSize(element, asItemColumn(column, it))\"\n [ratingColor]=\"getRatingColor(element, asItemColumn(column, it))\"\n [outlineColor]=\"getRatingOutlineColor(element, asItemColumn(column, it))\"\n [ariaLabel]=\"getRatingAriaLabel(element, asItemColumn(column, it)) || column.header\">\n </praxis-table-rating>\n </ng-container>\n <ng-container *ngSwitchCase=\"'html'\">\n <span [innerHTML]=\"getSafeHtml(element, asItemColumn(column, it))\"></span>\n </ng-container>\n <!-- Value item: render base cell text alongside visuals -->\n <ng-container *ngSwitchCase=\"'value'\">\n <span class=\"pfx-cell-value\">{{ getComposeItemValue(element, column, it) }}</span>\n </ng-container>\n </ng-container>\n </ng-container>\n </span>\n </ng-container>\n\n <!-- Default text rendering -->\n <ng-container *ngSwitchDefault>\n {{ getCellValue(element, column) }}\n </ng-container>\n </ng-container>\n </div>\n </td>\n </ng-container>\n }\n @if (config.actions?.row?.enabled) {\n <ng-container matColumnDef=\"_actions\" [sticky]=\"config.actions?.row?.sticky === true || config.actions?.row?.sticky === 'start'\" [stickyEnd]=\"config.actions?.row?.sticky === 'end'\">\n <th mat-header-cell *matHeaderCellDef #actionsHeaderCell [style.width]=\"getRowActionsWidthStyle()\" class=\"praxis-actions-header\" [class.align-start]=\"getActionsHeaderAlign() === 'start'\" [class.align-center]=\"getActionsHeaderAlign() === 'center'\" [class.align-end]=\"getActionsHeaderAlign() === 'end'\">\n <div class=\"praxis-actions-header__content\" [matTooltip]=\"getActionsHeaderTooltip() || ''\" [matTooltipDisabled]=\"!getActionsHeaderTooltip()\">\n @if (getActionsHeaderIcon(); as hi) { <mat-icon [praxisIcon]=\"hi\"></mat-icon> }\n @if (getActionsHeaderLabel(); as hl) { <span class=\"label\">{{ hl }}</span> }\n </div>\n </th>\n <td\n mat-cell\n *matCellDef=\"let row\"\n class=\"praxis-actions-cell\"\n [class.dense]=\"dense\"\n [style.width]=\"getRowActionsWidthStyle()\"\n >\n <div\n class=\"praxis-actions-cell__content\"\n [class.praxis-actions-cell__content--discovering]=\"isRowDiscoveryPending(row)\"\n [attr.aria-busy]=\"isRowDiscoveryPending(row) ? 'true' : null\"\n >\n <!-- A\u00E7\u00F5es inline -->\n <!-- Inline actions: icons mode -->\n @if (config.actions?.row?.display === 'icons' || !config.actions?.row?.display) {\n <ng-container *ngFor=\"let a of getInlineRowActions(row); trackBy: trackAction\">\n <span\n class=\"praxis-row-action-anchor\"\n [class.praxis-row-action-anchor--workflow]=\"isWorkflowRowAction(a)\"\n [class.praxis-row-action-anchor--blocked]=\"isBlockedWorkflowRowAction(a, row)\"\n [matTooltip]=\"getActionTooltip(a, row)\"\n [matTooltipDisabled]=\"!getActionTooltip(a, row)\"\n matTooltipPosition=\"above\"\n matTooltipClass=\"praxis-tooltip\"\n >\n <button\n mat-icon-button\n class=\"praxis-icon-btn\"\n [class.praxis-icon-btn--workflow]=\"isWorkflowRowAction(a)\"\n [class.praxis-icon-btn--blocked]=\"isBlockedWorkflowRowAction(a, row)\"\n [disabled]=\"isActionDisabled(a, row)\"\n (click)=\"onRowAction(getActionId(a), row, $event, getRowActionRuntimeOptions(a, row))\"\n [attr.aria-label]=\"a.label || getActionId(a)\"\n [color]=\"a.color || null\"\n >\n <mat-icon [praxisIcon]=\"a.icon\"></mat-icon>\n </button>\n </span>\n </ng-container>\n }\n\n <!-- Inline actions: buttons mode (show label + icon) -->\n @if (config.actions?.row?.display === 'buttons') {\n <ng-container *ngFor=\"let a of getInlineRowActions(row); trackBy: trackAction\">\n <span\n class=\"praxis-row-action-anchor\"\n [class.praxis-row-action-anchor--workflow]=\"isWorkflowRowAction(a)\"\n [class.praxis-row-action-anchor--blocked]=\"isBlockedWorkflowRowAction(a, row)\"\n [matTooltip]=\"getActionTooltip(a, row)\"\n [matTooltipDisabled]=\"!getActionTooltip(a, row)\"\n matTooltipPosition=\"above\"\n matTooltipClass=\"praxis-tooltip\"\n >\n <button\n mat-flat-button\n class=\"praxis-row-btn\"\n [class.praxis-row-btn--workflow]=\"isWorkflowRowAction(a)\"\n [class.praxis-row-btn--blocked]=\"isBlockedWorkflowRowAction(a, row)\"\n [disabled]=\"isActionDisabled(a, row)\"\n (click)=\"onRowAction(getActionId(a), row, $event, getRowActionRuntimeOptions(a, row))\"\n [attr.aria-label]=\"a.label || getActionId(a)\"\n [color]=\"a.color || null\"\n >\n <mat-icon [praxisIcon]=\"a.icon\"></mat-icon>\n <span>{{ a.label || getActionId(a) }}</span>\n </button>\n </span>\n </ng-container>\n }\n\n <!-- Menu de overflow -->\n @if (hasOverflowRowActions(row)) {\n <button\n mat-icon-button\n class=\"praxis-icon-btn praxis-more-btn\"\n [matMenuTriggerFor]=\"rowMoreMenu\"\n (menuOpened)=\"onRowOverflowMenuOpened(row)\"\n [color]=\"getRowMenuButtonColor() || null\"\n aria-label=\"Mais a\u00E7\u00F5es\"\n [matTooltip]=\"getRowMenuTooltip(row)\"\n matTooltipPosition=\"above\"\n >\n <mat-icon [praxisIcon]=\"getRowMenuIcon()\"></mat-icon>\n </button>\n }\n <mat-menu #rowMoreMenu=\"matMenu\" xPosition=\"before\">\n @if (hasRowOverflowMenuLoadingState(row)) {\n <button mat-menu-item disabled>\n <mat-icon>hourglass_empty</mat-icon>\n <span>{{ getRowOverflowMenuLoadingLabel() }}</span>\n </button>\n }\n <ng-container\n *ngFor=\"let a of getOverflowRowActions(row); trackBy: trackAction\"\n >\n <button\n mat-menu-item\n (click)=\"onRowAction(getActionId(a), row, $event, getRowActionRuntimeOptions(a, row))\"\n [disabled]=\"isActionDisabled(a, row)\"\n >\n <mat-icon [color]=\"a.color || null\" [praxisIcon]=\"a.icon\"></mat-icon>\n <span>{{ a.label || getActionId(a) }}</span>\n </button>\n </ng-container>\n @if (hasRowOverflowMenuEmptyState(row)) {\n <button mat-menu-item disabled>\n <mat-icon>info</mat-icon>\n <span>{{ getRowOverflowMenuEmptyLabel(row) }}</span>\n </button>\n }\n </mat-menu>\n </div>\n </td>\n </ng-container>\n }\n\n <tr\n mat-header-row\n *matHeaderRowDef=\"displayedColumns\"\n ></tr>\n @if (!isVirtualized()) {\n <tr\n mat-row\n *matRowDef=\"let row; let i = index; columns: displayedColumns\"\n [class.pfx-row-selected]=\"selection.isSelected(row)\"\n [class.pfx-row-expanded]=\"isRowExpansionRuntimeEnabled() && isRowExpanded(row, i)\"\n [attr.aria-selected]=\"config.behavior?.selection?.enabled ? (selection.isSelected(row) ? 'true' : 'false') : null\"\n [attr.aria-expanded]=\"isRowExpansionRuntimeEnabled() ? (isRowExpanded(row, i) ? 'true' : 'false') : null\"\n [ngClass]=\"getRowClasses(row)\"\n [ngStyle]=\"getRowNgStyle(row)\"\n [matTooltip]=\"getRowTooltip(row) || null\"\n [matTooltipDisabled]=\"!getRowTooltip(row)\"\n [matTooltipPosition]=\"getRowTooltipPosition(row)\"\n [matTooltipShowDelay]=\"getRowTooltipShowDelay(row)\"\n (click)=\"onRowClicked(row, i, $event)\"\n (dblclick)=\"onRowDoubleClicked(row, i)\"\n ></tr>\n @if (isRowExpansionRuntimeEnabled()) {\n <ng-container matColumnDef=\"_detail\">\n <td\n mat-cell\n *matCellDef=\"let row; let i = index\"\n class=\"pfx-expansion-detail-cell\"\n [attr.colspan]=\"displayedColumns.length\"\n >\n <section\n class=\"pfx-expansion-detail-panel\"\n [ngClass]=\"getExpansionMotionPresetClass()\"\n [ngStyle]=\"getExpansionMotionStyle()\"\n [attr.id]=\"getRowExpansionDetailId(row, i)\"\n role=\"region\"\n [attr.aria-label]=\"getRowExpansionRegionAriaLabel(row, i)\"\n [attr.aria-busy]=\"getExpansionDetailViewState(row, i).status === 'loading' ? 'true' : 'false'\"\n >\n @let detailState = getExpansionDetailViewState(row, i);\n @if (detailState.status === 'loading') {\n <div class=\"pfx-expansion-detail-message\" role=\"status\" aria-live=\"polite\">\n Carregando detail schema...\n </div>\n } @else if (detailState.status !== 'ready') {\n <div\n class=\"pfx-expansion-detail-message pfx-expansion-detail-message--error\"\n role=\"alert\"\n aria-live=\"assertive\"\n aria-atomic=\"true\"\n >\n {{ detailState.message || 'Detail indispon\u00EDvel para esta linha.' }}\n </div>\n } @else {\n @if (getExpansionDetailLayout(detailState.schema) === 'tabs') {\n @let detailTabs = getExpansionDetailTabs(detailState.schema);\n @if (detailTabs.length) {\n <div class=\"pfx-expansion-detail-tabs\" role=\"tablist\" aria-label=\"Se\u00E7\u00F5es do detail\">\n @for (tab of detailTabs; track $index; let tabIndex = $index) {\n <button\n type=\"button\"\n class=\"pfx-expansion-detail-tab-btn\"\n role=\"tab\"\n [attr.id]=\"getExpansionDetailTabId(row, i, tab, tabIndex)\"\n [attr.aria-controls]=\"getExpansionDetailPanelId(row, i, tab, tabIndex)\"\n [attr.aria-selected]=\"isExpansionDetailTabActive(row, i, tab, tabIndex, detailTabs) ? 'true' : 'false'\"\n [attr.tabindex]=\"isExpansionDetailTabActive(row, i, tab, tabIndex, detailTabs) ? '0' : '-1'\"\n [class.is-active]=\"isExpansionDetailTabActive(row, i, tab, tabIndex, detailTabs)\"\n (click)=\"onExpansionDetailTabSelect(row, i, tab, tabIndex, $event)\"\n (keydown)=\"onExpansionDetailTabKeydown($event, row, i, tabIndex, detailTabs)\"\n >\n {{ getExpansionDetailNodeTitle(tab, 'Tab') }}\n </button>\n }\n </div>\n @for (tab of detailTabs; track $index; let tabIndex = $index) {\n @if (isExpansionDetailTabActive(row, i, tab, tabIndex, detailTabs)) {\n <div\n class=\"pfx-expansion-detail-tab-panel\"\n role=\"tabpanel\"\n [attr.id]=\"getExpansionDetailPanelId(row, i, tab, tabIndex)\"\n [attr.aria-labelledby]=\"getExpansionDetailTabId(row, i, tab, tabIndex)\"\n >\n @for (childNode of getExpansionDetailNodeChildren(tab); track $index) {\n <ng-container\n *ngTemplateOutlet=\"\n expansionDetailNodeTemplate;\n context: { $implicit: childNode, row: row, index: i }\n \"\n ></ng-container>\n }\n </div>\n }\n }\n } @else {\n <div class=\"pfx-expansion-detail-message\">\n Schema em layout tabs sem abas v\u00E1lidas.\n </div>\n }\n } @else {\n <div class=\"pfx-expansion-detail-stack\">\n @for (node of getExpansionDetailItems(detailState.schema); track $index) {\n <ng-container\n *ngTemplateOutlet=\"\n expansionDetailNodeTemplate;\n context: { $implicit: node, row: row, index: i }\n \"\n ></ng-container>\n }\n </div>\n }\n }\n\n <ng-template #expansionDetailNodeTemplate let-node let-row=\"row\" let-index=\"index\">\n @switch (getExpansionDetailNodeType(node)) {\n @case ('card') {\n <article class=\"pfx-expansion-node pfx-expansion-node-card\">\n <header class=\"pfx-expansion-node-card__header\">\n <h5 class=\"pfx-expansion-node-card__title\">\n {{ getExpansionDetailNodeTitle(node, 'Card') }}\n </h5>\n @if (node?.subtitle) {\n <p class=\"pfx-expansion-node-card__subtitle\">{{ node?.subtitle }}</p>\n }\n </header>\n @for (childNode of getExpansionDetailNodeChildren(node); track $index) {\n <ng-container\n *ngTemplateOutlet=\"\n expansionDetailNodeTemplate;\n context: { $implicit: childNode, row: row, index: index }\n \"\n ></ng-container>\n }\n </article>\n }\n @case ('value') {\n <div class=\"pfx-expansion-node pfx-expansion-node-value\">\n <span class=\"pfx-expansion-node-value__label\">\n {{ getExpansionDetailNodeTitle(node, 'Valor') }}\n </span>\n <strong class=\"pfx-expansion-node-value__content\">\n {{ getExpansionDetailValue(row, node) }}\n </strong>\n </div>\n }\n @case ('list') {\n <section class=\"pfx-expansion-node pfx-expansion-node-list\">\n <h6 class=\"pfx-expansion-node-list__title\">\n {{ getExpansionDetailNodeTitle(node, 'Lista') }}\n </h6>\n @let listItems = getExpansionDetailListItems(row, node);\n @if (listItems.length) {\n <ul>\n @for (entry of listItems; track $index) {\n <li>{{ entry }}</li>\n }\n </ul>\n } @else {\n <p class=\"pfx-expansion-node-placeholder\">Sem itens.</p>\n }\n </section>\n }\n @case ('richText') {\n <div\n class=\"pfx-expansion-node pfx-expansion-node-richtext\"\n [innerHTML]=\"getExpansionDetailRichText(node)\"\n ></div>\n }\n @case ('formRef') {\n <div class=\"pfx-expansion-node pfx-expansion-node-placeholder\">\n Formul\u00E1rio referenciado: <code>{{ node?.schemaId || node?.id || 'sem-id' }}</code>\n </div>\n }\n @case ('tableRef') {\n <div class=\"pfx-expansion-node pfx-expansion-node-placeholder\">\n Tabela referenciada: <code>{{ node?.schemaId || node?.id || 'sem-id' }}</code>\n </div>\n }\n @case ('chartRef') {\n <div class=\"pfx-expansion-node pfx-expansion-node-placeholder\">\n Gr\u00E1fico referenciado: <code>{{ node?.schemaId || node?.id || 'sem-id' }}</code>\n </div>\n }\n @case ('templateRef') {\n <div class=\"pfx-expansion-node pfx-expansion-node-placeholder\">\n Template referenciado: <code>{{ node?.id || node?.templateId || 'sem-id' }}</code>\n </div>\n }\n @case ('action') {\n <div class=\"pfx-expansion-node pfx-expansion-node-placeholder\">\n A\u00E7\u00E3o declarada: <code>{{ node?.id || node?.actionId || 'sem-id' }}</code>\n </div>\n }\n @case ('tab') {\n <div class=\"pfx-expansion-node pfx-expansion-node-placeholder\">\n Node <code>tab</code> fora de contexto de tabs.\n </div>\n }\n @default {\n <div class=\"pfx-expansion-node pfx-expansion-node-placeholder\">\n Node n\u00E3o suportado: <code>{{ getExpansionDetailNodeType(node) }}</code>\n </div>\n }\n }\n </ng-template>\n </section>\n </td>\n </ng-container>\n <tr\n mat-row\n *matRowDef=\"let row; columns: expansionDetailRowColumns; when: isExpansionDetailRow\"\n class=\"pfx-expansion-detail-row\"\n ></tr>\n }\n }\n</table>\n}\n\n<!-- Virtual rows path (header preserved above) -->\n@if (shouldRenderDataSurface() && !schemaError && !dataError && isVirtualized()) {\n <cdk-virtual-scroll-viewport\n class=\"ptable-viewport\"\n [itemSize]=\"getVirtItemHeight()\"\n [minBufferPx]=\"getVirtBufferSize() * getVirtItemHeight()\"\n [maxBufferPx]=\"getVirtBufferSize() * getVirtItemHeight() * 2\"\n [style.minHeight]=\"getVirtMinHeightHostStyle()\"\n >\n <table\n class=\"mat-mdc-table\"\n [ngClass]=\"getTableElevationClassName()\"\n [style.width]=\"getVirtualTableWidthStyle()\"\n >\n <tbody>\n <tr class=\"mat-mdc-row\"\n *cdkVirtualFor=\"let row of dataSource.data; let i = index; trackBy: trackByRow\"\n [class.pfx-row-selected]=\"selection.isSelected(row)\"\n [attr.aria-selected]=\"config.behavior?.selection?.enabled ? (selection.isSelected(row) ? 'true' : 'false') : null\"\n [ngClass]=\"getRowClasses(row)\"\n [ngStyle]=\"getRowNgStyle(row)\"\n [matTooltip]=\"getRowTooltip(row) || null\"\n [matTooltipDisabled]=\"!getRowTooltip(row)\"\n [matTooltipPosition]=\"getRowTooltipPosition(row)\"\n [matTooltipShowDelay]=\"getRowTooltipShowDelay(row)\"\n (click)=\"onRowClicked(row, i, $event)\"\n (dblclick)=\"onRowDoubleClicked(row, i)\">\n <!-- Selection column -->\n @if (config.behavior?.selection?.enabled) { <td class=\"mat-mdc-cell\">\n <mat-checkbox\n (click)=\"$event.stopPropagation()\"\n (change)=\"toggleRow(row)\"\n [checked]=\"selection.isSelected(row)\">\n </mat-checkbox>\n </td> }\n <!-- Data columns -->\n @for (column of visibleColumns; track column.field) {\n <td class=\"mat-mdc-cell\"\n [style.text-align]=\"getColumnTextAlignStyle(column)\"\n [style.width]=\"getColumnWidthStyle(column)\"\n [attr.style]=\"getColumnCellAttrStyle(column)\"\n [ngClass]=\"getCellClasses(row, column)\"\n [ngStyle]=\"getCellNgStyle(row, column)\">\n <div\n class=\"pfx-cell-content\"\n [ngClass]=\"getCellContentClasses(row, column)\"\n [ngStyle]=\"getCellContentNgStyle(row, column)\"\n >\n <ng-container [ngSwitch]=\"getEffectiveRendererType(row, column)\">\n <ng-container *ngSwitchCase=\"'icon'\">\n <mat-icon [color]=\"getIconColor(row, column) || null\"\n [ngStyle]=\"getIconStyle(row, column)\"\n [attr.aria-label]=\"getIconAriaLabel(row, column) || null\">\n {{ getIconName(row, column) }}\n </mat-icon>\n </ng-container>\n <ng-container *ngSwitchCase=\"'image'\">\n <img class=\"pfx-cell-image\"\n [src]=\"getImageSrc(row, column)\"\n [attr.alt]=\"getImageAlt(row, column) || ''\"\n [attr.loading]=\"getImageLazy(row, column) ? 'lazy' : null\"\n [style.width.px]=\"getImageWidth(row, column)\"\n [style.height.px]=\"getImageHeight(row, column)\"\n [class.shape-rounded]=\"getImageShape(row, column) === 'rounded'\"\n [class.shape-circle]=\"getImageShape(row, column) === 'circle'\"\n [style.object-fit]=\"getImageFit(row, column)\" />\n </ng-container>\n <ng-container *ngSwitchCase=\"'badge'\">\n <span class=\"pfx-badge\" [ngClass]=\"getBadgeClasses(row, column)\">\n @if (getBadgeIcon(row, column); as bi) { <mat-icon class=\"pfx-badge-icon\">{{ bi }}</mat-icon> }\n <span class=\"pfx-badge-text\">{{ getBadgeText(row, column) }}</span>\n </span>\n </ng-container>\n <ng-container *ngSwitchDefault>\n {{ getCellValue(row, column) }}\n </ng-container>\n </ng-container>\n </div>\n </td>\n }\n\n <!-- Actions column -->\n @if (config.actions?.row?.enabled) {\n <td class=\"mat-mdc-cell praxis-actions-cell\" [class.dense]=\"dense\" [style.width]=\"getRowActionsWidthStyle()\">\n <div\n class=\"praxis-actions-cell__content\"\n [class.praxis-actions-cell__content--discovering]=\"isRowDiscoveryPending(row)\"\n [attr.aria-busy]=\"isRowDiscoveryPending(row) ? 'true' : null\"\n >\n @if (config.actions?.row?.display === 'icons' || !config.actions?.row?.display) {\n <ng-container *ngFor=\"let a of getInlineRowActions(row); trackBy: trackAction\">\n <span\n class=\"praxis-row-action-anchor\"\n [class.praxis-row-action-anchor--workflow]=\"isWorkflowRowAction(a)\"\n [class.praxis-row-action-anchor--blocked]=\"isBlockedWorkflowRowAction(a, row)\"\n [matTooltip]=\"getActionTooltip(a, row)\"\n [matTooltipDisabled]=\"!getActionTooltip(a, row)\"\n matTooltipPosition=\"above\"\n matTooltipClass=\"praxis-tooltip\"\n >\n <button mat-icon-button class=\"praxis-icon-btn\"\n [class.praxis-icon-btn--workflow]=\"isWorkflowRowAction(a)\"\n [class.praxis-icon-btn--blocked]=\"isBlockedWorkflowRowAction(a, row)\"\n [disabled]=\"isActionDisabled(a, row)\"\n (click)=\"onRowAction(getActionId(a), row, $event, getRowActionRuntimeOptions(a, row))\"\n [attr.aria-label]=\"a.label || getActionId(a)\"\n [color]=\"a.color || null\">\n <mat-icon [praxisIcon]=\"a.icon\"></mat-icon>\n </button>\n </span>\n </ng-container>\n }\n @if (config.actions?.row?.display === 'buttons') {\n <ng-container *ngFor=\"let a of getInlineRowActions(row); trackBy: trackAction\">\n <span\n class=\"praxis-row-action-anchor\"\n [class.praxis-row-action-anchor--workflow]=\"isWorkflowRowAction(a)\"\n [class.praxis-row-action-anchor--blocked]=\"isBlockedWorkflowRowAction(a, row)\"\n [matTooltip]=\"getActionTooltip(a, row)\"\n [matTooltipDisabled]=\"!getActionTooltip(a, row)\"\n matTooltipPosition=\"above\"\n matTooltipClass=\"praxis-tooltip\"\n >\n <button mat-flat-button class=\"praxis-row-btn\"\n [class.praxis-row-btn--workflow]=\"isWorkflowRowAction(a)\"\n [class.praxis-row-btn--blocked]=\"isBlockedWorkflowRowAction(a, row)\"\n [disabled]=\"isActionDisabled(a, row)\"\n (click)=\"onRowAction(getActionId(a), row, $event, getRowActionRuntimeOptions(a, row))\"\n [attr.aria-label]=\"a.label || getActionId(a)\"\n [color]=\"a.color || null\">\n <mat-icon [praxisIcon]=\"a.icon\"></mat-icon>\n <span>{{ a.label || getActionId(a) }}</span>\n </button>\n </span>\n </ng-container>\n }\n @if (hasOverflowRowActions(row)) {\n <button mat-icon-button class=\"praxis-icon-btn praxis-more-btn\"\n [matMenuTriggerFor]=\"rowMoreMenuV\"\n (menuOpened)=\"onRowOverflowMenuOpened(row)\"\n [color]=\"getRowMenuButtonColor() || null\"\n aria-label=\"Mais a\u00E7\u00F5es\"\n [matTooltip]=\"getRowMenuTooltip(row)\"\n matTooltipPosition=\"above\">\n <mat-icon [praxisIcon]=\"getRowMenuIcon()\"></mat-icon>\n </button>\n }\n <mat-menu #rowMoreMenuV=\"matMenu\" xPosition=\"before\">\n @if (hasRowOverflowMenuLoadingState(row)) {\n <button mat-menu-item disabled>\n <mat-icon>hourglass_empty</mat-icon>\n <span>{{ getRowOverflowMenuLoadingLabel() }}</span>\n </button>\n }\n <ng-container *ngFor=\"let a of getOverflowRowActions(row); trackBy: trackAction\">\n <button mat-menu-item (click)=\"onRowAction(getActionId(a), row, $event, getRowActionRuntimeOptions(a, row))\" [disabled]=\"isActionDisabled(a, row)\">\n <mat-icon [color]=\"a.color || null\" [praxisIcon]=\"a.icon\"></mat-icon>\n <span>{{ a.label || getActionId(a) }}</span>\n </button>\n </ng-container>\n @if (hasRowOverflowMenuEmptyState(row)) {\n <button mat-menu-item disabled>\n <mat-icon>info</mat-icon>\n <span>{{ getRowOverflowMenuEmptyLabel(row) }}</span>\n </button>\n }\n </mat-menu>\n </div>\n </td>\n }\n </tr>\n </tbody>\n </table>\n </cdk-virtual-scroll-viewport>\n}\n\n</div>\n@if (\n shouldRenderDataSurface()\n && !schemaError\n && !dataError\n && shouldRenderFloatingBulkActions()\n && getFloatingBulkActions().length\n && !shouldHideFloatingBulkActions()\n) {\n <div [class]=\"'praxis-floating-bulk-actions ' + getFloatingBulkPositionClass()\">\n @for (action of getFloatingBulkActions(); track getActionId(action)) {\n <button\n mat-mini-fab\n [color]=\"action.color || 'primary'\"\n [disabled]=\"isFloatingBulkActionDisabled(action)\"\n (click)=\"onToolbarAction({ action: getActionId(action), actionConfig: action })\"\n [attr.aria-label]=\"action.label || getActionId(action)\"\n [matTooltip]=\"action.label || getActionId(action)\"\n matTooltipPosition=\"left\"\n >\n <mat-icon [praxisIcon]=\"action.icon || 'done_all'\"></mat-icon>\n </button>\n }\n </div>\n}\n<!-- Barra de a\u00E7\u00F5es no rodap\u00E9 (opcional) -->\n@if (shouldRenderDataSurface() && !schemaError && !dataError && showToolbar && shouldRenderFooterToolbar()) {\n <praxis-table-toolbar\n [config]=\"config\"\n [backgroundColor]=\"getToolbarActionsBackgroundColor()\"\n [style.--pfx-filter-h]=\"getToolbarLayoutHeightHostStyle()\"\n [class.footer-flat]=\"hasBottomPaginator()\"\n class=\"praxis-toolbar-footer\"\n placement=\"footer\"\n [showMain]=\"shouldShowFooterToolbarMain()\"\n [showEndActions]=\"shouldShowFooterToolbarEndActions()\"\n [showReset]=\"shouldShowFooterToolbarReset()\"\n [showActionsGroup]=\"shouldShowToolbarActionsBottom()\"\n [showMobileActions]=\"shouldShowToolbarActionsBottom()\"\n [evaluationContext]=\"getToolbarEvaluationContext()\"\n (toolbarAction)=\"onToolbarAction($event)\"\n >\n <praxis-filter\n *ngIf=\"shouldShowFooterToolbarMain() && shouldRenderAdvancedFilter()\"\n advancedFilter\n [resourcePath]=\"getAdvancedFilterResourcePath()\"\n [filterId]=\"tableId\"\n [formId]=\"tableId\"\n [persistenceKey]=\"getAdvancedFilterPersistenceKey()\"\n [fieldMetadata]=\"getAdvancedFilterFieldMetadata()\"\n [enableCustomization]=\"enableCustomization\"\n [alwaysVisibleFields]=\"config.behavior?.filtering?.advancedFilters?.settings?.alwaysVisibleFields\"\n [alwaysVisibleFieldMetadataOverrides]=\"config.behavior?.filtering?.advancedFilters?.settings?.alwaysVisibleFieldMetadataOverrides ?? {}\"\n [selectedFieldIds]=\"config.behavior?.filtering?.advancedFilters?.settings?.selectedFieldIds ?? []\"\n [allowSaveTags]=\"config.behavior?.filtering?.advancedFilters?.settings?.allowSaveTags\"\n [changeDebounceMs]=\"config.behavior?.filtering?.advancedFilters?.settings?.changeDebounceMs ?? 300\"\n [i18n]=\"getFilterI18n()\"\n [mode]=\"'filter'\"\n [showFilterSettings]=\"enableCustomization\"\n (change)=\"onAdvancedFilterChange($event)\"\n (requestSearch)=\"onAdvancedFilterSubmit($event)\"\n (clear)=\"onAdvancedFilterClear()\"\n ></praxis-filter>\n <ng-container *ngIf=\"shouldShowFooterToolbarMain() && shouldRenderAdvancedFilter()\">\n <ng-content select=\"[advancedFilter]\"></ng-content>\n </ng-container>\n <ng-container *ngIf=\"shouldShowFooterToolbarMain() && shouldRenderAdvancedFilter()\">\n <ng-content select=\"[toolbar]\"></ng-content>\n </ng-container>\n @if (shouldShowFooterToolbarMain() && shouldRenderAdvancedFilter()) {\n @defer (on idle) {\n @if (aiAdapter) {\n <praxis-ai-assistant\n [adapter]=\"aiAdapter\"\n end-actions\n ></praxis-ai-assistant>\n }\n }\n }\n <button\n *ngIf=\"shouldShowFooterToolbarMain() && shouldRenderAdvancedFilter() && enableCustomization\"\n end-actions\n mat-icon-button\n color=\"primary\"\n data-role=\"table-settings\"\n data-testid=\"table-settings-trigger\"\n (click)=\"openTableSettings()\"\n aria-label=\"Configura\u00E7\u00F5es\"\n [matBadge]=\"schemaOutdated ? '!' : ''\"\n [matBadgeHidden]=\"!schemaOutdated\"\n matBadgeColor=\"warn\"\n matBadgeSize=\"small\"\n matBadgePosition=\"above after\"\n [matTooltip]=\"schemaOutdated ? 'Schema do servidor mudou \u2014 Reconciliar' : 'Configura\u00E7\u00F5es'\"\n matTooltipPosition=\"below\"\n >\n <mat-icon>settings</mat-icon>\n </button>\n </praxis-table-toolbar>\n}\n<!-- Paginadores (top/bottom) -->\n@if (shouldRenderDataSurface() && !schemaError && !dataError && getPaginationEnabled() && (config.behavior?.pagination?.position === 'top' || config.behavior?.pagination?.position === 'both')) {\n <mat-paginator\n [length]=\"getPaginationLength()\"\n [pageSize]=\"getPaginationPageSize()\"\n [pageSizeOptions]=\"getPaginationPageSizeOptions()\"\n [showFirstLastButtons]=\"getPaginationShowFirstLast()\"\n (page)=\"onPageChange($event)\"\n [class.compact]=\"config.behavior?.pagination?.style === 'compact'\"\n >\n </mat-paginator>\n}\n\n@if (shouldRenderDataSurface() && !schemaError && !dataError && getPaginationEnabled() && (config.behavior?.pagination?.position === 'bottom' || config.behavior?.pagination?.position === 'both' || !config.behavior?.pagination?.position)) {\n <mat-paginator\n [length]=\"getPaginationLength()\"\n [pageSize]=\"getPaginationPageSize()\"\n [pageSizeOptions]=\"getPaginationPageSizeOptions()\"\n [showFirstLastButtons]=\"getPaginationShowFirstLast()\"\n (page)=\"onPageChange($event)\"\n [class.compact]=\"config.behavior?.pagination?.style === 'compact'\"\n [class.footer-stack]=\"shouldShowToolbarActionsBottom()\"\n >\n </mat-paginator>\n}\n", styles: ["@charset \"UTF-8\";table{width:100%}.praxis-visually-hidden-status{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0}.praxis-column-reorder-status{margin:8px 0;padding:10px 12px;border-radius:8px;border:1px solid var(--p-table-border-color);background:var(--p-table-row-hover-bg);color:var(--p-table-header-fg);font-size:12px;line-height:1.4;box-shadow:0 4px 12px #00000014;animation:pfx-column-reorder-status-in var(--p-table-drag-status-enter-duration, .18s) var(--p-table-motion-easing, cubic-bezier(0, 0, .2, 1))}@keyframes pfx-column-reorder-status-in{0%{opacity:0;transform:translateY(-4px)}to{opacity:1;transform:translateY(0)}}.praxis-actions-cell{height:100%;padding-inline:12px;white-space:nowrap}.pfx-expansion-col-header,.pfx-expansion-col-cell{width:52px;min-width:52px;text-align:center}.pfx-expansion-toggle:focus-visible{outline:2px solid var(--md-sys-color-primary);outline-offset:2px}.pfx-expansion-detail-row{background:var(--md-sys-color-surface-container-low)}.pfx-expansion-detail-cell{padding:0!important;border-bottom:1px solid var(--p-table-border-color)}.pfx-expansion-detail-panel{padding:12px 16px;border-left:3px solid var(--md-sys-color-primary)}.pfx-expansion-detail-panel.pfx-expansion-motion-none{animation:none;transition:none}.pfx-expansion-detail-panel.pfx-expansion-motion-subtle-slide{animation:pfx-expansion-subtle-slide-in var(--pfx-expansion-motion-duration, .16s) var(--pfx-expansion-motion-easing, cubic-bezier(.2, 0, 0, 1))}.pfx-expansion-detail-panel.pfx-expansion-motion-accordion{animation:pfx-expansion-accordion-in var(--pfx-expansion-motion-duration, .18s) var(--pfx-expansion-motion-easing, cubic-bezier(.2, 0, 0, 1));transform-origin:top center}.pfx-expansion-detail-panel.pfx-expansion-motion-fade-scale{animation:pfx-expansion-fade-scale-in var(--pfx-expansion-motion-duration, .16s) var(--pfx-expansion-motion-easing, cubic-bezier(.2, 0, 0, 1));transform-origin:top center}@keyframes pfx-expansion-subtle-slide-in{0%{opacity:0;transform:translateY(-4px)}to{opacity:1;transform:translateY(0)}}@keyframes pfx-expansion-accordion-in{0%{opacity:0;transform:scaleY(.96)}to{opacity:1;transform:scaleY(1)}}@keyframes pfx-expansion-fade-scale-in{0%{opacity:0;transform:translateY(-2px) scale(.985)}to{opacity:1;transform:translateY(0) scale(1)}}.pfx-expansion-detail-schema{margin:0;font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-size:12px;line-height:1.4;white-space:pre-wrap;word-break:break-word;color:var(--md-sys-color-on-surface-variant)}.pfx-expansion-detail-message{font-size:13px;color:var(--md-sys-color-on-surface-variant)}.pfx-expansion-detail-message--error{color:var(--md-sys-color-error)}.pfx-expansion-detail-stack{display:grid;gap:10px}.pfx-expansion-detail-tabs{display:flex;flex-wrap:wrap;gap:8px;margin-bottom:10px}.pfx-expansion-detail-tab-btn{border:1px solid var(--p-table-border-color);background:var(--md-sys-color-surface);color:var(--md-sys-color-on-surface);border-radius:999px;padding:6px 12px;font-size:12px;line-height:1.2;cursor:pointer}.pfx-expansion-detail-tab-btn.is-active{border-color:var(--md-sys-color-primary);color:var(--md-sys-color-primary);font-weight:600}.pfx-expansion-detail-tab-btn:focus-visible{outline:2px solid var(--md-sys-color-primary);outline-offset:2px}.pfx-expansion-detail-tab-panel{display:grid;gap:10px}.pfx-expansion-node{border:1px solid var(--p-table-border-color);border-radius:8px;padding:10px 12px;background:var(--md-sys-color-surface)}.pfx-expansion-node-card__header{margin-bottom:8px}.pfx-expansion-node-card__title{margin:0;font-size:14px;line-height:1.3}.pfx-expansion-node-card__subtitle{margin:4px 0 0;font-size:12px;color:var(--md-sys-color-on-surface-variant)}.pfx-expansion-node-value{display:flex;align-items:baseline;gap:8px}.pfx-expansion-node-value__label{color:var(--md-sys-color-on-surface-variant);font-size:12px}.pfx-expansion-node-value__content{font-size:14px}.pfx-expansion-node-list__title{margin:0 0 6px;font-size:13px}.pfx-expansion-node-list ul{margin:0;padding-left:18px}.pfx-expansion-node-richtext :where(p,ul,ol,h1,h2,h3,h4,h5,h6){margin-top:0;margin-bottom:8px}.pfx-expansion-node-placeholder{font-size:12px;color:var(--md-sys-color-on-surface-variant)}:host.density-compact{--p-header-padding: 8px 12px;--p-cell-padding: 8px 12px;--p-actions-btn-size: 32px;--p-actions-icon-size: 18px}:host.density-comfortable{--p-header-padding: 12px 16px;--p-cell-padding: 12px 16px;--p-actions-btn-size: 40px;--p-actions-icon-size: 22px}:host.density-spacious{--p-header-padding: 16px 20px;--p-cell-padding: 16px 20px;--p-actions-btn-size: 44px;--p-actions-icon-size: 24px}:host.density-compact ::ng-deep .mat-mdc-cell{padding:var(--p-cell-padding, 8px 12px)}:host.density-comfortable ::ng-deep .mat-mdc-cell{padding:var(--p-cell-padding, 12px 16px)}:host.density-spacious ::ng-deep .mat-mdc-cell{padding:var(--p-cell-padding, 16px 20px)}:host.density-compact .praxis-actions-cell{padding-inline:8px}:host.density-spacious .praxis-actions-cell{padding-inline:16px}.praxis-actions-cell__content{display:flex;align-items:center;justify-content:flex-end;gap:8px;width:100%;transition:opacity .12s ease}.praxis-actions-cell.dense .praxis-actions-cell__content{gap:6px}.praxis-actions-cell__content--discovering{opacity:.78}.praxis-row-action-anchor{display:inline-flex;align-items:center}.praxis-row-action-anchor--workflow{position:relative}.praxis-row-action-anchor--workflow:after{content:\"\";position:absolute;right:4px;top:4px;width:6px;height:6px;border-radius:999px;background:var(--md-sys-color-secondary);opacity:.9;pointer-events:none}.praxis-row-action-anchor--blocked:after{background:var(--md-sys-color-error)}.praxis-icon-btn{width:var(--p-actions-btn-size, 40px);height:var(--p-actions-btn-size, 40px);border:0;background:transparent;padding:0;display:inline-flex;align-items:center;justify-content:center;border-radius:9999px;cursor:pointer;--mat-icon-button-state-layer-size: var(--p-actions-btn-size, 40px)}.praxis-icon-btn:hover{background:var(--md-sys-color-surface-variant)}.praxis-icon-btn:focus-visible{outline:2px solid var(--md-sys-color-primary);outline-offset:2px}.praxis-icon-btn mat-icon,.praxis-icon-btn .mat-icon{font-size:var(--p-actions-icon-size, 22px);width:var(--p-actions-icon-size, 22px);height:var(--p-actions-icon-size, 22px);line-height:var(--p-actions-icon-size, 22px)}.praxis-icon-btn--workflow{background:color-mix(in srgb,var(--md-sys-color-secondary-container) 36%,transparent)}.praxis-icon-btn--blocked{background:color-mix(in srgb,var(--md-sys-color-error-container) 42%,transparent)}.praxis-more-btn{width:var(--p-actions-more-btn-size, var(--p-actions-btn-size, 40px));height:var(--p-actions-more-btn-size, var(--p-actions-btn-size, 40px));--mat-icon-button-state-layer-size: var(--p-actions-more-btn-size, var(--p-actions-btn-size, 40px));background-image:var(--p-actions-more-btn-gradient, none);background-size:100% 100%;background-repeat:no-repeat}.praxis-more-btn mat-icon,.praxis-more-btn .mat-icon{font-size:var(--p-actions-more-icon-size, var(--p-actions-icon-size, 22px));width:var(--p-actions-more-icon-size, var(--p-actions-icon-size, 22px));height:var(--p-actions-more-icon-size, var(--p-actions-icon-size, 22px));line-height:var(--p-actions-more-icon-size, var(--p-actions-icon-size, 22px));color:var(--p-actions-more-icon-color);background-image:var(--p-actions-more-icon-gradient, none);-webkit-background-clip:text;background-clip:text}.praxis-row-btn--workflow{box-shadow:inset 0 0 0 1px color-mix(in srgb,var(--md-sys-color-secondary) 28%,transparent)}.praxis-row-btn--blocked{box-shadow:inset 0 0 0 1px color-mix(in srgb,var(--md-sys-color-error) 28%,transparent)}.praxis-icon-btn.destructive mat-icon{color:var(--md-sys-color-error)}.mat-mdc-tooltip.praxis-tooltip{margin-top:-8px;margin-bottom:8px}.spacer{flex:1 1 auto}.praxis-table-header{display:flex;flex-wrap:wrap;align-items:flex-start;gap:8px;margin:16px 0 12px;width:100%;clear:both;position:relative}.praxis-table-header.stacked{margin:0}.praxis-table-header>praxis-table-toolbar{flex:1 0 100%}.praxis-floating-bulk-actions{position:fixed;z-index:var(--praxis-layer-floating-local, 200);display:inline-flex;align-items:center;gap:8px;padding:8px;border-radius:999px;background:var(--md-sys-color-surface-container-highest);box-shadow:0 8px 20px #00000029}.praxis-floating-bulk-actions.pos-bottom-right{right:20px;bottom:20px}.praxis-floating-bulk-actions.pos-bottom-left{left:20px;bottom:20px}.praxis-floating-bulk-actions.pos-top-right{right:20px;top:20px}.praxis-floating-bulk-actions.pos-top-left{left:20px;top:20px}@media(max-width:768px){.praxis-floating-bulk-actions{gap:6px;padding:6px}.praxis-floating-bulk-actions.pos-bottom-right{right:12px;left:auto;bottom:12px}.praxis-floating-bulk-actions.pos-bottom-left{left:12px;right:auto;bottom:12px}.praxis-floating-bulk-actions.pos-top-right{right:12px;left:auto;top:12px}.praxis-floating-bulk-actions.pos-top-left{left:12px;right:auto;top:12px}}:host{display:block;width:100%;min-width:0;max-width:100%;--pfx-toolbar-pad-y: 6px;--pfx-toolbar-pad-x: 12px;--p-table-bg: var(--md-sys-color-surface-container-highest);--p-table-text-color: var(--md-sys-color-on-surface);--p-table-header-bg: var(--md-sys-color-surface-container-highest);--p-table-header-fg: var(--md-sys-color-on-surface);--p-table-border-color: var(--md-sys-color-outline-variant);--p-table-row-even-bg: var(--md-sys-color-surface-container);--p-table-row-hover-bg: var(--md-sys-color-surface-container-high);--p-table-row-selected-bg: var(--md-sys-color-primary-container);--p-table-badge-soft-primary-bg: var(--md-sys-color-primary-container);--p-table-badge-soft-primary-fg: var(--md-sys-color-on-primary-container);--p-table-badge-soft-accent-bg: var(--md-sys-color-secondary-container);--p-table-badge-soft-accent-fg: var(--md-sys-color-on-secondary-container);--p-table-badge-soft-warn-bg: var(--md-sys-color-error-container);--p-table-badge-soft-warn-fg: var(--md-sys-color-on-error-container);--p-table-state-success-bg: var(--md-sys-color-tertiary-container);--p-table-state-success-fg: var(--md-sys-color-on-tertiary-container);--p-table-state-warning-bg: var(--md-sys-color-secondary-container);--p-table-state-warning-fg: var(--md-sys-color-on-secondary-container);--p-table-state-danger-bg: var(--md-sys-color-error-container);--p-table-state-danger-fg: var(--md-sys-color-on-error-container);--p-table-state-highlight-bg: var(--md-sys-color-primary-container);--p-table-state-highlight-fg: var(--md-sys-color-on-primary-container);--p-table-drag-handle-size: 14px;--p-table-drag-handle-color: var(--md-sys-color-on-surface-variant);--p-table-drag-handle-hover-color: var(--md-sys-color-on-surface);--p-table-drag-handle-base-opacity: 0;--p-table-drag-handle-visible-opacity: .72;--p-table-drag-handle-active-opacity: 1;--p-table-drag-handle-transition-duration: .16s;--p-table-reorder-transition-duration: .16s;--p-table-drag-preview-scale: 1.01;--p-table-drag-status-enter-duration: .18s;--p-table-drag-preview-shadow: 0 14px 32px rgba(0, 0, 0, .28), 0 0 0 1px var(--p-table-border-color)}:host ::ng-deep .mat-mdc-table{background:var(--p-table-bg);color:var(--p-table-text-color);border-radius:12px 12px 0 0;width:100%;box-shadow:var(--p-table-surface-shadow);transition:box-shadow var(--p-table-selection-transition-duration, .18s) var(--p-table-motion-easing, cubic-bezier(0, 0, .2, 1))}:host ::ng-deep .mat-mdc-table:hover{box-shadow:var(--p-table-surface-shadow-hover, var(--p-table-surface-shadow))}:host ::ng-deep .mat-mdc-table.table-stack-top{border-top-left-radius:0;border-top-right-radius:0}:host ::ng-deep .praxis-toolbar-footer{border:0 solid var(--p-table-border-color);border-top:0;border-radius:0;background:var(--p-table-bg)}:host ::ng-deep .mat-mdc-paginator.footer-stack{border-top-left-radius:0;border-top-right-radius:0;border-top:0}:host ::ng-deep .mat-mdc-paginator.footer-stack .mat-mdc-paginator-container{padding:8px 12px}:host [data-role=table-settings].mat-mdc-icon-button{--mdc-icon-button-icon-color: var(--md-sys-color-primary);color:var(--md-sys-color-primary)}.pfx-link{color:var(--md-sys-color-primary);text-decoration:underline;cursor:pointer}.pfx-chip{display:inline-flex;align-items:center;gap:4px;padding:2px 8px;border-radius:10px;font-size:12px;line-height:1;border:1px solid transparent}.pfx-chip-icon{font-size:14px;width:14px;height:14px}.pfx-chip--outlined{background:transparent;border-color:var(--md-sys-color-outline-variant);color:var(--md-sys-color-on-surface)}.pfx-chip--filled-primary{background:var(--md-sys-color-primary);color:var(--md-sys-color-on-primary)}.pfx-chip--filled-accent{background:var(--md-sys-color-secondary);color:var(--md-sys-color-on-secondary)}.pfx-chip--filled-warn{background:var(--md-sys-color-error);color:var(--md-sys-color-on-error)}.pfx-chip--soft-primary{background:var(--p-table-badge-soft-primary-bg);color:var(--p-table-badge-soft-primary-fg)}.pfx-chip--soft-accent{background:var(--p-table-badge-soft-accent-bg);color:var(--p-table-badge-soft-accent-fg)}.pfx-chip--soft-warn{background:var(--p-table-badge-soft-warn-bg);color:var(--p-table-badge-soft-warn-fg)}.pfx-progress{position:relative;width:100%;max-width:140px;height:8px;background:var(--md-sys-color-surface-container-highest);border-radius:4px;overflow:hidden;display:inline-block;vertical-align:middle}.pfx-progress-bar{height:100%;background:var(--md-sys-color-primary);transition:width .2s ease}.pfx-progress-label{margin-left:8px;font-size:12px;opacity:.8;display:inline-block;vertical-align:middle}.pfx-avatar{display:inline-flex;align-items:center;justify-content:center;background:var(--md-sys-color-surface-container);color:var(--md-sys-color-on-surface);border-radius:4px;overflow:hidden;font-weight:600}.pfx-avatar.shape-rounded{border-radius:8px}.pfx-avatar.shape-circle{border-radius:999px}.pfx-avatar--initials{text-transform:uppercase;font-size:12px}.pfx-cell-compose{display:inline-flex;align-items:center;gap:6px}.pfx-cell-compose.dir-col{flex-direction:column;align-items:stretch}.pfx-cell-compose.align-start{justify-content:flex-start}.pfx-cell-compose.align-center{justify-content:center}.pfx-cell-compose.align-end{justify-content:flex-end}.pfx-cell-compose.wrap{flex-wrap:wrap}.pfx-cell-compose.ellipsis{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.px-scroll-viewport{width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch;overscroll-behavior-x:contain}.px-scroll-viewport.scroll-none{overflow-x:visible}.px-scroll-viewport.scroll-auto ::ng-deep .mat-mdc-table{width:max-content;min-width:100%}.px-scroll-viewport.scroll-wrap ::ng-deep .mat-mdc-header-cell,.px-scroll-viewport.scroll-wrap ::ng-deep .mat-mdc-cell{white-space:normal;text-overflow:initial}.px-scroll-viewport.scroll-wrap ::ng-deep .mat-mdc-table{width:100%}:host ::ng-deep .mat-mdc-header-row{position:sticky;top:0;z-index:var(--praxis-layer-sticky-local, 100);background:var(--p-table-header-bg);color:var(--p-table-header-fg);box-shadow:var(--p-table-header-shadow, 0 1px 0 var(--p-table-border-color));border-bottom:1px solid var(--p-table-border-color)}:host ::ng-deep .mat-mdc-header-cell,:host ::ng-deep .mat-sort-header-content,:host ::ng-deep .mat-mdc-header-row .mat-icon{color:var(--p-table-header-fg)!important;font-weight:600}:host ::ng-deep .mat-mdc-header-cell.mat-sort-header-sorted .mat-sort-header-arrow,:host ::ng-deep .mat-mdc-header-cell:hover .mat-sort-header-arrow{color:var(--p-table-header-fg)!important}:host ::ng-deep .mat-mdc-header-cell.mat-sort-header-sorted .mat-sort-header-arrow .mat-sort-header-indicator,:host ::ng-deep .mat-mdc-header-cell.mat-sort-header-sorted .mat-sort-header-arrow .mat-sort-header-stem,:host ::ng-deep .mat-mdc-header-cell.mat-sort-header-sorted .mat-sort-header-arrow .mat-sort-header-pointer,:host ::ng-deep .mat-mdc-header-cell.mat-sort-header-sorted .mat-sort-header-arrow .mat-sort-header-pointer-left,:host ::ng-deep .mat-mdc-header-cell.mat-sort-header-sorted .mat-sort-header-arrow .mat-sort-header-pointer-right{border-color:var(--p-table-header-fg)!important;background:var(--p-table-header-fg)!important}:host ::ng-deep .mat-mdc-header-cell{padding:var(--p-header-padding, 12px 16px)!important;font-size:var(--p-header-font-size, inherit);font-weight:var(--p-header-font-weight, 600);letter-spacing:var(--p-header-letter-spacing, normal);text-transform:var(--p-header-text-transform, none);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}:host ::ng-deep .pfx-column-drag-enabled .mat-mdc-header-cell.praxis-header-draggable .mat-sort-header-container{display:flex;align-items:center;width:100%;gap:4px;cursor:inherit}:host ::ng-deep .pfx-column-drag-enabled .mat-mdc-header-cell.praxis-header-draggable{-webkit-user-select:none;user-select:none;cursor:grab;padding-left:0!important}:host ::ng-deep .pfx-column-drag-enabled .mat-mdc-header-cell.praxis-header-draggable.cdk-drag-dragging{cursor:grabbing}:host ::ng-deep .pfx-column-drag-enabled .mat-mdc-header-cell.praxis-header-draggable .mat-sort-header-content{display:inline-flex;align-items:center;gap:4px;flex:1 1 auto;min-width:0}:host ::ng-deep .pfx-column-drag-enabled .mat-mdc-header-cell .praxis-header-label{display:inline-flex;align-items:center;gap:4px;flex:1 1 auto;min-width:0}:host ::ng-deep .pfx-column-drag-enabled .mat-mdc-header-cell .praxis-header-label-text{flex:1 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}:host ::ng-deep .pfx-column-drag-enabled .mat-mdc-header-cell .praxis-column-drag-handle{-webkit-appearance:none;appearance:none;border:0;background:transparent;color:var(--p-table-drag-handle-color);width:var(--p-table-drag-handle-size);min-width:var(--p-table-drag-handle-size);flex:0 0 var(--p-table-drag-handle-size);height:var(--p-table-drag-handle-size);padding:0;display:inline-flex;align-items:center;justify-content:center;border-radius:0;cursor:inherit;pointer-events:none;touch-action:none;opacity:var(--p-table-drag-handle-base-opacity, .42);transform:none;order:-1;margin-inline-end:0;transition:opacity var(--p-table-drag-handle-transition-duration, .16s) var(--p-table-motion-easing, cubic-bezier(0, 0, .2, 1)),color var(--p-table-drag-handle-transition-duration, .16s) var(--p-table-motion-easing, cubic-bezier(0, 0, .2, 1))}:host ::ng-deep .pfx-column-drag-enabled .mat-mdc-header-cell.praxis-header-draggable:hover .praxis-column-drag-handle,:host ::ng-deep .pfx-column-drag-enabled .mat-mdc-header-cell.praxis-header-draggable:focus-within .praxis-column-drag-handle{opacity:var(--p-table-drag-handle-visible-opacity, .72);color:var(--p-table-drag-handle-hover-color, var(--p-table-drag-handle-color))}:host ::ng-deep .pfx-column-drag-enabled .mat-mdc-header-cell .praxis-column-drag-handle:active{opacity:var(--p-table-drag-handle-active-opacity, 1);cursor:grabbing}:host ::ng-deep .pfx-column-drag-enabled .mat-mdc-header-cell .praxis-column-drag-handle .mat-icon{font-size:14px;width:14px;height:14px;line-height:14px;transition:transform .18s var(--p-table-motion-easing, cubic-bezier(0, 0, .2, 1))}:host ::ng-deep .pfx-column-drag-enabled .mat-mdc-header-cell.praxis-header-draggable:hover .praxis-column-drag-handle .mat-icon{transform:none}:host ::ng-deep .pfx-column-drag-indicator .cdk-drop-list-dragging .mat-mdc-header-cell:not(.cdk-drag-placeholder){transition:transform var(--p-table-reorder-transition-duration, .18s) var(--p-table-motion-easing, cubic-bezier(0, 0, .2, 1))}:host ::ng-deep .pfx-column-drag-indicator .mat-mdc-header-cell.cdk-drag-animating{transition:transform var(--p-table-reorder-transition-duration, .16s) var(--p-table-motion-easing, cubic-bezier(0, 0, .2, 1))}.pfx-column-drag-preview{box-sizing:border-box;display:flex;align-items:center;border-radius:10px;border:1px solid var(--p-table-border-color);background:linear-gradient(135deg,var(--p-table-header-bg) 0%,var(--p-table-row-hover-bg) 100%);color:var(--p-table-header-fg);box-shadow:var(--p-table-drag-preview-shadow);transform:scale(var(--p-table-drag-preview-scale, 1.01));pointer-events:none;z-index:var(--praxis-layer-authoring-hover, 300)}.pfx-column-drag-preview .praxis-column-drag-handle,.pfx-column-drag-preview .mat-sort-header-arrow,.pfx-column-drag-preview .mat-sort-header-indicator,.pfx-column-drag-preview .mat-sort-header-stem,.pfx-column-drag-preview .mat-sort-header-pointer,.pfx-column-drag-preview .mat-sort-header-pointer-left,.pfx-column-drag-preview .mat-sort-header-pointer-right{display:none!important}.pfx-column-drag-preview .mat-sort-header-container{display:flex;align-items:center;width:100%;min-height:100%;padding-right:0!important}.pfx-column-drag-preview .mat-sort-header-content,.pfx-column-drag-preview .praxis-header-label{display:inline-flex;align-items:center;min-width:0;width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}:host ::ng-deep .pfx-column-drag-indicator .cdk-drag-placeholder{opacity:1;border:1px dashed var(--p-table-border-color);background:var(--p-table-row-hover-bg)}:host ::ng-deep .pfx-column-drag-indicator .cdk-drag-placeholder *{opacity:0}:host ::ng-deep .pfx-column-drag-indicator .mat-mdc-header-cell.cdk-drag-dragging{opacity:.58}@media(prefers-reduced-motion:reduce){:host ::ng-deep .pfx-column-drag-indicator .cdk-drop-list-dragging .mat-mdc-header-cell:not(.cdk-drag-placeholder){transition:none}:host ::ng-deep .pfx-column-drag-enabled .mat-mdc-header-cell .praxis-column-drag-handle,:host ::ng-deep .pfx-column-drag-enabled .mat-mdc-header-cell .praxis-column-drag-handle .mat-icon,.pfx-column-drag-preview{transition:none;transform:none}.praxis-column-reorder-status{animation:none}.pfx-expansion-detail-panel{animation:none!important;transition:none!important;transform:none!important}:host ::ng-deep .mat-mdc-row{transition:none}:host ::ng-deep .mat-mdc-table{transition:none}}.praxis-actions-header{text-align:right}.praxis-actions-header.align-start{text-align:left}.praxis-actions-header.align-center{text-align:center}.praxis-actions-header.align-end{text-align:right}.praxis-actions-header .praxis-actions-header__content{display:inline-flex;align-items:center;gap:var(--p-actions-header-gap, 6px);color:var(--p-actions-header-color, inherit)}.praxis-actions-header .praxis-actions-header__content .mat-icon{font-size:18px;width:18px;height:18px;line-height:18px}:host ::ng-deep .mat-mdc-header-cell .mat-sort-header-container{padding-right:20px}:host ::ng-deep .pfx-column-drag-enabled .mat-mdc-header-cell.praxis-header-draggable .mat-sort-header-container{padding-right:12px}@media(pointer:coarse){:host{--p-table-drag-handle-size: 18px;--p-table-drag-handle-base-opacity: .56;--p-table-drag-handle-visible-opacity: .92}}:host ::ng-deep .mat-mdc-cell{color:var(--p-table-text-color);font-size:var(--p-cell-font-size, inherit);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}:host ::ng-deep .mat-mdc-cell .pfx-cell-content,:host ::ng-deep .mat-cell .pfx-cell-content{display:inline-flex;align-items:center;gap:6px;width:100%;min-width:0;overflow:hidden}:host ::ng-deep .mat-mdc-row:hover{background:var(--p-table-row-hover-bg)}:host ::ng-deep .mat-mdc-row{transition:background-color var(--p-table-hover-transition-duration, .18s) var(--p-table-motion-easing, cubic-bezier(0, 0, .2, 1)),box-shadow var(--p-table-selection-transition-duration, .18s) var(--p-table-motion-easing, cubic-bezier(0, 0, .2, 1))}:host ::ng-deep .mat-mdc-row:nth-child(2n){background:var(--p-table-row-even-bg)}:host ::ng-deep .mat-mdc-row:nth-child(2n):hover{background:var(--p-table-row-hover-bg)}:host ::ng-deep .mat-mdc-row.pfx-row-selected,:host ::ng-deep .mat-mdc-row.pfx-row-selected:hover{background:var(--p-table-row-selected-bg)}:host.row-borders ::ng-deep .mat-mdc-row .mat-mdc-cell{border-bottom:1px solid var(--p-table-border-color)}:host.row-borders ::ng-deep .mat-mdc-header-row .mat-mdc-header-cell{border-bottom:none}:host.col-borders ::ng-deep .mat-mdc-header-row .mat-mdc-header-cell,:host.col-borders ::ng-deep .mat-mdc-row .mat-mdc-cell{border-right:1px solid var(--p-table-border-color)}:host.col-borders ::ng-deep .mat-mdc-header-row .mat-mdc-header-cell:last-child,:host.col-borders ::ng-deep .mat-mdc-row .mat-mdc-cell:last-child{border-right:none}.ptable-error{display:flex;align-items:center;gap:12px;padding:12px;margin:8px 0;border:1px solid var(--md-sys-color-error);border-radius:8px}.ptable-error__content{flex:1}.ptable-error__title{font-weight:600}.ptable-info-banner{display:flex;gap:12px;align-items:center;padding:8px 12px;margin:8px 0;border-radius:8px;border:1px solid var(--md-sys-color-primary);background:var(--md-sys-color-primary-container);color:var(--md-sys-color-on-primary-container)}.ptable-info-banner .text{flex:1;font-weight:600}.ptable-info-banner .actions{display:flex;gap:8px}.pfx-cell-image{display:inline-block;vertical-align:middle;background:var(--md-sys-color-surface-variant);border:1px solid var(--md-sys-color-outline-variant)}.pfx-cell-image.shape-rounded{border-radius:8px}.pfx-cell-image.shape-circle{border-radius:9999px}.pfx-badge{display:inline-flex;align-items:center;gap:6px;line-height:1;padding:4px 8px;border-radius:9999px;font-size:12px;font-weight:600;border:1px solid transparent}.pfx-badge .pfx-badge-icon{font-size:16px;width:16px;height:16px}.pfx-badge--filled-primary{background:var(--md-sys-color-primary);color:var(--md-sys-color-on-primary)}.pfx-badge--filled-accent{background:var(--md-sys-color-secondary);color:var(--md-sys-color-on-secondary)}.pfx-badge--filled-warn{background:var(--md-sys-color-error);color:var(--md-sys-color-on-error)}.pfx-badge--outlined{background:transparent;border-color:var(--md-sys-color-outline-variant);color:inherit}.pfx-badge--soft-primary{background:var(--p-table-badge-soft-primary-bg);color:var(--p-table-badge-soft-primary-fg)}.pfx-badge--soft-accent{background:var(--p-table-badge-soft-accent-bg);color:var(--p-table-badge-soft-accent-fg)}.pfx-badge--soft-warn{background:var(--p-table-badge-soft-warn-bg);color:var(--p-table-badge-soft-warn-fg)}.row--success,.row--success td,td.row--success{background-color:var(--p-table-state-success-bg)!important;color:var(--p-table-state-success-fg)!important}.row--warning,.row--warning td,td.row--warning{background-color:var(--p-table-state-warning-bg)!important;color:var(--p-table-state-warning-fg)!important}.row--danger,.row--danger td,td.row--danger{background-color:var(--p-table-state-danger-bg)!important;color:var(--p-table-state-danger-fg)!important}.row--highlight,.row--highlight td,td.row--highlight{background-color:var(--p-table-state-highlight-bg)!important;color:var(--p-table-state-highlight-fg)!important;font-weight:600}.row--muted,.row--muted td,td.row--muted{opacity:.7;filter:saturate(.6)}\n"] }]
|
|
47115
|
+
], template: "@if (shouldShowEmptyState()) {\n <praxis-empty-state-card\n icon=\"link\"\n [title]=\"'Conecte a tabela \u00C3\u00A0 fonte de dados'\"\n [description]=\"'Informe a rota do recurso da API para carregar colunas e dados automaticamente.'\"\n [primaryAction]=\"{ label: 'Conectar \u00C3\u00A0 fonte de dados', icon: 'bolt', action: openQuickConnect.bind(this) }\"\n ></praxis-empty-state-card>\n}\n\n<!-- Error State with Quick Connect CTA -->\n@if (isRemoteMode() && (schemaError || dataError)) {\n<div class=\"ptable-error\" role=\"alert\" aria-live=\"assertive\">\n <mat-icon color=\"warn\" aria-hidden=\"true\">error</mat-icon>\n <div class=\"ptable-error__content\">\n <praxis-rich-content\n rootClassName=\"ptable-error__title\"\n [nodes]=\"getTableChromeTextRichContentNodes('Erro', 'ptable-error__title-text')\"\n ></praxis-rich-content>\n <praxis-rich-content\n rootClassName=\"ptable-error__message\"\n [nodes]=\"getTableChromeTextRichContentNodes(errorMessage || 'Ocorreu um erro ao carregar a tabela.', 'ptable-error__message-text')\"\n ></praxis-rich-content>\n </div>\n <button mat-flat-button color=\"primary\" (click)=\"openQuickConnect()\">\n <mat-icon>bolt</mat-icon>\n <praxis-rich-content\n rootClassName=\"ptable-error__action-label\"\n [nodes]=\"getTableChromeTextRichContentNodes('Conectar a recurso', 'ptable-error__action-label-text')\"\n ></praxis-rich-content>\n </button>\n @if (enableCustomization) {\n <button\n mat-icon-button\n color=\"primary\"\n data-role=\"table-settings\"\n data-testid=\"table-settings-trigger\"\n (click)=\"openTableSettings()\"\n [attr.aria-label]=\"getTableSettingsLabel()\"\n [matTooltip]=\"getTableSettingsLabel()\"\n matTooltipPosition=\"below\"\n >\n <mat-icon>settings</mat-icon>\n </button>\n }\n @if (!schemaError) {\n <button mat-stroked-button (click)=\"retryData()\">\n <praxis-rich-content\n rootClassName=\"ptable-error__action-label\"\n [nodes]=\"getTableChromeTextRichContentNodes('Tentar novamente', 'ptable-error__action-label-text')\"\n ></praxis-rich-content>\n </button>\n }\n @if (schemaError) {\n <button mat-stroked-button (click)=\"reloadSchema()\">\n <praxis-rich-content\n rootClassName=\"ptable-error__action-label\"\n [nodes]=\"getTableChromeTextRichContentNodes('Recarregar colunas', 'ptable-error__action-label-text')\"\n ></praxis-rich-content>\n </button>\n }\n </div>\n}\n\n<!-- Inline banner for schema change (only in edit mode) -->\n@if (shouldShowOutdatedInline()) {\n<div class=\"ptable-info-banner\" role=\"status\" aria-live=\"polite\">\n <praxis-rich-content\n rootClassName=\"text\"\n [nodes]=\"getTableChromeTextRichContentNodes('O schema do servidor mudou. Reconciliar agora?', 'ptable-info-banner__text')\"\n ></praxis-rich-content>\n <div class=\"actions\">\n <button mat-stroked-button color=\"primary\" (click)=\"onReconcileRequested()\">\n <mat-icon>sync</mat-icon>\n <praxis-rich-content\n rootClassName=\"ptable-info-banner__action-label\"\n [nodes]=\"getTableChromeTextRichContentNodes('Reconciliar', 'ptable-info-banner__action-label-text')\"\n ></praxis-rich-content>\n </button>\n <button mat-button (click)=\"onSnoozeOutdated()\">\n <praxis-rich-content\n rootClassName=\"ptable-info-banner__action-label\"\n [nodes]=\"getTableChromeTextRichContentNodes('Lembrar depois', 'ptable-info-banner__action-label-text')\"\n ></praxis-rich-content>\n </button>\n <button mat-button (click)=\"onIgnoreOutdated()\">\n <praxis-rich-content\n rootClassName=\"ptable-info-banner__action-label\"\n [nodes]=\"getTableChromeTextRichContentNodes('Ignorar', 'ptable-info-banner__action-label-text')\"\n ></praxis-rich-content>\n </button>\n </div>\n </div>\n}\n\n@if (shouldRenderDataSurface() && !schemaError && !dataError && toolbarV2) {\n <div class=\"praxis-table-header\" [class.edit-mode]=\"enableCustomization\" [class.stacked]=\"showToolbar\">\n @if (showToolbar && shouldShowToolbarTopPlacement()) {\n <praxis-table-toolbar\n [config]=\"config\"\n [backgroundColor]=\"getToolbarActionsBackgroundColor()\"\n [style.--pfx-filter-h]=\"getToolbarLayoutHeightHostStyle()\"\n [evaluationContext]=\"getToolbarEvaluationContext()\"\n [showActionsGroup]=\"shouldShowToolbarActionsTop()\"\n [showMobileActions]=\"shouldShowToolbarActionsTop()\"\n (toolbarAction)=\"onToolbarAction($event)\"\n (reset)=\"onResetPreferences()\"\n >\n @if (shouldRenderAdvancedFilter()) {\n <praxis-filter\n advancedFilter\n [resourcePath]=\"getAdvancedFilterResourcePath()\"\n [filterId]=\"tableId\"\n [formId]=\"tableId\"\n [persistenceKey]=\"getAdvancedFilterPersistenceKey()\"\n [fieldMetadata]=\"getAdvancedFilterFieldMetadata()\"\n [enableCustomization]=\"enableCustomization\"\n \n [alwaysVisibleFields]=\"config.behavior?.filtering?.advancedFilters?.settings?.alwaysVisibleFields\"\n [alwaysVisibleFieldMetadataOverrides]=\"config.behavior?.filtering?.advancedFilters?.settings?.alwaysVisibleFieldMetadataOverrides ?? {}\"\n [selectedFieldIds]=\"config.behavior?.filtering?.advancedFilters?.settings?.selectedFieldIds ?? []\"\n [allowSaveTags]=\"config.behavior?.filtering?.advancedFilters?.settings?.allowSaveTags\"\n [changeDebounceMs]=\"config.behavior?.filtering?.advancedFilters?.settings?.changeDebounceMs ?? 300\"\n [i18n]=\"getFilterI18n()\"\n [mode]=\"'filter'\"\n [showFilterSettings]=\"enableCustomization\"\n (change)=\"onAdvancedFilterChange($event)\"\n (requestSearch)=\"onAdvancedFilterSubmit($event)\"\n (clear)=\"onAdvancedFilterClear()\"\n ></praxis-filter>\n }\n <ng-content select=\"[advancedFilter]\" />\n <ng-content select=\"[toolbar]\" />\n \n <!-- AI Assistant in Toolbar -->\n @defer (on idle) {\n @if (aiAdapter) {\n <praxis-ai-assistant [adapter]=\"aiAdapter\" end-actions></praxis-ai-assistant>\n }\n }\n\n @if (enableCustomization) {\n <button end-actions mat-icon-button color=\"primary\" data-role=\"table-settings\" data-testid=\"table-settings-trigger\"\n (click)=\"openTableSettings()\" [attr.aria-label]=\"getTableSettingsLabel()\"\n [matBadge]=\"schemaOutdated ? '!' : ''\"\n [matBadgeHidden]=\"!schemaOutdated\"\n matBadgeColor=\"warn\" matBadgeSize=\"small\" matBadgePosition=\"above after\"\n [matTooltip]=\"getTableSettingsTooltip()\"\n matTooltipPosition=\"below\">\n <mat-icon>settings</mat-icon>\n </button>\n }\n </praxis-table-toolbar>\n }\n @if (!showToolbar && enableCustomization) {\n <div class=\"ptable-header-actions\">\n @defer (on idle) {\n @if (aiAdapter) {\n <praxis-ai-assistant [adapter]=\"aiAdapter\"></praxis-ai-assistant>\n }\n }\n <button mat-icon-button color=\"primary\" data-role=\"table-settings\" data-testid=\"table-settings-trigger\" (click)=\"openTableSettings()\" [attr.aria-label]=\"getTableSettingsLabel()\"\n [matBadge]=\"schemaOutdated ? '!' : ''\"\n [matBadgeHidden]=\"!schemaOutdated\"\n matBadgeColor=\"warn\" matBadgeSize=\"small\" matBadgePosition=\"above after\"\n [matTooltip]=\"getTableSettingsTooltip()\"\n matTooltipPosition=\"below\">\n <mat-icon>settings</mat-icon>\n </button>\n @if (isRemoteMode()) {\n <button mat-icon-button (click)=\"disconnect()\" [attr.aria-label]=\"getDisconnectLabel()\" [matTooltip]=\"getDisconnectTooltip()\">\n <mat-icon>link_off</mat-icon>\n </button>\n }\n </div>\n }\n </div>\n} @else {\n @if (shouldRenderDataSurface() && !schemaError && !dataError) {\n @if (showToolbar && shouldShowToolbarTopPlacement()) {\n <praxis-table-toolbar\n [config]=\"config\"\n [backgroundColor]=\"getToolbarActionsBackgroundColor()\"\n [style.--pfx-filter-h]=\"getToolbarLayoutHeightHostStyle()\"\n [evaluationContext]=\"getToolbarEvaluationContext()\"\n [showActionsGroup]=\"shouldShowToolbarActionsTop()\"\n [showMobileActions]=\"shouldShowToolbarActionsTop()\"\n (toolbarAction)=\"onToolbarAction($event)\"\n (reset)=\"onResetPreferences()\"\n >\n @if (shouldRenderAdvancedFilter()) {\n <praxis-filter\n advancedFilter\n [resourcePath]=\"getAdvancedFilterResourcePath()\"\n [filterId]=\"tableId\"\n [formId]=\"tableId\"\n [persistenceKey]=\"getAdvancedFilterPersistenceKey()\"\n [fieldMetadata]=\"getAdvancedFilterFieldMetadata()\"\n [enableCustomization]=\"enableCustomization\"\n \n [alwaysVisibleFields]=\"config.behavior?.filtering?.advancedFilters?.settings?.alwaysVisibleFields\"\n [alwaysVisibleFieldMetadataOverrides]=\"config.behavior?.filtering?.advancedFilters?.settings?.alwaysVisibleFieldMetadataOverrides ?? {}\"\n [selectedFieldIds]=\"config.behavior?.filtering?.advancedFilters?.settings?.selectedFieldIds ?? []\"\n [allowSaveTags]=\"config.behavior?.filtering?.advancedFilters?.settings?.allowSaveTags\"\n [changeDebounceMs]=\"config.behavior?.filtering?.advancedFilters?.settings?.changeDebounceMs ?? 300\"\n [i18n]=\"getFilterI18n()\"\n [mode]=\"'filter'\"\n [showFilterSettings]=\"enableCustomization\"\n (change)=\"onAdvancedFilterChange($event)\"\n (requestSearch)=\"onAdvancedFilterSubmit($event)\"\n (clear)=\"onAdvancedFilterClear()\"\n ></praxis-filter>\n }\n <ng-content select=\"[advancedFilter]\" />\n <ng-content select=\"[toolbar]\" />\n @defer (on idle) {\n @if (aiAdapter) {\n <praxis-ai-assistant [adapter]=\"aiAdapter\" end-actions></praxis-ai-assistant>\n }\n }\n @if (enableCustomization) {\n <button end-actions mat-icon-button color=\"primary\" data-role=\"table-settings\" data-testid=\"table-settings-trigger\"\n (click)=\"openTableSettings()\" [attr.aria-label]=\"getTableSettingsLabel()\"\n [matBadge]=\"schemaOutdated ? '!' : ''\"\n [matBadgeHidden]=\"!schemaOutdated\"\n matBadgeColor=\"warn\" matBadgeSize=\"small\" matBadgePosition=\"above after\"\n [matTooltip]=\"getTableSettingsTooltip()\"\n matTooltipPosition=\"below\">\n <mat-icon>settings</mat-icon>\n </button>\n }\n </praxis-table-toolbar>\n }\n @if (!showToolbar && enableCustomization) {\n <div class=\"ptable-header-actions\">\n <button mat-icon-button color=\"primary\" data-role=\"table-settings\" data-testid=\"table-settings-trigger\" (click)=\"openTableSettings()\" [attr.aria-label]=\"getTableSettingsLabel()\"\n [matBadge]=\"schemaOutdated ? '!' : ''\"\n [matBadgeHidden]=\"!schemaOutdated\"\n matBadgeColor=\"warn\" matBadgeSize=\"small\" matBadgePosition=\"above after\"\n [matTooltip]=\"getTableSettingsTooltip()\"\n matTooltipPosition=\"below\">\n <mat-icon>settings</mat-icon>\n </button>\n </div>\n }\n }\n}\n<div class=\"px-scroll-viewport\"\n cdkScrollable\n [class.scroll-auto]=\"horizontalScroll === 'auto'\"\n [class.scroll-wrap]=\"horizontalScroll === 'wrap'\"\n [class.scroll-none]=\"horizontalScroll === 'none'\">\n\n@if (shouldRenderDataSurface() && !schemaError && !dataError) {\n<div class=\"praxis-visually-hidden-status\" role=\"status\" aria-live=\"polite\" aria-atomic=\"true\">\n {{ columnReorderStatusMessage }}\n</div>\n@if (columnReorderVisualStatusMessage) {\n <div class=\"praxis-column-reorder-status\" role=\"note\">\n {{ columnReorderVisualStatusMessage }}\n </div>\n}\n<table\n mat-table\n data-testid=\"table-column-drag-drop-list\"\n [dataSource]=\"dataSource\"\n [multiTemplateDataRows]=\"isRowExpansionRuntimeEnabled()\"\n cdkDropList\n [cdkDropListDisabled]=\"!isColumnDraggingEnabled()\"\n [cdkDropListData]=\"visibleDataColumnsForDrag\"\n cdkDropListOrientation=\"horizontal\"\n (cdkDropListDropped)=\"onColumnDrop($event)\"\n matSort\n (matSortChange)=\"onSortChange($event)\"\n [matSortDisabled]=\"!getSortingEnabled()\"\n [ngClass]=\"getTableElevationClassName()\"\n [class.table-stack-top]=\"showToolbar\"\n [class.pfx-column-drag-enabled]=\"isColumnDraggingEnabled()\"\n [class.pfx-column-drag-indicator]=\"isColumnDragIndicatorEnabled()\"\n>\n @if (config.behavior?.selection?.enabled) {\n <ng-container\n matColumnDef=\"_select\"\n >\n <th mat-header-cell *matHeaderCellDef>\n @if (canSelectAll()) {\n <mat-checkbox\n (change)=\"masterToggle()\"\n [checked]=\"isAllSelected()\"\n [indeterminate]=\"selection.hasValue() && !isAllSelected()\"\n ></mat-checkbox>\n }\n </th>\n <td mat-cell *matCellDef=\"let row\">\n <mat-checkbox\n (click)=\"$event.stopPropagation()\"\n (change)=\"toggleRow(row)\"\n [checked]=\"selection.isSelected(row)\"\n ></mat-checkbox>\n </td>\n </ng-container>\n }\n @if (isRowExpansionRuntimeEnabled()) {\n <ng-container matColumnDef=\"_expander\">\n <th mat-header-cell *matHeaderCellDef class=\"pfx-expansion-col-header\">\n <span class=\"praxis-visually-hidden-status\">Expandir detalhes da linha</span>\n </th>\n <td mat-cell *matCellDef=\"let row; let i = index\" class=\"pfx-expansion-col-cell\">\n <button\n mat-icon-button\n class=\"pfx-expansion-toggle\"\n [disabled]=\"!isRowExpandable(row, i) || !isExpansionIconTriggerEnabled()\"\n [attr.aria-expanded]=\"isRowExpanded(row, i) ? 'true' : 'false'\"\n [attr.aria-controls]=\"getRowExpansionDetailId(row, i)\"\n [attr.aria-label]=\"getRowExpansionToggleAriaLabel(row, i)\"\n (click)=\"onExpansionToggleFromIcon(row, i, $event)\"\n (keydown)=\"onExpansionToggleKeydown($event, row, i)\"\n >\n <mat-icon [praxisIcon]=\"isRowExpanded(row, i)\n ? getExpansionExpandedIcon()\n : getExpansionCollapsedIcon()\"></mat-icon>\n </button>\n </td>\n </ng-container>\n }\n @for (column of visibleColumns; track column.field) {\n <ng-container\n [matColumnDef]=\"column.field\"\n [sticky]=\"column.sticky === true || column.sticky === 'start'\"\n [stickyEnd]=\"column.sticky === 'end'\"\n >\n <th\n mat-header-cell\n *matHeaderCellDef\n mat-sort-header\n cdkDrag\n [cdkDragData]=\"column\"\n cdkDragLockAxis=\"x\"\n cdkDragPreviewClass=\"pfx-column-drag-preview\"\n (cdkDragStarted)=\"onColumnDragStarted(column)\"\n (cdkDragEnded)=\"onColumnDragEnded($event, column)\"\n (keydown)=\"onColumnDragHandleKeydown($event, column)\"\n [cdkDragDisabled]=\"!isColumnDraggingEnabled() || !isColumnDraggable(column)\"\n [class.praxis-header-draggable]=\"isColumnDraggingEnabled() && isColumnDraggable(column)\"\n [disabled]=\"!getSortingEnabled() || column.sortable === false\"\n [style.text-align]=\"getColumnTextAlignStyle(column)\"\n [style.width]=\"getColumnWidthStyle(column)\"\n [attr.style]=\"getColumnHeaderAttrStyle(column)\"\n [attr.aria-label]=\"isColumnDraggingEnabled() && isColumnDraggable(column) ? getColumnDragHandleAriaLabel(column) : null\"\n >\n <span class=\"praxis-header-label\" data-testid=\"column-header-label\">\n @if (isColumnDraggingEnabled() && isColumnDraggable(column)) {\n <span\n class=\"praxis-column-drag-handle\"\n data-testid=\"column-drag-handle\"\n [attr.data-column-field]=\"column.field\"\n aria-hidden=\"true\"\n >\n <mat-icon [praxisIcon]=\"'drag_indicator'\"></mat-icon>\n </span>\n }\n <span class=\"praxis-header-label-text\">{{ column.header }}</span>\n </span>\n </th>\n <td\n mat-cell\n *matCellDef=\"let element\"\n [style.text-align]=\"getColumnTextAlignStyle(column)\"\n [style.width]=\"getColumnWidthStyle(column)\"\n [attr.style]=\"getColumnCellAttrStyle(column)\"\n [ngClass]=\"getCellClasses(element, column)\"\n [ngStyle]=\"getCellNgStyle(element, column)\"\n >\n <div\n class=\"pfx-cell-content\"\n [ngClass]=\"getCellContentClasses(element, column)\"\n [ngStyle]=\"getCellContentNgStyle(element, column)\"\n >\n <ng-container [ngSwitch]=\"getEffectiveRendererType(element, column)\">\n <!-- Icon renderer -->\n <ng-container *ngSwitchCase=\"'icon'\">\n <span\n class=\"pfx-icon-renderer\"\n [style.color]=\"getIconColor(element, column) || null\"\n [ngStyle]=\"getIconStyle(element, column)\"\n [attr.aria-label]=\"getIconAriaLabel(element, column) || null\"\n >\n <praxis-rich-content\n rootClassName=\"pfx-icon-renderer__content\"\n [nodes]=\"getIconRichContentNodes(element, column)\"\n ></praxis-rich-content>\n </span>\n </ng-container>\n\n <!-- Image renderer -->\n <ng-container *ngSwitchCase=\"'image'\">\n <span class=\"pfx-cell-image\">\n <praxis-rich-content\n rootClassName=\"pfx-cell-image__content\"\n [nodes]=\"getImageRichContentNodes(element, column)\"\n ></praxis-rich-content>\n </span>\n </ng-container>\n\n <!-- Badge renderer -->\n <ng-container *ngSwitchCase=\"'badge'\">\n <span class=\"pfx-badge\" [ngClass]=\"getBadgeClasses(element, column)\">\n <praxis-rich-content\n rootClassName=\"pfx-badge__content\"\n [nodes]=\"getBadgeRichContentNodes(element, column)\"\n ></praxis-rich-content>\n </span>\n </ng-container>\n\n <!-- Link renderer -->\n <ng-container *ngSwitchCase=\"'link'\">\n <a\n class=\"pfx-link\"\n [attr.href]=\"getLinkHref(element, column) || null\"\n [attr.target]=\"getLinkTarget(element, column) || null\"\n [attr.rel]=\"getLinkRel(element, column) || null\"\n (click)=\"$event.stopPropagation()\"\n ><praxis-rich-content\n rootClassName=\"pfx-link__content\"\n [nodes]=\"getLinkRichContentNodes(element, column)\"\n ></praxis-rich-content></a\n >\n </ng-container>\n\n <!-- Button renderer -->\n <ng-container *ngSwitchCase=\"'button'\">\n <ng-container [ngSwitch]=\"getButtonVariant(element, column)\">\n <button\n *ngSwitchCase=\"'outlined'\"\n mat-stroked-button\n [color]=\"getButtonColor(element, column) || null\"\n [disabled]=\"isButtonDisabled(element, column)\"\n [attr.aria-label]=\"getButtonAriaLabel(element, column) || getButtonLabel(element, column)\"\n (click)=\"onButtonClick(element, column, $event)\"\n >\n <praxis-rich-content\n rootClassName=\"pfx-button-renderer__content\"\n [nodes]=\"getButtonRichContentNodes(element, column)\"\n ></praxis-rich-content>\n </button>\n <button\n *ngSwitchCase=\"'text'\"\n mat-button\n [color]=\"getButtonColor(element, column) || null\"\n [disabled]=\"isButtonDisabled(element, column)\"\n [attr.aria-label]=\"getButtonAriaLabel(element, column) || getButtonLabel(element, column)\"\n (click)=\"onButtonClick(element, column, $event)\"\n >\n <praxis-rich-content\n rootClassName=\"pfx-button-renderer__content\"\n [nodes]=\"getButtonRichContentNodes(element, column)\"\n ></praxis-rich-content>\n </button>\n <button\n *ngSwitchDefault\n mat-flat-button\n [color]=\"getButtonColor(element, column) || null\"\n [disabled]=\"isButtonDisabled(element, column)\"\n [attr.aria-label]=\"getButtonAriaLabel(element, column) || getButtonLabel(element, column)\"\n (click)=\"onButtonClick(element, column, $event)\"\n >\n <praxis-rich-content\n rootClassName=\"pfx-button-renderer__content\"\n [nodes]=\"getButtonRichContentNodes(element, column)\"\n ></praxis-rich-content>\n </button>\n </ng-container>\n </ng-container>\n\n <!-- Chip renderer -->\n <ng-container *ngSwitchCase=\"'chip'\">\n <span class=\"pfx-chip\" [ngClass]=\"getChipClasses(element, column)\">\n <praxis-rich-content\n rootClassName=\"pfx-chip__content\"\n [nodes]=\"getChipRichContentNodes(element, column)\"\n ></praxis-rich-content>\n </span>\n </ng-container>\n\n <!-- Progress renderer -->\n <ng-container *ngSwitchCase=\"'progress'\">\n <div class=\"pfx-progress\">\n <praxis-rich-content\n rootClassName=\"pfx-progress__content\"\n [context]=\"getProgressRichContentContext(element, column)\"\n [nodes]=\"getProgressRichContentNodes(element, column)\"\n ></praxis-rich-content>\n </div>\n </ng-container>\n\n <!-- Avatar renderer -->\n <ng-container *ngSwitchCase=\"'avatar'\">\n <span class=\"pfx-avatar-renderer\"\n [ngStyle]=\"getAvatarStyle(element, column)\"\n [class.shape-rounded]=\"getAvatarShape(element, column) === 'rounded'\"\n [class.shape-circle]=\"getAvatarShape(element, column) === 'circle'\">\n <praxis-rich-content\n rootClassName=\"pfx-avatar-renderer__content\"\n [nodes]=\"getAvatarRichContentNodes(element, column)\"\n ></praxis-rich-content>\n </span>\n </ng-container>\n\n <!-- Toggle renderer -->\n <ng-container *ngSwitchCase=\"'toggle'\">\n <mat-slide-toggle\n [checked]=\"getToggleState(element, column)\"\n [disabled]=\"isToggleDisabled(element, column)\"\n [attr.aria-label]=\"getToggleAriaLabel(element, column) || 'Alternar'\"\n (change)=\"onToggleChange(element, column, $event)\"\n (click)=\"$event.stopPropagation()\"\n ></mat-slide-toggle>\n </ng-container>\n\n <!-- Menu renderer -->\n <ng-container *ngSwitchCase=\"'menu'\">\n <button mat-icon-button [matMenuTriggerFor]=\"menuRef\" (click)=\"$event.stopPropagation()\" [attr.aria-label]=\"getMenuAriaLabel(element, column) || 'Menu'\">\n <praxis-rich-content rootClassName=\"pfx-menu-trigger__content\" [nodes]=\"getMenuTriggerRichContentNodes()\"></praxis-rich-content>\n </button>\n <mat-menu #menuRef=\"matMenu\">\n <button mat-menu-item *ngFor=\"let it of getMenuItems(element, column)\" (click)=\"onMenuItemClick(it, element, $event)\" [disabled]=\"!it.__visible\" >\n <praxis-rich-content\n rootClassName=\"pfx-menu-item__content\"\n [nodes]=\"getMenuItemRichContentNodes(it)\"\n ></praxis-rich-content>\n </button>\n </mat-menu>\n </ng-container>\n\n <!-- Rating renderer -->\n <ng-container *ngSwitchCase=\"'rating'\">\n <praxis-table-rating\n class=\"pfx-rating-cell\"\n [itemsCount]=\"getRatingMax(element, column)\"\n [value]=\"getRatingValue(element, column)\"\n [size]=\"getRatingSize(element, column)\"\n [ratingColor]=\"getRatingColor(element, column)\"\n [outlineColor]=\"getRatingOutlineColor(element, column)\"\n [ariaLabel]=\"getRatingAriaLabel(element, column) || column.header\">\n </praxis-table-rating>\n </ng-container>\n\n <!-- HTML renderer (sanitizado) -->\n <ng-container *ngSwitchCase=\"'html'\">\n <span [innerHTML]=\"getSafeHtml(element, column)\"></span>\n </ng-container>\n\n <!-- Compose renderer -->\n <ng-container *ngSwitchCase=\"'compose'\">\n <span class=\"pfx-cell-compose\" [ngClass]=\"getComposeClasses(element, column)\" [ngStyle]=\"getComposeGapStyle(element, column)\">\n <ng-container *ngFor=\"let it of getComposeItems(element, column)\">\n <ng-container [ngSwitch]=\"getItemEffectiveType(element, column, it)\">\n <!-- Reuse helpers by projecting item as faux column -->\n <ng-container *ngSwitchCase=\"'icon'\">\n <span class=\"pfx-icon-renderer\" [style.color]=\"getIconColor(element, asItemColumn(column, it)) || null\" [ngStyle]=\"getIconStyle(element, asItemColumn(column, it))\" [attr.aria-label]=\"getIconAriaLabel(element, asItemColumn(column, it)) || null\"><praxis-rich-content rootClassName=\"pfx-icon-renderer__content\" [nodes]=\"getIconRichContentNodes(element, asItemColumn(column, it))\"></praxis-rich-content></span>\n </ng-container>\n <ng-container *ngSwitchCase=\"'image'\">\n <span class=\"pfx-cell-image\"><praxis-rich-content rootClassName=\"pfx-cell-image__content\" [nodes]=\"getImageRichContentNodes(element, asItemColumn(column, it))\"></praxis-rich-content></span>\n </ng-container>\n <ng-container *ngSwitchCase=\"'badge'\">\n <span class=\"pfx-badge\" [ngClass]=\"getBadgeClasses(element, asItemColumn(column, it))\"><praxis-rich-content rootClassName=\"pfx-badge__content\" [nodes]=\"getBadgeRichContentNodes(element, asItemColumn(column, it))\"></praxis-rich-content></span>\n </ng-container>\n <ng-container *ngSwitchCase=\"'link'\">\n <a class=\"pfx-link\" [attr.href]=\"getLinkHref(element, asItemColumn(column, it)) || null\" [attr.target]=\"getLinkTarget(element, asItemColumn(column, it)) || null\" [attr.rel]=\"getLinkRel(element, asItemColumn(column, it)) || null\" (click)=\"$event.stopPropagation()\"><praxis-rich-content rootClassName=\"pfx-link__content\" [nodes]=\"getLinkRichContentNodes(element, asItemColumn(column, it))\"></praxis-rich-content></a>\n </ng-container>\n <ng-container *ngSwitchCase=\"'button'\">\n <ng-container [ngSwitch]=\"getButtonVariant(element, asItemColumn(column, it))\">\n <button *ngSwitchCase=\"'outlined'\" mat-stroked-button [color]=\"getButtonColor(element, asItemColumn(column, it)) || null\" [disabled]=\"isButtonDisabled(element, asItemColumn(column, it))\" [attr.aria-label]=\"getButtonAriaLabel(element, asItemColumn(column, it)) || getButtonLabel(element, asItemColumn(column, it))\" (click)=\"onButtonClick(element, asItemColumn(column, it), $event)\"><praxis-rich-content rootClassName=\"pfx-button-renderer__content\" [nodes]=\"getButtonRichContentNodes(element, asItemColumn(column, it))\"></praxis-rich-content></button>\n <button *ngSwitchCase=\"'text'\" mat-button [color]=\"getButtonColor(element, asItemColumn(column, it)) || null\" [disabled]=\"isButtonDisabled(element, asItemColumn(column, it))\" [attr.aria-label]=\"getButtonAriaLabel(element, asItemColumn(column, it)) || getButtonLabel(element, asItemColumn(column, it))\" (click)=\"onButtonClick(element, asItemColumn(column, it), $event)\"><praxis-rich-content rootClassName=\"pfx-button-renderer__content\" [nodes]=\"getButtonRichContentNodes(element, asItemColumn(column, it))\"></praxis-rich-content></button>\n <button *ngSwitchDefault mat-flat-button [color]=\"getButtonColor(element, asItemColumn(column, it)) || null\" [disabled]=\"isButtonDisabled(element, asItemColumn(column, it))\" [attr.aria-label]=\"getButtonAriaLabel(element, asItemColumn(column, it)) || getButtonLabel(element, asItemColumn(column, it))\" (click)=\"onButtonClick(element, asItemColumn(column, it), $event)\"><praxis-rich-content rootClassName=\"pfx-button-renderer__content\" [nodes]=\"getButtonRichContentNodes(element, asItemColumn(column, it))\"></praxis-rich-content></button>\n </ng-container>\n </ng-container>\n <ng-container *ngSwitchCase=\"'chip'\">\n <span class=\"pfx-chip\" [ngClass]=\"getChipClasses(element, asItemColumn(column, it))\"><praxis-rich-content rootClassName=\"pfx-chip__content\" [nodes]=\"getChipRichContentNodes(element, asItemColumn(column, it))\"></praxis-rich-content></span>\n </ng-container>\n <ng-container *ngSwitchCase=\"'progress'\">\n <div class=\"pfx-progress\">\n <praxis-rich-content\n rootClassName=\"pfx-progress__content\"\n [context]=\"getProgressRichContentContext(element, asItemColumn(column, it))\"\n [nodes]=\"getProgressRichContentNodes(element, asItemColumn(column, it))\"\n ></praxis-rich-content>\n </div>\n </ng-container>\n <ng-container *ngSwitchCase=\"'avatar'\">\n <span class=\"pfx-avatar-renderer\" [ngStyle]=\"getAvatarStyle(element, asItemColumn(column, it))\" [class.shape-rounded]=\"getAvatarShape(element, asItemColumn(column, it)) === 'rounded'\" [class.shape-circle]=\"getAvatarShape(element, asItemColumn(column, it)) === 'circle'\"><praxis-rich-content rootClassName=\"pfx-avatar-renderer__content\" [nodes]=\"getAvatarRichContentNodes(element, asItemColumn(column, it))\"></praxis-rich-content></span>\n </ng-container>\n <ng-container *ngSwitchCase=\"'toggle'\">\n <mat-slide-toggle [checked]=\"getToggleState(element, asItemColumn(column, it))\" [disabled]=\"isToggleDisabled(element, asItemColumn(column, it))\" [attr.aria-label]=\"getToggleAriaLabel(element, asItemColumn(column, it)) || 'Alternar'\" (change)=\"onToggleChange(element, asItemColumn(column, it), $event)\" (click)=\"$event.stopPropagation()\"></mat-slide-toggle>\n </ng-container>\n <ng-container *ngSwitchCase=\"'menu'\">\n <button mat-icon-button [matMenuTriggerFor]=\"menuRef\" (click)=\"$event.stopPropagation()\" [attr.aria-label]=\"getMenuAriaLabel(element, asItemColumn(column, it)) || 'Menu'\"><praxis-rich-content rootClassName=\"pfx-menu-trigger__content\" [nodes]=\"getMenuTriggerRichContentNodes()\"></praxis-rich-content></button>\n <mat-menu #menuRef=\"matMenu\">\n <button mat-menu-item *ngFor=\"let mi of getMenuItems(element, asItemColumn(column, it))\" (click)=\"onMenuItemClick(mi, element, $event)\" [disabled]=\"!mi.__visible\">\n <praxis-rich-content\n rootClassName=\"pfx-menu-item__content\"\n [nodes]=\"getMenuItemRichContentNodes(mi)\"\n ></praxis-rich-content>\n </button>\n </mat-menu>\n </ng-container>\n <ng-container *ngSwitchCase=\"'rating'\">\n <praxis-table-rating\n class=\"pfx-rating-cell\"\n [itemsCount]=\"getRatingMax(element, asItemColumn(column, it))\"\n [value]=\"getRatingValue(element, asItemColumn(column, it))\"\n [size]=\"getRatingSize(element, asItemColumn(column, it))\"\n [ratingColor]=\"getRatingColor(element, asItemColumn(column, it))\"\n [outlineColor]=\"getRatingOutlineColor(element, asItemColumn(column, it))\"\n [ariaLabel]=\"getRatingAriaLabel(element, asItemColumn(column, it)) || column.header\">\n </praxis-table-rating>\n </ng-container>\n <ng-container *ngSwitchCase=\"'html'\">\n <span [innerHTML]=\"getSafeHtml(element, asItemColumn(column, it))\"></span>\n </ng-container>\n <!-- Value item: render base cell text alongside visuals -->\n <ng-container *ngSwitchCase=\"'value'\">\n <span class=\"pfx-cell-value\">{{ getComposeItemValue(element, column, it) }}</span>\n </ng-container>\n </ng-container>\n </ng-container>\n </span>\n </ng-container>\n\n <!-- Default text rendering -->\n <ng-container *ngSwitchDefault>\n {{ getCellValue(element, column) }}\n </ng-container>\n </ng-container>\n </div>\n </td>\n </ng-container>\n }\n @if (config.actions?.row?.enabled) {\n <ng-container matColumnDef=\"_actions\" [sticky]=\"config.actions?.row?.sticky === true || config.actions?.row?.sticky === 'start'\" [stickyEnd]=\"config.actions?.row?.sticky === 'end'\">\n <th mat-header-cell *matHeaderCellDef #actionsHeaderCell [style.width]=\"getRowActionsWidthStyle()\" class=\"praxis-actions-header\" [class.align-start]=\"getActionsHeaderAlign() === 'start'\" [class.align-center]=\"getActionsHeaderAlign() === 'center'\" [class.align-end]=\"getActionsHeaderAlign() === 'end'\">\n <div class=\"praxis-actions-header__content\" [matTooltip]=\"getActionsHeaderTooltip() || ''\" [matTooltipDisabled]=\"!getActionsHeaderTooltip()\">\n <praxis-rich-content\n rootClassName=\"praxis-actions-header__nodes\"\n [nodes]=\"getActionsHeaderRichContentNodes()\"\n ></praxis-rich-content>\n </div>\n </th>\n <td\n mat-cell\n *matCellDef=\"let row\"\n class=\"praxis-actions-cell\"\n [class.dense]=\"dense\"\n [style.width]=\"getRowActionsWidthStyle()\"\n >\n <div\n class=\"praxis-actions-cell__content\"\n [class.praxis-actions-cell__content--discovering]=\"isRowDiscoveryPending(row)\"\n [attr.aria-busy]=\"isRowDiscoveryPending(row) ? 'true' : null\"\n >\n <!-- A\u00C3\u00A7\u00C3\u00B5es inline -->\n <!-- Inline actions: icons mode -->\n @if (config.actions?.row?.display === 'icons' || !config.actions?.row?.display) {\n <ng-container *ngFor=\"let a of getInlineRowActions(row); trackBy: trackAction\">\n <span\n class=\"praxis-row-action-anchor\"\n [class.praxis-row-action-anchor--workflow]=\"isWorkflowRowAction(a)\"\n [class.praxis-row-action-anchor--blocked]=\"isBlockedWorkflowRowAction(a, row)\"\n [matTooltip]=\"getActionTooltip(a, row)\"\n [matTooltipDisabled]=\"!getActionTooltip(a, row)\"\n matTooltipPosition=\"above\"\n matTooltipClass=\"praxis-tooltip\"\n >\n <button\n mat-icon-button\n class=\"praxis-icon-btn\"\n [class.praxis-icon-btn--workflow]=\"isWorkflowRowAction(a)\"\n [class.praxis-icon-btn--blocked]=\"isBlockedWorkflowRowAction(a, row)\"\n [disabled]=\"isActionDisabled(a, row)\"\n (click)=\"onRowAction(getActionId(a), row, $event, getRowActionRuntimeOptions(a, row))\"\n [attr.aria-label]=\"a.label || getActionId(a)\"\n [color]=\"a.color || null\"\n >\n <praxis-rich-content\n rootClassName=\"praxis-row-action__content\"\n [nodes]=\"getRowActionIconRichContentNodes(a)\"\n ></praxis-rich-content>\n </button>\n </span>\n </ng-container>\n }\n\n <!-- Inline actions: buttons mode (show label + icon) -->\n @if (config.actions?.row?.display === 'buttons') {\n <ng-container *ngFor=\"let a of getInlineRowActions(row); trackBy: trackAction\">\n <span\n class=\"praxis-row-action-anchor\"\n [class.praxis-row-action-anchor--workflow]=\"isWorkflowRowAction(a)\"\n [class.praxis-row-action-anchor--blocked]=\"isBlockedWorkflowRowAction(a, row)\"\n [matTooltip]=\"getActionTooltip(a, row)\"\n [matTooltipDisabled]=\"!getActionTooltip(a, row)\"\n matTooltipPosition=\"above\"\n matTooltipClass=\"praxis-tooltip\"\n >\n <button\n mat-flat-button\n class=\"praxis-row-btn\"\n [class.praxis-row-btn--workflow]=\"isWorkflowRowAction(a)\"\n [class.praxis-row-btn--blocked]=\"isBlockedWorkflowRowAction(a, row)\"\n [disabled]=\"isActionDisabled(a, row)\"\n (click)=\"onRowAction(getActionId(a), row, $event, getRowActionRuntimeOptions(a, row))\"\n [attr.aria-label]=\"a.label || getActionId(a)\"\n [color]=\"a.color || null\"\n >\n <praxis-rich-content\n rootClassName=\"praxis-row-action__content\"\n [nodes]=\"getRowActionRichContentNodes(a)\"\n ></praxis-rich-content>\n </button>\n </span>\n </ng-container>\n }\n\n <!-- Menu de overflow -->\n @if (hasOverflowRowActions(row)) {\n <button\n mat-icon-button\n class=\"praxis-icon-btn praxis-more-btn\"\n [matMenuTriggerFor]=\"rowMoreMenu\"\n (menuOpened)=\"onRowOverflowMenuOpened(row)\"\n [color]=\"getRowMenuButtonColor() || null\"\n [attr.aria-label]=\"getRowMenuTooltip(row)\"\n [matTooltip]=\"getRowMenuTooltip(row)\"\n matTooltipPosition=\"above\"\n >\n <mat-icon [praxisIcon]=\"getRowMenuIcon()\"></mat-icon>\n </button>\n }\n <mat-menu #rowMoreMenu=\"matMenu\" xPosition=\"before\">\n @if (hasRowOverflowMenuLoadingState(row)) {\n <button mat-menu-item disabled>\n <mat-icon>hourglass_empty</mat-icon>\n <praxis-rich-content\n rootClassName=\"praxis-row-overflow-menu__label\"\n [nodes]=\"getTableChromeTextRichContentNodes(getRowOverflowMenuLoadingLabel(), 'praxis-row-overflow-menu__label-text')\"\n ></praxis-rich-content>\n </button>\n }\n <ng-container\n *ngFor=\"let a of getOverflowRowActions(row); trackBy: trackAction\"\n >\n <button\n mat-menu-item\n (click)=\"onRowAction(getActionId(a), row, $event, getRowActionRuntimeOptions(a, row))\"\n [disabled]=\"isActionDisabled(a, row)\"\n >\n <mat-icon [color]=\"a.color || null\" [praxisIcon]=\"a.icon\"></mat-icon>\n <praxis-rich-content\n rootClassName=\"praxis-row-overflow-menu__label\"\n [nodes]=\"getTableChromeTextRichContentNodes(a.label || getActionId(a), 'praxis-row-overflow-menu__label-text')\"\n ></praxis-rich-content>\n </button>\n </ng-container>\n @if (hasRowOverflowMenuEmptyState(row)) {\n <button mat-menu-item disabled>\n <mat-icon>info</mat-icon>\n <praxis-rich-content\n rootClassName=\"praxis-row-overflow-menu__label\"\n [nodes]=\"getTableChromeTextRichContentNodes(getRowOverflowMenuEmptyLabel(row), 'praxis-row-overflow-menu__label-text')\"\n ></praxis-rich-content>\n </button>\n }\n </mat-menu>\n </div>\n </td>\n </ng-container>\n }\n\n <tr\n mat-header-row\n *matHeaderRowDef=\"displayedColumns\"\n ></tr>\n @if (!isVirtualized()) {\n <tr\n mat-row\n *matRowDef=\"let row; let i = index; columns: displayedColumns\"\n [class.pfx-row-selected]=\"selection.isSelected(row)\"\n [class.pfx-row-expanded]=\"isRowExpansionRuntimeEnabled() && isRowExpanded(row, i)\"\n [attr.aria-selected]=\"config.behavior?.selection?.enabled ? (selection.isSelected(row) ? 'true' : 'false') : null\"\n [attr.aria-expanded]=\"isRowExpansionRuntimeEnabled() ? (isRowExpanded(row, i) ? 'true' : 'false') : null\"\n [ngClass]=\"getRowClasses(row)\"\n [ngStyle]=\"getRowNgStyle(row)\"\n [matTooltip]=\"getRowTooltip(row) || null\"\n [matTooltipDisabled]=\"!getRowTooltip(row)\"\n [matTooltipPosition]=\"getRowTooltipPosition(row)\"\n [matTooltipShowDelay]=\"getRowTooltipShowDelay(row)\"\n (click)=\"onRowClicked(row, i, $event)\"\n (dblclick)=\"onRowDoubleClicked(row, i)\"\n ></tr>\n @if (isRowExpansionRuntimeEnabled()) {\n <ng-container matColumnDef=\"_detail\">\n <td\n mat-cell\n *matCellDef=\"let row; let i = index\"\n class=\"pfx-expansion-detail-cell\"\n [attr.colspan]=\"displayedColumns.length\"\n >\n <section\n class=\"pfx-expansion-detail-panel\"\n [ngClass]=\"getExpansionMotionPresetClass()\"\n [ngStyle]=\"getExpansionMotionStyle()\"\n [attr.id]=\"getRowExpansionDetailId(row, i)\"\n role=\"region\"\n [attr.aria-label]=\"getRowExpansionRegionAriaLabel(row, i)\"\n [attr.aria-busy]=\"getExpansionDetailViewState(row, i).status === 'loading' ? 'true' : 'false'\"\n >\n @let detailState = getExpansionDetailViewState(row, i);\n @if (detailState.status === 'loading') {\n <div class=\"pfx-expansion-detail-message\" role=\"status\" aria-live=\"polite\">\n <praxis-rich-content\n rootClassName=\"pfx-expansion-detail-message__content\"\n [nodes]=\"getExpansionDetailTextRichContentNodes('Carregando detail schema...', 'pfx-expansion-detail-message__text')\"\n [context]=\"getExpansionDetailRichContentContext(row, i)\"\n ></praxis-rich-content>\n </div>\n } @else if (detailState.status !== 'ready') {\n <div\n class=\"pfx-expansion-detail-message pfx-expansion-detail-message--error\"\n role=\"alert\"\n aria-live=\"assertive\"\n aria-atomic=\"true\"\n >\n <praxis-rich-content\n rootClassName=\"pfx-expansion-detail-message__content\"\n [nodes]=\"getExpansionDetailTextRichContentNodes(detailState.message || 'Detail indispon\u00EDvel para esta linha.', 'pfx-expansion-detail-message__text')\"\n [context]=\"getExpansionDetailRichContentContext(row, i)\"\n ></praxis-rich-content>\n </div>\n } @else {\n @if (getExpansionDetailLayout(detailState.schema) === 'tabs') {\n @let detailTabs = getExpansionDetailTabs(detailState.schema);\n @if (detailTabs.length) {\n <div class=\"pfx-expansion-detail-tabs\" role=\"tablist\" aria-label=\"Se\u00C3\u00A7\u00C3\u00B5es do detail\">\n @for (tab of detailTabs; track $index; let tabIndex = $index) {\n <button\n type=\"button\"\n class=\"pfx-expansion-detail-tab-btn\"\n role=\"tab\"\n [attr.id]=\"getExpansionDetailTabId(row, i, tab, tabIndex)\"\n [attr.aria-controls]=\"getExpansionDetailPanelId(row, i, tab, tabIndex)\"\n [attr.aria-selected]=\"isExpansionDetailTabActive(row, i, tab, tabIndex, detailTabs) ? 'true' : 'false'\"\n [attr.tabindex]=\"isExpansionDetailTabActive(row, i, tab, tabIndex, detailTabs) ? '0' : '-1'\"\n [class.is-active]=\"isExpansionDetailTabActive(row, i, tab, tabIndex, detailTabs)\"\n (click)=\"onExpansionDetailTabSelect(row, i, tab, tabIndex, $event)\"\n (keydown)=\"onExpansionDetailTabKeydown($event, row, i, tabIndex, detailTabs)\"\n >\n <praxis-rich-content\n rootClassName=\"pfx-expansion-detail-tab-btn__content\"\n [nodes]=\"getExpansionDetailTabButtonRichContentNodes(tab)\"\n [context]=\"getExpansionDetailRichContentContext(row, i)\"\n ></praxis-rich-content>\n </button>\n }\n </div>\n @for (tab of detailTabs; track $index; let tabIndex = $index) {\n @if (isExpansionDetailTabActive(row, i, tab, tabIndex, detailTabs)) {\n <div\n class=\"pfx-expansion-detail-tab-panel\"\n role=\"tabpanel\"\n [attr.id]=\"getExpansionDetailPanelId(row, i, tab, tabIndex)\"\n [attr.aria-labelledby]=\"getExpansionDetailTabId(row, i, tab, tabIndex)\"\n >\n @if (getExpansionDetailTabRichContentNodes(tab, row, i); as richNodes) {\n <praxis-rich-content\n class=\"pfx-expansion-node-host pfx-expansion-node-host--tab\"\n [nodes]=\"richNodes\"\n [context]=\"getExpansionDetailRichContentContext(row, i)\"\n ></praxis-rich-content>\n } @else {\n @for (childNode of getExpansionDetailNodeChildren(tab); track $index) {\n <ng-container\n *ngTemplateOutlet=\"\n expansionDetailNodeTemplate;\n context: { $implicit: childNode, row: row, index: i }\n \"\n ></ng-container>\n }\n }\n </div>\n }\n }\n } @else {\n <div class=\"pfx-expansion-detail-message\">\n <praxis-rich-content\n rootClassName=\"pfx-expansion-detail-message__content\"\n [nodes]=\"getExpansionDetailTextRichContentNodes('Schema em layout tabs sem abas v\u00E1lidas.', 'pfx-expansion-detail-message__text')\"\n [context]=\"getExpansionDetailRichContentContext(row, i)\"\n ></praxis-rich-content>\n </div>\n }\n } @else {\n <div class=\"pfx-expansion-detail-stack\">\n @for (node of getExpansionDetailItems(detailState.schema); track $index) {\n <ng-container\n *ngTemplateOutlet=\"\n expansionDetailNodeTemplate;\n context: { $implicit: node, row: row, index: i }\n \"\n ></ng-container>\n }\n </div>\n }\n }\n\n <ng-template #expansionDetailNodeTemplate let-node let-row=\"row\" let-index=\"index\">\n @if (getExpansionDetailRichContentNodes(node, row, index); as richNodes) {\n <praxis-rich-content\n class=\"pfx-expansion-node-host\"\n [nodes]=\"richNodes\"\n [context]=\"getExpansionDetailRichContentContext(row, index)\"\n ></praxis-rich-content>\n } @else {\n @switch (getExpansionDetailNodeType(node)) {\n @case ('list') {\n <section class=\"pfx-expansion-node pfx-expansion-node-list\">\n <praxis-rich-content\n rootClassName=\"pfx-expansion-node-list__title\"\n [nodes]=\"getExpansionDetailTextRichContentNodes(getExpansionDetailNodeTitle(node, 'Lista'), 'pfx-expansion-node-list__title-text')\"\n [context]=\"getExpansionDetailRichContentContext(row, index)\"\n ></praxis-rich-content>\n @let listItems = getExpansionDetailListItems(row, node);\n @let listEntries = getExpansionDetailListEntries(row, node);\n @if (listItems.length) {\n <ul>\n @for (entry of listEntries; track $index) {\n <li>\n @if (getExpansionDetailListItemRichContentNodes(entry); as richNodes) {\n <praxis-rich-content\n class=\"pfx-expansion-node-list__item-host\"\n [nodes]=\"richNodes\"\n [context]=\"getExpansionDetailRichContentContext(row, index)\"\n ></praxis-rich-content>\n } @else {\n {{ formatExpansionDetailListEntry(entry) }}\n }\n </li>\n }\n </ul>\n } @else {\n <praxis-rich-content\n rootClassName=\"pfx-expansion-node-placeholder\"\n [nodes]=\"getExpansionDetailTextRichContentNodes('Sem itens.', 'pfx-expansion-node-placeholder__text')\"\n [context]=\"getExpansionDetailRichContentContext(row, index)\"\n ></praxis-rich-content>\n }\n </section>\n }\n @case ('detailList') {\n <section class=\"pfx-expansion-node pfx-expansion-node-rich-list\">\n <praxis-rich-content\n rootClassName=\"pfx-expansion-node-rich-list__title\"\n [nodes]=\"getExpansionDetailTextRichContentNodes(getExpansionDetailNodeTitle(node, 'Cole\u00E7\u00E3o rica'), 'pfx-expansion-node-rich-list__title-text')\"\n [context]=\"getExpansionDetailRichContentContext(row, index)\"\n ></praxis-rich-content>\n @let richListEntries = getExpansionDetailRichListEntries(row, node);\n @if (richListEntries.length) {\n <div class=\"pfx-expansion-node-rich-list__items\">\n @for (entry of richListEntries; track $index) {\n <article [class]=\"getExpansionDetailRichListItemClassName(node)\">\n <praxis-rich-content\n class=\"pfx-expansion-node-rich-list__item-host\"\n [nodes]=\"getExpansionDetailRichListItemNodes(node)\"\n [context]=\"getExpansionDetailRichListItemContext(row, index, node, entry, $index)\"\n ></praxis-rich-content>\n @let itemActions = getExpansionDetailRichListItemActions(node, row, index, entry, $index);\n @if (itemActions.length) {\n <div class=\"pfx-expansion-node-rich-list__item-actions\">\n @for (action of itemActions; track action.actionId) {\n <button\n type=\"button\"\n mat-stroked-button\n class=\"pfx-expansion-node-rich-list__item-action-btn\"\n [disabled]=\"isExpansionDetailRichListItemActionDisabled(action, row, index, node, entry, $index)\"\n (click)=\"onExpansionDetailRichListItemAction(action, row, index, node, entry, $index, $event)\"\n >\n <praxis-rich-content\n class=\"pfx-expansion-node-rich-list__item-action-host\"\n [nodes]=\"getExpansionDetailRichListItemActionNodes(action)\"\n [context]=\"getExpansionDetailRichListItemContext(row, index, node, entry, $index)\"\n ></praxis-rich-content>\n </button>\n }\n </div>\n }\n </article>\n }\n </div>\n } @else {\n <praxis-rich-content\n rootClassName=\"pfx-expansion-node-placeholder\"\n [nodes]=\"getExpansionDetailTextRichContentNodes(getExpansionDetailRichListEmptyText(node), 'pfx-expansion-node-placeholder__text')\"\n [context]=\"getExpansionDetailRichContentContext(row, index)\"\n ></praxis-rich-content>\n }\n </section>\n }\n @case ('cardGrid') {\n <section class=\"pfx-expansion-node pfx-expansion-node-card-grid\">\n @if (getExpansionDetailCardGridHeaderNodes(node); as cardGridHeaderNodes) {\n @if (cardGridHeaderNodes.length) {\n <praxis-rich-content\n rootClassName=\"pfx-expansion-node-card-grid__header\"\n [nodes]=\"cardGridHeaderNodes\"\n [context]=\"getExpansionDetailRichContentContext(row, index)\"\n ></praxis-rich-content>\n }\n }\n @let gridCards = getExpansionDetailCardGridCards(node);\n @if (gridCards.length) {\n <div\n class=\"pfx-expansion-node-card-grid__cards\"\n [ngStyle]=\"getExpansionDetailCardGridStyles(node)\"\n >\n @for (card of gridCards; track $index) {\n <praxis-rich-content\n class=\"pfx-expansion-node-card-grid__card-host\"\n [nodes]=\"getExpansionDetailCardGridCardNodes(card)\"\n [context]=\"getExpansionDetailRichContentContext(row, index)\"\n ></praxis-rich-content>\n }\n </div>\n } @else {\n <praxis-rich-content\n rootClassName=\"pfx-expansion-node-placeholder\"\n [nodes]=\"getExpansionDetailTextRichContentNodes('Sem itens.', 'pfx-expansion-node-placeholder__text')\"\n [context]=\"getExpansionDetailRichContentContext(row, index)\"\n ></praxis-rich-content>\n }\n </section>\n }\n @case ('richText') {\n <div\n class=\"pfx-expansion-node pfx-expansion-node-richtext\"\n [innerHTML]=\"getExpansionDetailRichText(node)\"\n ></div>\n }\n @case ('formRef') {\n <section class=\"pfx-expansion-node pfx-expansion-node-embed\">\n <praxis-rich-content\n rootClassName=\"pfx-expansion-node-embed__header\"\n [nodes]=\"getExpansionDetailEmbedHeaderNodes(node)\"\n [context]=\"getExpansionDetailRichContentContext(row, index)\"\n ></praxis-rich-content>\n <praxis-rich-content\n rootClassName=\"pfx-expansion-node-embed__meta\"\n [nodes]=\"getExpansionDetailEmbedMetaNodes(node)\"\n [context]=\"getExpansionDetailRichContentContext(row, index)\"\n ></praxis-rich-content>\n <praxis-rich-content\n rootClassName=\"pfx-expansion-node-embed__empty\"\n [nodes]=\"getExpansionDetailTextRichContentNodes(getExpansionDetailEmbedEmptyText(node), 'pfx-expansion-node-embed__empty-text')\"\n [context]=\"getExpansionDetailRichContentContext(row, index)\"\n ></praxis-rich-content>\n @if (getExpansionDetailEmbedAction(node, row, index); as embedAction) {\n <button\n type=\"button\"\n mat-stroked-button\n class=\"pfx-expansion-node-embed__action-btn\"\n [disabled]=\"isExpansionDetailEmbedActionDisabled(embedAction, row, index)\"\n (click)=\"onExpansionDetailEmbedAction(embedAction, row, index, $event)\"\n >\n <praxis-rich-content\n class=\"pfx-expansion-node-embed__action-host\"\n [nodes]=\"getExpansionDetailEmbedActionNodes(embedAction)\"\n [context]=\"getExpansionDetailRichContentContext(row, index)\"\n ></praxis-rich-content>\n </button>\n }\n </section>\n }\n @case ('tableRef') {\n <section class=\"pfx-expansion-node pfx-expansion-node-embed\">\n <praxis-rich-content\n rootClassName=\"pfx-expansion-node-embed__header\"\n [nodes]=\"getExpansionDetailEmbedHeaderNodes(node)\"\n [context]=\"getExpansionDetailRichContentContext(row, index)\"\n ></praxis-rich-content>\n <praxis-rich-content\n rootClassName=\"pfx-expansion-node-embed__meta\"\n [nodes]=\"getExpansionDetailEmbedMetaNodes(node)\"\n [context]=\"getExpansionDetailRichContentContext(row, index)\"\n ></praxis-rich-content>\n <praxis-rich-content\n rootClassName=\"pfx-expansion-node-embed__empty\"\n [nodes]=\"getExpansionDetailTextRichContentNodes(getExpansionDetailEmbedEmptyText(node), 'pfx-expansion-node-embed__empty-text')\"\n [context]=\"getExpansionDetailRichContentContext(row, index)\"\n ></praxis-rich-content>\n @if (getExpansionDetailEmbedAction(node, row, index); as embedAction) {\n <button\n type=\"button\"\n mat-stroked-button\n class=\"pfx-expansion-node-embed__action-btn\"\n [disabled]=\"isExpansionDetailEmbedActionDisabled(embedAction, row, index)\"\n (click)=\"onExpansionDetailEmbedAction(embedAction, row, index, $event)\"\n >\n <praxis-rich-content\n class=\"pfx-expansion-node-embed__action-host\"\n [nodes]=\"getExpansionDetailEmbedActionNodes(embedAction)\"\n [context]=\"getExpansionDetailRichContentContext(row, index)\"\n ></praxis-rich-content>\n </button>\n }\n </section>\n }\n @case ('chartRef') {\n <section class=\"pfx-expansion-node pfx-expansion-node-embed\">\n <praxis-rich-content\n rootClassName=\"pfx-expansion-node-embed__header\"\n [nodes]=\"getExpansionDetailEmbedHeaderNodes(node)\"\n [context]=\"getExpansionDetailRichContentContext(row, index)\"\n ></praxis-rich-content>\n <praxis-rich-content\n rootClassName=\"pfx-expansion-node-embed__meta\"\n [nodes]=\"getExpansionDetailEmbedMetaNodes(node)\"\n [context]=\"getExpansionDetailRichContentContext(row, index)\"\n ></praxis-rich-content>\n <praxis-rich-content\n rootClassName=\"pfx-expansion-node-embed__empty\"\n [nodes]=\"getExpansionDetailTextRichContentNodes(getExpansionDetailEmbedEmptyText(node), 'pfx-expansion-node-embed__empty-text')\"\n [context]=\"getExpansionDetailRichContentContext(row, index)\"\n ></praxis-rich-content>\n @if (getExpansionDetailEmbedAction(node, row, index); as embedAction) {\n <button\n type=\"button\"\n mat-stroked-button\n class=\"pfx-expansion-node-embed__action-btn\"\n [disabled]=\"isExpansionDetailEmbedActionDisabled(embedAction, row, index)\"\n (click)=\"onExpansionDetailEmbedAction(embedAction, row, index, $event)\"\n >\n <praxis-rich-content\n class=\"pfx-expansion-node-embed__action-host\"\n [nodes]=\"getExpansionDetailEmbedActionNodes(embedAction)\"\n [context]=\"getExpansionDetailRichContentContext(row, index)\"\n ></praxis-rich-content>\n </button>\n }\n </section>\n }\n @case ('templateRef') {\n <section class=\"pfx-expansion-node pfx-expansion-node-embed\">\n <praxis-rich-content\n rootClassName=\"pfx-expansion-node-embed__header\"\n [nodes]=\"getExpansionDetailEmbedHeaderNodes(node)\"\n [context]=\"getExpansionDetailRichContentContext(row, index)\"\n ></praxis-rich-content>\n <praxis-rich-content\n rootClassName=\"pfx-expansion-node-embed__meta\"\n [nodes]=\"getExpansionDetailEmbedMetaNodes(node)\"\n [context]=\"getExpansionDetailRichContentContext(row, index)\"\n ></praxis-rich-content>\n <praxis-rich-content\n rootClassName=\"pfx-expansion-node-embed__empty\"\n [nodes]=\"getExpansionDetailTextRichContentNodes(getExpansionDetailEmbedEmptyText(node), 'pfx-expansion-node-embed__empty-text')\"\n [context]=\"getExpansionDetailRichContentContext(row, index)\"\n ></praxis-rich-content>\n @if (getExpansionDetailEmbedAction(node, row, index); as embedAction) {\n <button\n type=\"button\"\n mat-stroked-button\n class=\"pfx-expansion-node-embed__action-btn\"\n [disabled]=\"isExpansionDetailEmbedActionDisabled(embedAction, row, index)\"\n (click)=\"onExpansionDetailEmbedAction(embedAction, row, index, $event)\"\n >\n <praxis-rich-content\n class=\"pfx-expansion-node-embed__action-host\"\n [nodes]=\"getExpansionDetailEmbedActionNodes(embedAction)\"\n [context]=\"getExpansionDetailRichContentContext(row, index)\"\n ></praxis-rich-content>\n </button>\n }\n </section>\n }\n @case ('diagramEmbed') {\n <section class=\"pfx-expansion-node pfx-expansion-node-embed\">\n <praxis-rich-content\n rootClassName=\"pfx-expansion-node-embed__header\"\n [nodes]=\"getExpansionDetailEmbedHeaderNodes(node)\"\n [context]=\"getExpansionDetailRichContentContext(row, index)\"\n ></praxis-rich-content>\n <praxis-rich-content\n rootClassName=\"pfx-expansion-node-embed__meta\"\n [nodes]=\"getExpansionDetailEmbedMetaNodes(node)\"\n [context]=\"getExpansionDetailRichContentContext(row, index)\"\n ></praxis-rich-content>\n @if (getExpansionDetailDiagramSource(row, node); as diagramSource) {\n <div class=\"pfx-expansion-node-embed__diagram\">\n <praxis-rich-content\n rootClassName=\"pfx-expansion-node-embed__diagram-label\"\n [nodes]=\"getExpansionDetailTextRichContentNodes(getExpansionDetailDiagramSourceLabel(), 'pfx-expansion-node-embed__diagram-label-text')\"\n [context]=\"getExpansionDetailRichContentContext(row, index)\"\n ></praxis-rich-content>\n <pre class=\"pfx-expansion-node-embed__diagram-source\">{{ diagramSource }}</pre>\n </div>\n } @else {\n <praxis-rich-content\n rootClassName=\"pfx-expansion-node-embed__empty\"\n [nodes]=\"getExpansionDetailTextRichContentNodes(getExpansionDetailEmbedEmptyText(node), 'pfx-expansion-node-embed__empty-text')\"\n [context]=\"getExpansionDetailRichContentContext(row, index)\"\n ></praxis-rich-content>\n }\n @if (getExpansionDetailEmbedAction(node, row, index); as embedAction) {\n <button\n type=\"button\"\n mat-stroked-button\n class=\"pfx-expansion-node-embed__action-btn\"\n [disabled]=\"isExpansionDetailEmbedActionDisabled(embedAction, row, index)\"\n (click)=\"onExpansionDetailEmbedAction(embedAction, row, index, $event)\"\n >\n <praxis-rich-content\n class=\"pfx-expansion-node-embed__action-host\"\n [nodes]=\"getExpansionDetailEmbedActionNodes(embedAction)\"\n [context]=\"getExpansionDetailRichContentContext(row, index)\"\n ></praxis-rich-content>\n </button>\n }\n </section>\n }\n @case ('action') {\n <div class=\"pfx-expansion-node pfx-expansion-node-action\">\n <button\n type=\"button\"\n mat-stroked-button\n [disabled]=\"isExpansionDetailActionDisabled(node)\"\n (click)=\"onExpansionDetailAction(node, row, $event)\"\n >\n <praxis-rich-content\n class=\"pfx-expansion-node-action__content\"\n [nodes]=\"getExpansionDetailActionRichContentNodes(node)\"\n [context]=\"getExpansionDetailRichContentContext(row, index)\"\n ></praxis-rich-content>\n </button>\n @if (getExpansionDetailActionStatusText(node); as actionStatusText) {\n <praxis-rich-content\n rootClassName=\"pfx-expansion-node-action__status\"\n [nodes]=\"getExpansionDetailTextRichContentNodes(actionStatusText, 'pfx-expansion-node-action__status-text')\"\n [context]=\"getExpansionDetailRichContentContext(row, index)\"\n ></praxis-rich-content>\n }\n </div>\n }\n @case ('actionBar') {\n <section class=\"pfx-expansion-node pfx-expansion-node-action-bar\">\n <praxis-rich-content\n rootClassName=\"pfx-expansion-node-action-bar__title\"\n [nodes]=\"getExpansionDetailTextRichContentNodes(getExpansionDetailActionBarTitle(node), 'pfx-expansion-node-action-bar__title-text')\"\n [context]=\"getExpansionDetailRichContentContext(row, index)\"\n ></praxis-rich-content>\n @let actionBarActions = getExpansionDetailActionBarActions(node, row, index);\n @if (actionBarActions.length) {\n <div class=\"pfx-expansion-node-action-bar__actions\">\n @for (action of actionBarActions; track action.actionId) {\n <button\n type=\"button\"\n mat-stroked-button\n class=\"pfx-expansion-node-action-bar__action-btn\"\n [disabled]=\"isExpansionDetailActionBarActionDisabled(action, row, index)\"\n (click)=\"onExpansionDetailActionBarAction(action, row, index, $event)\"\n >\n <praxis-rich-content\n class=\"pfx-expansion-node-action-bar__action-host\"\n [nodes]=\"getExpansionDetailActionBarActionNodes(action)\"\n [context]=\"getExpansionDetailRichContentContext(row, index)\"\n ></praxis-rich-content>\n </button>\n }\n </div>\n } @else {\n <praxis-rich-content\n rootClassName=\"pfx-expansion-node-placeholder\"\n [nodes]=\"getExpansionDetailTextRichContentNodes(getExpansionDetailActionBarEmptyText(node), 'pfx-expansion-node-placeholder__text')\"\n [context]=\"getExpansionDetailRichContentContext(row, index)\"\n ></praxis-rich-content>\n }\n </section>\n }\n @case ('tab') {\n <div class=\"pfx-expansion-node pfx-expansion-node-placeholder\">\n <praxis-rich-content\n rootClassName=\"pfx-expansion-node-placeholder__content\"\n [nodes]=\"getExpansionDetailTextRichContentNodes('Node', 'pfx-expansion-node-placeholder__text')\"\n [context]=\"getExpansionDetailRichContentContext(row, index)\"\n ></praxis-rich-content>\n <code>tab</code>\n <praxis-rich-content\n rootClassName=\"pfx-expansion-node-placeholder__content\"\n [nodes]=\"getExpansionDetailTextRichContentNodes('fora de contexto de tabs.', 'pfx-expansion-node-placeholder__text')\"\n [context]=\"getExpansionDetailRichContentContext(row, index)\"\n ></praxis-rich-content>\n </div>\n }\n @default {\n <div class=\"pfx-expansion-node pfx-expansion-node-placeholder\">\n <praxis-rich-content\n rootClassName=\"pfx-expansion-node-placeholder__content\"\n [nodes]=\"getExpansionDetailTextRichContentNodes('Node n\u00E3o suportado:', 'pfx-expansion-node-placeholder__text')\"\n [context]=\"getExpansionDetailRichContentContext(row, index)\"\n ></praxis-rich-content>\n <code>{{ getExpansionDetailNodeType(node) }}</code>\n </div>\n }\n }\n }\n </ng-template>\n </section>\n </td>\n </ng-container>\n <tr\n mat-row\n *matRowDef=\"let row; columns: expansionDetailRowColumns; when: isExpansionDetailRow\"\n class=\"pfx-expansion-detail-row\"\n ></tr>\n }\n }\n</table>\n}\n\n<!-- Virtual rows path (header preserved above) -->\n@if (shouldRenderDataSurface() && !schemaError && !dataError && isVirtualized()) {\n <cdk-virtual-scroll-viewport\n class=\"ptable-viewport\"\n [itemSize]=\"getVirtItemHeight()\"\n [minBufferPx]=\"getVirtBufferSize() * getVirtItemHeight()\"\n [maxBufferPx]=\"getVirtBufferSize() * getVirtItemHeight() * 2\"\n [style.minHeight]=\"getVirtMinHeightHostStyle()\"\n >\n <table\n class=\"mat-mdc-table\"\n [ngClass]=\"getTableElevationClassName()\"\n [style.width]=\"getVirtualTableWidthStyle()\"\n >\n <tbody>\n <tr class=\"mat-mdc-row\"\n *cdkVirtualFor=\"let row of dataSource.data; let i = index; trackBy: trackByRow\"\n [class.pfx-row-selected]=\"selection.isSelected(row)\"\n [attr.aria-selected]=\"config.behavior?.selection?.enabled ? (selection.isSelected(row) ? 'true' : 'false') : null\"\n [ngClass]=\"getRowClasses(row)\"\n [ngStyle]=\"getRowNgStyle(row)\"\n [matTooltip]=\"getRowTooltip(row) || null\"\n [matTooltipDisabled]=\"!getRowTooltip(row)\"\n [matTooltipPosition]=\"getRowTooltipPosition(row)\"\n [matTooltipShowDelay]=\"getRowTooltipShowDelay(row)\"\n (click)=\"onRowClicked(row, i, $event)\"\n (dblclick)=\"onRowDoubleClicked(row, i)\">\n <!-- Selection column -->\n @if (config.behavior?.selection?.enabled) { <td class=\"mat-mdc-cell\">\n <mat-checkbox\n (click)=\"$event.stopPropagation()\"\n (change)=\"toggleRow(row)\"\n [checked]=\"selection.isSelected(row)\">\n </mat-checkbox>\n </td> }\n <!-- Data columns -->\n @for (column of visibleColumns; track column.field) {\n <td class=\"mat-mdc-cell\"\n [style.text-align]=\"getColumnTextAlignStyle(column)\"\n [style.width]=\"getColumnWidthStyle(column)\"\n [attr.style]=\"getColumnCellAttrStyle(column)\"\n [ngClass]=\"getCellClasses(row, column)\"\n [ngStyle]=\"getCellNgStyle(row, column)\">\n <div\n class=\"pfx-cell-content\"\n [ngClass]=\"getCellContentClasses(row, column)\"\n [ngStyle]=\"getCellContentNgStyle(row, column)\"\n >\n <ng-container [ngSwitch]=\"getEffectiveRendererType(row, column)\">\n <ng-container *ngSwitchCase=\"'icon'\">\n <span class=\"pfx-icon-renderer\"\n [style.color]=\"getIconColor(row, column) || null\"\n [ngStyle]=\"getIconStyle(row, column)\"\n [attr.aria-label]=\"getIconAriaLabel(row, column) || null\">\n <praxis-rich-content\n rootClassName=\"pfx-icon-renderer__content\"\n [nodes]=\"getIconRichContentNodes(row, column)\"\n ></praxis-rich-content>\n </span>\n </ng-container>\n <ng-container *ngSwitchCase=\"'image'\">\n <span class=\"pfx-cell-image\">\n <praxis-rich-content\n rootClassName=\"pfx-cell-image__content\"\n [nodes]=\"getImageRichContentNodes(row, column)\"\n ></praxis-rich-content>\n </span>\n </ng-container>\n <ng-container *ngSwitchCase=\"'badge'\">\n <span class=\"pfx-badge\" [ngClass]=\"getBadgeClasses(row, column)\">\n <praxis-rich-content\n rootClassName=\"pfx-badge__content\"\n [nodes]=\"getBadgeRichContentNodes(row, column)\"\n ></praxis-rich-content>\n </span>\n </ng-container>\n <ng-container *ngSwitchCase=\"'chip'\">\n <span class=\"pfx-chip\" [ngClass]=\"getChipClasses(row, column)\">\n <praxis-rich-content\n rootClassName=\"pfx-chip__content\"\n [nodes]=\"getChipRichContentNodes(row, column)\"\n ></praxis-rich-content>\n </span>\n </ng-container>\n <ng-container *ngSwitchCase=\"'progress'\">\n <div class=\"pfx-progress\">\n <praxis-rich-content\n rootClassName=\"pfx-progress__content\"\n [context]=\"getProgressRichContentContext(row, column)\"\n [nodes]=\"getProgressRichContentNodes(row, column)\"\n ></praxis-rich-content>\n </div>\n </ng-container>\n <ng-container *ngSwitchCase=\"'avatar'\">\n <span\n class=\"pfx-avatar-renderer\"\n [ngStyle]=\"getAvatarStyle(row, column)\"\n [class.shape-rounded]=\"getAvatarShape(row, column) === 'rounded'\"\n [class.shape-circle]=\"getAvatarShape(row, column) === 'circle'\"\n >\n <praxis-rich-content\n rootClassName=\"pfx-avatar-renderer__content\"\n [nodes]=\"getAvatarRichContentNodes(row, column)\"\n ></praxis-rich-content>\n </span>\n </ng-container>\n <ng-container *ngSwitchCase=\"'link'\">\n <a\n class=\"pfx-link\"\n [attr.href]=\"getLinkHref(row, column) || null\"\n [attr.target]=\"getLinkTarget(row, column) || null\"\n [attr.rel]=\"getLinkRel(row, column) || null\"\n (click)=\"$event.stopPropagation()\"\n >\n <praxis-rich-content\n rootClassName=\"pfx-link__content\"\n [nodes]=\"getLinkRichContentNodes(row, column)\"\n ></praxis-rich-content>\n </a>\n </ng-container>\n <ng-container *ngSwitchCase=\"'button'\">\n <ng-container [ngSwitch]=\"getButtonVariant(row, column)\">\n <button\n *ngSwitchCase=\"'outlined'\"\n mat-stroked-button\n [color]=\"getButtonColor(row, column) || null\"\n [disabled]=\"isButtonDisabled(row, column)\"\n [attr.aria-label]=\"getButtonAriaLabel(row, column) || getButtonLabel(row, column)\"\n (click)=\"onButtonClick(row, column, $event)\"\n >\n <praxis-rich-content\n rootClassName=\"pfx-button-renderer__content\"\n [nodes]=\"getButtonRichContentNodes(row, column)\"\n ></praxis-rich-content>\n </button>\n <button\n *ngSwitchCase=\"'text'\"\n mat-button\n [color]=\"getButtonColor(row, column) || null\"\n [disabled]=\"isButtonDisabled(row, column)\"\n [attr.aria-label]=\"getButtonAriaLabel(row, column) || getButtonLabel(row, column)\"\n (click)=\"onButtonClick(row, column, $event)\"\n >\n <praxis-rich-content\n rootClassName=\"pfx-button-renderer__content\"\n [nodes]=\"getButtonRichContentNodes(row, column)\"\n ></praxis-rich-content>\n </button>\n <button\n *ngSwitchDefault\n mat-flat-button\n [color]=\"getButtonColor(row, column) || null\"\n [disabled]=\"isButtonDisabled(row, column)\"\n [attr.aria-label]=\"getButtonAriaLabel(row, column) || getButtonLabel(row, column)\"\n (click)=\"onButtonClick(row, column, $event)\"\n >\n <praxis-rich-content\n rootClassName=\"pfx-button-renderer__content\"\n [nodes]=\"getButtonRichContentNodes(row, column)\"\n ></praxis-rich-content>\n </button>\n </ng-container>\n </ng-container>\n <ng-container *ngSwitchCase=\"'menu'\">\n <button\n mat-icon-button\n [matMenuTriggerFor]=\"menuRef\"\n (click)=\"$event.stopPropagation()\"\n [attr.aria-label]=\"getMenuAriaLabel(row, column) || 'Menu'\"\n >\n <praxis-rich-content\n rootClassName=\"pfx-menu-trigger__content\"\n [nodes]=\"getMenuTriggerRichContentNodes()\"\n ></praxis-rich-content>\n </button>\n <mat-menu #menuRef=\"matMenu\">\n <button\n mat-menu-item\n *ngFor=\"let it of getMenuItems(row, column)\"\n (click)=\"onMenuItemClick(it, row, $event)\"\n [disabled]=\"!it.__visible\"\n >\n <praxis-rich-content\n rootClassName=\"pfx-menu-item__content\"\n [nodes]=\"getMenuItemRichContentNodes(it)\"\n ></praxis-rich-content>\n </button>\n </mat-menu>\n </ng-container>\n <ng-container *ngSwitchDefault>\n {{ getCellValue(row, column) }}\n </ng-container>\n </ng-container>\n </div>\n </td>\n }\n\n <!-- Actions column -->\n @if (config.actions?.row?.enabled) {\n <td class=\"mat-mdc-cell praxis-actions-cell\" [class.dense]=\"dense\" [style.width]=\"getRowActionsWidthStyle()\">\n <div\n class=\"praxis-actions-cell__content\"\n [class.praxis-actions-cell__content--discovering]=\"isRowDiscoveryPending(row)\"\n [attr.aria-busy]=\"isRowDiscoveryPending(row) ? 'true' : null\"\n >\n @if (config.actions?.row?.display === 'icons' || !config.actions?.row?.display) {\n <ng-container *ngFor=\"let a of getInlineRowActions(row); trackBy: trackAction\">\n <span\n class=\"praxis-row-action-anchor\"\n [class.praxis-row-action-anchor--workflow]=\"isWorkflowRowAction(a)\"\n [class.praxis-row-action-anchor--blocked]=\"isBlockedWorkflowRowAction(a, row)\"\n [matTooltip]=\"getActionTooltip(a, row)\"\n [matTooltipDisabled]=\"!getActionTooltip(a, row)\"\n matTooltipPosition=\"above\"\n matTooltipClass=\"praxis-tooltip\"\n >\n <button mat-icon-button class=\"praxis-icon-btn\"\n [class.praxis-icon-btn--workflow]=\"isWorkflowRowAction(a)\"\n [class.praxis-icon-btn--blocked]=\"isBlockedWorkflowRowAction(a, row)\"\n [disabled]=\"isActionDisabled(a, row)\"\n (click)=\"onRowAction(getActionId(a), row, $event, getRowActionRuntimeOptions(a, row))\"\n [attr.aria-label]=\"a.label || getActionId(a)\"\n [color]=\"a.color || null\">\n <praxis-rich-content\n rootClassName=\"praxis-row-action__content\"\n [nodes]=\"getRowActionIconRichContentNodes(a)\"\n ></praxis-rich-content>\n </button>\n </span>\n </ng-container>\n }\n @if (config.actions?.row?.display === 'buttons') {\n <ng-container *ngFor=\"let a of getInlineRowActions(row); trackBy: trackAction\">\n <span\n class=\"praxis-row-action-anchor\"\n [class.praxis-row-action-anchor--workflow]=\"isWorkflowRowAction(a)\"\n [class.praxis-row-action-anchor--blocked]=\"isBlockedWorkflowRowAction(a, row)\"\n [matTooltip]=\"getActionTooltip(a, row)\"\n [matTooltipDisabled]=\"!getActionTooltip(a, row)\"\n matTooltipPosition=\"above\"\n matTooltipClass=\"praxis-tooltip\"\n >\n <button mat-flat-button class=\"praxis-row-btn\"\n [class.praxis-row-btn--workflow]=\"isWorkflowRowAction(a)\"\n [class.praxis-row-btn--blocked]=\"isBlockedWorkflowRowAction(a, row)\"\n [disabled]=\"isActionDisabled(a, row)\"\n (click)=\"onRowAction(getActionId(a), row, $event, getRowActionRuntimeOptions(a, row))\"\n [attr.aria-label]=\"a.label || getActionId(a)\"\n [color]=\"a.color || null\">\n <praxis-rich-content\n rootClassName=\"praxis-row-action__content\"\n [nodes]=\"getRowActionRichContentNodes(a)\"\n ></praxis-rich-content>\n </button>\n </span>\n </ng-container>\n }\n @if (hasOverflowRowActions(row)) {\n <button mat-icon-button class=\"praxis-icon-btn praxis-more-btn\"\n [matMenuTriggerFor]=\"rowMoreMenuV\"\n (menuOpened)=\"onRowOverflowMenuOpened(row)\"\n [color]=\"getRowMenuButtonColor() || null\"\n [attr.aria-label]=\"getRowMenuTooltip(row)\"\n [matTooltip]=\"getRowMenuTooltip(row)\"\n matTooltipPosition=\"above\">\n <mat-icon [praxisIcon]=\"getRowMenuIcon()\"></mat-icon>\n </button>\n }\n <mat-menu #rowMoreMenuV=\"matMenu\" xPosition=\"before\">\n @if (hasRowOverflowMenuLoadingState(row)) {\n <button mat-menu-item disabled>\n <mat-icon>hourglass_empty</mat-icon>\n <praxis-rich-content\n rootClassName=\"praxis-row-overflow-menu__label\"\n [nodes]=\"getTableChromeTextRichContentNodes(getRowOverflowMenuLoadingLabel(), 'praxis-row-overflow-menu__label-text')\"\n ></praxis-rich-content>\n </button>\n }\n <ng-container *ngFor=\"let a of getOverflowRowActions(row); trackBy: trackAction\">\n <button mat-menu-item (click)=\"onRowAction(getActionId(a), row, $event, getRowActionRuntimeOptions(a, row))\" [disabled]=\"isActionDisabled(a, row)\">\n <mat-icon [color]=\"a.color || null\" [praxisIcon]=\"a.icon\"></mat-icon>\n <praxis-rich-content\n rootClassName=\"praxis-row-overflow-menu__label\"\n [nodes]=\"getTableChromeTextRichContentNodes(a.label || getActionId(a), 'praxis-row-overflow-menu__label-text')\"\n ></praxis-rich-content>\n </button>\n </ng-container>\n @if (hasRowOverflowMenuEmptyState(row)) {\n <button mat-menu-item disabled>\n <mat-icon>info</mat-icon>\n <praxis-rich-content\n rootClassName=\"praxis-row-overflow-menu__label\"\n [nodes]=\"getTableChromeTextRichContentNodes(getRowOverflowMenuEmptyLabel(row), 'praxis-row-overflow-menu__label-text')\"\n ></praxis-rich-content>\n </button>\n }\n </mat-menu>\n </div>\n </td>\n }\n </tr>\n </tbody>\n </table>\n </cdk-virtual-scroll-viewport>\n}\n\n</div>\n@if (shouldShowLoadingSurface()) {\n <div class=\"ptable-loading-state\" role=\"status\" aria-live=\"polite\">\n <div class=\"ptable-loading-state__hero\" aria-hidden=\"true\">\n <span class=\"ptable-loading-state__line ptable-loading-state__line--wide\"></span>\n <span class=\"ptable-loading-state__line ptable-loading-state__line--short\"></span>\n <div class=\"ptable-loading-state__rows\">\n @for (placeholder of [1, 2, 3]; track placeholder) {\n <div class=\"ptable-loading-state__row\">\n <span class=\"ptable-loading-state__cell ptable-loading-state__cell--short\"></span>\n <span class=\"ptable-loading-state__cell\"></span>\n <span class=\"ptable-loading-state__cell ptable-loading-state__cell--wide\"></span>\n </div>\n }\n </div>\n </div>\n <div class=\"ptable-loading-state__message\">\n {{ getLoadingSurfaceMessage() }}\n </div>\n </div>\n}\n@if (shouldShowNoDataState()) {\n <div class=\"ptable-no-data-state\" role=\"status\" aria-live=\"polite\">\n <praxis-empty-state-card\n [icon]=\"getNoDataStateIcon()\"\n [title]=\"getNoDataStateTitle()\"\n [description]=\"getNoDataStateDescription()\"\n [primaryAction]=\"getNoDataStatePrimaryAction()\"\n [secondaryActions]=\"getNoDataStateSecondaryActions()\"\n [inline]=\"true\"\n ></praxis-empty-state-card>\n </div>\n}\n@if (\n shouldRenderDataSurface()\n && !schemaError\n && !dataError\n && shouldRenderFloatingBulkActions()\n && getFloatingBulkActions().length\n && !shouldHideFloatingBulkActions()\n) {\n <div [class]=\"'praxis-floating-bulk-actions ' + getFloatingBulkPositionClass()\">\n @for (action of getFloatingBulkActions(); track getActionId(action)) {\n <button\n mat-mini-fab\n [color]=\"action.color || 'primary'\"\n [disabled]=\"isFloatingBulkActionDisabled(action)\"\n (click)=\"onToolbarAction({ action: getActionId(action), actionConfig: action })\"\n [attr.aria-label]=\"action.label || getActionId(action)\"\n [matTooltip]=\"action.label || getActionId(action)\"\n matTooltipPosition=\"left\"\n >\n <praxis-rich-content\n rootClassName=\"praxis-floating-bulk-actions__content\"\n [nodes]=\"getFloatingBulkActionRichContentNodes(action)\"\n ></praxis-rich-content>\n </button>\n }\n </div>\n}\n<!-- Barra de a\u00C3\u00A7\u00C3\u00B5es no rodap\u00C3\u00A9 (opcional) -->\n@if (shouldRenderDataSurface() && !schemaError && !dataError && showToolbar && shouldRenderFooterToolbar()) {\n <praxis-table-toolbar\n [config]=\"config\"\n [backgroundColor]=\"getToolbarActionsBackgroundColor()\"\n [style.--pfx-filter-h]=\"getToolbarLayoutHeightHostStyle()\"\n [class.footer-flat]=\"hasBottomPaginator()\"\n class=\"praxis-toolbar-footer\"\n placement=\"footer\"\n [showMain]=\"shouldShowFooterToolbarMain()\"\n [showEndActions]=\"shouldShowFooterToolbarEndActions()\"\n [showReset]=\"shouldShowFooterToolbarReset()\"\n [showActionsGroup]=\"shouldShowToolbarActionsBottom()\"\n [showMobileActions]=\"shouldShowToolbarActionsBottom()\"\n [evaluationContext]=\"getToolbarEvaluationContext()\"\n (toolbarAction)=\"onToolbarAction($event)\"\n >\n <praxis-filter\n *ngIf=\"shouldShowFooterToolbarMain() && shouldRenderAdvancedFilter()\"\n advancedFilter\n [resourcePath]=\"getAdvancedFilterResourcePath()\"\n [filterId]=\"tableId\"\n [formId]=\"tableId\"\n [persistenceKey]=\"getAdvancedFilterPersistenceKey()\"\n [fieldMetadata]=\"getAdvancedFilterFieldMetadata()\"\n [enableCustomization]=\"enableCustomization\"\n [alwaysVisibleFields]=\"config.behavior?.filtering?.advancedFilters?.settings?.alwaysVisibleFields\"\n [alwaysVisibleFieldMetadataOverrides]=\"config.behavior?.filtering?.advancedFilters?.settings?.alwaysVisibleFieldMetadataOverrides ?? {}\"\n [selectedFieldIds]=\"config.behavior?.filtering?.advancedFilters?.settings?.selectedFieldIds ?? []\"\n [allowSaveTags]=\"config.behavior?.filtering?.advancedFilters?.settings?.allowSaveTags\"\n [changeDebounceMs]=\"config.behavior?.filtering?.advancedFilters?.settings?.changeDebounceMs ?? 300\"\n [i18n]=\"getFilterI18n()\"\n [mode]=\"'filter'\"\n [showFilterSettings]=\"enableCustomization\"\n (change)=\"onAdvancedFilterChange($event)\"\n (requestSearch)=\"onAdvancedFilterSubmit($event)\"\n (clear)=\"onAdvancedFilterClear()\"\n ></praxis-filter>\n <ng-container *ngIf=\"shouldShowFooterToolbarMain() && shouldRenderAdvancedFilter()\">\n <ng-content select=\"[advancedFilter]\"></ng-content>\n </ng-container>\n <ng-container *ngIf=\"shouldShowFooterToolbarMain() && shouldRenderAdvancedFilter()\">\n <ng-content select=\"[toolbar]\"></ng-content>\n </ng-container>\n @if (shouldShowFooterToolbarMain() && shouldRenderAdvancedFilter()) {\n @defer (on idle) {\n @if (aiAdapter) {\n <praxis-ai-assistant\n [adapter]=\"aiAdapter\"\n end-actions\n ></praxis-ai-assistant>\n }\n }\n }\n <button\n *ngIf=\"shouldShowFooterToolbarMain() && shouldRenderAdvancedFilter() && enableCustomization\"\n end-actions\n mat-icon-button\n color=\"primary\"\n data-role=\"table-settings\"\n data-testid=\"table-settings-trigger\"\n (click)=\"openTableSettings()\"\n [attr.aria-label]=\"getTableSettingsLabel()\"\n [matBadge]=\"schemaOutdated ? '!' : ''\"\n [matBadgeHidden]=\"!schemaOutdated\"\n matBadgeColor=\"warn\"\n matBadgeSize=\"small\"\n matBadgePosition=\"above after\"\n [matTooltip]=\"getTableSettingsTooltip()\"\n matTooltipPosition=\"below\"\n >\n <mat-icon>settings</mat-icon>\n </button>\n </praxis-table-toolbar>\n}\n<!-- Paginadores (top/bottom) -->\n@if (shouldRenderDataSurface() && !schemaError && !dataError && getPaginationEnabled() && (config.behavior?.pagination?.position === 'top' || config.behavior?.pagination?.position === 'both')) {\n <mat-paginator\n [length]=\"getPaginationLength()\"\n [pageSize]=\"getPaginationPageSize()\"\n [pageSizeOptions]=\"getPaginationPageSizeOptions()\"\n [showFirstLastButtons]=\"getPaginationShowFirstLast()\"\n (page)=\"onPageChange($event)\"\n [class.compact]=\"config.behavior?.pagination?.style === 'compact'\"\n >\n </mat-paginator>\n}\n\n@if (shouldRenderDataSurface() && !schemaError && !dataError && getPaginationEnabled() && (config.behavior?.pagination?.position === 'bottom' || config.behavior?.pagination?.position === 'both' || !config.behavior?.pagination?.position)) {\n <mat-paginator\n [length]=\"getPaginationLength()\"\n [pageSize]=\"getPaginationPageSize()\"\n [pageSizeOptions]=\"getPaginationPageSizeOptions()\"\n [showFirstLastButtons]=\"getPaginationShowFirstLast()\"\n (page)=\"onPageChange($event)\"\n [class.compact]=\"config.behavior?.pagination?.style === 'compact'\"\n [class.footer-stack]=\"shouldShowToolbarActionsBottom()\"\n >\n </mat-paginator>\n}\n", styles: ["@charset \"UTF-8\";table{width:100%}.praxis-visually-hidden-status{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0}.praxis-column-reorder-status{margin:8px 0;padding:10px 12px;border-radius:8px;border:1px solid var(--p-table-border-color);background:var(--p-table-row-hover-bg);color:var(--p-table-header-fg);font-size:12px;line-height:1.4;box-shadow:0 4px 12px #00000014;animation:pfx-column-reorder-status-in var(--p-table-drag-status-enter-duration, .18s) var(--p-table-motion-easing, cubic-bezier(0, 0, .2, 1))}@keyframes pfx-column-reorder-status-in{0%{opacity:0;transform:translateY(-4px)}to{opacity:1;transform:translateY(0)}}.praxis-actions-cell{height:100%;padding-inline:12px;white-space:nowrap}.pfx-expansion-col-header,.pfx-expansion-col-cell{width:52px;min-width:52px;text-align:center}.pfx-expansion-toggle:focus-visible{outline:2px solid var(--md-sys-color-primary);outline-offset:2px}.pfx-expansion-detail-row{background:var(--md-sys-color-surface-container-low)}.pfx-expansion-detail-cell{padding:0!important;border-bottom:1px solid var(--p-table-border-color)}.pfx-expansion-detail-panel{padding:12px 16px;border-left:3px solid var(--md-sys-color-primary)}.pfx-expansion-detail-panel.pfx-expansion-motion-none{animation:none;transition:none}.pfx-expansion-detail-panel.pfx-expansion-motion-subtle-slide{animation:pfx-expansion-subtle-slide-in var(--pfx-expansion-motion-duration, .16s) var(--pfx-expansion-motion-easing, cubic-bezier(.2, 0, 0, 1))}.pfx-expansion-detail-panel.pfx-expansion-motion-accordion{animation:pfx-expansion-accordion-in var(--pfx-expansion-motion-duration, .18s) var(--pfx-expansion-motion-easing, cubic-bezier(.2, 0, 0, 1));transform-origin:top center}.pfx-expansion-detail-panel.pfx-expansion-motion-fade-scale{animation:pfx-expansion-fade-scale-in var(--pfx-expansion-motion-duration, .16s) var(--pfx-expansion-motion-easing, cubic-bezier(.2, 0, 0, 1));transform-origin:top center}@keyframes pfx-expansion-subtle-slide-in{0%{opacity:0;transform:translateY(-4px)}to{opacity:1;transform:translateY(0)}}@keyframes pfx-expansion-accordion-in{0%{opacity:0;transform:scaleY(.96)}to{opacity:1;transform:scaleY(1)}}@keyframes pfx-expansion-fade-scale-in{0%{opacity:0;transform:translateY(-2px) scale(.985)}to{opacity:1;transform:translateY(0) scale(1)}}.pfx-expansion-detail-schema{margin:0;font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-size:12px;line-height:1.4;white-space:pre-wrap;word-break:break-word;color:var(--md-sys-color-on-surface-variant)}.pfx-expansion-detail-message{font-size:13px;color:var(--md-sys-color-on-surface-variant)}.pfx-expansion-detail-message--error{color:var(--md-sys-color-error)}.pfx-expansion-detail-stack{display:grid;gap:10px}.pfx-expansion-detail-tabs{display:flex;flex-wrap:wrap;gap:8px;margin-bottom:10px}.pfx-expansion-detail-tab-btn{border:1px solid var(--p-table-border-color);background:var(--md-sys-color-surface);color:var(--md-sys-color-on-surface);border-radius:999px;padding:6px 12px;font-size:12px;line-height:1.2;cursor:pointer}.pfx-expansion-detail-tab-btn__content{display:inline-flex;align-items:center;gap:6px;min-width:0}.pfx-expansion-detail-tab-btn__icon .prx-rich-icon{font-size:16px;line-height:1}.pfx-expansion-detail-tab-btn__title{white-space:nowrap}.pfx-expansion-detail-tab-btn__badge .prx-rich-badge{padding:0 8px;min-height:18px;background:color-mix(in srgb,currentColor 12%,transparent);color:inherit}.pfx-expansion-detail-tab-btn.is-active{border-color:var(--md-sys-color-primary);color:var(--md-sys-color-primary);font-weight:600}.pfx-expansion-detail-tab-btn:focus-visible{outline:2px solid var(--md-sys-color-primary);outline-offset:2px}.pfx-expansion-detail-tab-panel{display:grid;gap:10px}.pfx-expansion-node{border:1px solid var(--p-table-border-color);border-radius:8px;padding:10px 12px;background:var(--md-sys-color-surface)}.pfx-expansion-node-card__header{margin-bottom:8px}.pfx-expansion-node-card__title{margin:0;font-size:14px;line-height:1.3}.pfx-expansion-node-card__subtitle{margin:4px 0 0;font-size:12px;color:var(--md-sys-color-on-surface-variant)}.pfx-expansion-node-value{display:flex;align-items:baseline;gap:8px}.pfx-expansion-node-value__label{color:var(--md-sys-color-on-surface-variant);font-size:12px}.pfx-expansion-node-value__content{font-size:14px}.pfx-expansion-node-list__title{margin:0 0 6px;font-size:13px}.pfx-expansion-node-list ul{margin:0;padding-left:18px}.pfx-expansion-node-rich-list__title{margin:0 0 8px;font-size:13px}.pfx-expansion-node-rich-list__items{display:grid;gap:12px}.pfx-expansion-node-rich-list__item{display:grid;gap:10px;padding:12px;border:1px solid var(--md-sys-color-outline-variant, #d7dbe5);border-radius:14px;background:var(--md-sys-color-surface-container-lowest, #fff)}.pfx-expansion-node-rich-list__item--row{grid-template-columns:minmax(0,1fr) auto;align-items:center}.pfx-expansion-node-rich-list__item--stack{grid-template-columns:minmax(0,1fr)}.pfx-expansion-node-rich-list__item--card-list{grid-template-columns:minmax(0,1fr);box-shadow:0 4px 14px #0f172a0a}.pfx-expansion-node-rich-list__item-host{min-width:0}.pfx-expansion-node-rich-list__item-actions{display:flex;flex-wrap:wrap;gap:8px;align-items:center}.pfx-expansion-node-rich-list__item-action-btn{min-width:0}.pfx-expansion-node-rich-list__item-action-host{display:inline-flex;align-items:center}.pfx-expansion-node-action-bar__title{margin:0 0 12px}.pfx-expansion-node-action-bar__actions{display:flex;flex-wrap:wrap;gap:8px;align-items:center}.pfx-expansion-node-action-bar__action-btn{min-width:0}.pfx-expansion-node-action-bar__action-host{display:inline-flex;align-items:center}.pfx-expansion-node-card-grid__header{margin:0 0 12px}.pfx-expansion-node-card-grid__cards{display:grid;gap:12px;grid-template-columns:var(--pfx-expansion-card-grid-columns, repeat(auto-fit, minmax(var(--pfx-expansion-card-grid-min-width, 220px), 1fr)))}.pfx-expansion-node-card-grid__card-host{min-width:0}.pfx-expansion-node-card-grid__card-host [data-rich-node-type=card]{height:100%}.pfx-expansion-node-richtext :where(p,ul,ol,h1,h2,h3,h4,h5,h6){margin-top:0;margin-bottom:8px}.pfx-expansion-node-placeholder{font-size:12px;color:var(--md-sys-color-on-surface-variant)}:host.density-compact{--p-header-padding: 6px 10px;--p-cell-padding: 6px 10px;--p-actions-btn-size: 30px;--p-actions-icon-size: 16px}:host.density-comfortable{--p-header-padding: 10px 14px;--p-cell-padding: 10px 14px;--p-actions-btn-size: 36px;--p-actions-icon-size: 18px}:host.density-spacious{--p-header-padding: 16px 20px;--p-cell-padding: 16px 20px;--p-actions-btn-size: 44px;--p-actions-icon-size: 24px}:host.density-compact ::ng-deep .mat-mdc-cell{padding:var(--p-cell-padding, 8px 12px)}:host.density-comfortable ::ng-deep .mat-mdc-cell{padding:var(--p-cell-padding, 12px 16px)}:host.density-spacious ::ng-deep .mat-mdc-cell{padding:var(--p-cell-padding, 16px 20px)}:host.density-compact .praxis-actions-cell{padding-inline:8px}:host.density-spacious .praxis-actions-cell{padding-inline:16px}.praxis-actions-cell__content{display:flex;align-items:center;justify-content:flex-end;gap:6px;width:100%;transition:opacity .12s ease}.praxis-actions-cell.dense .praxis-actions-cell__content{gap:6px}.praxis-actions-cell__content--discovering{opacity:.78}.praxis-row-action-anchor{display:inline-flex;align-items:center}.praxis-row-action-anchor--workflow{position:relative}.praxis-row-action-anchor--workflow:after{content:\"\";position:absolute;right:4px;top:4px;width:6px;height:6px;border-radius:999px;background:var(--md-sys-color-secondary);opacity:.9;pointer-events:none}.praxis-row-action-anchor--blocked:after{background:var(--md-sys-color-error)}.praxis-icon-btn{width:var(--p-actions-btn-size, 40px);height:var(--p-actions-btn-size, 40px);border:0;background:transparent;padding:0;display:inline-flex;align-items:center;justify-content:center;border-radius:9999px;cursor:pointer;--mat-icon-button-state-layer-size: var(--p-actions-btn-size, 40px)}.praxis-icon-btn:hover{background:var(--md-sys-color-surface-variant)}.praxis-icon-btn:focus-visible{outline:2px solid var(--md-sys-color-primary);outline-offset:2px}.praxis-icon-btn mat-icon,.praxis-icon-btn .mat-icon{font-size:var(--p-actions-icon-size, 22px);width:var(--p-actions-icon-size, 22px);height:var(--p-actions-icon-size, 22px);line-height:var(--p-actions-icon-size, 22px)}.praxis-icon-btn--workflow{background:color-mix(in srgb,var(--md-sys-color-secondary-container) 36%,transparent)}.praxis-icon-btn--blocked{background:color-mix(in srgb,var(--md-sys-color-error-container) 42%,transparent)}.praxis-more-btn{width:var(--p-actions-more-btn-size, var(--p-actions-btn-size, 40px));height:var(--p-actions-more-btn-size, var(--p-actions-btn-size, 40px));--mat-icon-button-state-layer-size: var(--p-actions-more-btn-size, var(--p-actions-btn-size, 40px));background-image:var(--p-actions-more-btn-gradient, none);background-size:100% 100%;background-repeat:no-repeat}.praxis-more-btn mat-icon,.praxis-more-btn .mat-icon{font-size:var(--p-actions-more-icon-size, var(--p-actions-icon-size, 22px));width:var(--p-actions-more-icon-size, var(--p-actions-icon-size, 22px));height:var(--p-actions-more-icon-size, var(--p-actions-icon-size, 22px));line-height:var(--p-actions-more-icon-size, var(--p-actions-icon-size, 22px));color:var(--p-actions-more-icon-color);background-image:var(--p-actions-more-icon-gradient, none);-webkit-background-clip:text;background-clip:text}.praxis-row-btn--workflow{box-shadow:inset 0 0 0 1px color-mix(in srgb,var(--md-sys-color-secondary) 28%,transparent)}.praxis-row-btn--blocked{box-shadow:inset 0 0 0 1px color-mix(in srgb,var(--md-sys-color-error) 28%,transparent)}.praxis-icon-btn.destructive mat-icon{color:var(--md-sys-color-error)}.mat-mdc-tooltip.praxis-tooltip{margin-top:-8px;margin-bottom:8px}.spacer{flex:1 1 auto}.praxis-table-header{display:flex;flex-wrap:wrap;align-items:flex-start;gap:6px;margin:10px 0 8px;width:100%;clear:both;position:relative}.praxis-table-header.stacked{margin:0}.praxis-table-header>praxis-table-toolbar{flex:1 0 100%}.praxis-floating-bulk-actions{position:fixed;z-index:var(--praxis-layer-floating-local, 200);display:inline-flex;align-items:center;gap:8px;padding:8px;border-radius:999px;background:var(--md-sys-color-surface-container-highest);box-shadow:0 8px 20px #00000029}.praxis-floating-bulk-actions.pos-bottom-right{right:20px;bottom:20px}.praxis-floating-bulk-actions.pos-bottom-left{left:20px;bottom:20px}.praxis-floating-bulk-actions.pos-top-right{right:20px;top:20px}.praxis-floating-bulk-actions.pos-top-left{left:20px;top:20px}@media(max-width:768px){.praxis-floating-bulk-actions{gap:6px;padding:6px}.praxis-floating-bulk-actions.pos-bottom-right{right:12px;left:auto;bottom:12px}.praxis-floating-bulk-actions.pos-bottom-left{left:12px;right:auto;bottom:12px}.praxis-floating-bulk-actions.pos-top-right{right:12px;left:auto;top:12px}.praxis-floating-bulk-actions.pos-top-left{left:12px;right:auto;top:12px}}:host{display:block;width:100%;min-width:0;max-width:100%;--pfx-toolbar-pad-y: 6px;--pfx-toolbar-pad-x: 12px;--p-table-bg: var(--md-sys-color-surface-container-highest);--p-table-text-color: var(--md-sys-color-on-surface);--p-table-header-bg: var(--md-sys-color-surface-container-highest);--p-table-header-fg: var(--md-sys-color-on-surface);--p-table-border-color: var(--md-sys-color-outline-variant);--p-table-row-even-bg: var(--md-sys-color-surface-container);--p-table-row-hover-bg: var(--md-sys-color-surface-container-high);--p-table-row-selected-bg: var(--md-sys-color-primary-container);--p-table-badge-soft-primary-bg: var(--md-sys-color-primary-container);--p-table-badge-soft-primary-fg: var(--md-sys-color-on-primary-container);--p-table-badge-soft-accent-bg: var(--md-sys-color-secondary-container);--p-table-badge-soft-accent-fg: var(--md-sys-color-on-secondary-container);--p-table-badge-soft-warn-bg: var(--md-sys-color-error-container);--p-table-badge-soft-warn-fg: var(--md-sys-color-on-error-container);--p-table-state-success-bg: var(--md-sys-color-tertiary-container);--p-table-state-success-fg: var(--md-sys-color-on-tertiary-container);--p-table-state-warning-bg: var(--md-sys-color-secondary-container);--p-table-state-warning-fg: var(--md-sys-color-on-secondary-container);--p-table-state-danger-bg: var(--md-sys-color-error-container);--p-table-state-danger-fg: var(--md-sys-color-on-error-container);--p-table-state-highlight-bg: var(--md-sys-color-primary-container);--p-table-state-highlight-fg: var(--md-sys-color-on-primary-container);--p-table-drag-handle-size: 14px;--p-table-drag-handle-color: var(--md-sys-color-on-surface-variant);--p-table-drag-handle-hover-color: var(--md-sys-color-on-surface);--p-table-drag-handle-base-opacity: 0;--p-table-drag-handle-visible-opacity: .72;--p-table-drag-handle-active-opacity: 1;--p-table-drag-handle-transition-duration: .16s;--p-table-reorder-transition-duration: .16s;--p-table-drag-preview-scale: 1.01;--p-table-drag-status-enter-duration: .18s;--p-table-drag-preview-shadow: 0 14px 32px rgba(0, 0, 0, .28), 0 0 0 1px var(--p-table-border-color)}:host ::ng-deep .mat-mdc-table{background:var(--p-table-bg);color:var(--p-table-text-color);border-radius:12px 12px 0 0;width:100%;box-shadow:var(--p-table-surface-shadow);transition:box-shadow var(--p-table-selection-transition-duration, .18s) var(--p-table-motion-easing, cubic-bezier(0, 0, .2, 1))}:host ::ng-deep .mat-mdc-table:hover{box-shadow:var(--p-table-surface-shadow-hover, var(--p-table-surface-shadow))}:host ::ng-deep .mat-mdc-table.table-stack-top{border-top-left-radius:0;border-top-right-radius:0}:host ::ng-deep .praxis-toolbar-footer{border:0 solid var(--p-table-border-color);border-top:0;border-radius:0;background:var(--p-table-bg)}:host ::ng-deep .mat-mdc-paginator.footer-stack{border-top-left-radius:0;border-top-right-radius:0;border-top:0}:host ::ng-deep .mat-mdc-paginator.footer-stack .mat-mdc-paginator-container{padding:6px 10px}:host ::ng-deep .mat-mdc-paginator{border-top:1px solid color-mix(in srgb,var(--p-table-border-color) 82%,transparent);background:color-mix(in srgb,var(--p-table-bg) 94%,white)}:host ::ng-deep .mat-mdc-paginator .mat-mdc-paginator-container{min-height:40px;padding:4px 8px;gap:6px}:host ::ng-deep .mat-mdc-paginator .mat-mdc-paginator-range-label,:host ::ng-deep .mat-mdc-paginator .mat-mdc-select-value-text{font-size:12px;color:color-mix(in srgb,var(--p-table-text-color) 76%,white)}:host [data-role=table-settings].mat-mdc-icon-button{--mdc-icon-button-icon-color: var(--md-sys-color-primary);color:var(--md-sys-color-primary)}.pfx-link{color:var(--md-sys-color-primary);text-decoration:underline;cursor:pointer}.pfx-chip{display:inline-flex;align-items:center;gap:4px;padding:2px 8px;border-radius:10px;font-size:12px;line-height:1;border:1px solid transparent}.pfx-chip-icon{font-size:14px;width:14px;height:14px}.pfx-chip--outlined{background:transparent;border-color:var(--md-sys-color-outline-variant);color:var(--md-sys-color-on-surface)}.pfx-chip--filled-primary{background:var(--md-sys-color-primary);color:var(--md-sys-color-on-primary)}.pfx-chip--filled-accent{background:var(--md-sys-color-secondary);color:var(--md-sys-color-on-secondary)}.pfx-chip--filled-warn{background:var(--md-sys-color-error);color:var(--md-sys-color-on-error)}.pfx-chip--soft-primary{background:var(--p-table-badge-soft-primary-bg);color:var(--p-table-badge-soft-primary-fg)}.pfx-chip--soft-accent{background:var(--p-table-badge-soft-accent-bg);color:var(--p-table-badge-soft-accent-fg)}.pfx-chip--soft-warn{background:var(--p-table-badge-soft-warn-bg);color:var(--p-table-badge-soft-warn-fg)}.pfx-progress{position:relative;width:100%;max-width:140px;height:8px;background:var(--md-sys-color-surface-container-highest);border-radius:4px;overflow:hidden;display:inline-block;vertical-align:middle}.pfx-progress-bar{height:100%;background:var(--md-sys-color-primary);transition:width .2s ease}.pfx-progress-label{margin-left:8px;font-size:12px;opacity:.8;display:inline-block;vertical-align:middle}.pfx-avatar{display:inline-flex;align-items:center;justify-content:center;background:var(--md-sys-color-surface-container);color:var(--md-sys-color-on-surface);border-radius:4px;overflow:hidden;font-weight:600}.pfx-avatar.shape-rounded{border-radius:8px}.pfx-avatar.shape-circle{border-radius:999px}.pfx-avatar--initials{text-transform:uppercase;font-size:12px}.pfx-cell-compose{display:inline-flex;align-items:center;gap:6px}.pfx-cell-compose.dir-col{flex-direction:column;align-items:stretch}.pfx-cell-compose.align-start{justify-content:flex-start}.pfx-cell-compose.align-center{justify-content:center}.pfx-cell-compose.align-end{justify-content:flex-end}.pfx-cell-compose.wrap{flex-wrap:wrap}.pfx-cell-compose.ellipsis{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.px-scroll-viewport{width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch;overscroll-behavior-x:contain}.px-scroll-viewport.scroll-none{overflow-x:visible}.px-scroll-viewport.scroll-auto ::ng-deep .mat-mdc-table{width:max-content;min-width:100%}.px-scroll-viewport.scroll-wrap ::ng-deep .mat-mdc-header-cell,.px-scroll-viewport.scroll-wrap ::ng-deep .mat-mdc-cell{white-space:normal;text-overflow:initial}.px-scroll-viewport.scroll-wrap ::ng-deep .mat-mdc-table{width:100%}:host ::ng-deep .mat-mdc-header-row{position:sticky;top:0;z-index:var(--praxis-layer-sticky-local, 100);background:var(--p-table-header-bg);color:var(--p-table-header-fg);box-shadow:var(--p-table-header-shadow, 0 1px 0 var(--p-table-border-color));border-bottom:1px solid var(--p-table-border-color)}:host ::ng-deep .mat-mdc-header-cell,:host ::ng-deep .mat-sort-header-content,:host ::ng-deep .mat-mdc-header-row .mat-icon{color:var(--p-table-header-fg)!important;font-weight:600}:host ::ng-deep .mat-mdc-header-cell.mat-sort-header-sorted .mat-sort-header-arrow,:host ::ng-deep .mat-mdc-header-cell:hover .mat-sort-header-arrow{color:var(--p-table-header-fg)!important}:host ::ng-deep .mat-mdc-header-cell.mat-sort-header-sorted .mat-sort-header-arrow .mat-sort-header-indicator,:host ::ng-deep .mat-mdc-header-cell.mat-sort-header-sorted .mat-sort-header-arrow .mat-sort-header-stem,:host ::ng-deep .mat-mdc-header-cell.mat-sort-header-sorted .mat-sort-header-arrow .mat-sort-header-pointer,:host ::ng-deep .mat-mdc-header-cell.mat-sort-header-sorted .mat-sort-header-arrow .mat-sort-header-pointer-left,:host ::ng-deep .mat-mdc-header-cell.mat-sort-header-sorted .mat-sort-header-arrow .mat-sort-header-pointer-right{border-color:var(--p-table-header-fg)!important;background:var(--p-table-header-fg)!important}:host ::ng-deep .mat-mdc-header-cell{padding:var(--p-header-padding, 12px 16px)!important;font-size:var(--p-header-font-size, inherit);font-weight:var(--p-header-font-weight, 600);letter-spacing:var(--p-header-letter-spacing, normal);text-transform:var(--p-header-text-transform, none);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}:host ::ng-deep .pfx-column-drag-enabled .mat-mdc-header-cell.praxis-header-draggable .mat-sort-header-container{display:flex;align-items:center;width:100%;gap:4px;cursor:inherit}:host ::ng-deep .pfx-column-drag-enabled .mat-mdc-header-cell.praxis-header-draggable{-webkit-user-select:none;user-select:none;cursor:grab;padding-left:0!important}:host ::ng-deep .pfx-column-drag-enabled .mat-mdc-header-cell.praxis-header-draggable.cdk-drag-dragging{cursor:grabbing}:host ::ng-deep .pfx-column-drag-enabled .mat-mdc-header-cell.praxis-header-draggable .mat-sort-header-content{display:inline-flex;align-items:center;gap:4px;flex:1 1 auto;min-width:0}:host ::ng-deep .pfx-column-drag-enabled .mat-mdc-header-cell .praxis-header-label{display:inline-flex;align-items:center;gap:4px;flex:1 1 auto;min-width:0}:host ::ng-deep .pfx-column-drag-enabled .mat-mdc-header-cell .praxis-header-label-text{flex:1 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}:host ::ng-deep .pfx-column-drag-enabled .mat-mdc-header-cell .praxis-column-drag-handle{-webkit-appearance:none;appearance:none;border:0;background:transparent;color:var(--p-table-drag-handle-color);width:var(--p-table-drag-handle-size);min-width:var(--p-table-drag-handle-size);flex:0 0 var(--p-table-drag-handle-size);height:var(--p-table-drag-handle-size);padding:0;display:inline-flex;align-items:center;justify-content:center;border-radius:0;cursor:inherit;pointer-events:none;touch-action:none;opacity:var(--p-table-drag-handle-base-opacity, .42);transform:none;order:-1;margin-inline-end:0;transition:opacity var(--p-table-drag-handle-transition-duration, .16s) var(--p-table-motion-easing, cubic-bezier(0, 0, .2, 1)),color var(--p-table-drag-handle-transition-duration, .16s) var(--p-table-motion-easing, cubic-bezier(0, 0, .2, 1))}:host ::ng-deep .pfx-column-drag-enabled .mat-mdc-header-cell.praxis-header-draggable:hover .praxis-column-drag-handle,:host ::ng-deep .pfx-column-drag-enabled .mat-mdc-header-cell.praxis-header-draggable:focus-within .praxis-column-drag-handle{opacity:var(--p-table-drag-handle-visible-opacity, .72);color:var(--p-table-drag-handle-hover-color, var(--p-table-drag-handle-color))}:host ::ng-deep .pfx-column-drag-enabled .mat-mdc-header-cell .praxis-column-drag-handle:active{opacity:var(--p-table-drag-handle-active-opacity, 1);cursor:grabbing}:host ::ng-deep .pfx-column-drag-enabled .mat-mdc-header-cell .praxis-column-drag-handle .mat-icon{font-size:14px;width:14px;height:14px;line-height:14px;transition:transform .18s var(--p-table-motion-easing, cubic-bezier(0, 0, .2, 1))}:host ::ng-deep .pfx-column-drag-enabled .mat-mdc-header-cell.praxis-header-draggable:hover .praxis-column-drag-handle .mat-icon{transform:none}:host ::ng-deep .pfx-column-drag-indicator .cdk-drop-list-dragging .mat-mdc-header-cell:not(.cdk-drag-placeholder){transition:transform var(--p-table-reorder-transition-duration, .18s) var(--p-table-motion-easing, cubic-bezier(0, 0, .2, 1))}:host ::ng-deep .pfx-column-drag-indicator .mat-mdc-header-cell.cdk-drag-animating{transition:transform var(--p-table-reorder-transition-duration, .16s) var(--p-table-motion-easing, cubic-bezier(0, 0, .2, 1))}.pfx-column-drag-preview{box-sizing:border-box;display:flex;align-items:center;border-radius:10px;border:1px solid var(--p-table-border-color);background:linear-gradient(135deg,var(--p-table-header-bg) 0%,var(--p-table-row-hover-bg) 100%);color:var(--p-table-header-fg);box-shadow:var(--p-table-drag-preview-shadow);transform:scale(var(--p-table-drag-preview-scale, 1.01));pointer-events:none;z-index:var(--praxis-layer-authoring-hover, 300)}.pfx-column-drag-preview .praxis-column-drag-handle,.pfx-column-drag-preview .mat-sort-header-arrow,.pfx-column-drag-preview .mat-sort-header-indicator,.pfx-column-drag-preview .mat-sort-header-stem,.pfx-column-drag-preview .mat-sort-header-pointer,.pfx-column-drag-preview .mat-sort-header-pointer-left,.pfx-column-drag-preview .mat-sort-header-pointer-right{display:none!important}.pfx-column-drag-preview .mat-sort-header-container{display:flex;align-items:center;width:100%;min-height:100%;padding-right:0!important}.pfx-column-drag-preview .mat-sort-header-content,.pfx-column-drag-preview .praxis-header-label{display:inline-flex;align-items:center;min-width:0;width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}:host ::ng-deep .pfx-column-drag-indicator .cdk-drag-placeholder{opacity:1;border:1px dashed var(--p-table-border-color);background:var(--p-table-row-hover-bg)}:host ::ng-deep .pfx-column-drag-indicator .cdk-drag-placeholder *{opacity:0}:host ::ng-deep .pfx-column-drag-indicator .mat-mdc-header-cell.cdk-drag-dragging{opacity:.58}@media(prefers-reduced-motion:reduce){:host ::ng-deep .pfx-column-drag-indicator .cdk-drop-list-dragging .mat-mdc-header-cell:not(.cdk-drag-placeholder){transition:none}:host ::ng-deep .pfx-column-drag-enabled .mat-mdc-header-cell .praxis-column-drag-handle,:host ::ng-deep .pfx-column-drag-enabled .mat-mdc-header-cell .praxis-column-drag-handle .mat-icon,.pfx-column-drag-preview{transition:none;transform:none}.praxis-column-reorder-status{animation:none}.pfx-expansion-detail-panel{animation:none!important;transition:none!important;transform:none!important}:host ::ng-deep .mat-mdc-row{transition:none}:host ::ng-deep .mat-mdc-table{transition:none}}.praxis-actions-header{text-align:right}.praxis-actions-header.align-start{text-align:left}.praxis-actions-header.align-center{text-align:center}.praxis-actions-header.align-end{text-align:right}.praxis-actions-header .praxis-actions-header__content{display:inline-flex;align-items:center;gap:var(--p-actions-header-gap, 6px);color:var(--p-actions-header-color, inherit)}.praxis-actions-header .praxis-actions-header__content .mat-icon{font-size:18px;width:18px;height:18px;line-height:18px}:host ::ng-deep .mat-mdc-header-cell .mat-sort-header-container{padding-right:20px}:host ::ng-deep .pfx-column-drag-enabled .mat-mdc-header-cell.praxis-header-draggable .mat-sort-header-container{padding-right:12px}@media(pointer:coarse){:host{--p-table-drag-handle-size: 18px;--p-table-drag-handle-base-opacity: .56;--p-table-drag-handle-visible-opacity: .92}}:host ::ng-deep .mat-mdc-cell{color:var(--p-table-text-color);font-size:var(--p-cell-font-size, inherit);line-height:1.25;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}:host ::ng-deep .mat-mdc-cell .pfx-cell-content,:host ::ng-deep .mat-cell .pfx-cell-content{display:inline-flex;align-items:center;gap:6px;width:100%;min-width:0;overflow:hidden}:host ::ng-deep .mat-mdc-row:hover{background:var(--p-table-row-hover-bg)}:host ::ng-deep .mat-mdc-row{transition:background-color var(--p-table-hover-transition-duration, .18s) var(--p-table-motion-easing, cubic-bezier(0, 0, .2, 1)),box-shadow var(--p-table-selection-transition-duration, .18s) var(--p-table-motion-easing, cubic-bezier(0, 0, .2, 1))}:host ::ng-deep .mat-mdc-row:nth-child(2n){background:var(--p-table-row-even-bg)}:host ::ng-deep .mat-mdc-row:nth-child(2n):hover{background:var(--p-table-row-hover-bg)}:host ::ng-deep .mat-mdc-row.pfx-row-selected,:host ::ng-deep .mat-mdc-row.pfx-row-selected:hover{background:var(--p-table-row-selected-bg)}:host.row-borders ::ng-deep .mat-mdc-row .mat-mdc-cell{border-bottom:1px solid var(--p-table-border-color)}:host.row-borders ::ng-deep .mat-mdc-header-row .mat-mdc-header-cell{border-bottom:none}:host.col-borders ::ng-deep .mat-mdc-header-row .mat-mdc-header-cell,:host.col-borders ::ng-deep .mat-mdc-row .mat-mdc-cell{border-right:1px solid var(--p-table-border-color)}:host.col-borders ::ng-deep .mat-mdc-header-row .mat-mdc-header-cell:last-child,:host.col-borders ::ng-deep .mat-mdc-row .mat-mdc-cell:last-child{border-right:none}.ptable-error{display:flex;align-items:center;gap:12px;padding:12px;margin:8px 0;border:1px solid var(--md-sys-color-error);border-radius:8px}.ptable-error__content{flex:1}.ptable-error__title{font-weight:600}.ptable-info-banner{display:flex;gap:12px;align-items:center;padding:8px 12px;margin:8px 0;border-radius:8px;border:1px solid var(--md-sys-color-primary);background:var(--md-sys-color-primary-container);color:var(--md-sys-color-on-primary-container)}.ptable-info-banner .text{flex:1;font-weight:600}.ptable-info-banner .actions{display:flex;gap:8px}.pfx-cell-image{display:inline-block;vertical-align:middle;background:var(--md-sys-color-surface-variant);border:1px solid var(--md-sys-color-outline-variant)}.pfx-cell-image.shape-rounded{border-radius:8px}.pfx-cell-image.shape-circle{border-radius:9999px}.pfx-badge{display:inline-flex;align-items:center;gap:6px;line-height:1;padding:4px 8px;border-radius:9999px;font-size:12px;font-weight:600;border:1px solid transparent}.pfx-badge .pfx-badge-icon{font-size:16px;width:16px;height:16px}.pfx-badge--filled-primary{background:var(--md-sys-color-primary);color:var(--md-sys-color-on-primary)}.pfx-badge--filled-accent{background:var(--md-sys-color-secondary);color:var(--md-sys-color-on-secondary)}.pfx-badge--filled-warn{background:var(--md-sys-color-error);color:var(--md-sys-color-on-error)}.pfx-badge--outlined{background:transparent;border-color:var(--md-sys-color-outline-variant);color:inherit}.pfx-badge--soft-primary{background:var(--p-table-badge-soft-primary-bg);color:var(--p-table-badge-soft-primary-fg)}.pfx-badge--soft-accent{background:var(--p-table-badge-soft-accent-bg);color:var(--p-table-badge-soft-accent-fg)}.pfx-badge--soft-warn{background:var(--p-table-badge-soft-warn-bg);color:var(--p-table-badge-soft-warn-fg)}.row--success,.row--success td,td.row--success{background-color:var(--p-table-state-success-bg)!important;color:var(--p-table-state-success-fg)!important}.row--warning,.row--warning td,td.row--warning{background-color:var(--p-table-state-warning-bg)!important;color:var(--p-table-state-warning-fg)!important}.row--danger,.row--danger td,td.row--danger{background-color:var(--p-table-state-danger-bg)!important;color:var(--p-table-state-danger-fg)!important}.row--highlight,.row--highlight td,td.row--highlight{background-color:var(--p-table-state-highlight-bg)!important;color:var(--p-table-state-highlight-fg)!important;font-weight:600}.row--muted,.row--muted td,td.row--muted{opacity:.7;filter:saturate(.6)}.pfx-expansion-node-embed{display:flex;flex-direction:column;gap:12px;padding:16px;border:1px solid var(--md-sys-color-outline-variant);border-radius:16px;background:var(--md-sys-color-surface-container-low, var(--md-sys-color-surface))}.ptable-loading-state{padding:8px 12px 4px;display:grid;gap:10px}.ptable-loading-state__hero{display:grid;gap:10px;padding:14px;border-radius:8px;border:1px solid rgba(18,99,180,.08);background:linear-gradient(180deg,#ffffffa6,#ffffff47),linear-gradient(0deg,#1263b408,#1263b400)}.ptable-loading-state__rows{display:grid;gap:8px}.ptable-loading-state__row{display:grid;grid-template-columns:96px minmax(0,1fr) minmax(140px,1.2fr);gap:8px}.ptable-loading-state__line,.ptable-loading-state__cell{display:block;height:12px;border-radius:999px;background:linear-gradient(90deg,#1263b414,#1263b42e,#1263b414);background-size:200% 100%;animation:ptable-loading-wave 1.2s ease-in-out infinite}.ptable-loading-state__line--wide{width:180px}.ptable-loading-state__line--short{width:96px}.ptable-loading-state__cell--short{width:100%;max-width:84px}.ptable-loading-state__cell--wide{width:100%}.ptable-loading-state__message{font-size:.85rem;color:var(--md-sys-color-on-surface-variant, #5a5d67);padding-inline:4px}.pfx-expansion-node-embed__header,.pfx-expansion-node-embed__meta,.pfx-expansion-node-embed__empty,.pfx-expansion-node-embed__diagram-label{display:block}.ptable-no-data-state{padding:8px 12px 4px}.ptable-no-data-state ::ng-deep .empty-card{margin:0;border-radius:8px}@keyframes ptable-loading-wave{0%{background-position:100% 0}to{background-position:-100% 0}}.pfx-expansion-node-embed__diagram{display:flex;flex-direction:column;gap:8px}.pfx-expansion-node-embed__diagram-source{margin:0;padding:12px;overflow:auto;border-radius:12px;border:1px solid var(--md-sys-color-outline-variant);background:var(--md-sys-color-surface-container-highest, var(--md-sys-color-surface));color:var(--md-sys-color-on-surface);font-family:Consolas,Courier New,monospace;font-size:12px;line-height:1.4;white-space:pre-wrap}.pfx-expansion-node-embed__action-btn{align-self:flex-start}.pfx-expansion-node-embed__action-host{display:inline-flex}\n"] }]
|
|
45476
47116
|
}], ctorParameters: () => [{ type: i0.ChangeDetectorRef }, { type: i3$1.SettingsPanelService }, { type: i1.GenericCrudService }, { type: TableDefaultsProvider }, { type: FilterConfigService }, { type: DataFormattingService }, { type: i6$3.PraxisDialog }, { type: i2$2.MatSnackBar }, { type: undefined, decorators: [{
|
|
45477
47117
|
type: Inject,
|
|
45478
47118
|
args: [ASYNC_CONFIG_STORAGE]
|
|
@@ -45909,6 +47549,1406 @@ function normalizeError(error) {
|
|
|
45909
47549
|
return 'Unknown analytics table contract error.';
|
|
45910
47550
|
}
|
|
45911
47551
|
|
|
47552
|
+
function isTableRendererSupportedByRichContentP0(renderer) {
|
|
47553
|
+
if (!renderer) {
|
|
47554
|
+
return false;
|
|
47555
|
+
}
|
|
47556
|
+
switch (renderer.type) {
|
|
47557
|
+
case 'icon':
|
|
47558
|
+
case 'image':
|
|
47559
|
+
case 'badge':
|
|
47560
|
+
case 'chip':
|
|
47561
|
+
case 'progress':
|
|
47562
|
+
case 'avatar':
|
|
47563
|
+
case 'compose':
|
|
47564
|
+
return true;
|
|
47565
|
+
default:
|
|
47566
|
+
return false;
|
|
47567
|
+
}
|
|
47568
|
+
}
|
|
47569
|
+
function mapTableRendererToRichContentP0(renderer) {
|
|
47570
|
+
if (!renderer) {
|
|
47571
|
+
return null;
|
|
47572
|
+
}
|
|
47573
|
+
switch (renderer.type) {
|
|
47574
|
+
case 'icon':
|
|
47575
|
+
return mapIconRenderer(renderer);
|
|
47576
|
+
case 'image':
|
|
47577
|
+
return mapImageRenderer(renderer);
|
|
47578
|
+
case 'badge':
|
|
47579
|
+
return mapBadgeRenderer(renderer);
|
|
47580
|
+
case 'chip':
|
|
47581
|
+
return mapChipRenderer(renderer);
|
|
47582
|
+
case 'progress':
|
|
47583
|
+
return mapProgressRenderer(renderer);
|
|
47584
|
+
case 'avatar':
|
|
47585
|
+
return mapAvatarRenderer(renderer);
|
|
47586
|
+
case 'compose':
|
|
47587
|
+
return mapComposeRenderer(renderer);
|
|
47588
|
+
default:
|
|
47589
|
+
return null;
|
|
47590
|
+
}
|
|
47591
|
+
}
|
|
47592
|
+
function mapIconRenderer(renderer) {
|
|
47593
|
+
return {
|
|
47594
|
+
type: 'icon',
|
|
47595
|
+
icon: renderer.icon?.name || renderer.icon?.nameField || '',
|
|
47596
|
+
};
|
|
47597
|
+
}
|
|
47598
|
+
function mapImageRenderer(renderer) {
|
|
47599
|
+
return {
|
|
47600
|
+
type: 'image',
|
|
47601
|
+
src: renderer.image?.src,
|
|
47602
|
+
srcExpr: asRowExpr(renderer.image?.srcField),
|
|
47603
|
+
alt: renderer.image?.alt,
|
|
47604
|
+
altExpr: asRowExpr(renderer.image?.altField),
|
|
47605
|
+
};
|
|
47606
|
+
}
|
|
47607
|
+
function mapBadgeRenderer(renderer) {
|
|
47608
|
+
return {
|
|
47609
|
+
type: 'badge',
|
|
47610
|
+
label: renderer.badge?.text,
|
|
47611
|
+
labelExpr: asRowExpr(renderer.badge?.textField),
|
|
47612
|
+
icon: renderer.badge?.icon,
|
|
47613
|
+
};
|
|
47614
|
+
}
|
|
47615
|
+
function mapChipRenderer(renderer) {
|
|
47616
|
+
return {
|
|
47617
|
+
type: 'badge',
|
|
47618
|
+
label: renderer.chip?.text,
|
|
47619
|
+
labelExpr: asRowExpr(renderer.chip?.textField),
|
|
47620
|
+
icon: renderer.chip?.icon,
|
|
47621
|
+
};
|
|
47622
|
+
}
|
|
47623
|
+
function mapProgressRenderer(renderer) {
|
|
47624
|
+
return {
|
|
47625
|
+
type: 'progress',
|
|
47626
|
+
valueExpr: renderer.progress?.valueExpr || '${row.value}',
|
|
47627
|
+
showPercent: renderer.progress?.showLabel,
|
|
47628
|
+
};
|
|
47629
|
+
}
|
|
47630
|
+
function mapAvatarRenderer(renderer) {
|
|
47631
|
+
return {
|
|
47632
|
+
type: 'avatar',
|
|
47633
|
+
imageSrc: renderer.avatar?.src,
|
|
47634
|
+
imageSrcExpr: asRowExpr(renderer.avatar?.srcField),
|
|
47635
|
+
nameExpr: asRowExpr(renderer.avatar?.altField),
|
|
47636
|
+
initialsExpr: renderer.avatar?.initialsExpr,
|
|
47637
|
+
};
|
|
47638
|
+
}
|
|
47639
|
+
function mapComposeRenderer(renderer) {
|
|
47640
|
+
const items = (renderer.compose?.items || [])
|
|
47641
|
+
.map(item => mapComposeItemToRichContent(item))
|
|
47642
|
+
.filter(isRichPresenterNode);
|
|
47643
|
+
return {
|
|
47644
|
+
type: 'compose',
|
|
47645
|
+
direction: renderer.compose?.layout?.direction || 'row',
|
|
47646
|
+
gap: normalizeGap(renderer.compose?.layout?.gap),
|
|
47647
|
+
wrap: renderer.compose?.layout?.wrap,
|
|
47648
|
+
items,
|
|
47649
|
+
};
|
|
47650
|
+
}
|
|
47651
|
+
function mapComposeItemToRichContent(item) {
|
|
47652
|
+
switch (item.type) {
|
|
47653
|
+
case 'icon':
|
|
47654
|
+
return mapTableRendererToRichContentP0({
|
|
47655
|
+
type: 'icon',
|
|
47656
|
+
icon: item.icon,
|
|
47657
|
+
});
|
|
47658
|
+
case 'image':
|
|
47659
|
+
return mapTableRendererToRichContentP0({
|
|
47660
|
+
type: 'image',
|
|
47661
|
+
image: item.image,
|
|
47662
|
+
});
|
|
47663
|
+
case 'badge':
|
|
47664
|
+
return mapTableRendererToRichContentP0({
|
|
47665
|
+
type: 'badge',
|
|
47666
|
+
badge: item.badge,
|
|
47667
|
+
});
|
|
47668
|
+
case 'chip':
|
|
47669
|
+
return mapTableRendererToRichContentP0({
|
|
47670
|
+
type: 'chip',
|
|
47671
|
+
chip: item.chip,
|
|
47672
|
+
});
|
|
47673
|
+
case 'progress':
|
|
47674
|
+
return mapTableRendererToRichContentP0({
|
|
47675
|
+
type: 'progress',
|
|
47676
|
+
progress: item.progress,
|
|
47677
|
+
});
|
|
47678
|
+
case 'avatar':
|
|
47679
|
+
return mapTableRendererToRichContentP0({
|
|
47680
|
+
type: 'avatar',
|
|
47681
|
+
avatar: item.avatar,
|
|
47682
|
+
});
|
|
47683
|
+
default:
|
|
47684
|
+
return null;
|
|
47685
|
+
}
|
|
47686
|
+
}
|
|
47687
|
+
function isRichPresenterNode(node) {
|
|
47688
|
+
return !!node && node.type !== 'compose';
|
|
47689
|
+
}
|
|
47690
|
+
function asRowExpr(field) {
|
|
47691
|
+
return field ? `\${row.${field}}` : undefined;
|
|
47692
|
+
}
|
|
47693
|
+
function normalizeGap(gap) {
|
|
47694
|
+
switch (gap) {
|
|
47695
|
+
case 4:
|
|
47696
|
+
return 'xs';
|
|
47697
|
+
case 8:
|
|
47698
|
+
return 'sm';
|
|
47699
|
+
case 16:
|
|
47700
|
+
return 'lg';
|
|
47701
|
+
case 20:
|
|
47702
|
+
return 'xl';
|
|
47703
|
+
default:
|
|
47704
|
+
return gap == null ? undefined : 'md';
|
|
47705
|
+
}
|
|
47706
|
+
}
|
|
47707
|
+
|
|
47708
|
+
class PraxisTableInlineAuthoringEditorComponent {
|
|
47709
|
+
i18n;
|
|
47710
|
+
config = { columns: [] };
|
|
47711
|
+
readonly = false;
|
|
47712
|
+
configChange = new EventEmitter();
|
|
47713
|
+
workingConfig = { columns: [] };
|
|
47714
|
+
toolbarTitle = '';
|
|
47715
|
+
toolbarSubtitle = '';
|
|
47716
|
+
toolbarVisible = true;
|
|
47717
|
+
density = 'comfortable';
|
|
47718
|
+
toolbarActionsPosition = 'top';
|
|
47719
|
+
toolbarHeight = 64;
|
|
47720
|
+
toolbarActionsBackgroundColor = '';
|
|
47721
|
+
paginationEnabled = true;
|
|
47722
|
+
pageSize = 10;
|
|
47723
|
+
pageSizeOptionsText = '5, 10, 25, 50';
|
|
47724
|
+
showFirstLastButtons = true;
|
|
47725
|
+
paginationStrategy = 'client';
|
|
47726
|
+
paginationPosition = 'bottom';
|
|
47727
|
+
paginationStyle = 'default';
|
|
47728
|
+
sortingEnabled = true;
|
|
47729
|
+
sortingStrategy = 'client';
|
|
47730
|
+
allowClearSort = true;
|
|
47731
|
+
defaultSortField = '';
|
|
47732
|
+
defaultSortDirection = 'asc';
|
|
47733
|
+
loadingMessage = '';
|
|
47734
|
+
emptyMessage = '';
|
|
47735
|
+
noResultsMessage = '';
|
|
47736
|
+
errorMessage = '';
|
|
47737
|
+
loadingMoreMessage = '';
|
|
47738
|
+
lastInputSignature = '';
|
|
47739
|
+
constructor(i18n) {
|
|
47740
|
+
this.i18n = i18n;
|
|
47741
|
+
}
|
|
47742
|
+
ngOnChanges() {
|
|
47743
|
+
const signature = JSON.stringify(this.config || { columns: [] });
|
|
47744
|
+
if (signature === this.lastInputSignature) {
|
|
47745
|
+
return;
|
|
47746
|
+
}
|
|
47747
|
+
this.lastInputSignature = signature;
|
|
47748
|
+
this.workingConfig = cloneTableConfig(this.config);
|
|
47749
|
+
this.toolbarTitle = this.workingConfig.toolbar?.title || '';
|
|
47750
|
+
this.toolbarSubtitle = this.workingConfig.toolbar?.subtitle || '';
|
|
47751
|
+
this.toolbarVisible = this.workingConfig.toolbar?.visible !== false;
|
|
47752
|
+
this.density = this.workingConfig.appearance?.density || 'comfortable';
|
|
47753
|
+
this.toolbarActionsPosition =
|
|
47754
|
+
this.workingConfig.toolbar?.actionsPosition
|
|
47755
|
+
|| this.workingConfig.toolbar?.position
|
|
47756
|
+
|| 'top';
|
|
47757
|
+
this.toolbarHeight = this.workingConfig.toolbar?.layout?.height || 64;
|
|
47758
|
+
this.toolbarActionsBackgroundColor = this.workingConfig.toolbar?.actionsBackgroundColor || '';
|
|
47759
|
+
this.paginationEnabled = this.workingConfig.behavior?.pagination?.enabled !== false;
|
|
47760
|
+
this.pageSize = this.workingConfig.behavior?.pagination?.pageSize || 10;
|
|
47761
|
+
this.pageSizeOptionsText = this.arrayToString(this.workingConfig.behavior?.pagination?.pageSizeOptions || [5, 10, 25, 50]);
|
|
47762
|
+
this.showFirstLastButtons =
|
|
47763
|
+
this.workingConfig.behavior?.pagination?.showFirstLastButtons !== false;
|
|
47764
|
+
this.paginationStrategy = this.workingConfig.behavior?.pagination?.strategy || 'client';
|
|
47765
|
+
this.paginationPosition = this.workingConfig.behavior?.pagination?.position || 'bottom';
|
|
47766
|
+
this.paginationStyle = this.workingConfig.behavior?.pagination?.style || 'default';
|
|
47767
|
+
this.sortingEnabled = this.workingConfig.behavior?.sorting?.enabled !== false;
|
|
47768
|
+
this.sortingStrategy = this.workingConfig.behavior?.sorting?.strategy || 'client';
|
|
47769
|
+
this.allowClearSort = this.workingConfig.behavior?.sorting?.allowClearSort !== false;
|
|
47770
|
+
this.defaultSortField = this.getDefaultSortField(this.workingConfig);
|
|
47771
|
+
this.defaultSortDirection = this.getDefaultSortDirection(this.workingConfig);
|
|
47772
|
+
this.loadingMessage =
|
|
47773
|
+
this.workingConfig.messages?.states?.loading
|
|
47774
|
+
|| this.tx('messages.loading.placeholder', 'Loading...');
|
|
47775
|
+
this.emptyMessage =
|
|
47776
|
+
this.workingConfig.messages?.states?.empty
|
|
47777
|
+
|| this.tx('messages.empty.placeholder', 'No data available');
|
|
47778
|
+
this.noResultsMessage =
|
|
47779
|
+
this.workingConfig.messages?.states?.noResults
|
|
47780
|
+
|| this.tx('messages.noResults.placeholder', 'No results found');
|
|
47781
|
+
this.errorMessage =
|
|
47782
|
+
this.workingConfig.messages?.states?.error
|
|
47783
|
+
|| this.tx('messages.error.placeholder', 'Error loading data');
|
|
47784
|
+
this.loadingMoreMessage =
|
|
47785
|
+
this.workingConfig.messages?.states?.loadingMore
|
|
47786
|
+
|| this.tx('messages.loadingMore.placeholder', 'Loading more data...');
|
|
47787
|
+
}
|
|
47788
|
+
setToolbarTitle(value) {
|
|
47789
|
+
this.toolbarTitle = value || '';
|
|
47790
|
+
this.patchToolbar({ title: this.toolbarTitle || undefined });
|
|
47791
|
+
}
|
|
47792
|
+
setToolbarSubtitle(value) {
|
|
47793
|
+
this.toolbarSubtitle = value || '';
|
|
47794
|
+
this.patchToolbar({ subtitle: this.toolbarSubtitle || undefined });
|
|
47795
|
+
}
|
|
47796
|
+
setToolbarVisible(value) {
|
|
47797
|
+
this.toolbarVisible = !!value;
|
|
47798
|
+
this.patchToolbar({ visible: this.toolbarVisible });
|
|
47799
|
+
}
|
|
47800
|
+
setDensity(value) {
|
|
47801
|
+
this.density = value || 'comfortable';
|
|
47802
|
+
this.workingConfig = {
|
|
47803
|
+
...this.workingConfig,
|
|
47804
|
+
appearance: {
|
|
47805
|
+
...(this.workingConfig.appearance || {}),
|
|
47806
|
+
density: this.density,
|
|
47807
|
+
},
|
|
47808
|
+
};
|
|
47809
|
+
this.emitConfig();
|
|
47810
|
+
}
|
|
47811
|
+
setToolbarActionsPosition(value) {
|
|
47812
|
+
this.toolbarActionsPosition = value || 'top';
|
|
47813
|
+
this.patchToolbar({
|
|
47814
|
+
actionsPosition: this.toolbarActionsPosition,
|
|
47815
|
+
position: this.toolbarActionsPosition,
|
|
47816
|
+
});
|
|
47817
|
+
}
|
|
47818
|
+
setToolbarHeight(value) {
|
|
47819
|
+
const nextHeight = clampNumber(value, 40, 120, 64);
|
|
47820
|
+
this.toolbarHeight = nextHeight;
|
|
47821
|
+
this.patchToolbar({
|
|
47822
|
+
layout: {
|
|
47823
|
+
alignment: this.workingConfig.toolbar?.layout?.alignment || 'space-between',
|
|
47824
|
+
showSeparator: this.workingConfig.toolbar?.layout?.showSeparator ?? false,
|
|
47825
|
+
...(this.workingConfig.toolbar?.layout || {}),
|
|
47826
|
+
height: nextHeight,
|
|
47827
|
+
},
|
|
47828
|
+
});
|
|
47829
|
+
}
|
|
47830
|
+
setToolbarActionsBackgroundColor(value) {
|
|
47831
|
+
this.toolbarActionsBackgroundColor = value || '';
|
|
47832
|
+
this.patchToolbar({
|
|
47833
|
+
actionsBackgroundColor: this.toolbarActionsBackgroundColor || undefined,
|
|
47834
|
+
});
|
|
47835
|
+
}
|
|
47836
|
+
setPaginationEnabled(value) {
|
|
47837
|
+
this.paginationEnabled = !!value;
|
|
47838
|
+
this.patchPagination();
|
|
47839
|
+
}
|
|
47840
|
+
setPaginationPageSize(value) {
|
|
47841
|
+
this.pageSize = clampNumber(value, 1, 500, 10);
|
|
47842
|
+
this.patchPagination();
|
|
47843
|
+
}
|
|
47844
|
+
setPaginationPageSizeOptions(value) {
|
|
47845
|
+
this.pageSizeOptionsText = value || '';
|
|
47846
|
+
this.patchPagination();
|
|
47847
|
+
}
|
|
47848
|
+
setPaginationShowFirstLastButtons(value) {
|
|
47849
|
+
this.showFirstLastButtons = !!value;
|
|
47850
|
+
this.patchPagination();
|
|
47851
|
+
}
|
|
47852
|
+
setPaginationStrategy(value) {
|
|
47853
|
+
this.paginationStrategy = value || 'client';
|
|
47854
|
+
this.patchPagination();
|
|
47855
|
+
}
|
|
47856
|
+
setPaginationPosition(value) {
|
|
47857
|
+
this.paginationPosition = value || 'bottom';
|
|
47858
|
+
this.patchPagination();
|
|
47859
|
+
}
|
|
47860
|
+
setPaginationStyle(value) {
|
|
47861
|
+
this.paginationStyle = value || 'default';
|
|
47862
|
+
this.patchPagination();
|
|
47863
|
+
}
|
|
47864
|
+
setSortingEnabled(value) {
|
|
47865
|
+
this.sortingEnabled = !!value;
|
|
47866
|
+
this.patchSorting();
|
|
47867
|
+
}
|
|
47868
|
+
setSortingStrategy(value) {
|
|
47869
|
+
this.sortingStrategy = value || 'client';
|
|
47870
|
+
this.patchSorting();
|
|
47871
|
+
}
|
|
47872
|
+
setSortingAllowClear(value) {
|
|
47873
|
+
this.allowClearSort = !!value;
|
|
47874
|
+
this.patchSorting();
|
|
47875
|
+
}
|
|
47876
|
+
setSortingDefaultField(value) {
|
|
47877
|
+
this.defaultSortField = value || '';
|
|
47878
|
+
this.patchSorting();
|
|
47879
|
+
}
|
|
47880
|
+
setSortingDefaultDirection(value) {
|
|
47881
|
+
this.defaultSortDirection = value || 'asc';
|
|
47882
|
+
this.patchSorting();
|
|
47883
|
+
}
|
|
47884
|
+
setStateMessage(key, value) {
|
|
47885
|
+
const nextValue = value || '';
|
|
47886
|
+
if (key === 'loading') {
|
|
47887
|
+
this.loadingMessage = nextValue;
|
|
47888
|
+
}
|
|
47889
|
+
else if (key === 'empty') {
|
|
47890
|
+
this.emptyMessage = nextValue;
|
|
47891
|
+
}
|
|
47892
|
+
else if (key === 'noResults') {
|
|
47893
|
+
this.noResultsMessage = nextValue;
|
|
47894
|
+
}
|
|
47895
|
+
else {
|
|
47896
|
+
this.errorMessage = nextValue;
|
|
47897
|
+
}
|
|
47898
|
+
this.patchMessages({
|
|
47899
|
+
states: {
|
|
47900
|
+
...(this.workingConfig.messages?.states || {}),
|
|
47901
|
+
loading: this.loadingMessage,
|
|
47902
|
+
empty: this.emptyMessage,
|
|
47903
|
+
noResults: this.noResultsMessage,
|
|
47904
|
+
error: this.errorMessage,
|
|
47905
|
+
loadingMore: this.loadingMoreMessage,
|
|
47906
|
+
},
|
|
47907
|
+
});
|
|
47908
|
+
}
|
|
47909
|
+
onColumnsConfigChange(config) {
|
|
47910
|
+
this.workingConfig = cloneTableConfig(config);
|
|
47911
|
+
this.toolbarTitle = this.workingConfig.toolbar?.title || '';
|
|
47912
|
+
this.toolbarSubtitle = this.workingConfig.toolbar?.subtitle || '';
|
|
47913
|
+
this.toolbarVisible = this.workingConfig.toolbar?.visible !== false;
|
|
47914
|
+
this.density = this.workingConfig.appearance?.density || 'comfortable';
|
|
47915
|
+
this.toolbarActionsPosition =
|
|
47916
|
+
this.workingConfig.toolbar?.actionsPosition
|
|
47917
|
+
|| this.workingConfig.toolbar?.position
|
|
47918
|
+
|| 'top';
|
|
47919
|
+
this.toolbarHeight = this.workingConfig.toolbar?.layout?.height || 64;
|
|
47920
|
+
this.toolbarActionsBackgroundColor = this.workingConfig.toolbar?.actionsBackgroundColor || '';
|
|
47921
|
+
this.paginationEnabled = this.workingConfig.behavior?.pagination?.enabled !== false;
|
|
47922
|
+
this.pageSize = this.workingConfig.behavior?.pagination?.pageSize || 10;
|
|
47923
|
+
this.pageSizeOptionsText = this.arrayToString(this.workingConfig.behavior?.pagination?.pageSizeOptions || [5, 10, 25, 50]);
|
|
47924
|
+
this.showFirstLastButtons =
|
|
47925
|
+
this.workingConfig.behavior?.pagination?.showFirstLastButtons !== false;
|
|
47926
|
+
this.paginationStrategy = this.workingConfig.behavior?.pagination?.strategy || 'client';
|
|
47927
|
+
this.paginationPosition = this.workingConfig.behavior?.pagination?.position || 'bottom';
|
|
47928
|
+
this.paginationStyle = this.workingConfig.behavior?.pagination?.style || 'default';
|
|
47929
|
+
this.sortingEnabled = this.workingConfig.behavior?.sorting?.enabled !== false;
|
|
47930
|
+
this.sortingStrategy = this.workingConfig.behavior?.sorting?.strategy || 'client';
|
|
47931
|
+
this.allowClearSort = this.workingConfig.behavior?.sorting?.allowClearSort !== false;
|
|
47932
|
+
this.defaultSortField = this.getDefaultSortField(this.workingConfig);
|
|
47933
|
+
this.defaultSortDirection = this.getDefaultSortDirection(this.workingConfig);
|
|
47934
|
+
this.loadingMessage =
|
|
47935
|
+
this.workingConfig.messages?.states?.loading
|
|
47936
|
+
|| this.tx('messages.loading.placeholder', 'Loading...');
|
|
47937
|
+
this.emptyMessage =
|
|
47938
|
+
this.workingConfig.messages?.states?.empty
|
|
47939
|
+
|| this.tx('messages.empty.placeholder', 'No data available');
|
|
47940
|
+
this.noResultsMessage =
|
|
47941
|
+
this.workingConfig.messages?.states?.noResults
|
|
47942
|
+
|| this.tx('messages.noResults.placeholder', 'No results found');
|
|
47943
|
+
this.errorMessage =
|
|
47944
|
+
this.workingConfig.messages?.states?.error
|
|
47945
|
+
|| this.tx('messages.error.placeholder', 'Error loading data');
|
|
47946
|
+
this.loadingMoreMessage =
|
|
47947
|
+
this.workingConfig.messages?.states?.loadingMore
|
|
47948
|
+
|| this.tx('messages.loadingMore.placeholder', 'Loading more data...');
|
|
47949
|
+
this.emitConfig();
|
|
47950
|
+
}
|
|
47951
|
+
columnCountLabel() {
|
|
47952
|
+
const count = this.workingConfig.columns?.length || 0;
|
|
47953
|
+
return this.tx('inlineAuthoring.columnCount', '{count} columns').replace('{count}', String(count));
|
|
47954
|
+
}
|
|
47955
|
+
toolbarSummary() {
|
|
47956
|
+
if (!this.toolbarVisible) {
|
|
47957
|
+
return this.tx('inlineAuthoring.summary.toolbarHidden', 'Hidden');
|
|
47958
|
+
}
|
|
47959
|
+
return this.toolbarTitle || this.tx('inlineAuthoring.summary.toolbarDefault', 'Visible without custom title');
|
|
47960
|
+
}
|
|
47961
|
+
densitySummary() {
|
|
47962
|
+
return {
|
|
47963
|
+
compact: this.tx('behavior.appearance.density.compact', 'Compact'),
|
|
47964
|
+
comfortable: this.tx('behavior.appearance.density.comfortable', 'Comfortable'),
|
|
47965
|
+
spacious: this.tx('behavior.appearance.density.spacious', 'Spacious'),
|
|
47966
|
+
}[this.density];
|
|
47967
|
+
}
|
|
47968
|
+
actionsPositionSummary() {
|
|
47969
|
+
return {
|
|
47970
|
+
top: this.tx('toolbar.actionsPosition.top', 'Above the table'),
|
|
47971
|
+
bottom: this.tx('toolbar.actionsPosition.bottom', 'Below the table'),
|
|
47972
|
+
both: this.tx('toolbar.actionsPosition.both', 'Top and bottom'),
|
|
47973
|
+
}[this.toolbarActionsPosition];
|
|
47974
|
+
}
|
|
47975
|
+
behaviorSummary() {
|
|
47976
|
+
const parts = [];
|
|
47977
|
+
if (this.paginationEnabled) {
|
|
47978
|
+
parts.push(`${this.tx('behavior.pagination.pageSize', 'Items per page')}: ${this.pageSize}`);
|
|
47979
|
+
}
|
|
47980
|
+
else {
|
|
47981
|
+
parts.push(this.tx('inlineAuthoring.summary.paginationOff', 'Pagination off'));
|
|
47982
|
+
}
|
|
47983
|
+
if (this.sortingEnabled) {
|
|
47984
|
+
parts.push(this.sortingStrategy === 'server'
|
|
47985
|
+
? this.tx('behavior.sorting.strategy.server', 'Server (remote sorting)')
|
|
47986
|
+
: this.tx('behavior.sorting.strategy.client', 'Client (local sorting)'));
|
|
47987
|
+
if (this.defaultSortField) {
|
|
47988
|
+
parts.push(`${this.defaultSortField} ${this.defaultSortDirection}`);
|
|
47989
|
+
}
|
|
47990
|
+
}
|
|
47991
|
+
else {
|
|
47992
|
+
parts.push(this.tx('inlineAuthoring.summary.sortingOff', 'Sorting off'));
|
|
47993
|
+
}
|
|
47994
|
+
return parts.join(' • ');
|
|
47995
|
+
}
|
|
47996
|
+
statesSummary() {
|
|
47997
|
+
const customized = [
|
|
47998
|
+
this.loadingMessage !== this.tx('messages.loading.placeholder', 'Loading...'),
|
|
47999
|
+
this.emptyMessage !== this.tx('messages.empty.placeholder', 'No data available'),
|
|
48000
|
+
this.noResultsMessage !== this.tx('messages.noResults.placeholder', 'No results found'),
|
|
48001
|
+
this.errorMessage !== this.tx('messages.error.placeholder', 'Error loading data'),
|
|
48002
|
+
].filter(Boolean).length;
|
|
48003
|
+
if (!customized) {
|
|
48004
|
+
return this.tx('inlineAuthoring.summary.statesDefault', 'Default copy');
|
|
48005
|
+
}
|
|
48006
|
+
return this.tx('inlineAuthoring.summary.statesCustom', '{count} customized states')
|
|
48007
|
+
.replace('{count}', String(customized));
|
|
48008
|
+
}
|
|
48009
|
+
columnsPreviewSummary() {
|
|
48010
|
+
const columns = this.workingConfig.columns || [];
|
|
48011
|
+
if (!columns.length) {
|
|
48012
|
+
return this.tx('inlineAuthoring.summary.columnsEmpty', 'No columns configured yet');
|
|
48013
|
+
}
|
|
48014
|
+
const preview = columns
|
|
48015
|
+
.slice(0, 3)
|
|
48016
|
+
.map((column) => column.header || column.field || '?')
|
|
48017
|
+
.join(', ');
|
|
48018
|
+
if (columns.length <= 3) {
|
|
48019
|
+
return preview;
|
|
48020
|
+
}
|
|
48021
|
+
return `${preview} +${columns.length - 3}`;
|
|
48022
|
+
}
|
|
48023
|
+
serializedConfig() {
|
|
48024
|
+
return JSON.stringify(this.workingConfig || { columns: [] }, null, 2);
|
|
48025
|
+
}
|
|
48026
|
+
tx(key, fallback) {
|
|
48027
|
+
return this.i18n.t(key, undefined, fallback, PRAXIS_TABLE_EDITOR_I18N_NAMESPACE);
|
|
48028
|
+
}
|
|
48029
|
+
emitConfig() {
|
|
48030
|
+
const next = cloneTableConfig(this.workingConfig);
|
|
48031
|
+
this.lastInputSignature = JSON.stringify(next);
|
|
48032
|
+
this.configChange.emit(next);
|
|
48033
|
+
}
|
|
48034
|
+
patchToolbar(patch) {
|
|
48035
|
+
this.workingConfig = {
|
|
48036
|
+
...this.workingConfig,
|
|
48037
|
+
toolbar: {
|
|
48038
|
+
visible: this.toolbarVisible,
|
|
48039
|
+
...(this.workingConfig.toolbar || {}),
|
|
48040
|
+
...patch,
|
|
48041
|
+
},
|
|
48042
|
+
};
|
|
48043
|
+
this.emitConfig();
|
|
48044
|
+
}
|
|
48045
|
+
patchBehavior(patch) {
|
|
48046
|
+
this.workingConfig = {
|
|
48047
|
+
...this.workingConfig,
|
|
48048
|
+
behavior: {
|
|
48049
|
+
...(this.workingConfig.behavior || {}),
|
|
48050
|
+
...patch,
|
|
48051
|
+
},
|
|
48052
|
+
};
|
|
48053
|
+
this.emitConfig();
|
|
48054
|
+
}
|
|
48055
|
+
patchPagination() {
|
|
48056
|
+
this.patchBehavior({
|
|
48057
|
+
pagination: {
|
|
48058
|
+
...(this.workingConfig.behavior?.pagination || {}),
|
|
48059
|
+
enabled: this.paginationEnabled,
|
|
48060
|
+
pageSize: this.pageSize,
|
|
48061
|
+
pageSizeOptions: this.parseNumberList(this.pageSizeOptionsText, [5, 10, 25, 50]),
|
|
48062
|
+
showFirstLastButtons: this.showFirstLastButtons,
|
|
48063
|
+
showPageNumbers: this.workingConfig.behavior?.pagination?.showPageNumbers ?? true,
|
|
48064
|
+
showPageInfo: this.workingConfig.behavior?.pagination?.showPageInfo ?? true,
|
|
48065
|
+
position: this.paginationPosition,
|
|
48066
|
+
style: this.paginationStyle,
|
|
48067
|
+
strategy: this.paginationStrategy,
|
|
48068
|
+
},
|
|
48069
|
+
});
|
|
48070
|
+
}
|
|
48071
|
+
patchSorting() {
|
|
48072
|
+
this.patchBehavior({
|
|
48073
|
+
sorting: {
|
|
48074
|
+
...(this.workingConfig.behavior?.sorting || {}),
|
|
48075
|
+
enabled: this.sortingEnabled,
|
|
48076
|
+
strategy: this.sortingStrategy,
|
|
48077
|
+
allowClearSort: this.allowClearSort,
|
|
48078
|
+
multiSort: this.workingConfig.behavior?.sorting?.multiSort ?? false,
|
|
48079
|
+
showSortIndicators: this.workingConfig.behavior?.sorting?.showSortIndicators ?? true,
|
|
48080
|
+
indicatorPosition: this.workingConfig.behavior?.sorting?.indicatorPosition || 'end',
|
|
48081
|
+
defaultSort: this.buildDefaultSort(),
|
|
48082
|
+
},
|
|
48083
|
+
});
|
|
48084
|
+
}
|
|
48085
|
+
patchMessages(patch) {
|
|
48086
|
+
this.workingConfig = {
|
|
48087
|
+
...this.workingConfig,
|
|
48088
|
+
messages: {
|
|
48089
|
+
...(this.workingConfig.messages || {}),
|
|
48090
|
+
...patch,
|
|
48091
|
+
},
|
|
48092
|
+
};
|
|
48093
|
+
this.emitConfig();
|
|
48094
|
+
}
|
|
48095
|
+
arrayToString(values) {
|
|
48096
|
+
return (values || []).join(', ');
|
|
48097
|
+
}
|
|
48098
|
+
parseNumberList(value, fallback) {
|
|
48099
|
+
const parsed = (value || '')
|
|
48100
|
+
.split(',')
|
|
48101
|
+
.map((item) => Number(item.trim()))
|
|
48102
|
+
.filter((item) => Number.isFinite(item) && item > 0);
|
|
48103
|
+
return parsed.length ? parsed : fallback;
|
|
48104
|
+
}
|
|
48105
|
+
buildDefaultSort() {
|
|
48106
|
+
if (!this.defaultSortField) {
|
|
48107
|
+
return undefined;
|
|
48108
|
+
}
|
|
48109
|
+
return {
|
|
48110
|
+
column: this.defaultSortField,
|
|
48111
|
+
direction: this.defaultSortDirection,
|
|
48112
|
+
};
|
|
48113
|
+
}
|
|
48114
|
+
getDefaultSortField(config) {
|
|
48115
|
+
const defaultSort = config.behavior?.sorting?.defaultSort;
|
|
48116
|
+
if (Array.isArray(defaultSort)) {
|
|
48117
|
+
return defaultSort[0]?.column || '';
|
|
48118
|
+
}
|
|
48119
|
+
return defaultSort?.column || '';
|
|
48120
|
+
}
|
|
48121
|
+
getDefaultSortDirection(config) {
|
|
48122
|
+
const defaultSort = config.behavior?.sorting?.defaultSort;
|
|
48123
|
+
const direction = Array.isArray(defaultSort)
|
|
48124
|
+
? defaultSort[0]?.direction
|
|
48125
|
+
: defaultSort?.direction;
|
|
48126
|
+
return direction === 'desc' ? 'desc' : 'asc';
|
|
48127
|
+
}
|
|
48128
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: PraxisTableInlineAuthoringEditorComponent, deps: [{ token: i1.PraxisI18nService }], target: i0.ɵɵFactoryTarget.Component });
|
|
48129
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.17", type: PraxisTableInlineAuthoringEditorComponent, isStandalone: true, selector: "praxis-table-inline-authoring-editor", inputs: { config: "config", readonly: "readonly" }, outputs: { configChange: "configChange" }, providers: [providePraxisI18nConfig(PRAXIS_TABLE_EDITOR_I18N_CONFIG)], usesOnChanges: true, ngImport: i0, template: `
|
|
48130
|
+
<section class="inline-authoring" data-testid="table-inline-authoring-editor">
|
|
48131
|
+
<header class="inline-authoring__header">
|
|
48132
|
+
<div>
|
|
48133
|
+
<h4>{{ tx('inlineAuthoring.title', 'Table structure') }}</h4>
|
|
48134
|
+
<p>{{ tx('inlineAuthoring.description', 'Edit the canonical TableConfig used by this CRUD surface.') }}</p>
|
|
48135
|
+
</div>
|
|
48136
|
+
<span class="inline-authoring__chip" data-testid="table-inline-editor-column-count">
|
|
48137
|
+
{{ columnCountLabel() }}
|
|
48138
|
+
</span>
|
|
48139
|
+
</header>
|
|
48140
|
+
|
|
48141
|
+
<mat-card class="inline-authoring__card">
|
|
48142
|
+
<section class="inline-authoring__summary" data-testid="table-inline-editor-summary">
|
|
48143
|
+
<div class="inline-authoring__summary-card">
|
|
48144
|
+
<span class="inline-authoring__summary-label">{{ tx('inlineAuthoring.summary.toolbar', 'Toolbar') }}</span>
|
|
48145
|
+
<strong data-testid="table-inline-editor-summary-toolbar">{{ toolbarSummary() }}</strong>
|
|
48146
|
+
</div>
|
|
48147
|
+
<div class="inline-authoring__summary-card">
|
|
48148
|
+
<span class="inline-authoring__summary-label">{{ tx('inlineAuthoring.summary.density', 'Density') }}</span>
|
|
48149
|
+
<strong data-testid="table-inline-editor-summary-density">{{ densitySummary() }}</strong>
|
|
48150
|
+
</div>
|
|
48151
|
+
<div class="inline-authoring__summary-card">
|
|
48152
|
+
<span class="inline-authoring__summary-label">{{ tx('inlineAuthoring.summary.actions', 'Actions') }}</span>
|
|
48153
|
+
<strong data-testid="table-inline-editor-summary-actions">{{ actionsPositionSummary() }}</strong>
|
|
48154
|
+
</div>
|
|
48155
|
+
<div class="inline-authoring__summary-card">
|
|
48156
|
+
<span class="inline-authoring__summary-label">{{ tx('inlineAuthoring.summary.behavior', 'List behavior') }}</span>
|
|
48157
|
+
<strong data-testid="table-inline-editor-summary-behavior">{{ behaviorSummary() }}</strong>
|
|
48158
|
+
</div>
|
|
48159
|
+
<div class="inline-authoring__summary-card">
|
|
48160
|
+
<span class="inline-authoring__summary-label">{{ tx('inlineAuthoring.summary.states', 'State messages') }}</span>
|
|
48161
|
+
<strong data-testid="table-inline-editor-summary-states">{{ statesSummary() }}</strong>
|
|
48162
|
+
</div>
|
|
48163
|
+
<div class="inline-authoring__summary-card inline-authoring__summary-card--wide">
|
|
48164
|
+
<span class="inline-authoring__summary-label">{{ tx('inlineAuthoring.summary.columns', 'Visible structure') }}</span>
|
|
48165
|
+
<strong data-testid="table-inline-editor-summary-columns">{{ columnsPreviewSummary() }}</strong>
|
|
48166
|
+
</div>
|
|
48167
|
+
</section>
|
|
48168
|
+
|
|
48169
|
+
<section class="inline-authoring__essentials">
|
|
48170
|
+
<div class="inline-authoring__section-copy">
|
|
48171
|
+
<h5>{{ tx('inlineAuthoring.essentialsTitle', 'Table essentials') }}</h5>
|
|
48172
|
+
<p>{{ tx('inlineAuthoring.essentialsDescription', 'Define the toolbar presence and the texts users see first.') }}</p>
|
|
48173
|
+
</div>
|
|
48174
|
+
|
|
48175
|
+
<div class="inline-authoring__grid">
|
|
48176
|
+
<mat-slide-toggle
|
|
48177
|
+
data-testid="table-inline-editor-toolbar-visible"
|
|
48178
|
+
[ngModel]="toolbarVisible"
|
|
48179
|
+
(ngModelChange)="setToolbarVisible($event)"
|
|
48180
|
+
[disabled]="readonly"
|
|
48181
|
+
>
|
|
48182
|
+
{{ tx('toolbar.visible', 'Show toolbar') }}
|
|
48183
|
+
</mat-slide-toggle>
|
|
48184
|
+
|
|
48185
|
+
<mat-form-field appearance="outline">
|
|
48186
|
+
<mat-label>{{ tx('toolbar.title.label', 'Toolbar title') }}</mat-label>
|
|
48187
|
+
<input
|
|
48188
|
+
matInput
|
|
48189
|
+
data-testid="table-inline-editor-toolbar-title"
|
|
48190
|
+
[ngModel]="toolbarTitle"
|
|
48191
|
+
(ngModelChange)="setToolbarTitle($event)"
|
|
48192
|
+
[disabled]="readonly"
|
|
48193
|
+
/>
|
|
48194
|
+
</mat-form-field>
|
|
48195
|
+
|
|
48196
|
+
<mat-form-field appearance="outline">
|
|
48197
|
+
<mat-label>{{ tx('toolbar.subtitle.label', 'Subtitle') }}</mat-label>
|
|
48198
|
+
<input
|
|
48199
|
+
matInput
|
|
48200
|
+
data-testid="table-inline-editor-toolbar-subtitle"
|
|
48201
|
+
[ngModel]="toolbarSubtitle"
|
|
48202
|
+
(ngModelChange)="setToolbarSubtitle($event)"
|
|
48203
|
+
[disabled]="readonly"
|
|
48204
|
+
/>
|
|
48205
|
+
</mat-form-field>
|
|
48206
|
+
|
|
48207
|
+
<mat-form-field appearance="outline">
|
|
48208
|
+
<mat-label>{{ tx('behavior.appearance.density', 'Density') }}</mat-label>
|
|
48209
|
+
<mat-select
|
|
48210
|
+
data-testid="table-inline-editor-density"
|
|
48211
|
+
[ngModel]="density"
|
|
48212
|
+
(ngModelChange)="setDensity($event)"
|
|
48213
|
+
[disabled]="readonly"
|
|
48214
|
+
>
|
|
48215
|
+
<mat-option value="compact">{{ tx('behavior.appearance.density.compact', 'Compact') }}</mat-option>
|
|
48216
|
+
<mat-option value="comfortable">{{ tx('behavior.appearance.density.comfortable', 'Comfortable') }}</mat-option>
|
|
48217
|
+
<mat-option value="spacious">{{ tx('behavior.appearance.density.spacious', 'Spacious') }}</mat-option>
|
|
48218
|
+
</mat-select>
|
|
48219
|
+
</mat-form-field>
|
|
48220
|
+
|
|
48221
|
+
<mat-form-field appearance="outline">
|
|
48222
|
+
<mat-label>{{ tx('toolbar.actionsPosition.label', 'Actions position') }}</mat-label>
|
|
48223
|
+
<mat-select
|
|
48224
|
+
data-testid="table-inline-editor-toolbar-actions-position"
|
|
48225
|
+
[ngModel]="toolbarActionsPosition"
|
|
48226
|
+
(ngModelChange)="setToolbarActionsPosition($event)"
|
|
48227
|
+
[disabled]="readonly"
|
|
48228
|
+
>
|
|
48229
|
+
<mat-option value="top">{{ tx('toolbar.actionsPosition.top', 'Above the table') }}</mat-option>
|
|
48230
|
+
<mat-option value="bottom">{{ tx('toolbar.actionsPosition.bottom', 'Below the table') }}</mat-option>
|
|
48231
|
+
<mat-option value="both">{{ tx('toolbar.actionsPosition.both', 'Top and bottom') }}</mat-option>
|
|
48232
|
+
</mat-select>
|
|
48233
|
+
</mat-form-field>
|
|
48234
|
+
|
|
48235
|
+
<mat-form-field appearance="outline">
|
|
48236
|
+
<mat-label>{{ tx('toolbar.height.label', 'Toolbar height (px)') }}</mat-label>
|
|
48237
|
+
<input
|
|
48238
|
+
matInput
|
|
48239
|
+
type="number"
|
|
48240
|
+
data-testid="table-inline-editor-toolbar-height"
|
|
48241
|
+
[ngModel]="toolbarHeight"
|
|
48242
|
+
(ngModelChange)="setToolbarHeight($event)"
|
|
48243
|
+
[disabled]="readonly"
|
|
48244
|
+
min="40"
|
|
48245
|
+
max="120"
|
|
48246
|
+
/>
|
|
48247
|
+
</mat-form-field>
|
|
48248
|
+
|
|
48249
|
+
<mat-form-field appearance="outline">
|
|
48250
|
+
<mat-label>{{ tx('toolbar.backgroundPreset.label', 'Actions background color') }}</mat-label>
|
|
48251
|
+
<mat-select
|
|
48252
|
+
data-testid="table-inline-editor-toolbar-background-preset"
|
|
48253
|
+
[ngModel]="toolbarActionsBackgroundColor"
|
|
48254
|
+
(ngModelChange)="setToolbarActionsBackgroundColor($event)"
|
|
48255
|
+
[disabled]="readonly"
|
|
48256
|
+
>
|
|
48257
|
+
<mat-option value="">{{ tx('toolbar.backgroundPreset.default', 'Theme default') }}</mat-option>
|
|
48258
|
+
<mat-option value="var(--p-table-header-bg)">{{ tx('toolbar.backgroundPreset.header', 'Table header') }}</mat-option>
|
|
48259
|
+
<mat-option value="var(--md-sys-color-surface)">{{ tx('toolbar.backgroundPreset.surface', 'Surface') }}</mat-option>
|
|
48260
|
+
<mat-option value="var(--md-sys-color-surface-container)">{{ tx('toolbar.backgroundPreset.surfaceContainer', 'Surface container') }}</mat-option>
|
|
48261
|
+
<mat-option value="var(--md-sys-color-surface-container-high)">{{ tx('toolbar.backgroundPreset.surfaceContainerHigh', 'Surface container high') }}</mat-option>
|
|
48262
|
+
<mat-option value="var(--md-sys-color-surface-container-highest)">{{ tx('toolbar.backgroundPreset.surfaceContainerHighest', 'Surface container highest') }}</mat-option>
|
|
48263
|
+
</mat-select>
|
|
48264
|
+
</mat-form-field>
|
|
48265
|
+
</div>
|
|
48266
|
+
</section>
|
|
48267
|
+
|
|
48268
|
+
<section class="inline-authoring__advanced" data-testid="table-inline-editor-advanced-intro">
|
|
48269
|
+
<div class="inline-authoring__section-copy">
|
|
48270
|
+
<h5>{{ tx('inlineAuthoring.advancedTitle', 'Advanced table details') }}</h5>
|
|
48271
|
+
<p>{{ tx('inlineAuthoring.advancedDescription', 'Open the next panels only when you need to tune list behavior, state copy, or visible columns.') }}</p>
|
|
48272
|
+
</div>
|
|
48273
|
+
|
|
48274
|
+
<section class="inline-authoring__advanced-summary">
|
|
48275
|
+
<div class="inline-authoring__advanced-card">
|
|
48276
|
+
<span class="inline-authoring__summary-label">{{ tx('inlineAuthoring.advanced.behavior', 'Behavior') }}</span>
|
|
48277
|
+
<strong data-testid="table-inline-editor-advanced-summary-behavior">{{ behaviorSummary() }}</strong>
|
|
48278
|
+
</div>
|
|
48279
|
+
<div class="inline-authoring__advanced-card">
|
|
48280
|
+
<span class="inline-authoring__summary-label">{{ tx('inlineAuthoring.advanced.states', 'State copy') }}</span>
|
|
48281
|
+
<strong data-testid="table-inline-editor-advanced-summary-states">{{ statesSummary() }}</strong>
|
|
48282
|
+
</div>
|
|
48283
|
+
<div class="inline-authoring__advanced-card">
|
|
48284
|
+
<span class="inline-authoring__summary-label">{{ tx('inlineAuthoring.advanced.columns', 'Columns') }}</span>
|
|
48285
|
+
<strong data-testid="table-inline-editor-advanced-summary-columns">{{ columnsPreviewSummary() }}</strong>
|
|
48286
|
+
</div>
|
|
48287
|
+
</section>
|
|
48288
|
+
</section>
|
|
48289
|
+
|
|
48290
|
+
@if (readonly) {
|
|
48291
|
+
<p class="inline-authoring__readonly" data-testid="table-inline-editor-readonly-hint">
|
|
48292
|
+
{{ tx('inlineAuthoring.readonlyHint', 'This authoring surface is read-only in the current context.') }}
|
|
48293
|
+
</p>
|
|
48294
|
+
<pre data-testid="table-inline-editor-json">{{ serializedConfig() }}</pre>
|
|
48295
|
+
} @else {
|
|
48296
|
+
<section class="inline-authoring__advanced-panels" data-testid="table-inline-editor-advanced-panels">
|
|
48297
|
+
<mat-expansion-panel class="inline-authoring__columns-panel" [expanded]="false" data-testid="table-inline-editor-behavior-panel">
|
|
48298
|
+
<mat-expansion-panel-header>
|
|
48299
|
+
<mat-panel-title>{{ tx('inlineAuthoring.behaviorTitle', 'List behavior') }}</mat-panel-title>
|
|
48300
|
+
<mat-panel-description>{{ behaviorSummary() }}</mat-panel-description>
|
|
48301
|
+
</mat-expansion-panel-header>
|
|
48302
|
+
<p class="inline-authoring__panel-description">
|
|
48303
|
+
{{ tx('inlineAuthoring.behaviorDescription', 'Control pagination and sorting with the same runtime-backed semantics used by the full table editor.') }}
|
|
48304
|
+
</p>
|
|
48305
|
+
<div class="inline-authoring__grid">
|
|
48306
|
+
<mat-slide-toggle
|
|
48307
|
+
data-testid="table-inline-editor-pagination-enabled"
|
|
48308
|
+
[ngModel]="paginationEnabled"
|
|
48309
|
+
(ngModelChange)="setPaginationEnabled($event)"
|
|
48310
|
+
[disabled]="readonly"
|
|
48311
|
+
>
|
|
48312
|
+
{{ tx('behavior.pagination.enabled', 'Enable pagination') }}
|
|
48313
|
+
</mat-slide-toggle>
|
|
48314
|
+
|
|
48315
|
+
<mat-form-field appearance="outline">
|
|
48316
|
+
<mat-label>{{ tx('behavior.pagination.pageSize', 'Items per page') }}</mat-label>
|
|
48317
|
+
<input
|
|
48318
|
+
matInput
|
|
48319
|
+
type="number"
|
|
48320
|
+
data-testid="table-inline-editor-pagination-page-size"
|
|
48321
|
+
[ngModel]="pageSize"
|
|
48322
|
+
(ngModelChange)="setPaginationPageSize($event)"
|
|
48323
|
+
[disabled]="readonly || !paginationEnabled"
|
|
48324
|
+
min="1"
|
|
48325
|
+
/>
|
|
48326
|
+
</mat-form-field>
|
|
48327
|
+
|
|
48328
|
+
<mat-form-field appearance="outline">
|
|
48329
|
+
<mat-label>{{ tx('behavior.pagination.pageSizeOptions', 'Page size options') }}</mat-label>
|
|
48330
|
+
<input
|
|
48331
|
+
matInput
|
|
48332
|
+
data-testid="table-inline-editor-pagination-page-size-options"
|
|
48333
|
+
[ngModel]="pageSizeOptionsText"
|
|
48334
|
+
(ngModelChange)="setPaginationPageSizeOptions($event)"
|
|
48335
|
+
[disabled]="readonly || !paginationEnabled"
|
|
48336
|
+
placeholder="5, 10, 25, 50"
|
|
48337
|
+
/>
|
|
48338
|
+
</mat-form-field>
|
|
48339
|
+
|
|
48340
|
+
<mat-slide-toggle
|
|
48341
|
+
data-testid="table-inline-editor-pagination-first-last"
|
|
48342
|
+
[ngModel]="showFirstLastButtons"
|
|
48343
|
+
(ngModelChange)="setPaginationShowFirstLastButtons($event)"
|
|
48344
|
+
[disabled]="readonly || !paginationEnabled"
|
|
48345
|
+
>
|
|
48346
|
+
{{ tx('behavior.pagination.firstLast', 'Show first/last page buttons') }}
|
|
48347
|
+
</mat-slide-toggle>
|
|
48348
|
+
|
|
48349
|
+
<mat-form-field appearance="outline">
|
|
48350
|
+
<mat-label>{{ tx('behavior.pagination.strategy', 'Pagination strategy') }}</mat-label>
|
|
48351
|
+
<mat-select
|
|
48352
|
+
data-testid="table-inline-editor-pagination-strategy"
|
|
48353
|
+
[ngModel]="paginationStrategy"
|
|
48354
|
+
(ngModelChange)="setPaginationStrategy($event)"
|
|
48355
|
+
[disabled]="readonly || !paginationEnabled"
|
|
48356
|
+
>
|
|
48357
|
+
<mat-option value="client">{{ tx('behavior.pagination.strategy.client', 'Client (local data)') }}</mat-option>
|
|
48358
|
+
<mat-option value="server">{{ tx('behavior.pagination.strategy.server', 'Server (remote pagination)') }}</mat-option>
|
|
48359
|
+
</mat-select>
|
|
48360
|
+
</mat-form-field>
|
|
48361
|
+
|
|
48362
|
+
<mat-form-field appearance="outline">
|
|
48363
|
+
<mat-label>{{ tx('behavior.pagination.position', 'Paginator position') }}</mat-label>
|
|
48364
|
+
<mat-select
|
|
48365
|
+
data-testid="table-inline-editor-pagination-position"
|
|
48366
|
+
[ngModel]="paginationPosition"
|
|
48367
|
+
(ngModelChange)="setPaginationPosition($event)"
|
|
48368
|
+
[disabled]="readonly || !paginationEnabled"
|
|
48369
|
+
>
|
|
48370
|
+
<mat-option value="top">{{ tx('behavior.pagination.position.top', 'Top') }}</mat-option>
|
|
48371
|
+
<mat-option value="bottom">{{ tx('behavior.pagination.position.bottom', 'Bottom') }}</mat-option>
|
|
48372
|
+
<mat-option value="both">{{ tx('behavior.pagination.position.both', 'Both') }}</mat-option>
|
|
48373
|
+
</mat-select>
|
|
48374
|
+
</mat-form-field>
|
|
48375
|
+
|
|
48376
|
+
<mat-form-field appearance="outline">
|
|
48377
|
+
<mat-label>{{ tx('behavior.pagination.style', 'Paginator style') }}</mat-label>
|
|
48378
|
+
<mat-select
|
|
48379
|
+
data-testid="table-inline-editor-pagination-style"
|
|
48380
|
+
[ngModel]="paginationStyle"
|
|
48381
|
+
(ngModelChange)="setPaginationStyle($event)"
|
|
48382
|
+
[disabled]="readonly || !paginationEnabled"
|
|
48383
|
+
>
|
|
48384
|
+
<mat-option value="default">{{ tx('behavior.pagination.style.default', 'Default') }}</mat-option>
|
|
48385
|
+
<mat-option value="simple">{{ tx('behavior.pagination.style.simple', 'Simple') }}</mat-option>
|
|
48386
|
+
<mat-option value="compact">{{ tx('behavior.pagination.style.compact', 'Compact') }}</mat-option>
|
|
48387
|
+
<mat-option value="advanced">{{ tx('behavior.pagination.style.advanced', 'Advanced') }}</mat-option>
|
|
48388
|
+
</mat-select>
|
|
48389
|
+
</mat-form-field>
|
|
48390
|
+
|
|
48391
|
+
<mat-slide-toggle
|
|
48392
|
+
data-testid="table-inline-editor-sorting-enabled"
|
|
48393
|
+
[ngModel]="sortingEnabled"
|
|
48394
|
+
(ngModelChange)="setSortingEnabled($event)"
|
|
48395
|
+
[disabled]="readonly"
|
|
48396
|
+
>
|
|
48397
|
+
{{ tx('behavior.sorting.enabled', 'Enable sorting') }}
|
|
48398
|
+
</mat-slide-toggle>
|
|
48399
|
+
|
|
48400
|
+
<mat-form-field appearance="outline">
|
|
48401
|
+
<mat-label>{{ tx('behavior.sorting.strategy', 'Sorting strategy') }}</mat-label>
|
|
48402
|
+
<mat-select
|
|
48403
|
+
data-testid="table-inline-editor-sorting-strategy"
|
|
48404
|
+
[ngModel]="sortingStrategy"
|
|
48405
|
+
(ngModelChange)="setSortingStrategy($event)"
|
|
48406
|
+
[disabled]="readonly || !sortingEnabled"
|
|
48407
|
+
>
|
|
48408
|
+
<mat-option value="client">{{ tx('behavior.sorting.strategy.client', 'Client (local sorting)') }}</mat-option>
|
|
48409
|
+
<mat-option value="server">{{ tx('behavior.sorting.strategy.server', 'Server (remote sorting)') }}</mat-option>
|
|
48410
|
+
</mat-select>
|
|
48411
|
+
</mat-form-field>
|
|
48412
|
+
|
|
48413
|
+
<mat-slide-toggle
|
|
48414
|
+
data-testid="table-inline-editor-sorting-allow-clear"
|
|
48415
|
+
[ngModel]="allowClearSort"
|
|
48416
|
+
(ngModelChange)="setSortingAllowClear($event)"
|
|
48417
|
+
[disabled]="readonly || !sortingEnabled"
|
|
48418
|
+
>
|
|
48419
|
+
{{ tx('behavior.sorting.allowClear', 'Allow clearing sort') }}
|
|
48420
|
+
</mat-slide-toggle>
|
|
48421
|
+
|
|
48422
|
+
<mat-form-field appearance="outline">
|
|
48423
|
+
<mat-label>{{ tx('behavior.sorting.defaultField', 'Initial sort - column') }}</mat-label>
|
|
48424
|
+
<mat-select
|
|
48425
|
+
data-testid="table-inline-editor-sorting-default-field"
|
|
48426
|
+
[ngModel]="defaultSortField"
|
|
48427
|
+
(ngModelChange)="setSortingDefaultField($event)"
|
|
48428
|
+
[disabled]="readonly || !sortingEnabled"
|
|
48429
|
+
>
|
|
48430
|
+
<mat-option value="">{{ tx('inlineAuthoring.noneOption', 'None') }}</mat-option>
|
|
48431
|
+
@for (column of workingConfig.columns || []; track column.field) {
|
|
48432
|
+
<mat-option [value]="column.field">{{ column.header || column.field }}</mat-option>
|
|
48433
|
+
}
|
|
48434
|
+
</mat-select>
|
|
48435
|
+
</mat-form-field>
|
|
48436
|
+
|
|
48437
|
+
<mat-form-field appearance="outline">
|
|
48438
|
+
<mat-label>{{ tx('behavior.sorting.direction', 'Direction') }}</mat-label>
|
|
48439
|
+
<mat-select
|
|
48440
|
+
data-testid="table-inline-editor-sorting-default-direction"
|
|
48441
|
+
[ngModel]="defaultSortDirection"
|
|
48442
|
+
(ngModelChange)="setSortingDefaultDirection($event)"
|
|
48443
|
+
[disabled]="readonly || !sortingEnabled || !defaultSortField"
|
|
48444
|
+
>
|
|
48445
|
+
<mat-option value="asc">{{ tx('behavior.sorting.direction.asc', 'Ascending') }}</mat-option>
|
|
48446
|
+
<mat-option value="desc">{{ tx('behavior.sorting.direction.desc', 'Descending') }}</mat-option>
|
|
48447
|
+
</mat-select>
|
|
48448
|
+
</mat-form-field>
|
|
48449
|
+
</div>
|
|
48450
|
+
</mat-expansion-panel>
|
|
48451
|
+
|
|
48452
|
+
<mat-expansion-panel class="inline-authoring__columns-panel" [expanded]="false" data-testid="table-inline-editor-states-panel">
|
|
48453
|
+
<mat-expansion-panel-header>
|
|
48454
|
+
<mat-panel-title>{{ tx('inlineAuthoring.statesTitle', 'State messages') }}</mat-panel-title>
|
|
48455
|
+
<mat-panel-description>{{ statesSummary() }}</mat-panel-description>
|
|
48456
|
+
</mat-expansion-panel-header>
|
|
48457
|
+
<p class="inline-authoring__panel-description">
|
|
48458
|
+
{{ tx('inlineAuthoring.statesDescription', 'Adjust the first messages users read when the list is loading, empty, filtered, or broken.') }}
|
|
48459
|
+
</p>
|
|
48460
|
+
<div class="inline-authoring__grid">
|
|
48461
|
+
<mat-form-field appearance="outline">
|
|
48462
|
+
<mat-label>{{ tx('messages.loading.label', 'Loading data') }}</mat-label>
|
|
48463
|
+
<input
|
|
48464
|
+
matInput
|
|
48465
|
+
data-testid="table-inline-editor-message-loading"
|
|
48466
|
+
[ngModel]="loadingMessage"
|
|
48467
|
+
(ngModelChange)="setStateMessage('loading', $event)"
|
|
48468
|
+
[disabled]="readonly"
|
|
48469
|
+
/>
|
|
48470
|
+
</mat-form-field>
|
|
48471
|
+
|
|
48472
|
+
<mat-form-field appearance="outline">
|
|
48473
|
+
<mat-label>{{ tx('messages.empty.label', 'No data found') }}</mat-label>
|
|
48474
|
+
<input
|
|
48475
|
+
matInput
|
|
48476
|
+
data-testid="table-inline-editor-message-empty"
|
|
48477
|
+
[ngModel]="emptyMessage"
|
|
48478
|
+
(ngModelChange)="setStateMessage('empty', $event)"
|
|
48479
|
+
[disabled]="readonly"
|
|
48480
|
+
/>
|
|
48481
|
+
</mat-form-field>
|
|
48482
|
+
|
|
48483
|
+
<mat-form-field appearance="outline">
|
|
48484
|
+
<mat-label>{{ tx('messages.noResults.label', 'No results') }}</mat-label>
|
|
48485
|
+
<input
|
|
48486
|
+
matInput
|
|
48487
|
+
data-testid="table-inline-editor-message-no-results"
|
|
48488
|
+
[ngModel]="noResultsMessage"
|
|
48489
|
+
(ngModelChange)="setStateMessage('noResults', $event)"
|
|
48490
|
+
[disabled]="readonly"
|
|
48491
|
+
/>
|
|
48492
|
+
</mat-form-field>
|
|
48493
|
+
|
|
48494
|
+
<mat-form-field appearance="outline">
|
|
48495
|
+
<mat-label>{{ tx('messages.error.label', 'Load error') }}</mat-label>
|
|
48496
|
+
<input
|
|
48497
|
+
matInput
|
|
48498
|
+
data-testid="table-inline-editor-message-error"
|
|
48499
|
+
[ngModel]="errorMessage"
|
|
48500
|
+
(ngModelChange)="setStateMessage('error', $event)"
|
|
48501
|
+
[disabled]="readonly"
|
|
48502
|
+
/>
|
|
48503
|
+
</mat-form-field>
|
|
48504
|
+
</div>
|
|
48505
|
+
</mat-expansion-panel>
|
|
48506
|
+
|
|
48507
|
+
<mat-expansion-panel class="inline-authoring__columns-panel" [expanded]="false" data-testid="table-inline-editor-columns-panel">
|
|
48508
|
+
<mat-expansion-panel-header>
|
|
48509
|
+
<mat-panel-title>{{ tx('inlineAuthoring.columnsTitle', 'Columns') }}</mat-panel-title>
|
|
48510
|
+
<mat-panel-description>{{ columnCountLabel() }}</mat-panel-description>
|
|
48511
|
+
</mat-expansion-panel-header>
|
|
48512
|
+
<p class="inline-authoring__panel-description">
|
|
48513
|
+
{{ tx('inlineAuthoring.columnsDescription', 'Open only when you need to adjust visible fields, labels, and renderers.') }}
|
|
48514
|
+
</p>
|
|
48515
|
+
<columns-config-editor
|
|
48516
|
+
[config]="workingConfig"
|
|
48517
|
+
(configChange)="onColumnsConfigChange($event)"
|
|
48518
|
+
/>
|
|
48519
|
+
</mat-expansion-panel>
|
|
48520
|
+
</section>
|
|
48521
|
+
}
|
|
48522
|
+
</mat-card>
|
|
48523
|
+
</section>
|
|
48524
|
+
`, isInline: true, styles: [":host{display:block}.inline-authoring{display:grid;gap:12px}.inline-authoring__header{display:flex;align-items:start;justify-content:space-between;gap:12px}.inline-authoring__header h4{margin:0;font-size:16px}.inline-authoring__header p{margin:4px 0 0;color:var(--md-sys-color-on-surface-variant,#5f6368)}.inline-authoring__chip{border-radius:999px;padding:6px 10px;font-size:12px;background:color-mix(in srgb,var(--md-sys-color-secondary-container,#d7e3ff) 70%,transparent);white-space:nowrap}.inline-authoring__card{display:grid;gap:12px;padding:14px;border-radius:18px}.inline-authoring__summary{display:grid;gap:10px;grid-template-columns:repeat(auto-fit,minmax(180px,1fr))}.inline-authoring__summary-card{display:grid;gap:4px;padding:12px;border-radius:14px;background:color-mix(in srgb,var(--md-sys-color-surface-container-high,#eef1f6) 92%,transparent);min-width:0}.inline-authoring__summary-card--wide{grid-column:span 2}.inline-authoring__summary-label{font-size:12px;color:var(--md-sys-color-on-surface-variant,#5f6368)}.inline-authoring__summary-card strong{font-size:13px;line-height:1.4;overflow:hidden;text-overflow:ellipsis}.inline-authoring__essentials{display:grid;gap:12px}.inline-authoring__advanced{display:grid;gap:12px;padding:12px;border-radius:16px;background:color-mix(in srgb,var(--md-sys-color-surface-container,#f5f7fb) 88%,transparent)}.inline-authoring__advanced-summary{display:grid;gap:10px;grid-template-columns:repeat(auto-fit,minmax(180px,1fr))}.inline-authoring__advanced-card{display:grid;gap:4px;padding:12px;border-radius:14px;background:color-mix(in srgb,var(--md-sys-color-surface,#fff) 92%,transparent);min-width:0}.inline-authoring__advanced-card strong{font-size:13px;line-height:1.4;overflow:hidden;text-overflow:ellipsis}.inline-authoring__advanced-panels{display:grid;gap:12px}.inline-authoring__section-copy{display:grid;gap:4px}.inline-authoring__section-copy h5{margin:0;font-size:14px}.inline-authoring__section-copy p{margin:0;color:var(--md-sys-color-on-surface-variant,#5f6368)}.inline-authoring__grid{display:grid;gap:12px;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));align-items:start}.inline-authoring__columns-panel{border:1px solid color-mix(in srgb,var(--md-sys-color-outline,#c5c7ce) 65%,transparent);border-radius:16px}.inline-authoring__panel-description{margin:0 0 12px;color:var(--md-sys-color-on-surface-variant,#5f6368)}.inline-authoring__readonly{margin:0;color:var(--md-sys-color-on-surface-variant,#5f6368)}pre{margin:0;overflow:auto;max-height:240px;padding:12px;border-radius:14px;background:color-mix(in srgb,var(--md-sys-color-surface-container-high,#eef1f6) 92%,transparent)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$1.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.MinValidator, selector: "input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]", inputs: ["min"] }, { kind: "directive", type: i1$1.MaxValidator, selector: "input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]", inputs: ["max"] }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: MatCardModule }, { kind: "component", type: i10$1.MatCard, selector: "mat-card", inputs: ["appearance"], exportAs: ["matCard"] }, { kind: "ngmodule", type: MatExpansionModule }, { kind: "component", type: i7$1.MatExpansionPanel, selector: "mat-expansion-panel", inputs: ["hideToggle", "togglePosition"], outputs: ["afterExpand", "afterCollapse"], exportAs: ["matExpansionPanel"] }, { kind: "component", type: i7$1.MatExpansionPanelHeader, selector: "mat-expansion-panel-header", inputs: ["expandedHeight", "collapsedHeight", "tabIndex"] }, { kind: "directive", type: i7$1.MatExpansionPanelTitle, selector: "mat-panel-title" }, { kind: "directive", type: i7$1.MatExpansionPanelDescription, selector: "mat-panel-description" }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i6.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i6.MatLabel, selector: "mat-label" }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i7.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly", "disabledInteractive"], exportAs: ["matInput"] }, { kind: "ngmodule", type: MatSelectModule }, { kind: "component", type: i5$1.MatSelect, selector: "mat-select", inputs: ["aria-describedby", "panelClass", "disabled", "disableRipple", "tabIndex", "hideSingleSelectionIndicator", "placeholder", "required", "multiple", "disableOptionCentering", "compareWith", "value", "aria-label", "aria-labelledby", "errorStateMatcher", "typeaheadDebounceInterval", "sortComparator", "id", "panelWidth", "canSelectNullableOptions"], outputs: ["openedChange", "opened", "closed", "selectionChange", "valueChange"], exportAs: ["matSelect"] }, { kind: "component", type: i5$1.MatOption, selector: "mat-option", inputs: ["value", "id", "disabled"], outputs: ["onSelectionChange"], exportAs: ["matOption"] }, { kind: "ngmodule", type: MatSlideToggleModule }, { kind: "component", type: i6$1.MatSlideToggle, selector: "mat-slide-toggle", inputs: ["name", "id", "labelPosition", "aria-label", "aria-labelledby", "aria-describedby", "required", "color", "disabled", "disableRipple", "tabIndex", "checked", "hideIcon", "disabledInteractive"], outputs: ["change", "toggleChange"], exportAs: ["matSlideToggle"] }, { kind: "component", type: ColumnsConfigEditorComponent, selector: "columns-config-editor", inputs: ["config"], outputs: ["configChange", "columnChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
48525
|
+
}
|
|
48526
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: PraxisTableInlineAuthoringEditorComponent, decorators: [{
|
|
48527
|
+
type: Component,
|
|
48528
|
+
args: [{ selector: 'praxis-table-inline-authoring-editor', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, imports: [
|
|
48529
|
+
CommonModule,
|
|
48530
|
+
FormsModule,
|
|
48531
|
+
MatCardModule,
|
|
48532
|
+
MatExpansionModule,
|
|
48533
|
+
MatFormFieldModule,
|
|
48534
|
+
MatInputModule,
|
|
48535
|
+
MatSelectModule,
|
|
48536
|
+
MatSlideToggleModule,
|
|
48537
|
+
ColumnsConfigEditorComponent,
|
|
48538
|
+
], providers: [providePraxisI18nConfig(PRAXIS_TABLE_EDITOR_I18N_CONFIG)], template: `
|
|
48539
|
+
<section class="inline-authoring" data-testid="table-inline-authoring-editor">
|
|
48540
|
+
<header class="inline-authoring__header">
|
|
48541
|
+
<div>
|
|
48542
|
+
<h4>{{ tx('inlineAuthoring.title', 'Table structure') }}</h4>
|
|
48543
|
+
<p>{{ tx('inlineAuthoring.description', 'Edit the canonical TableConfig used by this CRUD surface.') }}</p>
|
|
48544
|
+
</div>
|
|
48545
|
+
<span class="inline-authoring__chip" data-testid="table-inline-editor-column-count">
|
|
48546
|
+
{{ columnCountLabel() }}
|
|
48547
|
+
</span>
|
|
48548
|
+
</header>
|
|
48549
|
+
|
|
48550
|
+
<mat-card class="inline-authoring__card">
|
|
48551
|
+
<section class="inline-authoring__summary" data-testid="table-inline-editor-summary">
|
|
48552
|
+
<div class="inline-authoring__summary-card">
|
|
48553
|
+
<span class="inline-authoring__summary-label">{{ tx('inlineAuthoring.summary.toolbar', 'Toolbar') }}</span>
|
|
48554
|
+
<strong data-testid="table-inline-editor-summary-toolbar">{{ toolbarSummary() }}</strong>
|
|
48555
|
+
</div>
|
|
48556
|
+
<div class="inline-authoring__summary-card">
|
|
48557
|
+
<span class="inline-authoring__summary-label">{{ tx('inlineAuthoring.summary.density', 'Density') }}</span>
|
|
48558
|
+
<strong data-testid="table-inline-editor-summary-density">{{ densitySummary() }}</strong>
|
|
48559
|
+
</div>
|
|
48560
|
+
<div class="inline-authoring__summary-card">
|
|
48561
|
+
<span class="inline-authoring__summary-label">{{ tx('inlineAuthoring.summary.actions', 'Actions') }}</span>
|
|
48562
|
+
<strong data-testid="table-inline-editor-summary-actions">{{ actionsPositionSummary() }}</strong>
|
|
48563
|
+
</div>
|
|
48564
|
+
<div class="inline-authoring__summary-card">
|
|
48565
|
+
<span class="inline-authoring__summary-label">{{ tx('inlineAuthoring.summary.behavior', 'List behavior') }}</span>
|
|
48566
|
+
<strong data-testid="table-inline-editor-summary-behavior">{{ behaviorSummary() }}</strong>
|
|
48567
|
+
</div>
|
|
48568
|
+
<div class="inline-authoring__summary-card">
|
|
48569
|
+
<span class="inline-authoring__summary-label">{{ tx('inlineAuthoring.summary.states', 'State messages') }}</span>
|
|
48570
|
+
<strong data-testid="table-inline-editor-summary-states">{{ statesSummary() }}</strong>
|
|
48571
|
+
</div>
|
|
48572
|
+
<div class="inline-authoring__summary-card inline-authoring__summary-card--wide">
|
|
48573
|
+
<span class="inline-authoring__summary-label">{{ tx('inlineAuthoring.summary.columns', 'Visible structure') }}</span>
|
|
48574
|
+
<strong data-testid="table-inline-editor-summary-columns">{{ columnsPreviewSummary() }}</strong>
|
|
48575
|
+
</div>
|
|
48576
|
+
</section>
|
|
48577
|
+
|
|
48578
|
+
<section class="inline-authoring__essentials">
|
|
48579
|
+
<div class="inline-authoring__section-copy">
|
|
48580
|
+
<h5>{{ tx('inlineAuthoring.essentialsTitle', 'Table essentials') }}</h5>
|
|
48581
|
+
<p>{{ tx('inlineAuthoring.essentialsDescription', 'Define the toolbar presence and the texts users see first.') }}</p>
|
|
48582
|
+
</div>
|
|
48583
|
+
|
|
48584
|
+
<div class="inline-authoring__grid">
|
|
48585
|
+
<mat-slide-toggle
|
|
48586
|
+
data-testid="table-inline-editor-toolbar-visible"
|
|
48587
|
+
[ngModel]="toolbarVisible"
|
|
48588
|
+
(ngModelChange)="setToolbarVisible($event)"
|
|
48589
|
+
[disabled]="readonly"
|
|
48590
|
+
>
|
|
48591
|
+
{{ tx('toolbar.visible', 'Show toolbar') }}
|
|
48592
|
+
</mat-slide-toggle>
|
|
48593
|
+
|
|
48594
|
+
<mat-form-field appearance="outline">
|
|
48595
|
+
<mat-label>{{ tx('toolbar.title.label', 'Toolbar title') }}</mat-label>
|
|
48596
|
+
<input
|
|
48597
|
+
matInput
|
|
48598
|
+
data-testid="table-inline-editor-toolbar-title"
|
|
48599
|
+
[ngModel]="toolbarTitle"
|
|
48600
|
+
(ngModelChange)="setToolbarTitle($event)"
|
|
48601
|
+
[disabled]="readonly"
|
|
48602
|
+
/>
|
|
48603
|
+
</mat-form-field>
|
|
48604
|
+
|
|
48605
|
+
<mat-form-field appearance="outline">
|
|
48606
|
+
<mat-label>{{ tx('toolbar.subtitle.label', 'Subtitle') }}</mat-label>
|
|
48607
|
+
<input
|
|
48608
|
+
matInput
|
|
48609
|
+
data-testid="table-inline-editor-toolbar-subtitle"
|
|
48610
|
+
[ngModel]="toolbarSubtitle"
|
|
48611
|
+
(ngModelChange)="setToolbarSubtitle($event)"
|
|
48612
|
+
[disabled]="readonly"
|
|
48613
|
+
/>
|
|
48614
|
+
</mat-form-field>
|
|
48615
|
+
|
|
48616
|
+
<mat-form-field appearance="outline">
|
|
48617
|
+
<mat-label>{{ tx('behavior.appearance.density', 'Density') }}</mat-label>
|
|
48618
|
+
<mat-select
|
|
48619
|
+
data-testid="table-inline-editor-density"
|
|
48620
|
+
[ngModel]="density"
|
|
48621
|
+
(ngModelChange)="setDensity($event)"
|
|
48622
|
+
[disabled]="readonly"
|
|
48623
|
+
>
|
|
48624
|
+
<mat-option value="compact">{{ tx('behavior.appearance.density.compact', 'Compact') }}</mat-option>
|
|
48625
|
+
<mat-option value="comfortable">{{ tx('behavior.appearance.density.comfortable', 'Comfortable') }}</mat-option>
|
|
48626
|
+
<mat-option value="spacious">{{ tx('behavior.appearance.density.spacious', 'Spacious') }}</mat-option>
|
|
48627
|
+
</mat-select>
|
|
48628
|
+
</mat-form-field>
|
|
48629
|
+
|
|
48630
|
+
<mat-form-field appearance="outline">
|
|
48631
|
+
<mat-label>{{ tx('toolbar.actionsPosition.label', 'Actions position') }}</mat-label>
|
|
48632
|
+
<mat-select
|
|
48633
|
+
data-testid="table-inline-editor-toolbar-actions-position"
|
|
48634
|
+
[ngModel]="toolbarActionsPosition"
|
|
48635
|
+
(ngModelChange)="setToolbarActionsPosition($event)"
|
|
48636
|
+
[disabled]="readonly"
|
|
48637
|
+
>
|
|
48638
|
+
<mat-option value="top">{{ tx('toolbar.actionsPosition.top', 'Above the table') }}</mat-option>
|
|
48639
|
+
<mat-option value="bottom">{{ tx('toolbar.actionsPosition.bottom', 'Below the table') }}</mat-option>
|
|
48640
|
+
<mat-option value="both">{{ tx('toolbar.actionsPosition.both', 'Top and bottom') }}</mat-option>
|
|
48641
|
+
</mat-select>
|
|
48642
|
+
</mat-form-field>
|
|
48643
|
+
|
|
48644
|
+
<mat-form-field appearance="outline">
|
|
48645
|
+
<mat-label>{{ tx('toolbar.height.label', 'Toolbar height (px)') }}</mat-label>
|
|
48646
|
+
<input
|
|
48647
|
+
matInput
|
|
48648
|
+
type="number"
|
|
48649
|
+
data-testid="table-inline-editor-toolbar-height"
|
|
48650
|
+
[ngModel]="toolbarHeight"
|
|
48651
|
+
(ngModelChange)="setToolbarHeight($event)"
|
|
48652
|
+
[disabled]="readonly"
|
|
48653
|
+
min="40"
|
|
48654
|
+
max="120"
|
|
48655
|
+
/>
|
|
48656
|
+
</mat-form-field>
|
|
48657
|
+
|
|
48658
|
+
<mat-form-field appearance="outline">
|
|
48659
|
+
<mat-label>{{ tx('toolbar.backgroundPreset.label', 'Actions background color') }}</mat-label>
|
|
48660
|
+
<mat-select
|
|
48661
|
+
data-testid="table-inline-editor-toolbar-background-preset"
|
|
48662
|
+
[ngModel]="toolbarActionsBackgroundColor"
|
|
48663
|
+
(ngModelChange)="setToolbarActionsBackgroundColor($event)"
|
|
48664
|
+
[disabled]="readonly"
|
|
48665
|
+
>
|
|
48666
|
+
<mat-option value="">{{ tx('toolbar.backgroundPreset.default', 'Theme default') }}</mat-option>
|
|
48667
|
+
<mat-option value="var(--p-table-header-bg)">{{ tx('toolbar.backgroundPreset.header', 'Table header') }}</mat-option>
|
|
48668
|
+
<mat-option value="var(--md-sys-color-surface)">{{ tx('toolbar.backgroundPreset.surface', 'Surface') }}</mat-option>
|
|
48669
|
+
<mat-option value="var(--md-sys-color-surface-container)">{{ tx('toolbar.backgroundPreset.surfaceContainer', 'Surface container') }}</mat-option>
|
|
48670
|
+
<mat-option value="var(--md-sys-color-surface-container-high)">{{ tx('toolbar.backgroundPreset.surfaceContainerHigh', 'Surface container high') }}</mat-option>
|
|
48671
|
+
<mat-option value="var(--md-sys-color-surface-container-highest)">{{ tx('toolbar.backgroundPreset.surfaceContainerHighest', 'Surface container highest') }}</mat-option>
|
|
48672
|
+
</mat-select>
|
|
48673
|
+
</mat-form-field>
|
|
48674
|
+
</div>
|
|
48675
|
+
</section>
|
|
48676
|
+
|
|
48677
|
+
<section class="inline-authoring__advanced" data-testid="table-inline-editor-advanced-intro">
|
|
48678
|
+
<div class="inline-authoring__section-copy">
|
|
48679
|
+
<h5>{{ tx('inlineAuthoring.advancedTitle', 'Advanced table details') }}</h5>
|
|
48680
|
+
<p>{{ tx('inlineAuthoring.advancedDescription', 'Open the next panels only when you need to tune list behavior, state copy, or visible columns.') }}</p>
|
|
48681
|
+
</div>
|
|
48682
|
+
|
|
48683
|
+
<section class="inline-authoring__advanced-summary">
|
|
48684
|
+
<div class="inline-authoring__advanced-card">
|
|
48685
|
+
<span class="inline-authoring__summary-label">{{ tx('inlineAuthoring.advanced.behavior', 'Behavior') }}</span>
|
|
48686
|
+
<strong data-testid="table-inline-editor-advanced-summary-behavior">{{ behaviorSummary() }}</strong>
|
|
48687
|
+
</div>
|
|
48688
|
+
<div class="inline-authoring__advanced-card">
|
|
48689
|
+
<span class="inline-authoring__summary-label">{{ tx('inlineAuthoring.advanced.states', 'State copy') }}</span>
|
|
48690
|
+
<strong data-testid="table-inline-editor-advanced-summary-states">{{ statesSummary() }}</strong>
|
|
48691
|
+
</div>
|
|
48692
|
+
<div class="inline-authoring__advanced-card">
|
|
48693
|
+
<span class="inline-authoring__summary-label">{{ tx('inlineAuthoring.advanced.columns', 'Columns') }}</span>
|
|
48694
|
+
<strong data-testid="table-inline-editor-advanced-summary-columns">{{ columnsPreviewSummary() }}</strong>
|
|
48695
|
+
</div>
|
|
48696
|
+
</section>
|
|
48697
|
+
</section>
|
|
48698
|
+
|
|
48699
|
+
@if (readonly) {
|
|
48700
|
+
<p class="inline-authoring__readonly" data-testid="table-inline-editor-readonly-hint">
|
|
48701
|
+
{{ tx('inlineAuthoring.readonlyHint', 'This authoring surface is read-only in the current context.') }}
|
|
48702
|
+
</p>
|
|
48703
|
+
<pre data-testid="table-inline-editor-json">{{ serializedConfig() }}</pre>
|
|
48704
|
+
} @else {
|
|
48705
|
+
<section class="inline-authoring__advanced-panels" data-testid="table-inline-editor-advanced-panels">
|
|
48706
|
+
<mat-expansion-panel class="inline-authoring__columns-panel" [expanded]="false" data-testid="table-inline-editor-behavior-panel">
|
|
48707
|
+
<mat-expansion-panel-header>
|
|
48708
|
+
<mat-panel-title>{{ tx('inlineAuthoring.behaviorTitle', 'List behavior') }}</mat-panel-title>
|
|
48709
|
+
<mat-panel-description>{{ behaviorSummary() }}</mat-panel-description>
|
|
48710
|
+
</mat-expansion-panel-header>
|
|
48711
|
+
<p class="inline-authoring__panel-description">
|
|
48712
|
+
{{ tx('inlineAuthoring.behaviorDescription', 'Control pagination and sorting with the same runtime-backed semantics used by the full table editor.') }}
|
|
48713
|
+
</p>
|
|
48714
|
+
<div class="inline-authoring__grid">
|
|
48715
|
+
<mat-slide-toggle
|
|
48716
|
+
data-testid="table-inline-editor-pagination-enabled"
|
|
48717
|
+
[ngModel]="paginationEnabled"
|
|
48718
|
+
(ngModelChange)="setPaginationEnabled($event)"
|
|
48719
|
+
[disabled]="readonly"
|
|
48720
|
+
>
|
|
48721
|
+
{{ tx('behavior.pagination.enabled', 'Enable pagination') }}
|
|
48722
|
+
</mat-slide-toggle>
|
|
48723
|
+
|
|
48724
|
+
<mat-form-field appearance="outline">
|
|
48725
|
+
<mat-label>{{ tx('behavior.pagination.pageSize', 'Items per page') }}</mat-label>
|
|
48726
|
+
<input
|
|
48727
|
+
matInput
|
|
48728
|
+
type="number"
|
|
48729
|
+
data-testid="table-inline-editor-pagination-page-size"
|
|
48730
|
+
[ngModel]="pageSize"
|
|
48731
|
+
(ngModelChange)="setPaginationPageSize($event)"
|
|
48732
|
+
[disabled]="readonly || !paginationEnabled"
|
|
48733
|
+
min="1"
|
|
48734
|
+
/>
|
|
48735
|
+
</mat-form-field>
|
|
48736
|
+
|
|
48737
|
+
<mat-form-field appearance="outline">
|
|
48738
|
+
<mat-label>{{ tx('behavior.pagination.pageSizeOptions', 'Page size options') }}</mat-label>
|
|
48739
|
+
<input
|
|
48740
|
+
matInput
|
|
48741
|
+
data-testid="table-inline-editor-pagination-page-size-options"
|
|
48742
|
+
[ngModel]="pageSizeOptionsText"
|
|
48743
|
+
(ngModelChange)="setPaginationPageSizeOptions($event)"
|
|
48744
|
+
[disabled]="readonly || !paginationEnabled"
|
|
48745
|
+
placeholder="5, 10, 25, 50"
|
|
48746
|
+
/>
|
|
48747
|
+
</mat-form-field>
|
|
48748
|
+
|
|
48749
|
+
<mat-slide-toggle
|
|
48750
|
+
data-testid="table-inline-editor-pagination-first-last"
|
|
48751
|
+
[ngModel]="showFirstLastButtons"
|
|
48752
|
+
(ngModelChange)="setPaginationShowFirstLastButtons($event)"
|
|
48753
|
+
[disabled]="readonly || !paginationEnabled"
|
|
48754
|
+
>
|
|
48755
|
+
{{ tx('behavior.pagination.firstLast', 'Show first/last page buttons') }}
|
|
48756
|
+
</mat-slide-toggle>
|
|
48757
|
+
|
|
48758
|
+
<mat-form-field appearance="outline">
|
|
48759
|
+
<mat-label>{{ tx('behavior.pagination.strategy', 'Pagination strategy') }}</mat-label>
|
|
48760
|
+
<mat-select
|
|
48761
|
+
data-testid="table-inline-editor-pagination-strategy"
|
|
48762
|
+
[ngModel]="paginationStrategy"
|
|
48763
|
+
(ngModelChange)="setPaginationStrategy($event)"
|
|
48764
|
+
[disabled]="readonly || !paginationEnabled"
|
|
48765
|
+
>
|
|
48766
|
+
<mat-option value="client">{{ tx('behavior.pagination.strategy.client', 'Client (local data)') }}</mat-option>
|
|
48767
|
+
<mat-option value="server">{{ tx('behavior.pagination.strategy.server', 'Server (remote pagination)') }}</mat-option>
|
|
48768
|
+
</mat-select>
|
|
48769
|
+
</mat-form-field>
|
|
48770
|
+
|
|
48771
|
+
<mat-form-field appearance="outline">
|
|
48772
|
+
<mat-label>{{ tx('behavior.pagination.position', 'Paginator position') }}</mat-label>
|
|
48773
|
+
<mat-select
|
|
48774
|
+
data-testid="table-inline-editor-pagination-position"
|
|
48775
|
+
[ngModel]="paginationPosition"
|
|
48776
|
+
(ngModelChange)="setPaginationPosition($event)"
|
|
48777
|
+
[disabled]="readonly || !paginationEnabled"
|
|
48778
|
+
>
|
|
48779
|
+
<mat-option value="top">{{ tx('behavior.pagination.position.top', 'Top') }}</mat-option>
|
|
48780
|
+
<mat-option value="bottom">{{ tx('behavior.pagination.position.bottom', 'Bottom') }}</mat-option>
|
|
48781
|
+
<mat-option value="both">{{ tx('behavior.pagination.position.both', 'Both') }}</mat-option>
|
|
48782
|
+
</mat-select>
|
|
48783
|
+
</mat-form-field>
|
|
48784
|
+
|
|
48785
|
+
<mat-form-field appearance="outline">
|
|
48786
|
+
<mat-label>{{ tx('behavior.pagination.style', 'Paginator style') }}</mat-label>
|
|
48787
|
+
<mat-select
|
|
48788
|
+
data-testid="table-inline-editor-pagination-style"
|
|
48789
|
+
[ngModel]="paginationStyle"
|
|
48790
|
+
(ngModelChange)="setPaginationStyle($event)"
|
|
48791
|
+
[disabled]="readonly || !paginationEnabled"
|
|
48792
|
+
>
|
|
48793
|
+
<mat-option value="default">{{ tx('behavior.pagination.style.default', 'Default') }}</mat-option>
|
|
48794
|
+
<mat-option value="simple">{{ tx('behavior.pagination.style.simple', 'Simple') }}</mat-option>
|
|
48795
|
+
<mat-option value="compact">{{ tx('behavior.pagination.style.compact', 'Compact') }}</mat-option>
|
|
48796
|
+
<mat-option value="advanced">{{ tx('behavior.pagination.style.advanced', 'Advanced') }}</mat-option>
|
|
48797
|
+
</mat-select>
|
|
48798
|
+
</mat-form-field>
|
|
48799
|
+
|
|
48800
|
+
<mat-slide-toggle
|
|
48801
|
+
data-testid="table-inline-editor-sorting-enabled"
|
|
48802
|
+
[ngModel]="sortingEnabled"
|
|
48803
|
+
(ngModelChange)="setSortingEnabled($event)"
|
|
48804
|
+
[disabled]="readonly"
|
|
48805
|
+
>
|
|
48806
|
+
{{ tx('behavior.sorting.enabled', 'Enable sorting') }}
|
|
48807
|
+
</mat-slide-toggle>
|
|
48808
|
+
|
|
48809
|
+
<mat-form-field appearance="outline">
|
|
48810
|
+
<mat-label>{{ tx('behavior.sorting.strategy', 'Sorting strategy') }}</mat-label>
|
|
48811
|
+
<mat-select
|
|
48812
|
+
data-testid="table-inline-editor-sorting-strategy"
|
|
48813
|
+
[ngModel]="sortingStrategy"
|
|
48814
|
+
(ngModelChange)="setSortingStrategy($event)"
|
|
48815
|
+
[disabled]="readonly || !sortingEnabled"
|
|
48816
|
+
>
|
|
48817
|
+
<mat-option value="client">{{ tx('behavior.sorting.strategy.client', 'Client (local sorting)') }}</mat-option>
|
|
48818
|
+
<mat-option value="server">{{ tx('behavior.sorting.strategy.server', 'Server (remote sorting)') }}</mat-option>
|
|
48819
|
+
</mat-select>
|
|
48820
|
+
</mat-form-field>
|
|
48821
|
+
|
|
48822
|
+
<mat-slide-toggle
|
|
48823
|
+
data-testid="table-inline-editor-sorting-allow-clear"
|
|
48824
|
+
[ngModel]="allowClearSort"
|
|
48825
|
+
(ngModelChange)="setSortingAllowClear($event)"
|
|
48826
|
+
[disabled]="readonly || !sortingEnabled"
|
|
48827
|
+
>
|
|
48828
|
+
{{ tx('behavior.sorting.allowClear', 'Allow clearing sort') }}
|
|
48829
|
+
</mat-slide-toggle>
|
|
48830
|
+
|
|
48831
|
+
<mat-form-field appearance="outline">
|
|
48832
|
+
<mat-label>{{ tx('behavior.sorting.defaultField', 'Initial sort - column') }}</mat-label>
|
|
48833
|
+
<mat-select
|
|
48834
|
+
data-testid="table-inline-editor-sorting-default-field"
|
|
48835
|
+
[ngModel]="defaultSortField"
|
|
48836
|
+
(ngModelChange)="setSortingDefaultField($event)"
|
|
48837
|
+
[disabled]="readonly || !sortingEnabled"
|
|
48838
|
+
>
|
|
48839
|
+
<mat-option value="">{{ tx('inlineAuthoring.noneOption', 'None') }}</mat-option>
|
|
48840
|
+
@for (column of workingConfig.columns || []; track column.field) {
|
|
48841
|
+
<mat-option [value]="column.field">{{ column.header || column.field }}</mat-option>
|
|
48842
|
+
}
|
|
48843
|
+
</mat-select>
|
|
48844
|
+
</mat-form-field>
|
|
48845
|
+
|
|
48846
|
+
<mat-form-field appearance="outline">
|
|
48847
|
+
<mat-label>{{ tx('behavior.sorting.direction', 'Direction') }}</mat-label>
|
|
48848
|
+
<mat-select
|
|
48849
|
+
data-testid="table-inline-editor-sorting-default-direction"
|
|
48850
|
+
[ngModel]="defaultSortDirection"
|
|
48851
|
+
(ngModelChange)="setSortingDefaultDirection($event)"
|
|
48852
|
+
[disabled]="readonly || !sortingEnabled || !defaultSortField"
|
|
48853
|
+
>
|
|
48854
|
+
<mat-option value="asc">{{ tx('behavior.sorting.direction.asc', 'Ascending') }}</mat-option>
|
|
48855
|
+
<mat-option value="desc">{{ tx('behavior.sorting.direction.desc', 'Descending') }}</mat-option>
|
|
48856
|
+
</mat-select>
|
|
48857
|
+
</mat-form-field>
|
|
48858
|
+
</div>
|
|
48859
|
+
</mat-expansion-panel>
|
|
48860
|
+
|
|
48861
|
+
<mat-expansion-panel class="inline-authoring__columns-panel" [expanded]="false" data-testid="table-inline-editor-states-panel">
|
|
48862
|
+
<mat-expansion-panel-header>
|
|
48863
|
+
<mat-panel-title>{{ tx('inlineAuthoring.statesTitle', 'State messages') }}</mat-panel-title>
|
|
48864
|
+
<mat-panel-description>{{ statesSummary() }}</mat-panel-description>
|
|
48865
|
+
</mat-expansion-panel-header>
|
|
48866
|
+
<p class="inline-authoring__panel-description">
|
|
48867
|
+
{{ tx('inlineAuthoring.statesDescription', 'Adjust the first messages users read when the list is loading, empty, filtered, or broken.') }}
|
|
48868
|
+
</p>
|
|
48869
|
+
<div class="inline-authoring__grid">
|
|
48870
|
+
<mat-form-field appearance="outline">
|
|
48871
|
+
<mat-label>{{ tx('messages.loading.label', 'Loading data') }}</mat-label>
|
|
48872
|
+
<input
|
|
48873
|
+
matInput
|
|
48874
|
+
data-testid="table-inline-editor-message-loading"
|
|
48875
|
+
[ngModel]="loadingMessage"
|
|
48876
|
+
(ngModelChange)="setStateMessage('loading', $event)"
|
|
48877
|
+
[disabled]="readonly"
|
|
48878
|
+
/>
|
|
48879
|
+
</mat-form-field>
|
|
48880
|
+
|
|
48881
|
+
<mat-form-field appearance="outline">
|
|
48882
|
+
<mat-label>{{ tx('messages.empty.label', 'No data found') }}</mat-label>
|
|
48883
|
+
<input
|
|
48884
|
+
matInput
|
|
48885
|
+
data-testid="table-inline-editor-message-empty"
|
|
48886
|
+
[ngModel]="emptyMessage"
|
|
48887
|
+
(ngModelChange)="setStateMessage('empty', $event)"
|
|
48888
|
+
[disabled]="readonly"
|
|
48889
|
+
/>
|
|
48890
|
+
</mat-form-field>
|
|
48891
|
+
|
|
48892
|
+
<mat-form-field appearance="outline">
|
|
48893
|
+
<mat-label>{{ tx('messages.noResults.label', 'No results') }}</mat-label>
|
|
48894
|
+
<input
|
|
48895
|
+
matInput
|
|
48896
|
+
data-testid="table-inline-editor-message-no-results"
|
|
48897
|
+
[ngModel]="noResultsMessage"
|
|
48898
|
+
(ngModelChange)="setStateMessage('noResults', $event)"
|
|
48899
|
+
[disabled]="readonly"
|
|
48900
|
+
/>
|
|
48901
|
+
</mat-form-field>
|
|
48902
|
+
|
|
48903
|
+
<mat-form-field appearance="outline">
|
|
48904
|
+
<mat-label>{{ tx('messages.error.label', 'Load error') }}</mat-label>
|
|
48905
|
+
<input
|
|
48906
|
+
matInput
|
|
48907
|
+
data-testid="table-inline-editor-message-error"
|
|
48908
|
+
[ngModel]="errorMessage"
|
|
48909
|
+
(ngModelChange)="setStateMessage('error', $event)"
|
|
48910
|
+
[disabled]="readonly"
|
|
48911
|
+
/>
|
|
48912
|
+
</mat-form-field>
|
|
48913
|
+
</div>
|
|
48914
|
+
</mat-expansion-panel>
|
|
48915
|
+
|
|
48916
|
+
<mat-expansion-panel class="inline-authoring__columns-panel" [expanded]="false" data-testid="table-inline-editor-columns-panel">
|
|
48917
|
+
<mat-expansion-panel-header>
|
|
48918
|
+
<mat-panel-title>{{ tx('inlineAuthoring.columnsTitle', 'Columns') }}</mat-panel-title>
|
|
48919
|
+
<mat-panel-description>{{ columnCountLabel() }}</mat-panel-description>
|
|
48920
|
+
</mat-expansion-panel-header>
|
|
48921
|
+
<p class="inline-authoring__panel-description">
|
|
48922
|
+
{{ tx('inlineAuthoring.columnsDescription', 'Open only when you need to adjust visible fields, labels, and renderers.') }}
|
|
48923
|
+
</p>
|
|
48924
|
+
<columns-config-editor
|
|
48925
|
+
[config]="workingConfig"
|
|
48926
|
+
(configChange)="onColumnsConfigChange($event)"
|
|
48927
|
+
/>
|
|
48928
|
+
</mat-expansion-panel>
|
|
48929
|
+
</section>
|
|
48930
|
+
}
|
|
48931
|
+
</mat-card>
|
|
48932
|
+
</section>
|
|
48933
|
+
`, styles: [":host{display:block}.inline-authoring{display:grid;gap:12px}.inline-authoring__header{display:flex;align-items:start;justify-content:space-between;gap:12px}.inline-authoring__header h4{margin:0;font-size:16px}.inline-authoring__header p{margin:4px 0 0;color:var(--md-sys-color-on-surface-variant,#5f6368)}.inline-authoring__chip{border-radius:999px;padding:6px 10px;font-size:12px;background:color-mix(in srgb,var(--md-sys-color-secondary-container,#d7e3ff) 70%,transparent);white-space:nowrap}.inline-authoring__card{display:grid;gap:12px;padding:14px;border-radius:18px}.inline-authoring__summary{display:grid;gap:10px;grid-template-columns:repeat(auto-fit,minmax(180px,1fr))}.inline-authoring__summary-card{display:grid;gap:4px;padding:12px;border-radius:14px;background:color-mix(in srgb,var(--md-sys-color-surface-container-high,#eef1f6) 92%,transparent);min-width:0}.inline-authoring__summary-card--wide{grid-column:span 2}.inline-authoring__summary-label{font-size:12px;color:var(--md-sys-color-on-surface-variant,#5f6368)}.inline-authoring__summary-card strong{font-size:13px;line-height:1.4;overflow:hidden;text-overflow:ellipsis}.inline-authoring__essentials{display:grid;gap:12px}.inline-authoring__advanced{display:grid;gap:12px;padding:12px;border-radius:16px;background:color-mix(in srgb,var(--md-sys-color-surface-container,#f5f7fb) 88%,transparent)}.inline-authoring__advanced-summary{display:grid;gap:10px;grid-template-columns:repeat(auto-fit,minmax(180px,1fr))}.inline-authoring__advanced-card{display:grid;gap:4px;padding:12px;border-radius:14px;background:color-mix(in srgb,var(--md-sys-color-surface,#fff) 92%,transparent);min-width:0}.inline-authoring__advanced-card strong{font-size:13px;line-height:1.4;overflow:hidden;text-overflow:ellipsis}.inline-authoring__advanced-panels{display:grid;gap:12px}.inline-authoring__section-copy{display:grid;gap:4px}.inline-authoring__section-copy h5{margin:0;font-size:14px}.inline-authoring__section-copy p{margin:0;color:var(--md-sys-color-on-surface-variant,#5f6368)}.inline-authoring__grid{display:grid;gap:12px;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));align-items:start}.inline-authoring__columns-panel{border:1px solid color-mix(in srgb,var(--md-sys-color-outline,#c5c7ce) 65%,transparent);border-radius:16px}.inline-authoring__panel-description{margin:0 0 12px;color:var(--md-sys-color-on-surface-variant,#5f6368)}.inline-authoring__readonly{margin:0;color:var(--md-sys-color-on-surface-variant,#5f6368)}pre{margin:0;overflow:auto;max-height:240px;padding:12px;border-radius:14px;background:color-mix(in srgb,var(--md-sys-color-surface-container-high,#eef1f6) 92%,transparent)}\n"] }]
|
|
48934
|
+
}], ctorParameters: () => [{ type: i1.PraxisI18nService }], propDecorators: { config: [{
|
|
48935
|
+
type: Input
|
|
48936
|
+
}], readonly: [{
|
|
48937
|
+
type: Input
|
|
48938
|
+
}], configChange: [{
|
|
48939
|
+
type: Output
|
|
48940
|
+
}] } });
|
|
48941
|
+
function cloneTableConfig(config) {
|
|
48942
|
+
return JSON.parse(JSON.stringify(config || { columns: [] }));
|
|
48943
|
+
}
|
|
48944
|
+
function clampNumber(value, min, max, fallback) {
|
|
48945
|
+
const parsed = Number(value);
|
|
48946
|
+
if (!Number.isFinite(parsed)) {
|
|
48947
|
+
return fallback;
|
|
48948
|
+
}
|
|
48949
|
+
return Math.min(max, Math.max(min, parsed));
|
|
48950
|
+
}
|
|
48951
|
+
|
|
45912
48952
|
const PRAXIS_TABLE_PORTS = [
|
|
45913
48953
|
{
|
|
45914
48954
|
id: 'queryContext',
|
|
@@ -47166,4 +50206,4 @@ const TABLE_COMPONENT_AI_CAPABILITIES = {
|
|
|
47166
50206
|
* Generated bundle index. Do not edit.
|
|
47167
50207
|
*/
|
|
47168
50208
|
|
|
47169
|
-
export { AnalyticsTableConfigAdapterService, AnalyticsTableContractService, AnalyticsTableStatsApiService, BOOLEAN_PRESETS, BehaviorConfigEditorComponent, CURRENCY_PRESETS, ColumnsConfigEditorComponent, DATE_PRESETS, DataFormatterComponent, DataFormattingService, FORMULA_TEMPLATES, FilterConfigService, FilterSettingsComponent, FormulaGeneratorService, JsonConfigEditorComponent, MessagesLocalizationEditorComponent, NUMBER_PRESETS, PERCENTAGE_PRESETS, PRAXIS_FILTER_COMPONENT_METADATA, PRAXIS_TABLE_COMPONENT_METADATA, PraxisFilter, PraxisTable, PraxisTableConfigEditor, PraxisTableToolbar, STRING_PRESETS, TABLE_AI_CAPABILITIES, TABLE_COMPONENT_AI_CAPABILITIES, TASK_PRESETS, TableDefaultsProvider, TableRulesEditorComponent, ToolbarActionsEditorComponent, ValueMappingEditorComponent, VisualFormulaBuilderComponent, buildTableApplyPlan, createTableAuthoringDocument, getActionId, getEnum, getTableCapabilities, normalizeTableAuthoringDocument, parseLegacyOrTableDocument, providePraxisFilterMetadata, providePraxisTableMetadata, serializeTableAuthoringDocument, toCanonicalTableConfig, validateTableAuthoringDocument };
|
|
50209
|
+
export { AnalyticsTableConfigAdapterService, AnalyticsTableContractService, AnalyticsTableStatsApiService, BOOLEAN_PRESETS, BehaviorConfigEditorComponent, CURRENCY_PRESETS, ColumnsConfigEditorComponent, DATE_PRESETS, DataFormatterComponent, DataFormattingService, FORMULA_TEMPLATES, FilterConfigService, FilterSettingsComponent, FormulaGeneratorService, JsonConfigEditorComponent, MessagesLocalizationEditorComponent, NUMBER_PRESETS, PERCENTAGE_PRESETS, PRAXIS_FILTER_COMPONENT_METADATA, PRAXIS_TABLE_COMPONENT_METADATA, PraxisFilter, PraxisTable, PraxisTableConfigEditor, PraxisTableInlineAuthoringEditorComponent, PraxisTableToolbar, STRING_PRESETS, TABLE_AI_CAPABILITIES, TABLE_COMPONENT_AI_CAPABILITIES, TASK_PRESETS, TableDefaultsProvider, TableRulesEditorComponent, ToolbarActionsEditorComponent, ValueMappingEditorComponent, VisualFormulaBuilderComponent, buildTableApplyPlan, createTableAuthoringDocument, getActionId, getEnum, getTableCapabilities, isTableRendererSupportedByRichContentP0, mapTableRendererToRichContentP0, normalizeTableAuthoringDocument, parseLegacyOrTableDocument, providePraxisFilterMetadata, providePraxisTableMetadata, serializeTableAuthoringDocument, toCanonicalTableConfig, validateTableAuthoringDocument };
|