@praxisui/table 1.0.0-beta.15 → 1.0.0-beta.17
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 +8 -0
- package/fesm2022/{praxisui-table-filter-form-dialog-host.component-DI8aWSSJ.mjs → praxisui-table-filter-form-dialog-host.component-Du_IEq0W.mjs} +10 -2
- package/fesm2022/praxisui-table-filter-form-dialog-host.component-Du_IEq0W.mjs.map +1 -0
- package/fesm2022/praxisui-table.mjs +217 -23
- package/fesm2022/praxisui-table.mjs.map +1 -1
- package/index.d.ts +26 -2
- package/package.json +9 -9
- package/fesm2022/praxisui-table-filter-form-dialog-host.component-DI8aWSSJ.mjs.map +0 -1
|
@@ -409,7 +409,7 @@ class PraxisTableToolbar {
|
|
|
409
409
|
</div>
|
|
410
410
|
</div>
|
|
411
411
|
</mat-toolbar>
|
|
412
|
-
`, isInline: true, styles: [":host{display:block}:host(.debug-layout) .praxis-toolbar{outline:2px solid #ff4d4f}:host(.debug-layout) .toolbar-main{outline:1px dashed #3b82f6}:host(.debug-layout) .toolbar-actions{outline:1px dashed #22c55e}.praxis-toolbar{border-radius:12px 12px 0 0;background:transparent;box-shadow:none;padding:8px 12px;min-height:var(--pfx-filter-h, 44px);display:flex;flex-direction:row;align-items:
|
|
412
|
+
`, isInline: true, styles: [":host{display:block}:host(.debug-layout) .praxis-toolbar{outline:2px solid #ff4d4f}:host(.debug-layout) .toolbar-main{outline:1px dashed #3b82f6}:host(.debug-layout) .toolbar-actions{outline:1px dashed #22c55e}.praxis-toolbar{border-radius:12px 12px 0 0;background:transparent;box-shadow:none;padding:8px 12px;min-height:var(--pfx-filter-h, 44px);display:flex;flex-direction:row;align-items:flex-start;gap:8px;flex-wrap:wrap}.toolbar-main{display:flex;align-items:stretch;min-width:0;gap:8px;min-height:var(--pfx-filter-h, 44px);flex:1 0 100%}.toolbar-actions{display:flex;align-items:center;gap:8px;min-height:var(--pfx-filter-h, 44px);flex:0 0 auto}.actions-group{display:flex;align-items:center;gap:8px}.action-btn{height:40px}.pfx-tonal{background:var(--mat-sys-secondary-container, color-mix(in srgb, currentColor 12%, transparent));color:var(--mat-sys-on-secondary-container, currentColor)}.pfx-tonal:hover{background:color-mix(in srgb,var(--mat-sys-secondary-container, currentColor) 90%,black 0%)}.mobile-actions{display:none;align-items:center;gap:8px}.overflow-trigger{height:40px}.spacer{flex:1 1 auto;min-width:8px}.end-actions{display:flex;align-items:center;gap:8px}@media (min-width: 1024px){.toolbar-actions{justify-content:flex-end}.toolbar-actions .spacer{display:none}}@media (max-width: 1023px){.actions-group{display:none}.mobile-actions{display:flex}.toolbar-actions .spacer{flex:1 1 auto}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { 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: "ngmodule", type: MatIconModule }, { kind: "component", type: i4.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "directive", type: PraxisIconDirective, selector: "mat-icon[praxisIcon]", inputs: ["praxisIcon"] }, { kind: "ngmodule", type: MatMenuModule }, { kind: "component", type: i5.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: i5.MatMenuItem, selector: "[mat-menu-item]", inputs: ["role", "disabled", "disableRipple"], exportAs: ["matMenuItem"] }, { kind: "directive", type: i5.MatMenuTrigger, selector: "[mat-menu-trigger-for], [matMenuTriggerFor]", inputs: ["mat-menu-trigger-for", "matMenuTriggerFor", "matMenuTriggerData", "matMenuTriggerRestoreFocus"], outputs: ["menuOpened", "onMenuOpen", "menuClosed", "onMenuClose"], exportAs: ["matMenuTrigger"] }] });
|
|
413
413
|
}
|
|
414
414
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: PraxisTableToolbar, decorators: [{
|
|
415
415
|
type: Component,
|
|
@@ -616,7 +616,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.4", ngImpor
|
|
|
616
616
|
</div>
|
|
617
617
|
</div>
|
|
618
618
|
</mat-toolbar>
|
|
619
|
-
`, host: { '[class.debug-layout]': 'debugLayout' }, styles: [":host{display:block}:host(.debug-layout) .praxis-toolbar{outline:2px solid #ff4d4f}:host(.debug-layout) .toolbar-main{outline:1px dashed #3b82f6}:host(.debug-layout) .toolbar-actions{outline:1px dashed #22c55e}.praxis-toolbar{border-radius:12px 12px 0 0;background:transparent;box-shadow:none;padding:8px 12px;min-height:var(--pfx-filter-h, 44px);display:flex;flex-direction:row;align-items:
|
|
619
|
+
`, host: { '[class.debug-layout]': 'debugLayout' }, styles: [":host{display:block}:host(.debug-layout) .praxis-toolbar{outline:2px solid #ff4d4f}:host(.debug-layout) .toolbar-main{outline:1px dashed #3b82f6}:host(.debug-layout) .toolbar-actions{outline:1px dashed #22c55e}.praxis-toolbar{border-radius:12px 12px 0 0;background:transparent;box-shadow:none;padding:8px 12px;min-height:var(--pfx-filter-h, 44px);display:flex;flex-direction:row;align-items:flex-start;gap:8px;flex-wrap:wrap}.toolbar-main{display:flex;align-items:stretch;min-width:0;gap:8px;min-height:var(--pfx-filter-h, 44px);flex:1 0 100%}.toolbar-actions{display:flex;align-items:center;gap:8px;min-height:var(--pfx-filter-h, 44px);flex:0 0 auto}.actions-group{display:flex;align-items:center;gap:8px}.action-btn{height:40px}.pfx-tonal{background:var(--mat-sys-secondary-container, color-mix(in srgb, currentColor 12%, transparent));color:var(--mat-sys-on-secondary-container, currentColor)}.pfx-tonal:hover{background:color-mix(in srgb,var(--mat-sys-secondary-container, currentColor) 90%,black 0%)}.mobile-actions{display:none;align-items:center;gap:8px}.overflow-trigger{height:40px}.spacer{flex:1 1 auto;min-width:8px}.end-actions{display:flex;align-items:center;gap:8px}@media (min-width: 1024px){.toolbar-actions{justify-content:flex-end}.toolbar-actions .spacer{display:none}}@media (max-width: 1023px){.actions-group{display:none}.mobile-actions{display:flex}.toolbar-actions .spacer{flex:1 1 auto}}\n"] }]
|
|
620
620
|
}], propDecorators: { config: [{
|
|
621
621
|
type: Input
|
|
622
622
|
}], debugLayout: [{
|
|
@@ -9077,6 +9077,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.4", ngImpor
|
|
|
9077
9077
|
class BehaviorConfigEditorComponent {
|
|
9078
9078
|
fb;
|
|
9079
9079
|
config = { columns: [] };
|
|
9080
|
+
// Opcional: informa se há recurso remoto para ajustar defaults
|
|
9081
|
+
resourcePath;
|
|
9080
9082
|
configChange = new EventEmitter();
|
|
9081
9083
|
behaviorChange = new EventEmitter();
|
|
9082
9084
|
behaviorForm;
|
|
@@ -9108,7 +9110,8 @@ class BehaviorConfigEditorComponent {
|
|
|
9108
9110
|
this.arrayToString(pagination.pageSizeOptions || [5, 10, 25, 50]),
|
|
9109
9111
|
],
|
|
9110
9112
|
showFirstLastButtons: [pagination.showFirstLastButtons !== false],
|
|
9111
|
-
|
|
9113
|
+
// Default adaptado: se houver resourcePath e não houver override, usar 'server'
|
|
9114
|
+
paginationStrategy: [this.resourcePath ? 'server' : 'client'], // V2 only
|
|
9112
9115
|
paginationPosition: ['bottom'],
|
|
9113
9116
|
paginationStyle: ['default'],
|
|
9114
9117
|
// Sorting
|
|
@@ -9156,7 +9159,8 @@ class BehaviorConfigEditorComponent {
|
|
|
9156
9159
|
pageSize: behavior.pagination.pageSize || 10,
|
|
9157
9160
|
pageSizeOptions: this.arrayToString(behavior.pagination.pageSizeOptions || [5, 10, 25, 50]),
|
|
9158
9161
|
showFirstLastButtons: behavior.pagination.showFirstLastButtons !== false,
|
|
9159
|
-
|
|
9162
|
+
// Se a estratégia não estiver definida, respeitar contexto de resourcePath
|
|
9163
|
+
paginationStrategy: behavior.pagination.strategy ?? (this.resourcePath ? 'server' : 'client'),
|
|
9160
9164
|
paginationPosition: behavior.pagination.position || 'bottom',
|
|
9161
9165
|
paginationStyle: behavior.pagination.style || 'default',
|
|
9162
9166
|
});
|
|
@@ -9375,7 +9379,7 @@ class BehaviorConfigEditorComponent {
|
|
|
9375
9379
|
.filter((n) => !isNaN(n));
|
|
9376
9380
|
}
|
|
9377
9381
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: BehaviorConfigEditorComponent, deps: [{ token: i1$1.FormBuilder }], target: i0.ɵɵFactoryTarget.Component });
|
|
9378
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.1.4", type: BehaviorConfigEditorComponent, isStandalone: true, selector: "behavior-config-editor", inputs: { config: "config" }, outputs: { configChange: "configChange", behaviorChange: "behaviorChange" }, ngImport: i0, template: `
|
|
9382
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.1.4", type: BehaviorConfigEditorComponent, isStandalone: true, selector: "behavior-config-editor", inputs: { config: "config", resourcePath: "resourcePath" }, outputs: { configChange: "configChange", behaviorChange: "behaviorChange" }, ngImport: i0, template: `
|
|
9379
9383
|
<div class="behavior-config-container">
|
|
9380
9384
|
<form [formGroup]="behaviorForm">
|
|
9381
9385
|
<!-- Paginação -->
|
|
@@ -10259,6 +10263,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.4", ngImpor
|
|
|
10259
10263
|
`, styles: [".behavior-config-container{width:100%;padding:8px}.config-section{padding:16px}.config-fields{display:flex;flex-direction:column;gap:16px;margin-top:16px}.toggle-field{display:flex;align-items:center;gap:8px}.section-icon{margin-right:8px;color:var(--mat-sys-primary)}.info-icon{font-size:18px;width:18px;height:18px;color:var(--mat-sys-on-surface-variant);cursor:help}mat-form-field{width:100%}mat-expansion-panel{margin-bottom:8px;border-radius:8px;overflow:hidden}mat-expansion-panel-header{min-height:56px}mat-panel-description{color:var(--mat-sys-on-surface-variant)}\n"] }]
|
|
10260
10264
|
}], ctorParameters: () => [{ type: i1$1.FormBuilder }], propDecorators: { config: [{
|
|
10261
10265
|
type: Input
|
|
10266
|
+
}], resourcePath: [{
|
|
10267
|
+
type: Input
|
|
10262
10268
|
}], configChange: [{
|
|
10263
10269
|
type: Output
|
|
10264
10270
|
}], behaviorChange: [{
|
|
@@ -14162,6 +14168,7 @@ class FilterSettingsComponent {
|
|
|
14162
14168
|
overlayVariant: this.fb.nonNullable.control('card'),
|
|
14163
14169
|
overlayBackdrop: this.fb.nonNullable.control(true),
|
|
14164
14170
|
advancedOpenMode: this.fb.nonNullable.control('overlay'),
|
|
14171
|
+
showQuickFallback: this.fb.nonNullable.control(false),
|
|
14165
14172
|
});
|
|
14166
14173
|
this.canSave$ = this.form.valueChanges.pipe(map(() => this.form.dirty && this.form.valid), startWith(false));
|
|
14167
14174
|
// Expose state observables expected by SettingsPanel
|
|
@@ -14203,6 +14210,7 @@ class FilterSettingsComponent {
|
|
|
14203
14210
|
overlayVariant: this.injectedData.settings.overlayVariant ?? 'card',
|
|
14204
14211
|
overlayBackdrop: this.injectedData.settings.overlayBackdrop ?? true,
|
|
14205
14212
|
advancedOpenMode: this.injectedData.settings.advancedOpenMode ?? 'overlay',
|
|
14213
|
+
showQuickFallback: this.injectedData.settings.showQuickFallback ?? false,
|
|
14206
14214
|
});
|
|
14207
14215
|
}
|
|
14208
14216
|
if (this.injectedData.configKey) {
|
|
@@ -14421,6 +14429,7 @@ class FilterSettingsComponent {
|
|
|
14421
14429
|
overlayVariant: value.overlayVariant !== 'card' ? value.overlayVariant : undefined,
|
|
14422
14430
|
overlayBackdrop: value.overlayBackdrop !== true ? value.overlayBackdrop : undefined,
|
|
14423
14431
|
advancedOpenMode: value.advancedOpenMode !== 'overlay' ? value.advancedOpenMode : undefined,
|
|
14432
|
+
showQuickFallback: value.showQuickFallback ? true : undefined,
|
|
14424
14433
|
};
|
|
14425
14434
|
}
|
|
14426
14435
|
reset() {
|
|
@@ -14448,6 +14457,7 @@ class FilterSettingsComponent {
|
|
|
14448
14457
|
overlayVariant: this.initialSettings.overlayVariant ?? 'card',
|
|
14449
14458
|
overlayBackdrop: this.initialSettings.overlayBackdrop ?? true,
|
|
14450
14459
|
advancedOpenMode: this.initialSettings.advancedOpenMode ?? 'overlay',
|
|
14460
|
+
showQuickFallback: this.initialSettings.showQuickFallback ?? false,
|
|
14451
14461
|
});
|
|
14452
14462
|
}
|
|
14453
14463
|
clampDebounce(value) {
|
|
@@ -14467,7 +14477,7 @@ class FilterSettingsComponent {
|
|
|
14467
14477
|
return Math.min(4, Math.max(1, v));
|
|
14468
14478
|
}
|
|
14469
14479
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: FilterSettingsComponent, deps: [{ token: i1$1.FormBuilder }], target: i0.ɵɵFactoryTarget.Component });
|
|
14470
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.1.4", type: FilterSettingsComponent, isStandalone: true, selector: "filter-settings", inputs: { metadata: "metadata", settings: "settings", configKey: "configKey" }, outputs: { settingsChange: "settingsChange" }, usesOnChanges: true, ngImport: i0, template: "<form [formGroup]=\"form\">\n <mat-tab-group>\n <mat-tab label=\"Quick Field\">\n <mat-form-field appearance=\"outline\" class=\"full-width\">\n <mat-label>Quick Field</mat-label>\n <mat-select formControlName=\"quickField\">\n <mat-option [value]=\"meta.name\" *ngFor=\"let meta of metadata\">\n {{ meta.label || meta.name }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n </mat-tab>\n <mat-tab label=\"Always Visible\">\n <mat-form-field appearance=\"outline\" class=\"full-width\">\n <mat-label>Always Visible Fields</mat-label>\n <mat-select formControlName=\"alwaysVisibleFields\" multiple>\n <mat-option [value]=\"meta.name\" *ngFor=\"let meta of metadata\">\n {{ meta.label || meta.name }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n <div class=\"options\">\n <p><strong>Order (drag to reorder)</strong></p>\n <div cdkDropList (cdkDropListDropped)=\"dropAlwaysVisible($event)\" class=\"dnd-list\">\n <div class=\"dnd-item\" *ngFor=\"let name of form.controls.alwaysVisibleFields.value; let i = index\" cdkDrag>\n <mat-icon [praxisIcon]=\"'drag_indicator'\"></mat-icon>\n <span>{{ getFieldLabel(name) }}</span>\n </div>\n </div>\n </div>\n </mat-tab>\n <mat-tab label=\"Layout\">\n <div class=\"options\">\n <mat-form-field appearance=\"outline\" class=\"full-width\">\n <mat-label>Min width (px)</mat-label>\n <input matInput type=\"number\" formControlName=\"alwaysMinWidth\" min=\"240\" max=\"480\" />\n </mat-form-field>\n <mat-form-field appearance=\"outline\" class=\"full-width\">\n <mat-label>Columns \u2265600px</mat-label>\n <input matInput type=\"number\" formControlName=\"alwaysColsMd\" min=\"1\" max=\"3\" />\n </mat-form-field>\n <mat-form-field appearance=\"outline\" class=\"full-width\">\n <mat-label>Columns \u2265960px</mat-label>\n <input matInput type=\"number\" formControlName=\"alwaysColsLg\" min=\"1\" max=\"4\" />\n </mat-form-field>\n </div>\n </mat-tab>\n <mat-tab label=\"Booleans\">\n <div class=\"options\">\n <mat-checkbox formControlName=\"placeBooleansInActions\">Place toggles in actions</mat-checkbox>\n <mat-checkbox formControlName=\"showToggleLabels\">Show toggle labels</mat-checkbox>\n </div>\n </mat-tab>\n <mat-tab label=\"Options\">\n <div class=\"options\">\n <mat-form-field appearance=\"outline\" class=\"full-width\">\n <mat-label>Overlay theme</mat-label>\n <mat-select formControlName=\"overlayVariant\">\n <mat-option value=\"card\">Card</mat-option>\n <mat-option value=\"frosted\">Frosted</mat-option>\n </mat-select>\n </mat-form-field>\n <mat-checkbox formControlName=\"overlayBackdrop\">Overlay with backdrop</mat-checkbox>\n <mat-form-field appearance=\"outline\" class=\"full-width\">\n <mat-label>Advanced open mode</mat-label>\n <mat-select formControlName=\"advancedOpenMode\">\n <mat-option value=\"overlay\">Overlay (default)</mat-option>\n <mat-option value=\"modal\">Modal</mat-option>\n <mat-option value=\"drawer\">Drawer (right)</mat-option>\n </mat-select>\n </mat-form-field>\n <mat-form-field appearance=\"outline\" class=\"full-width\">\n <mat-label>Placeholder</mat-label>\n <input matInput formControlName=\"placeholder\" />\n </mat-form-field>\n <mat-checkbox formControlName=\"showAdvanced\"\n >Show Advanced</mat-checkbox\n >\n <mat-checkbox formControlName=\"autoSummary\">Enable auto summary</mat-checkbox>\n <mat-checkbox formControlName=\"confirmTagDelete\">Confirm tag delete</mat-checkbox>\n <div class=\"options\">\n <h4>Tag theme</h4>\n <mat-form-field appearance=\"outline\">\n <mat-label>Tag color</mat-label>\n <mat-select formControlName=\"tagColor\">\n <mat-option value=\"primary\">Primary</mat-option>\n <mat-option value=\"accent\">Accent</mat-option>\n <mat-option value=\"warn\">Warn</mat-option>\n <mat-option value=\"basic\">Basic</mat-option>\n </mat-select>\n </mat-form-field>\n <mat-form-field appearance=\"outline\">\n <mat-label>Tag variant</mat-label>\n <mat-select formControlName=\"tagVariant\">\n <mat-option value=\"filled\">Filled</mat-option>\n <mat-option value=\"outlined\">Outlined</mat-option>\n </mat-select>\n </mat-form-field>\n <mat-form-field appearance=\"outline\">\n <mat-label>Button color</mat-label>\n <mat-select formControlName=\"tagButtonColor\">\n <mat-option value=\"basic\">Basic</mat-option>\n <mat-option value=\"primary\">Primary</mat-option>\n <mat-option value=\"accent\">Accent</mat-option>\n <mat-option value=\"warn\">Warn</mat-option>\n </mat-select>\n </mat-form-field>\n </div>\n <div class=\"options\">\n <h4>Action buttons theme</h4>\n <mat-form-field appearance=\"outline\">\n <mat-label>Buttons color</mat-label>\n <mat-select formControlName=\"actionsButtonColor\">\n <mat-option value=\"basic\">Basic</mat-option>\n <mat-option value=\"primary\">Primary</mat-option>\n <mat-option value=\"accent\">Accent</mat-option>\n <mat-option value=\"warn\">Warn</mat-option>\n </mat-select>\n </mat-form-field>\n <mat-form-field appearance=\"outline\">\n <mat-label>Buttons variant</mat-label>\n <mat-select formControlName=\"actionsVariant\">\n <mat-option value=\"standard\">Standard</mat-option>\n <mat-option value=\"outlined\">Outlined</mat-option>\n </mat-select>\n </mat-form-field>\n </div>\n <div class=\"options\">\n <h4>Theme presets</h4>\n <div class=\"preset-row\">\n <button mat-stroked-button *ngFor=\"let p of presets\" (click)=\"applyPreset(p.key)\">{{ p.label }}</button>\n </div>\n </div>\n </div>\n </mat-tab>\n <mat-tab label=\"i18n\">\n <div class=\"options\">\n <mat-form-field appearance=\"outline\" class=\"full-width\">\n <mat-label>Search placeholder</mat-label>\n <input matInput [value]=\"settings?.placeholder || ''\" disabled />\n <mat-hint>Placeholder do quick (integra com i18n no futuro)</mat-hint>\n </mat-form-field>\n <!-- Espa\u00E7o reservado para i18n granular, se necess\u00E1rio -->\n </div>\n </mat-tab>\n <mat-tab label=\"Tags\" *ngIf=\"configKey\">\n <div class=\"options\">\n <div class=\"tags-header\">\n <span><strong>Saved tags</strong></span>\n <span class=\"spacer\"></span>\n <button mat-stroked-button color=\"warn\" (click)=\"clearTags()\">Clear all</button>\n </div>\n <div class=\"new-tag\">\n <mat-form-field appearance=\"outline\" class=\"full-width\">\n <mat-label>New tag label</mat-label>\n <input matInput [(ngModel)]=\"newTagLabel\" [ngModelOptions]=\"{standalone: true}\" />\n </mat-form-field>\n <mat-form-field appearance=\"outline\" class=\"full-width\">\n <mat-label>Patch (JSON, optional)</mat-label>\n <textarea matInput rows=\"3\" [(ngModel)]=\"newTagPatchText\" [ngModelOptions]=\"{standalone: true}\"></textarea>\n </mat-form-field>\n <div>\n <button mat-stroked-button color=\"primary\" (click)=\"addTag()\">Add</button>\n <button mat-stroked-button (click)=\"addTagFromCurrent()\" *ngIf=\"hasCurrentDto()\">Add from current filters</button>\n </div>\n </div>\n <mat-list>\n <mat-list-item *ngFor=\"let t of tags; index as i\">\n <span matListItemTitle>{{ t.label }}</span>\n <span matListItemLine>{{ t.id }}</span>\n <button mat-icon-button (click)=\"removeTag(i)\" matTooltip=\"Delete\">\n <mat-icon [praxisIcon]=\"'delete'\"></mat-icon>\n </button>\n <button mat-icon-button (click)=\"renameTagPrompt(i)\" matTooltip=\"Rename\">\n <mat-icon [praxisIcon]=\"'edit'\"></mat-icon>\n </button>\n </mat-list-item>\n </mat-list>\n <mat-form-field appearance=\"outline\" class=\"full-width\">\n <mat-label>Import/Export JSON</mat-label>\n <textarea matInput rows=\"6\" [(ngModel)]=\"exportJson\" [ngModelOptions]=\"{standalone: true}\"></textarea>\n </mat-form-field>\n <div>\n <button mat-stroked-button color=\"primary\" (click)=\"importTags()\">Import</button>\n <button mat-stroked-button (click)=\"loadTags()\">Reload</button>\n <button mat-stroked-button (click)=\"saveTags()\">Save</button>\n </div>\n </div>\n </mat-tab>\n <mat-tab label=\"Behavior\">\n <div class=\"options\">\n <mat-form-field appearance=\"outline\" class=\"full-width\">\n <mat-label>Mode</mat-label>\n <mat-select formControlName=\"mode\">\n <mat-option value=\"auto\">Auto</mat-option>\n <mat-option value=\"filter\">Filter</mat-option>\n <mat-option value=\"card\">Card</mat-option>\n </mat-select>\n </mat-form-field>\n <mat-checkbox formControlName=\"allowSaveTags\"\n >Allow Save Tags</mat-checkbox\n >\n <mat-checkbox formControlName=\"debugLayout\">Show debug layout</mat-checkbox>\n </div>\n </mat-tab>\n <mat-tab label=\"Advanced\">\n <div class=\"options\">\n <mat-form-field appearance=\"outline\" class=\"full-width\">\n <mat-label>Change Debounce (ms)</mat-label>\n <input\n matInput\n type=\"number\"\n formControlName=\"changeDebounceMs\"\n min=\"100\"\n max=\"1000\"\n />\n <mat-error *ngIf=\"form.controls.changeDebounceMs.invalid\">\n Value must be between 100 and 1000\n </mat-error>\n </mat-form-field>\n <div class=\"actions\">\n <button mat-stroked-button color=\"warn\" (click)=\"resetPreferences()\">\n <mat-icon [praxisIcon]=\"'restart_alt'\"></mat-icon>\n Reset filter preferences\n </button>\n </div>\n </div>\n </mat-tab>\n </mat-tab-group>\n</form>\n", styles: [".full-width{width:100%}.options{display:flex;flex-direction:column;gap:1rem;padding:1rem 0}.dnd-list{display:flex;flex-direction:column;gap:6px}.dnd-item{display:flex;align-items:center;gap:8px;padding:6px 8px;border:1px dashed rgba(255,255,255,.15);border-radius:6px;cursor:grab}.dnd-item mat-icon{opacity:.8}.tags-header{display:flex;align-items:center;gap:8px}.spacer{flex:1 1 auto}.new-tag{display:flex;flex-direction:column;gap:8px}.preset-row{display:flex;flex-wrap:wrap;gap:8px}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { 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.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { 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.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: MatTabsModule }, { kind: "component", type: i4$1.MatTab, selector: "mat-tab", inputs: ["disabled", "label", "aria-label", "aria-labelledby", "labelClass", "bodyClass", "id"], exportAs: ["matTab"] }, { kind: "component", type: i4$1.MatTabGroup, selector: "mat-tab-group", inputs: ["color", "fitInkBarToContent", "mat-stretch-tabs", "mat-align-tabs", "dynamicHeight", "selectedIndex", "headerPosition", "animationDuration", "contentTabIndex", "disablePagination", "disableRipple", "preserveContent", "backgroundColor", "aria-label", "aria-labelledby"], outputs: ["selectedIndexChange", "focusChange", "animationDone", "selectedTabChange"], exportAs: ["matTabGroup"] }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i3$1.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i3$1.MatLabel, selector: "mat-label" }, { kind: "directive", type: i3$1.MatHint, selector: "mat-hint", inputs: ["align", "id"] }, { kind: "directive", type: i3$1.MatError, selector: "mat-error, [matError]", inputs: ["id"] }, { 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: MatInputModule }, { kind: "directive", type: i6.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: 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: MatListModule }, { kind: "component", type: i8$1.MatList, selector: "mat-list", exportAs: ["matList"] }, { kind: "component", type: i8$1.MatListItem, selector: "mat-list-item, a[mat-list-item], button[mat-list-item]", inputs: ["activated"], exportAs: ["matListItem"] }, { kind: "directive", type: i8$1.MatListItemLine, selector: "[matListItemLine]" }, { kind: "directive", type: i8$1.MatListItemTitle, selector: "[matListItemTitle]" }, { 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: "ngmodule", type: MatIconModule }, { kind: "component", type: i4.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "directive", type: PraxisIconDirective, selector: "mat-icon[praxisIcon]", inputs: ["praxisIcon"] }, { kind: "ngmodule", type: DragDropModule }, { kind: "directive", type: i17.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: i17.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"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
14480
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.1.4", type: FilterSettingsComponent, isStandalone: true, selector: "filter-settings", inputs: { metadata: "metadata", settings: "settings", configKey: "configKey" }, outputs: { settingsChange: "settingsChange" }, usesOnChanges: true, ngImport: i0, template: "<form [formGroup]=\"form\">\n <mat-tab-group>\n <mat-tab label=\"Campo R\u00E1pido\">\n <mat-form-field appearance=\"outline\" class=\"full-width\">\n <mat-label>Quick Field</mat-label>\n <mat-select formControlName=\"quickField\">\n <mat-option [value]=\"meta.name\" *ngFor=\"let meta of metadata\">\n {{ meta.label || meta.name }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n </mat-tab>\n <mat-tab label=\"Sempre Vis\u00EDveis\">\n <mat-form-field appearance=\"outline\" class=\"full-width\">\n <mat-label>Always Visible Fields</mat-label>\n <mat-select formControlName=\"alwaysVisibleFields\" multiple>\n <mat-option [value]=\"meta.name\" *ngFor=\"let meta of metadata\">\n {{ meta.label || meta.name }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n <div class=\"options\">\n <p><strong>Ordem (arraste para reordenar)</strong></p>\n <div cdkDropList (cdkDropListDropped)=\"dropAlwaysVisible($event)\" class=\"dnd-list\">\n <div class=\"dnd-item\" *ngFor=\"let name of form.controls.alwaysVisibleFields.value; let i = index\" cdkDrag>\n <mat-icon [praxisIcon]=\"'drag_indicator'\"></mat-icon>\n <span>{{ getFieldLabel(name) }}</span>\n </div>\n </div>\n </div>\n </mat-tab>\n <mat-tab label=\"Layout\">\n <div class=\"options\">\n <mat-form-field appearance=\"outline\" class=\"full-width\">\n <mat-label>Largura m\u00EDnima (px)</mat-label>\n <input matInput type=\"number\" formControlName=\"alwaysMinWidth\" min=\"240\" max=\"480\" />\n </mat-form-field>\n <mat-form-field appearance=\"outline\" class=\"full-width\">\n <mat-label>Colunas \u2265600px</mat-label>\n <input matInput type=\"number\" formControlName=\"alwaysColsMd\" min=\"1\" max=\"3\" />\n </mat-form-field>\n <mat-form-field appearance=\"outline\" class=\"full-width\">\n <mat-label>Colunas \u2265960px</mat-label>\n <input matInput type=\"number\" formControlName=\"alwaysColsLg\" min=\"1\" max=\"4\" />\n </mat-form-field>\n </div>\n </mat-tab>\n <mat-tab label=\"Alternadores\">\n <div class=\"options\">\n <mat-checkbox formControlName=\"placeBooleansInActions\">Colocar alternadores na \u00E1rea de a\u00E7\u00F5es</mat-checkbox>\n <mat-checkbox formControlName=\"showToggleLabels\">Mostrar r\u00F3tulos dos alternadores</mat-checkbox>\n </div>\n </mat-tab>\n <mat-tab label=\"Op\u00E7\u00F5es\">\n <div class=\"options\">\n <mat-form-field appearance=\"outline\" class=\"full-width\">\n <mat-label>Tema do overlay</mat-label>\n <mat-select formControlName=\"overlayVariant\">\n <mat-option value=\"card\">Card</mat-option>\n <mat-option value=\"frosted\">Frosted</mat-option>\n </mat-select>\n </mat-form-field>\n <mat-checkbox formControlName=\"overlayBackdrop\">Overlay com backdrop</mat-checkbox>\n <mat-form-field appearance=\"outline\" class=\"full-width\">\n <mat-label>Modo de abertura do Avan\u00E7ado</mat-label>\n <mat-select formControlName=\"advancedOpenMode\">\n <mat-option value=\"overlay\">Overlay (default)</mat-option>\n <mat-option value=\"modal\">Modal</mat-option>\n <mat-option value=\"drawer\">Drawer (right)</mat-option>\n </mat-select>\n </mat-form-field>\n <mat-checkbox formControlName=\"showQuickFallback\">Mostrar \"Buscar\" quando n\u00E3o houver Quick</mat-checkbox>\n <mat-form-field appearance=\"outline\" class=\"full-width\">\n <mat-label>Placeholder da busca</mat-label>\n <input matInput formControlName=\"placeholder\" placeholder=\"Ex.: Buscar por nome\" />\n </mat-form-field>\n <mat-checkbox formControlName=\"showAdvanced\"\n >Mostrar Avan\u00E7ado</mat-checkbox\n >\n <mat-checkbox formControlName=\"autoSummary\">Ativar resumo autom\u00E1tico</mat-checkbox>\n <mat-checkbox formControlName=\"confirmTagDelete\">Confirmar exclus\u00E3o de atalho</mat-checkbox>\n <div class=\"options\">\n <h4>Tema das tags</h4>\n <mat-form-field appearance=\"outline\">\n <mat-label>Cor da tag</mat-label>\n <mat-select formControlName=\"tagColor\">\n <mat-option value=\"primary\">Primary</mat-option>\n <mat-option value=\"accent\">Accent</mat-option>\n <mat-option value=\"warn\">Warn</mat-option>\n <mat-option value=\"basic\">Basic</mat-option>\n </mat-select>\n </mat-form-field>\n <mat-form-field appearance=\"outline\">\n <mat-label>Variante da tag</mat-label>\n <mat-select formControlName=\"tagVariant\">\n <mat-option value=\"filled\">Filled</mat-option>\n <mat-option value=\"outlined\">Outlined</mat-option>\n </mat-select>\n </mat-form-field>\n <mat-form-field appearance=\"outline\">\n <mat-label>Cor dos bot\u00F5es</mat-label>\n <mat-select formControlName=\"tagButtonColor\">\n <mat-option value=\"basic\">Basic</mat-option>\n <mat-option value=\"primary\">Primary</mat-option>\n <mat-option value=\"accent\">Accent</mat-option>\n <mat-option value=\"warn\">Warn</mat-option>\n </mat-select>\n </mat-form-field>\n </div>\n <div class=\"options\">\n <h4>Tema dos bot\u00F5es de a\u00E7\u00E3o</h4>\n <mat-form-field appearance=\"outline\">\n <mat-label>Cor dos bot\u00F5es</mat-label>\n <mat-select formControlName=\"actionsButtonColor\">\n <mat-option value=\"basic\">Basic</mat-option>\n <mat-option value=\"primary\">Primary</mat-option>\n <mat-option value=\"accent\">Accent</mat-option>\n <mat-option value=\"warn\">Warn</mat-option>\n </mat-select>\n </mat-form-field>\n <mat-form-field appearance=\"outline\">\n <mat-label>Variante dos bot\u00F5es</mat-label>\n <mat-select formControlName=\"actionsVariant\">\n <mat-option value=\"standard\">Standard</mat-option>\n <mat-option value=\"outlined\">Outlined</mat-option>\n </mat-select>\n </mat-form-field>\n </div>\n <div class=\"options\">\n <h4>Predefini\u00E7\u00F5es de tema</h4>\n <div class=\"preset-row\">\n <button mat-stroked-button *ngFor=\"let p of presets\" (click)=\"applyPreset(p.key)\">{{ p.label }}</button>\n </div>\n </div>\n </div>\n </mat-tab>\n <mat-tab label=\"i18n\">\n <div class=\"options\">\n <mat-form-field appearance=\"outline\" class=\"full-width\">\n <mat-label>Placeholder da busca</mat-label>\n <input matInput [value]=\"settings?.placeholder || ''\" disabled />\n <mat-hint>Placeholder do Campo R\u00E1pido (integra com i18n futuramente)</mat-hint>\n </mat-form-field>\n <!-- Espa\u00E7o reservado para i18n granular, se necess\u00E1rio -->\n </div>\n </mat-tab>\n <mat-tab label=\"Atalhos\" *ngIf=\"configKey\">\n <div class=\"options\">\n <div class=\"tags-header\">\n <span><strong>Atalhos salvos</strong></span>\n <span class=\"spacer\"></span>\n <button mat-stroked-button color=\"warn\" (click)=\"clearTags()\">Apagar tudo</button>\n </div>\n <div class=\"new-tag\">\n <mat-form-field appearance=\"outline\" class=\"full-width\">\n <mat-label>R\u00F3tulo do novo atalho</mat-label>\n <input matInput [(ngModel)]=\"newTagLabel\" [ngModelOptions]=\"{standalone: true}\" />\n </mat-form-field>\n <mat-form-field appearance=\"outline\" class=\"full-width\">\n <mat-label>Patch (JSON, opcional)</mat-label>\n <textarea matInput rows=\"3\" [(ngModel)]=\"newTagPatchText\" [ngModelOptions]=\"{standalone: true}\"></textarea>\n </mat-form-field>\n <div>\n <button mat-stroked-button color=\"primary\" (click)=\"addTag()\">Adicionar</button>\n <button mat-stroked-button (click)=\"addTagFromCurrent()\" *ngIf=\"hasCurrentDto()\">Adicionar a partir dos filtros atuais</button>\n </div>\n </div>\n <mat-list>\n <mat-list-item *ngFor=\"let t of tags; index as i\">\n <span matListItemTitle>{{ t.label }}</span>\n <span matListItemLine>{{ t.id }}</span>\n <button mat-icon-button (click)=\"removeTag(i)\" matTooltip=\"Delete\">\n <mat-icon [praxisIcon]=\"'delete'\"></mat-icon>\n </button>\n <button mat-icon-button (click)=\"renameTagPrompt(i)\" matTooltip=\"Rename\">\n <mat-icon [praxisIcon]=\"'edit'\"></mat-icon>\n </button>\n </mat-list-item>\n </mat-list>\n <mat-form-field appearance=\"outline\" class=\"full-width\">\n <mat-label>Importar/Exportar JSON</mat-label>\n <textarea matInput rows=\"6\" [(ngModel)]=\"exportJson\" [ngModelOptions]=\"{standalone: true}\"></textarea>\n </mat-form-field>\n <div>\n <button mat-stroked-button color=\"primary\" (click)=\"importTags()\">Importar</button>\n <button mat-stroked-button (click)=\"loadTags()\">Recarregar</button>\n <button mat-stroked-button (click)=\"saveTags()\">Salvar</button>\n </div>\n </div>\n </mat-tab>\n <mat-tab label=\"Comportamento\">\n <div class=\"options\">\n <mat-form-field appearance=\"outline\" class=\"full-width\">\n <mat-label>Modo</mat-label>\n <mat-select formControlName=\"mode\">\n <mat-option value=\"auto\">Auto</mat-option>\n <mat-option value=\"filter\">Filter</mat-option>\n <mat-option value=\"card\">Card</mat-option>\n </mat-select>\n </mat-form-field>\n <mat-checkbox formControlName=\"allowSaveTags\"\n >Permitir salvar atalhos</mat-checkbox\n >\n <mat-checkbox formControlName=\"debugLayout\">Mostrar depura\u00E7\u00E3o de layout</mat-checkbox>\n </div>\n </mat-tab>\n <mat-tab label=\"Avan\u00E7ado\">\n <div class=\"options\">\n <mat-form-field appearance=\"outline\" class=\"full-width\">\n <mat-label>Debounce de altera\u00E7\u00F5es (ms)</mat-label>\n <input\n matInput\n type=\"number\"\n formControlName=\"changeDebounceMs\"\n min=\"100\"\n max=\"1000\"\n />\n <mat-error *ngIf=\"form.controls.changeDebounceMs.invalid\">\n Value must be between 100 and 1000\n </mat-error>\n </mat-form-field>\n <div class=\"actions\">\n <button mat-stroked-button color=\"warn\" (click)=\"resetPreferences()\">\n <mat-icon [praxisIcon]=\"'restart_alt'\"></mat-icon>\n Redefinir prefer\u00EAncias do filtro\n </button>\n </div>\n </div>\n </mat-tab>\n </mat-tab-group>\n</form>\n", styles: [".full-width{width:100%}.options{display:flex;flex-direction:column;gap:1rem;padding:1rem 0}.dnd-list{display:flex;flex-direction:column;gap:6px}.dnd-item{display:flex;align-items:center;gap:8px;padding:6px 8px;border:1px dashed rgba(255,255,255,.15);border-radius:6px;cursor:grab}.dnd-item mat-icon{opacity:.8}.tags-header{display:flex;align-items:center;gap:8px}.spacer{flex:1 1 auto}.new-tag{display:flex;flex-direction:column;gap:8px}.preset-row{display:flex;flex-wrap:wrap;gap:8px}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { 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.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { 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.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: MatTabsModule }, { kind: "component", type: i4$1.MatTab, selector: "mat-tab", inputs: ["disabled", "label", "aria-label", "aria-labelledby", "labelClass", "bodyClass", "id"], exportAs: ["matTab"] }, { kind: "component", type: i4$1.MatTabGroup, selector: "mat-tab-group", inputs: ["color", "fitInkBarToContent", "mat-stretch-tabs", "mat-align-tabs", "dynamicHeight", "selectedIndex", "headerPosition", "animationDuration", "contentTabIndex", "disablePagination", "disableRipple", "preserveContent", "backgroundColor", "aria-label", "aria-labelledby"], outputs: ["selectedIndexChange", "focusChange", "animationDone", "selectedTabChange"], exportAs: ["matTabGroup"] }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i3$1.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i3$1.MatLabel, selector: "mat-label" }, { kind: "directive", type: i3$1.MatHint, selector: "mat-hint", inputs: ["align", "id"] }, { kind: "directive", type: i3$1.MatError, selector: "mat-error, [matError]", inputs: ["id"] }, { 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: MatInputModule }, { kind: "directive", type: i6.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: 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: MatListModule }, { kind: "component", type: i8$1.MatList, selector: "mat-list", exportAs: ["matList"] }, { kind: "component", type: i8$1.MatListItem, selector: "mat-list-item, a[mat-list-item], button[mat-list-item]", inputs: ["activated"], exportAs: ["matListItem"] }, { kind: "directive", type: i8$1.MatListItemLine, selector: "[matListItemLine]" }, { kind: "directive", type: i8$1.MatListItemTitle, selector: "[matListItemTitle]" }, { 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: "ngmodule", type: MatIconModule }, { kind: "component", type: i4.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "directive", type: PraxisIconDirective, selector: "mat-icon[praxisIcon]", inputs: ["praxisIcon"] }, { kind: "ngmodule", type: DragDropModule }, { kind: "directive", type: i17.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: i17.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"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
14471
14481
|
}
|
|
14472
14482
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: FilterSettingsComponent, decorators: [{
|
|
14473
14483
|
type: Component,
|
|
@@ -14485,7 +14495,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.4", ngImpor
|
|
|
14485
14495
|
MatIconModule,
|
|
14486
14496
|
PraxisIconDirective,
|
|
14487
14497
|
DragDropModule,
|
|
14488
|
-
], template: "<form [formGroup]=\"form\">\n <mat-tab-group>\n <mat-tab label=\"Quick Field\">\n <mat-form-field appearance=\"outline\" class=\"full-width\">\n <mat-label>Quick Field</mat-label>\n <mat-select formControlName=\"quickField\">\n <mat-option [value]=\"meta.name\" *ngFor=\"let meta of metadata\">\n {{ meta.label || meta.name }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n </mat-tab>\n <mat-tab label=\"Always Visible\">\n <mat-form-field appearance=\"outline\" class=\"full-width\">\n <mat-label>Always Visible Fields</mat-label>\n <mat-select formControlName=\"alwaysVisibleFields\" multiple>\n <mat-option [value]=\"meta.name\" *ngFor=\"let meta of metadata\">\n {{ meta.label || meta.name }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n <div class=\"options\">\n <p><strong>Order (drag to reorder)</strong></p>\n <div cdkDropList (cdkDropListDropped)=\"dropAlwaysVisible($event)\" class=\"dnd-list\">\n <div class=\"dnd-item\" *ngFor=\"let name of form.controls.alwaysVisibleFields.value; let i = index\" cdkDrag>\n <mat-icon [praxisIcon]=\"'drag_indicator'\"></mat-icon>\n <span>{{ getFieldLabel(name) }}</span>\n </div>\n </div>\n </div>\n </mat-tab>\n <mat-tab label=\"Layout\">\n <div class=\"options\">\n <mat-form-field appearance=\"outline\" class=\"full-width\">\n <mat-label>Min width (px)</mat-label>\n <input matInput type=\"number\" formControlName=\"alwaysMinWidth\" min=\"240\" max=\"480\" />\n </mat-form-field>\n <mat-form-field appearance=\"outline\" class=\"full-width\">\n <mat-label>Columns \u2265600px</mat-label>\n <input matInput type=\"number\" formControlName=\"alwaysColsMd\" min=\"1\" max=\"3\" />\n </mat-form-field>\n <mat-form-field appearance=\"outline\" class=\"full-width\">\n <mat-label>Columns \u2265960px</mat-label>\n <input matInput type=\"number\" formControlName=\"alwaysColsLg\" min=\"1\" max=\"4\" />\n </mat-form-field>\n </div>\n </mat-tab>\n <mat-tab label=\"Booleans\">\n <div class=\"options\">\n <mat-checkbox formControlName=\"placeBooleansInActions\">Place toggles in actions</mat-checkbox>\n <mat-checkbox formControlName=\"showToggleLabels\">Show toggle labels</mat-checkbox>\n </div>\n </mat-tab>\n <mat-tab label=\"Options\">\n <div class=\"options\">\n <mat-form-field appearance=\"outline\" class=\"full-width\">\n <mat-label>Overlay theme</mat-label>\n <mat-select formControlName=\"overlayVariant\">\n <mat-option value=\"card\">Card</mat-option>\n <mat-option value=\"frosted\">Frosted</mat-option>\n </mat-select>\n </mat-form-field>\n <mat-checkbox formControlName=\"overlayBackdrop\">Overlay with backdrop</mat-checkbox>\n <mat-form-field appearance=\"outline\" class=\"full-width\">\n <mat-label>Advanced open mode</mat-label>\n <mat-select formControlName=\"advancedOpenMode\">\n <mat-option value=\"overlay\">Overlay (default)</mat-option>\n <mat-option value=\"modal\">Modal</mat-option>\n <mat-option value=\"drawer\">Drawer (right)</mat-option>\n </mat-select>\n </mat-form-field>\n <mat-form-field appearance=\"outline\" class=\"full-width\">\n <mat-label>Placeholder</mat-label>\n <input matInput formControlName=\"placeholder\" />\n </mat-form-field>\n <mat-checkbox formControlName=\"showAdvanced\"\n >Show Advanced</mat-checkbox\n >\n <mat-checkbox formControlName=\"autoSummary\">Enable auto summary</mat-checkbox>\n <mat-checkbox formControlName=\"confirmTagDelete\">Confirm tag delete</mat-checkbox>\n <div class=\"options\">\n <h4>Tag theme</h4>\n <mat-form-field appearance=\"outline\">\n <mat-label>Tag color</mat-label>\n <mat-select formControlName=\"tagColor\">\n <mat-option value=\"primary\">Primary</mat-option>\n <mat-option value=\"accent\">Accent</mat-option>\n <mat-option value=\"warn\">Warn</mat-option>\n <mat-option value=\"basic\">Basic</mat-option>\n </mat-select>\n </mat-form-field>\n <mat-form-field appearance=\"outline\">\n <mat-label>Tag variant</mat-label>\n <mat-select formControlName=\"tagVariant\">\n <mat-option value=\"filled\">Filled</mat-option>\n <mat-option value=\"outlined\">Outlined</mat-option>\n </mat-select>\n </mat-form-field>\n <mat-form-field appearance=\"outline\">\n <mat-label>Button color</mat-label>\n <mat-select formControlName=\"tagButtonColor\">\n <mat-option value=\"basic\">Basic</mat-option>\n <mat-option value=\"primary\">Primary</mat-option>\n <mat-option value=\"accent\">Accent</mat-option>\n <mat-option value=\"warn\">Warn</mat-option>\n </mat-select>\n </mat-form-field>\n </div>\n <div class=\"options\">\n <h4>Action buttons theme</h4>\n <mat-form-field appearance=\"outline\">\n <mat-label>Buttons color</mat-label>\n <mat-select formControlName=\"actionsButtonColor\">\n <mat-option value=\"basic\">Basic</mat-option>\n <mat-option value=\"primary\">Primary</mat-option>\n <mat-option value=\"accent\">Accent</mat-option>\n <mat-option value=\"warn\">Warn</mat-option>\n </mat-select>\n </mat-form-field>\n <mat-form-field appearance=\"outline\">\n <mat-label>Buttons variant</mat-label>\n <mat-select formControlName=\"actionsVariant\">\n <mat-option value=\"standard\">Standard</mat-option>\n <mat-option value=\"outlined\">Outlined</mat-option>\n </mat-select>\n </mat-form-field>\n </div>\n <div class=\"options\">\n <h4>Theme presets</h4>\n <div class=\"preset-row\">\n <button mat-stroked-button *ngFor=\"let p of presets\" (click)=\"applyPreset(p.key)\">{{ p.label }}</button>\n </div>\n </div>\n </div>\n </mat-tab>\n <mat-tab label=\"i18n\">\n <div class=\"options\">\n <mat-form-field appearance=\"outline\" class=\"full-width\">\n <mat-label>Search placeholder</mat-label>\n <input matInput [value]=\"settings?.placeholder || ''\" disabled />\n <mat-hint>Placeholder do quick (integra com i18n no futuro)</mat-hint>\n </mat-form-field>\n <!-- Espa\u00E7o reservado para i18n granular, se necess\u00E1rio -->\n </div>\n </mat-tab>\n <mat-tab label=\"Tags\" *ngIf=\"configKey\">\n <div class=\"options\">\n <div class=\"tags-header\">\n <span><strong>Saved tags</strong></span>\n <span class=\"spacer\"></span>\n <button mat-stroked-button color=\"warn\" (click)=\"clearTags()\">Clear all</button>\n </div>\n <div class=\"new-tag\">\n <mat-form-field appearance=\"outline\" class=\"full-width\">\n <mat-label>New tag label</mat-label>\n <input matInput [(ngModel)]=\"newTagLabel\" [ngModelOptions]=\"{standalone: true}\" />\n </mat-form-field>\n <mat-form-field appearance=\"outline\" class=\"full-width\">\n <mat-label>Patch (JSON, optional)</mat-label>\n <textarea matInput rows=\"3\" [(ngModel)]=\"newTagPatchText\" [ngModelOptions]=\"{standalone: true}\"></textarea>\n </mat-form-field>\n <div>\n <button mat-stroked-button color=\"primary\" (click)=\"addTag()\">Add</button>\n <button mat-stroked-button (click)=\"addTagFromCurrent()\" *ngIf=\"hasCurrentDto()\">Add from current filters</button>\n </div>\n </div>\n <mat-list>\n <mat-list-item *ngFor=\"let t of tags; index as i\">\n <span matListItemTitle>{{ t.label }}</span>\n <span matListItemLine>{{ t.id }}</span>\n <button mat-icon-button (click)=\"removeTag(i)\" matTooltip=\"Delete\">\n <mat-icon [praxisIcon]=\"'delete'\"></mat-icon>\n </button>\n <button mat-icon-button (click)=\"renameTagPrompt(i)\" matTooltip=\"Rename\">\n <mat-icon [praxisIcon]=\"'edit'\"></mat-icon>\n </button>\n </mat-list-item>\n </mat-list>\n <mat-form-field appearance=\"outline\" class=\"full-width\">\n <mat-label>Import/Export JSON</mat-label>\n <textarea matInput rows=\"6\" [(ngModel)]=\"exportJson\" [ngModelOptions]=\"{standalone: true}\"></textarea>\n </mat-form-field>\n <div>\n <button mat-stroked-button color=\"primary\" (click)=\"importTags()\">Import</button>\n <button mat-stroked-button (click)=\"loadTags()\">Reload</button>\n <button mat-stroked-button (click)=\"saveTags()\">Save</button>\n </div>\n </div>\n </mat-tab>\n <mat-tab label=\"Behavior\">\n <div class=\"options\">\n <mat-form-field appearance=\"outline\" class=\"full-width\">\n <mat-label>Mode</mat-label>\n <mat-select formControlName=\"mode\">\n <mat-option value=\"auto\">Auto</mat-option>\n <mat-option value=\"filter\">Filter</mat-option>\n <mat-option value=\"card\">Card</mat-option>\n </mat-select>\n </mat-form-field>\n <mat-checkbox formControlName=\"allowSaveTags\"\n >Allow Save Tags</mat-checkbox\n >\n <mat-checkbox formControlName=\"debugLayout\">Show debug layout</mat-checkbox>\n </div>\n </mat-tab>\n <mat-tab label=\"Advanced\">\n <div class=\"options\">\n <mat-form-field appearance=\"outline\" class=\"full-width\">\n <mat-label>Change Debounce (ms)</mat-label>\n <input\n matInput\n type=\"number\"\n formControlName=\"changeDebounceMs\"\n min=\"100\"\n max=\"1000\"\n />\n <mat-error *ngIf=\"form.controls.changeDebounceMs.invalid\">\n Value must be between 100 and 1000\n </mat-error>\n </mat-form-field>\n <div class=\"actions\">\n <button mat-stroked-button color=\"warn\" (click)=\"resetPreferences()\">\n <mat-icon [praxisIcon]=\"'restart_alt'\"></mat-icon>\n Reset filter preferences\n </button>\n </div>\n </div>\n </mat-tab>\n </mat-tab-group>\n</form>\n", styles: [".full-width{width:100%}.options{display:flex;flex-direction:column;gap:1rem;padding:1rem 0}.dnd-list{display:flex;flex-direction:column;gap:6px}.dnd-item{display:flex;align-items:center;gap:8px;padding:6px 8px;border:1px dashed rgba(255,255,255,.15);border-radius:6px;cursor:grab}.dnd-item mat-icon{opacity:.8}.tags-header{display:flex;align-items:center;gap:8px}.spacer{flex:1 1 auto}.new-tag{display:flex;flex-direction:column;gap:8px}.preset-row{display:flex;flex-wrap:wrap;gap:8px}\n"] }]
|
|
14498
|
+
], template: "<form [formGroup]=\"form\">\n <mat-tab-group>\n <mat-tab label=\"Campo R\u00E1pido\">\n <mat-form-field appearance=\"outline\" class=\"full-width\">\n <mat-label>Quick Field</mat-label>\n <mat-select formControlName=\"quickField\">\n <mat-option [value]=\"meta.name\" *ngFor=\"let meta of metadata\">\n {{ meta.label || meta.name }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n </mat-tab>\n <mat-tab label=\"Sempre Vis\u00EDveis\">\n <mat-form-field appearance=\"outline\" class=\"full-width\">\n <mat-label>Always Visible Fields</mat-label>\n <mat-select formControlName=\"alwaysVisibleFields\" multiple>\n <mat-option [value]=\"meta.name\" *ngFor=\"let meta of metadata\">\n {{ meta.label || meta.name }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n <div class=\"options\">\n <p><strong>Ordem (arraste para reordenar)</strong></p>\n <div cdkDropList (cdkDropListDropped)=\"dropAlwaysVisible($event)\" class=\"dnd-list\">\n <div class=\"dnd-item\" *ngFor=\"let name of form.controls.alwaysVisibleFields.value; let i = index\" cdkDrag>\n <mat-icon [praxisIcon]=\"'drag_indicator'\"></mat-icon>\n <span>{{ getFieldLabel(name) }}</span>\n </div>\n </div>\n </div>\n </mat-tab>\n <mat-tab label=\"Layout\">\n <div class=\"options\">\n <mat-form-field appearance=\"outline\" class=\"full-width\">\n <mat-label>Largura m\u00EDnima (px)</mat-label>\n <input matInput type=\"number\" formControlName=\"alwaysMinWidth\" min=\"240\" max=\"480\" />\n </mat-form-field>\n <mat-form-field appearance=\"outline\" class=\"full-width\">\n <mat-label>Colunas \u2265600px</mat-label>\n <input matInput type=\"number\" formControlName=\"alwaysColsMd\" min=\"1\" max=\"3\" />\n </mat-form-field>\n <mat-form-field appearance=\"outline\" class=\"full-width\">\n <mat-label>Colunas \u2265960px</mat-label>\n <input matInput type=\"number\" formControlName=\"alwaysColsLg\" min=\"1\" max=\"4\" />\n </mat-form-field>\n </div>\n </mat-tab>\n <mat-tab label=\"Alternadores\">\n <div class=\"options\">\n <mat-checkbox formControlName=\"placeBooleansInActions\">Colocar alternadores na \u00E1rea de a\u00E7\u00F5es</mat-checkbox>\n <mat-checkbox formControlName=\"showToggleLabels\">Mostrar r\u00F3tulos dos alternadores</mat-checkbox>\n </div>\n </mat-tab>\n <mat-tab label=\"Op\u00E7\u00F5es\">\n <div class=\"options\">\n <mat-form-field appearance=\"outline\" class=\"full-width\">\n <mat-label>Tema do overlay</mat-label>\n <mat-select formControlName=\"overlayVariant\">\n <mat-option value=\"card\">Card</mat-option>\n <mat-option value=\"frosted\">Frosted</mat-option>\n </mat-select>\n </mat-form-field>\n <mat-checkbox formControlName=\"overlayBackdrop\">Overlay com backdrop</mat-checkbox>\n <mat-form-field appearance=\"outline\" class=\"full-width\">\n <mat-label>Modo de abertura do Avan\u00E7ado</mat-label>\n <mat-select formControlName=\"advancedOpenMode\">\n <mat-option value=\"overlay\">Overlay (default)</mat-option>\n <mat-option value=\"modal\">Modal</mat-option>\n <mat-option value=\"drawer\">Drawer (right)</mat-option>\n </mat-select>\n </mat-form-field>\n <mat-checkbox formControlName=\"showQuickFallback\">Mostrar \"Buscar\" quando n\u00E3o houver Quick</mat-checkbox>\n <mat-form-field appearance=\"outline\" class=\"full-width\">\n <mat-label>Placeholder da busca</mat-label>\n <input matInput formControlName=\"placeholder\" placeholder=\"Ex.: Buscar por nome\" />\n </mat-form-field>\n <mat-checkbox formControlName=\"showAdvanced\"\n >Mostrar Avan\u00E7ado</mat-checkbox\n >\n <mat-checkbox formControlName=\"autoSummary\">Ativar resumo autom\u00E1tico</mat-checkbox>\n <mat-checkbox formControlName=\"confirmTagDelete\">Confirmar exclus\u00E3o de atalho</mat-checkbox>\n <div class=\"options\">\n <h4>Tema das tags</h4>\n <mat-form-field appearance=\"outline\">\n <mat-label>Cor da tag</mat-label>\n <mat-select formControlName=\"tagColor\">\n <mat-option value=\"primary\">Primary</mat-option>\n <mat-option value=\"accent\">Accent</mat-option>\n <mat-option value=\"warn\">Warn</mat-option>\n <mat-option value=\"basic\">Basic</mat-option>\n </mat-select>\n </mat-form-field>\n <mat-form-field appearance=\"outline\">\n <mat-label>Variante da tag</mat-label>\n <mat-select formControlName=\"tagVariant\">\n <mat-option value=\"filled\">Filled</mat-option>\n <mat-option value=\"outlined\">Outlined</mat-option>\n </mat-select>\n </mat-form-field>\n <mat-form-field appearance=\"outline\">\n <mat-label>Cor dos bot\u00F5es</mat-label>\n <mat-select formControlName=\"tagButtonColor\">\n <mat-option value=\"basic\">Basic</mat-option>\n <mat-option value=\"primary\">Primary</mat-option>\n <mat-option value=\"accent\">Accent</mat-option>\n <mat-option value=\"warn\">Warn</mat-option>\n </mat-select>\n </mat-form-field>\n </div>\n <div class=\"options\">\n <h4>Tema dos bot\u00F5es de a\u00E7\u00E3o</h4>\n <mat-form-field appearance=\"outline\">\n <mat-label>Cor dos bot\u00F5es</mat-label>\n <mat-select formControlName=\"actionsButtonColor\">\n <mat-option value=\"basic\">Basic</mat-option>\n <mat-option value=\"primary\">Primary</mat-option>\n <mat-option value=\"accent\">Accent</mat-option>\n <mat-option value=\"warn\">Warn</mat-option>\n </mat-select>\n </mat-form-field>\n <mat-form-field appearance=\"outline\">\n <mat-label>Variante dos bot\u00F5es</mat-label>\n <mat-select formControlName=\"actionsVariant\">\n <mat-option value=\"standard\">Standard</mat-option>\n <mat-option value=\"outlined\">Outlined</mat-option>\n </mat-select>\n </mat-form-field>\n </div>\n <div class=\"options\">\n <h4>Predefini\u00E7\u00F5es de tema</h4>\n <div class=\"preset-row\">\n <button mat-stroked-button *ngFor=\"let p of presets\" (click)=\"applyPreset(p.key)\">{{ p.label }}</button>\n </div>\n </div>\n </div>\n </mat-tab>\n <mat-tab label=\"i18n\">\n <div class=\"options\">\n <mat-form-field appearance=\"outline\" class=\"full-width\">\n <mat-label>Placeholder da busca</mat-label>\n <input matInput [value]=\"settings?.placeholder || ''\" disabled />\n <mat-hint>Placeholder do Campo R\u00E1pido (integra com i18n futuramente)</mat-hint>\n </mat-form-field>\n <!-- Espa\u00E7o reservado para i18n granular, se necess\u00E1rio -->\n </div>\n </mat-tab>\n <mat-tab label=\"Atalhos\" *ngIf=\"configKey\">\n <div class=\"options\">\n <div class=\"tags-header\">\n <span><strong>Atalhos salvos</strong></span>\n <span class=\"spacer\"></span>\n <button mat-stroked-button color=\"warn\" (click)=\"clearTags()\">Apagar tudo</button>\n </div>\n <div class=\"new-tag\">\n <mat-form-field appearance=\"outline\" class=\"full-width\">\n <mat-label>R\u00F3tulo do novo atalho</mat-label>\n <input matInput [(ngModel)]=\"newTagLabel\" [ngModelOptions]=\"{standalone: true}\" />\n </mat-form-field>\n <mat-form-field appearance=\"outline\" class=\"full-width\">\n <mat-label>Patch (JSON, opcional)</mat-label>\n <textarea matInput rows=\"3\" [(ngModel)]=\"newTagPatchText\" [ngModelOptions]=\"{standalone: true}\"></textarea>\n </mat-form-field>\n <div>\n <button mat-stroked-button color=\"primary\" (click)=\"addTag()\">Adicionar</button>\n <button mat-stroked-button (click)=\"addTagFromCurrent()\" *ngIf=\"hasCurrentDto()\">Adicionar a partir dos filtros atuais</button>\n </div>\n </div>\n <mat-list>\n <mat-list-item *ngFor=\"let t of tags; index as i\">\n <span matListItemTitle>{{ t.label }}</span>\n <span matListItemLine>{{ t.id }}</span>\n <button mat-icon-button (click)=\"removeTag(i)\" matTooltip=\"Delete\">\n <mat-icon [praxisIcon]=\"'delete'\"></mat-icon>\n </button>\n <button mat-icon-button (click)=\"renameTagPrompt(i)\" matTooltip=\"Rename\">\n <mat-icon [praxisIcon]=\"'edit'\"></mat-icon>\n </button>\n </mat-list-item>\n </mat-list>\n <mat-form-field appearance=\"outline\" class=\"full-width\">\n <mat-label>Importar/Exportar JSON</mat-label>\n <textarea matInput rows=\"6\" [(ngModel)]=\"exportJson\" [ngModelOptions]=\"{standalone: true}\"></textarea>\n </mat-form-field>\n <div>\n <button mat-stroked-button color=\"primary\" (click)=\"importTags()\">Importar</button>\n <button mat-stroked-button (click)=\"loadTags()\">Recarregar</button>\n <button mat-stroked-button (click)=\"saveTags()\">Salvar</button>\n </div>\n </div>\n </mat-tab>\n <mat-tab label=\"Comportamento\">\n <div class=\"options\">\n <mat-form-field appearance=\"outline\" class=\"full-width\">\n <mat-label>Modo</mat-label>\n <mat-select formControlName=\"mode\">\n <mat-option value=\"auto\">Auto</mat-option>\n <mat-option value=\"filter\">Filter</mat-option>\n <mat-option value=\"card\">Card</mat-option>\n </mat-select>\n </mat-form-field>\n <mat-checkbox formControlName=\"allowSaveTags\"\n >Permitir salvar atalhos</mat-checkbox\n >\n <mat-checkbox formControlName=\"debugLayout\">Mostrar depura\u00E7\u00E3o de layout</mat-checkbox>\n </div>\n </mat-tab>\n <mat-tab label=\"Avan\u00E7ado\">\n <div class=\"options\">\n <mat-form-field appearance=\"outline\" class=\"full-width\">\n <mat-label>Debounce de altera\u00E7\u00F5es (ms)</mat-label>\n <input\n matInput\n type=\"number\"\n formControlName=\"changeDebounceMs\"\n min=\"100\"\n max=\"1000\"\n />\n <mat-error *ngIf=\"form.controls.changeDebounceMs.invalid\">\n Value must be between 100 and 1000\n </mat-error>\n </mat-form-field>\n <div class=\"actions\">\n <button mat-stroked-button color=\"warn\" (click)=\"resetPreferences()\">\n <mat-icon [praxisIcon]=\"'restart_alt'\"></mat-icon>\n Redefinir prefer\u00EAncias do filtro\n </button>\n </div>\n </div>\n </mat-tab>\n </mat-tab-group>\n</form>\n", styles: [".full-width{width:100%}.options{display:flex;flex-direction:column;gap:1rem;padding:1rem 0}.dnd-list{display:flex;flex-direction:column;gap:6px}.dnd-item{display:flex;align-items:center;gap:8px;padding:6px 8px;border:1px dashed rgba(255,255,255,.15);border-radius:6px;cursor:grab}.dnd-item mat-icon{opacity:.8}.tags-header{display:flex;align-items:center;gap:8px}.spacer{flex:1 1 auto}.new-tag{display:flex;flex-direction:column;gap:8px}.preset-row{display:flex;flex-wrap:wrap;gap:8px}\n"] }]
|
|
14489
14499
|
}], ctorParameters: () => [{ type: i1$1.FormBuilder }], propDecorators: { metadata: [{
|
|
14490
14500
|
type: Input
|
|
14491
14501
|
}], settings: [{
|
|
@@ -19452,7 +19462,7 @@ class PraxisTableConfigEditor {
|
|
|
19452
19462
|
this.isBusy$.complete();
|
|
19453
19463
|
}
|
|
19454
19464
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: PraxisTableConfigEditor, deps: [{ token: i0.ChangeDetectorRef }, { token: i1$3.TableConfigService }, { token: SETTINGS_PANEL_DATA }, { token: SETTINGS_PANEL_REF, optional: true }], target: i0.ɵɵFactoryTarget.Component });
|
|
19455
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.1.4", type: PraxisTableConfigEditor, isStandalone: true, selector: "praxis-table-config-editor", providers: [TableConfigService], viewQueries: [{ propertyName: "behaviorEditor", first: true, predicate: BehaviorConfigEditorComponent, descendants: true }, { propertyName: "crudEditorSetter", first: true, predicate: ["crudEditorRef"], descendants: true }], ngImport: i0, template: " <mat-tab-group class=\"config-tabs\" [(selectedIndex)]=\"activeSectionIndex\">\n <mat-tab *ngFor=\"let section of sections\">\n <ng-template mat-tab-label>\n <mat-icon *ngIf=\"section.icon\" [praxisIcon]=\"section.icon\"></mat-icon>\n <span>{{ section.label }}</span>\n </ng-template>\n <div class=\"tab-content\">\n <ng-container [ngSwitch]=\"section.id\">\n <div *ngSwitchCase=\"'connect'\" style=\"display:grid; gap:12px; padding: 8px; grid-template-columns: 1fr 240px; align-items: start;\">\n <mat-form-field appearance=\"outline\">\n <mat-label>Recurso</mat-label>\n <input matInput [(ngModel)]=\"resourcePath\" (ngModelChange)=\"onResourcePathChange($event)\" placeholder=\"ex.: employees\" />\n <mat-icon matSuffix>link</mat-icon>\n </mat-form-field>\n <mat-form-field appearance=\"outline\">\n <mat-label>Chave prim\u00E1ria</mat-label>\n <input matInput [(ngModel)]=\"idField\" (ngModelChange)=\"onIdFieldChange($event)\" placeholder=\"ex.: id, uuid, codigo\" />\n <mat-icon matSuffix>fingerprint</mat-icon>\n </mat-form-field>\n <small style=\"opacity:.75\">Defina o recurso da API e, se necess\u00E1rio, a chave prim\u00E1ria</small>\n\n <!-- Diverg\u00EAncia: idField -->\n <div *ngIf=\"idFieldDiverges\" style=\"grid-column: 1 / -1; padding: 8px 12px; border-radius: 6px; background: #fff4e5; color: #8a4b00; display:flex; align-items:center; gap: 8px;\">\n <mat-icon>warning</mat-icon>\n <div style=\"flex:1;\">\n A chave prim\u00E1ria no servidor diverge da configura\u00E7\u00E3o atual.\n <span style=\"opacity:.85\">(config: {{ idField || 'id' }} | servidor: {{ serverIdField || 'id' }})</span>\n </div>\n <button mat-stroked-button color=\"primary\" type=\"button\" (click)=\"onReconcileIdField()\">Reconciliar</button>\n </div>\n\n <!-- Diverg\u00EAncia: serverHash -->\n <div *ngIf=\"schemaHashDiverges\" style=\"grid-column: 1 / -1; padding: 8px 12px; border-radius: 6px; background: #e6f4ff; color: #0b5aaa; display:flex; align-items:center; gap: 8px;\">\n <mat-icon>info</mat-icon>\n <div style=\"flex:1;\">\n O schema no servidor foi atualizado desde a \u00FAltima sincroniza\u00E7\u00E3o.\n </div>\n <button mat-stroked-button color=\"primary\" type=\"button\" (click)=\"onAcceptServerHash()\">Atualizar metadados</button>\n </div>\n </div>\n\n <div *ngSwitchCase=\"'overview'\" class=\"overview-grid\">\n <div class=\"overview-row\">\n <mat-form-field appearance=\"outline\" class=\"hs-field\">\n <mat-label>Scroll Horizontal</mat-label>\n <mat-select [(ngModel)]=\"horizontalScroll\" (ngModelChange)=\"onHorizontalScrollChange($event)\">\n <mat-option value=\"auto\">Auto (padr\u00E3o)</mat-option>\n <mat-option value=\"wrap\">Wrap (quebrar linhas)</mat-option>\n <mat-option value=\"none\">Host controla</mat-option>\n </mat-select>\n </mat-form-field>\n <div class=\"help small\">Controla como a tabela lida com largura horizontal e barra de rolagem.</div>\n </div>\n <behavior-config-editor\n [config]=\"editedConfig\"\n (configChange)=\"onBehaviorConfigChange($event)\"\n (behaviorChange)=\"onBehaviorChange($event)\"\n ></behavior-config-editor>\n </div>\n\n <columns-config-editor\n *ngSwitchCase=\"'columns'\"\n [config]=\"editedConfig\"\n (configChange)=\"onColumnsConfigChange($event)\"\n (columnChange)=\"onColumnChange($event)\"\n ></columns-config-editor>\n\n <table-rules-editor\n *ngSwitchCase=\"'rules'\"\n [config]=\"editedConfig\"\n [resourcePath]=\"resourcePath\"\n (configChange)=\"onRulesConfigChange($event)\"\n ></table-rules-editor>\n\n <header-appearance-editor\n *ngSwitchCase=\"'header'\"\n [config]=\"editedConfig\"\n (configChange)=\"onColumnsConfigChange($event)\"\n ></header-appearance-editor>\n\n <toolbar-actions-editor\n *ngSwitchCase=\"'toolbar'\"\n [config]=\"editedConfig\"\n (configChange)=\"onToolbarActionsConfigChange($event)\"\n (toolbarActionsChange)=\"onToolbarActionsChange($event)\"\n ></toolbar-actions-editor>\n\n <!-- Aba extra para integra\u00E7\u00F5es CRUD (vis\u00EDvel quando em contexto CRUD) -->\n <crud-integration-editor\n #crudEditorRef\n *ngSwitchCase=\"'crud'\"\n [tableId]=\"crudContext?.tableId || 'default'\"\n [crudContext]=\"crudContext\"\n ></crud-integration-editor>\n\n <filter-settings\n *ngSwitchCase=\"'filters'\"\n [metadata]=\"columnMetas\"\n [settings]=\"\n editedConfig.behavior?.filtering?.advancedFilters?.settings\n \"\n (settingsChange)=\"onFilterSettingsChange($event)\"\n ></filter-settings>\n\n <messages-localization-editor\n *ngSwitchCase=\"'messages'\"\n [config]=\"editedConfig\"\n (configChange)=\"onMessagesLocalizationConfigChange($event)\"\n (messagesLocalizationChange)=\"\n onMessagesLocalizationChange($event)\n \"\n ></messages-localization-editor>\n\n <confirm-dialog-appearance-editor\n *ngSwitchCase=\"'dialogs'\"\n [config]=\"editedConfig\"\n (configChange)=\"onJsonConfigChange($event)\"\n ></confirm-dialog-appearance-editor>\n\n\n <json-config-editor\n *ngSwitchCase=\"'json'\"\n [config]=\"editedConfig\"\n (configChange)=\"onJsonConfigChange($event)\"\n (editorEvent)=\"onJsonEditorEvent($event)\"\n ></json-config-editor>\n </ng-container>\n </div>\n </mat-tab>\n </mat-tab-group>\n<div class=\"config-editor-status\" *ngIf=\"statusMessage\">\n <span\n class=\"status-text\"\n [class.error]=\"hasErrors\"\n [class.success]=\"hasSuccess\"\n >{{ statusMessage }}</span\n >\n</div>\n", styles: ["@charset \"UTF-8\";.config-tabs{flex:1 1 auto;display:flex;flex-direction:column}.config-tabs .mat-mdc-tab{min-width:120px}.config-tabs .mat-mdc-tab-body-wrapper,.config-tabs .mat-mdc-tab-group-container{flex:1 1 auto;min-height:0}.config-tabs .mat-mdc-tab-body-content{height:100%;min-height:0;overflow:visible}.tab-content{display:flex;flex-direction:column;flex:1 1 auto;min-height:0;padding:8px 8px 56px;box-sizing:border-box;overflow:visible}.overview-grid{display:grid;grid-template-columns:1fr;gap:12px}.overview-grid .overview-row{display:grid;grid-template-columns:280px 1fr;align-items:end;gap:12px}.overview-grid .overview-row .help.small{opacity:.75;font-size:12px}.educational-card{margin-bottom:24px;background:var(--mat-sys-surface-container-low);border-left:4px solid var(--mat-sys-primary);flex-shrink:0}.config-editor-status{padding:12px 16px;margin-top:auto;border-top:1px solid rgba(0,0,0,.12);background:var(--mat-sys-surface-container);flex-shrink:0;position:relative}.status-text{font-size:.875rem;line-height:1.2}.status-text.error{color:var(--mat-sys-error)}.status-text.success{color:var(--mat-sys-primary)}@media (max-width: 768px){.tab-content{padding:8px}.config-editor-status{padding:12px 16px}:host{display:flex;flex-direction:column;flex:1 1 auto;min-height:0}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1.NgSwitch, selector: "[ngSwitch]", inputs: ["ngSwitch"] }, { kind: "directive", type: i1.NgSwitchCase, selector: "[ngSwitchCase]", inputs: ["ngSwitchCase"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i4.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatTabsModule }, { kind: "directive", type: i4$1.MatTabLabel, selector: "[mat-tab-label], [matTabLabel]" }, { kind: "component", type: i4$1.MatTab, selector: "mat-tab", inputs: ["disabled", "label", "aria-label", "aria-labelledby", "labelClass", "bodyClass", "id"], exportAs: ["matTab"] }, { kind: "component", type: i4$1.MatTabGroup, selector: "mat-tab-group", inputs: ["color", "fitInkBarToContent", "mat-stretch-tabs", "mat-align-tabs", "dynamicHeight", "selectedIndex", "headerPosition", "animationDuration", "contentTabIndex", "disablePagination", "disableRipple", "preserveContent", "backgroundColor", "aria-label", "aria-labelledby"], outputs: ["selectedIndexChange", "focusChange", "animationDone", "selectedTabChange"], exportAs: ["matTabGroup"] }, { 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.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i3$1.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i3$1.MatLabel, selector: "mat-label" }, { kind: "directive", type: i3$1.MatSuffix, selector: "[matSuffix], [matIconSuffix], [matTextSuffix]", inputs: ["matTextSuffix"] }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i6.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: "directive", type: PraxisIconDirective, selector: "mat-icon[praxisIcon]", inputs: ["praxisIcon"] }, { kind: "component", type: JsonConfigEditorComponent, selector: "json-config-editor", inputs: ["config"], outputs: ["configChange", "validationChange", "editorEvent"] }, { kind: "component", type: ColumnsConfigEditorComponent, selector: "columns-config-editor", inputs: ["config"], outputs: ["configChange", "columnChange"] }, { kind: "component", type: BehaviorConfigEditorComponent, selector: "behavior-config-editor", inputs: ["config"], outputs: ["configChange", "behaviorChange"] }, { kind: "component", type: HeaderAppearanceEditorComponent, selector: "header-appearance-editor", inputs: ["config"], outputs: ["configChange"] }, { kind: "component", type: ToolbarActionsEditorComponent, selector: "toolbar-actions-editor", inputs: ["config"], outputs: ["configChange", "toolbarActionsChange"] }, { kind: "component", type: MessagesLocalizationEditorComponent, selector: "messages-localization-editor", inputs: ["config"], outputs: ["configChange", "messagesLocalizationChange"] }, { kind: "component", type: FilterSettingsComponent, selector: "filter-settings", inputs: ["metadata", "settings", "configKey"], outputs: ["settingsChange"] }, { kind: "component", type: CrudIntegrationEditorComponent, selector: "crud-integration-editor", inputs: ["tableId", "crudContext"] }, { kind: "component", type: ConfirmDialogAppearanceEditorComponent, selector: "confirm-dialog-appearance-editor", inputs: ["config"], outputs: ["configChange"] }, { kind: "component", type: TableRulesEditorComponent, selector: "table-rules-editor", inputs: ["config", "resourcePath", "fields", "i18nRules", "debugLogs", "debugLevel"], outputs: ["configChange"] }] });
|
|
19465
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.1.4", type: PraxisTableConfigEditor, isStandalone: true, selector: "praxis-table-config-editor", providers: [TableConfigService], viewQueries: [{ propertyName: "behaviorEditor", first: true, predicate: BehaviorConfigEditorComponent, descendants: true }, { propertyName: "crudEditorSetter", first: true, predicate: ["crudEditorRef"], descendants: true }], ngImport: i0, template: " <mat-tab-group class=\"config-tabs\" [(selectedIndex)]=\"activeSectionIndex\">\n <mat-tab *ngFor=\"let section of sections\">\n <ng-template mat-tab-label>\n <mat-icon *ngIf=\"section.icon\" [praxisIcon]=\"section.icon\"></mat-icon>\n <span>{{ section.label }}</span>\n </ng-template>\n <div class=\"tab-content\">\n <ng-container [ngSwitch]=\"section.id\">\n <div *ngSwitchCase=\"'connect'\" style=\"display:grid; gap:12px; padding: 8px; grid-template-columns: 1fr 240px; align-items: start;\">\n <mat-form-field appearance=\"outline\">\n <mat-label>Recurso</mat-label>\n <input matInput [(ngModel)]=\"resourcePath\" (ngModelChange)=\"onResourcePathChange($event)\" placeholder=\"ex.: employees\" />\n <mat-icon matSuffix>link</mat-icon>\n </mat-form-field>\n <mat-form-field appearance=\"outline\">\n <mat-label>Chave prim\u00E1ria</mat-label>\n <input matInput [(ngModel)]=\"idField\" (ngModelChange)=\"onIdFieldChange($event)\" placeholder=\"ex.: id, uuid, codigo\" />\n <mat-icon matSuffix>fingerprint</mat-icon>\n </mat-form-field>\n <small style=\"opacity:.75\">Defina o recurso da API e, se necess\u00E1rio, a chave prim\u00E1ria</small>\n\n <!-- Diverg\u00EAncia: idField -->\n <div *ngIf=\"idFieldDiverges\" style=\"grid-column: 1 / -1; padding: 8px 12px; border-radius: 6px; background: #fff4e5; color: #8a4b00; display:flex; align-items:center; gap: 8px;\">\n <mat-icon>warning</mat-icon>\n <div style=\"flex:1;\">\n A chave prim\u00E1ria no servidor diverge da configura\u00E7\u00E3o atual.\n <span style=\"opacity:.85\">(config: {{ idField || 'id' }} | servidor: {{ serverIdField || 'id' }})</span>\n </div>\n <button mat-stroked-button color=\"primary\" type=\"button\" (click)=\"onReconcileIdField()\">Reconciliar</button>\n </div>\n\n <!-- Diverg\u00EAncia: serverHash -->\n <div *ngIf=\"schemaHashDiverges\" style=\"grid-column: 1 / -1; padding: 8px 12px; border-radius: 6px; background: #e6f4ff; color: #0b5aaa; display:flex; align-items:center; gap: 8px;\">\n <mat-icon>info</mat-icon>\n <div style=\"flex:1;\">\n O schema no servidor foi atualizado desde a \u00FAltima sincroniza\u00E7\u00E3o.\n </div>\n <button mat-stroked-button color=\"primary\" type=\"button\" (click)=\"onAcceptServerHash()\">Atualizar metadados</button>\n </div>\n </div>\n\n <div *ngSwitchCase=\"'overview'\" class=\"overview-grid\">\n <div class=\"overview-row\">\n <mat-form-field appearance=\"outline\" class=\"hs-field\">\n <mat-label>Scroll Horizontal</mat-label>\n <mat-select [(ngModel)]=\"horizontalScroll\" (ngModelChange)=\"onHorizontalScrollChange($event)\">\n <mat-option value=\"auto\">Auto (padr\u00E3o)</mat-option>\n <mat-option value=\"wrap\">Wrap (quebrar linhas)</mat-option>\n <mat-option value=\"none\">Host controla</mat-option>\n </mat-select>\n </mat-form-field>\n <div class=\"help small\">Controla como a tabela lida com largura horizontal e barra de rolagem.</div>\n </div>\n <behavior-config-editor\n [config]=\"editedConfig\"\n [resourcePath]=\"resourcePath\"\n (configChange)=\"onBehaviorConfigChange($event)\"\n (behaviorChange)=\"onBehaviorChange($event)\"\n ></behavior-config-editor>\n </div>\n\n <columns-config-editor\n *ngSwitchCase=\"'columns'\"\n [config]=\"editedConfig\"\n (configChange)=\"onColumnsConfigChange($event)\"\n (columnChange)=\"onColumnChange($event)\"\n ></columns-config-editor>\n\n <table-rules-editor\n *ngSwitchCase=\"'rules'\"\n [config]=\"editedConfig\"\n [resourcePath]=\"resourcePath\"\n (configChange)=\"onRulesConfigChange($event)\"\n ></table-rules-editor>\n\n <header-appearance-editor\n *ngSwitchCase=\"'header'\"\n [config]=\"editedConfig\"\n (configChange)=\"onColumnsConfigChange($event)\"\n ></header-appearance-editor>\n\n <toolbar-actions-editor\n *ngSwitchCase=\"'toolbar'\"\n [config]=\"editedConfig\"\n (configChange)=\"onToolbarActionsConfigChange($event)\"\n (toolbarActionsChange)=\"onToolbarActionsChange($event)\"\n ></toolbar-actions-editor>\n\n <!-- Aba extra para integra\u00E7\u00F5es CRUD (vis\u00EDvel quando em contexto CRUD) -->\n <crud-integration-editor\n #crudEditorRef\n *ngSwitchCase=\"'crud'\"\n [tableId]=\"crudContext?.tableId || 'default'\"\n [crudContext]=\"crudContext\"\n ></crud-integration-editor>\n\n <filter-settings\n *ngSwitchCase=\"'filters'\"\n [metadata]=\"columnMetas\"\n [settings]=\"\n editedConfig.behavior?.filtering?.advancedFilters?.settings\n \"\n (settingsChange)=\"onFilterSettingsChange($event)\"\n ></filter-settings>\n\n <messages-localization-editor\n *ngSwitchCase=\"'messages'\"\n [config]=\"editedConfig\"\n (configChange)=\"onMessagesLocalizationConfigChange($event)\"\n (messagesLocalizationChange)=\"\n onMessagesLocalizationChange($event)\n \"\n ></messages-localization-editor>\n\n <confirm-dialog-appearance-editor\n *ngSwitchCase=\"'dialogs'\"\n [config]=\"editedConfig\"\n (configChange)=\"onJsonConfigChange($event)\"\n ></confirm-dialog-appearance-editor>\n\n\n <json-config-editor\n *ngSwitchCase=\"'json'\"\n [config]=\"editedConfig\"\n (configChange)=\"onJsonConfigChange($event)\"\n (editorEvent)=\"onJsonEditorEvent($event)\"\n ></json-config-editor>\n </ng-container>\n </div>\n </mat-tab>\n </mat-tab-group>\n<div class=\"config-editor-status\" *ngIf=\"statusMessage\">\n <span\n class=\"status-text\"\n [class.error]=\"hasErrors\"\n [class.success]=\"hasSuccess\"\n >{{ statusMessage }}</span\n >\n</div>\n", styles: ["@charset \"UTF-8\";.config-tabs{flex:1 1 auto;display:flex;flex-direction:column}.config-tabs .mat-mdc-tab{min-width:120px}.config-tabs .mat-mdc-tab-body-wrapper,.config-tabs .mat-mdc-tab-group-container{flex:1 1 auto;min-height:0}.config-tabs .mat-mdc-tab-body-content{height:100%;min-height:0;overflow:visible}.tab-content{display:flex;flex-direction:column;flex:1 1 auto;min-height:0;padding:8px 8px 56px;box-sizing:border-box;overflow:visible}.overview-grid{display:grid;grid-template-columns:1fr;gap:12px}.overview-grid .overview-row{display:grid;grid-template-columns:280px 1fr;align-items:end;gap:12px}.overview-grid .overview-row .help.small{opacity:.75;font-size:12px}.educational-card{margin-bottom:24px;background:var(--mat-sys-surface-container-low);border-left:4px solid var(--mat-sys-primary);flex-shrink:0}.config-editor-status{padding:12px 16px;margin-top:auto;border-top:1px solid rgba(0,0,0,.12);background:var(--mat-sys-surface-container);flex-shrink:0;position:relative}.status-text{font-size:.875rem;line-height:1.2}.status-text.error{color:var(--mat-sys-error)}.status-text.success{color:var(--mat-sys-primary)}@media (max-width: 768px){.tab-content{padding:8px}.config-editor-status{padding:12px 16px}:host{display:flex;flex-direction:column;flex:1 1 auto;min-height:0}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1.NgSwitch, selector: "[ngSwitch]", inputs: ["ngSwitch"] }, { kind: "directive", type: i1.NgSwitchCase, selector: "[ngSwitchCase]", inputs: ["ngSwitchCase"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i4.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatTabsModule }, { kind: "directive", type: i4$1.MatTabLabel, selector: "[mat-tab-label], [matTabLabel]" }, { kind: "component", type: i4$1.MatTab, selector: "mat-tab", inputs: ["disabled", "label", "aria-label", "aria-labelledby", "labelClass", "bodyClass", "id"], exportAs: ["matTab"] }, { kind: "component", type: i4$1.MatTabGroup, selector: "mat-tab-group", inputs: ["color", "fitInkBarToContent", "mat-stretch-tabs", "mat-align-tabs", "dynamicHeight", "selectedIndex", "headerPosition", "animationDuration", "contentTabIndex", "disablePagination", "disableRipple", "preserveContent", "backgroundColor", "aria-label", "aria-labelledby"], outputs: ["selectedIndexChange", "focusChange", "animationDone", "selectedTabChange"], exportAs: ["matTabGroup"] }, { 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.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i3$1.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i3$1.MatLabel, selector: "mat-label" }, { kind: "directive", type: i3$1.MatSuffix, selector: "[matSuffix], [matIconSuffix], [matTextSuffix]", inputs: ["matTextSuffix"] }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i6.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: "directive", type: PraxisIconDirective, selector: "mat-icon[praxisIcon]", inputs: ["praxisIcon"] }, { kind: "component", type: JsonConfigEditorComponent, selector: "json-config-editor", inputs: ["config"], outputs: ["configChange", "validationChange", "editorEvent"] }, { kind: "component", type: ColumnsConfigEditorComponent, selector: "columns-config-editor", inputs: ["config"], outputs: ["configChange", "columnChange"] }, { kind: "component", type: BehaviorConfigEditorComponent, selector: "behavior-config-editor", inputs: ["config", "resourcePath"], outputs: ["configChange", "behaviorChange"] }, { kind: "component", type: HeaderAppearanceEditorComponent, selector: "header-appearance-editor", inputs: ["config"], outputs: ["configChange"] }, { kind: "component", type: ToolbarActionsEditorComponent, selector: "toolbar-actions-editor", inputs: ["config"], outputs: ["configChange", "toolbarActionsChange"] }, { kind: "component", type: MessagesLocalizationEditorComponent, selector: "messages-localization-editor", inputs: ["config"], outputs: ["configChange", "messagesLocalizationChange"] }, { kind: "component", type: FilterSettingsComponent, selector: "filter-settings", inputs: ["metadata", "settings", "configKey"], outputs: ["settingsChange"] }, { kind: "component", type: CrudIntegrationEditorComponent, selector: "crud-integration-editor", inputs: ["tableId", "crudContext"] }, { kind: "component", type: ConfirmDialogAppearanceEditorComponent, selector: "confirm-dialog-appearance-editor", inputs: ["config"], outputs: ["configChange"] }, { kind: "component", type: TableRulesEditorComponent, selector: "table-rules-editor", inputs: ["config", "resourcePath", "fields", "i18nRules", "debugLogs", "debugLevel"], outputs: ["configChange"] }] });
|
|
19456
19466
|
}
|
|
19457
19467
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: PraxisTableConfigEditor, decorators: [{
|
|
19458
19468
|
type: Component,
|
|
@@ -19475,7 +19485,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.4", ngImpor
|
|
|
19475
19485
|
CrudIntegrationEditorComponent,
|
|
19476
19486
|
ConfirmDialogAppearanceEditorComponent,
|
|
19477
19487
|
TableRulesEditorComponent,
|
|
19478
|
-
], providers: [TableConfigService], template: " <mat-tab-group class=\"config-tabs\" [(selectedIndex)]=\"activeSectionIndex\">\n <mat-tab *ngFor=\"let section of sections\">\n <ng-template mat-tab-label>\n <mat-icon *ngIf=\"section.icon\" [praxisIcon]=\"section.icon\"></mat-icon>\n <span>{{ section.label }}</span>\n </ng-template>\n <div class=\"tab-content\">\n <ng-container [ngSwitch]=\"section.id\">\n <div *ngSwitchCase=\"'connect'\" style=\"display:grid; gap:12px; padding: 8px; grid-template-columns: 1fr 240px; align-items: start;\">\n <mat-form-field appearance=\"outline\">\n <mat-label>Recurso</mat-label>\n <input matInput [(ngModel)]=\"resourcePath\" (ngModelChange)=\"onResourcePathChange($event)\" placeholder=\"ex.: employees\" />\n <mat-icon matSuffix>link</mat-icon>\n </mat-form-field>\n <mat-form-field appearance=\"outline\">\n <mat-label>Chave prim\u00E1ria</mat-label>\n <input matInput [(ngModel)]=\"idField\" (ngModelChange)=\"onIdFieldChange($event)\" placeholder=\"ex.: id, uuid, codigo\" />\n <mat-icon matSuffix>fingerprint</mat-icon>\n </mat-form-field>\n <small style=\"opacity:.75\">Defina o recurso da API e, se necess\u00E1rio, a chave prim\u00E1ria</small>\n\n <!-- Diverg\u00EAncia: idField -->\n <div *ngIf=\"idFieldDiverges\" style=\"grid-column: 1 / -1; padding: 8px 12px; border-radius: 6px; background: #fff4e5; color: #8a4b00; display:flex; align-items:center; gap: 8px;\">\n <mat-icon>warning</mat-icon>\n <div style=\"flex:1;\">\n A chave prim\u00E1ria no servidor diverge da configura\u00E7\u00E3o atual.\n <span style=\"opacity:.85\">(config: {{ idField || 'id' }} | servidor: {{ serverIdField || 'id' }})</span>\n </div>\n <button mat-stroked-button color=\"primary\" type=\"button\" (click)=\"onReconcileIdField()\">Reconciliar</button>\n </div>\n\n <!-- Diverg\u00EAncia: serverHash -->\n <div *ngIf=\"schemaHashDiverges\" style=\"grid-column: 1 / -1; padding: 8px 12px; border-radius: 6px; background: #e6f4ff; color: #0b5aaa; display:flex; align-items:center; gap: 8px;\">\n <mat-icon>info</mat-icon>\n <div style=\"flex:1;\">\n O schema no servidor foi atualizado desde a \u00FAltima sincroniza\u00E7\u00E3o.\n </div>\n <button mat-stroked-button color=\"primary\" type=\"button\" (click)=\"onAcceptServerHash()\">Atualizar metadados</button>\n </div>\n </div>\n\n <div *ngSwitchCase=\"'overview'\" class=\"overview-grid\">\n <div class=\"overview-row\">\n <mat-form-field appearance=\"outline\" class=\"hs-field\">\n <mat-label>Scroll Horizontal</mat-label>\n <mat-select [(ngModel)]=\"horizontalScroll\" (ngModelChange)=\"onHorizontalScrollChange($event)\">\n <mat-option value=\"auto\">Auto (padr\u00E3o)</mat-option>\n <mat-option value=\"wrap\">Wrap (quebrar linhas)</mat-option>\n <mat-option value=\"none\">Host controla</mat-option>\n </mat-select>\n </mat-form-field>\n <div class=\"help small\">Controla como a tabela lida com largura horizontal e barra de rolagem.</div>\n </div>\n <behavior-config-editor\n [config]=\"editedConfig\"\n (configChange)=\"onBehaviorConfigChange($event)\"\n (behaviorChange)=\"onBehaviorChange($event)\"\n ></behavior-config-editor>\n </div>\n\n <columns-config-editor\n *ngSwitchCase=\"'columns'\"\n [config]=\"editedConfig\"\n (configChange)=\"onColumnsConfigChange($event)\"\n (columnChange)=\"onColumnChange($event)\"\n ></columns-config-editor>\n\n <table-rules-editor\n *ngSwitchCase=\"'rules'\"\n [config]=\"editedConfig\"\n [resourcePath]=\"resourcePath\"\n (configChange)=\"onRulesConfigChange($event)\"\n ></table-rules-editor>\n\n <header-appearance-editor\n *ngSwitchCase=\"'header'\"\n [config]=\"editedConfig\"\n (configChange)=\"onColumnsConfigChange($event)\"\n ></header-appearance-editor>\n\n <toolbar-actions-editor\n *ngSwitchCase=\"'toolbar'\"\n [config]=\"editedConfig\"\n (configChange)=\"onToolbarActionsConfigChange($event)\"\n (toolbarActionsChange)=\"onToolbarActionsChange($event)\"\n ></toolbar-actions-editor>\n\n <!-- Aba extra para integra\u00E7\u00F5es CRUD (vis\u00EDvel quando em contexto CRUD) -->\n <crud-integration-editor\n #crudEditorRef\n *ngSwitchCase=\"'crud'\"\n [tableId]=\"crudContext?.tableId || 'default'\"\n [crudContext]=\"crudContext\"\n ></crud-integration-editor>\n\n <filter-settings\n *ngSwitchCase=\"'filters'\"\n [metadata]=\"columnMetas\"\n [settings]=\"\n editedConfig.behavior?.filtering?.advancedFilters?.settings\n \"\n (settingsChange)=\"onFilterSettingsChange($event)\"\n ></filter-settings>\n\n <messages-localization-editor\n *ngSwitchCase=\"'messages'\"\n [config]=\"editedConfig\"\n (configChange)=\"onMessagesLocalizationConfigChange($event)\"\n (messagesLocalizationChange)=\"\n onMessagesLocalizationChange($event)\n \"\n ></messages-localization-editor>\n\n <confirm-dialog-appearance-editor\n *ngSwitchCase=\"'dialogs'\"\n [config]=\"editedConfig\"\n (configChange)=\"onJsonConfigChange($event)\"\n ></confirm-dialog-appearance-editor>\n\n\n <json-config-editor\n *ngSwitchCase=\"'json'\"\n [config]=\"editedConfig\"\n (configChange)=\"onJsonConfigChange($event)\"\n (editorEvent)=\"onJsonEditorEvent($event)\"\n ></json-config-editor>\n </ng-container>\n </div>\n </mat-tab>\n </mat-tab-group>\n<div class=\"config-editor-status\" *ngIf=\"statusMessage\">\n <span\n class=\"status-text\"\n [class.error]=\"hasErrors\"\n [class.success]=\"hasSuccess\"\n >{{ statusMessage }}</span\n >\n</div>\n", styles: ["@charset \"UTF-8\";.config-tabs{flex:1 1 auto;display:flex;flex-direction:column}.config-tabs .mat-mdc-tab{min-width:120px}.config-tabs .mat-mdc-tab-body-wrapper,.config-tabs .mat-mdc-tab-group-container{flex:1 1 auto;min-height:0}.config-tabs .mat-mdc-tab-body-content{height:100%;min-height:0;overflow:visible}.tab-content{display:flex;flex-direction:column;flex:1 1 auto;min-height:0;padding:8px 8px 56px;box-sizing:border-box;overflow:visible}.overview-grid{display:grid;grid-template-columns:1fr;gap:12px}.overview-grid .overview-row{display:grid;grid-template-columns:280px 1fr;align-items:end;gap:12px}.overview-grid .overview-row .help.small{opacity:.75;font-size:12px}.educational-card{margin-bottom:24px;background:var(--mat-sys-surface-container-low);border-left:4px solid var(--mat-sys-primary);flex-shrink:0}.config-editor-status{padding:12px 16px;margin-top:auto;border-top:1px solid rgba(0,0,0,.12);background:var(--mat-sys-surface-container);flex-shrink:0;position:relative}.status-text{font-size:.875rem;line-height:1.2}.status-text.error{color:var(--mat-sys-error)}.status-text.success{color:var(--mat-sys-primary)}@media (max-width: 768px){.tab-content{padding:8px}.config-editor-status{padding:12px 16px}:host{display:flex;flex-direction:column;flex:1 1 auto;min-height:0}}\n"] }]
|
|
19488
|
+
], providers: [TableConfigService], template: " <mat-tab-group class=\"config-tabs\" [(selectedIndex)]=\"activeSectionIndex\">\n <mat-tab *ngFor=\"let section of sections\">\n <ng-template mat-tab-label>\n <mat-icon *ngIf=\"section.icon\" [praxisIcon]=\"section.icon\"></mat-icon>\n <span>{{ section.label }}</span>\n </ng-template>\n <div class=\"tab-content\">\n <ng-container [ngSwitch]=\"section.id\">\n <div *ngSwitchCase=\"'connect'\" style=\"display:grid; gap:12px; padding: 8px; grid-template-columns: 1fr 240px; align-items: start;\">\n <mat-form-field appearance=\"outline\">\n <mat-label>Recurso</mat-label>\n <input matInput [(ngModel)]=\"resourcePath\" (ngModelChange)=\"onResourcePathChange($event)\" placeholder=\"ex.: employees\" />\n <mat-icon matSuffix>link</mat-icon>\n </mat-form-field>\n <mat-form-field appearance=\"outline\">\n <mat-label>Chave prim\u00E1ria</mat-label>\n <input matInput [(ngModel)]=\"idField\" (ngModelChange)=\"onIdFieldChange($event)\" placeholder=\"ex.: id, uuid, codigo\" />\n <mat-icon matSuffix>fingerprint</mat-icon>\n </mat-form-field>\n <small style=\"opacity:.75\">Defina o recurso da API e, se necess\u00E1rio, a chave prim\u00E1ria</small>\n\n <!-- Diverg\u00EAncia: idField -->\n <div *ngIf=\"idFieldDiverges\" style=\"grid-column: 1 / -1; padding: 8px 12px; border-radius: 6px; background: #fff4e5; color: #8a4b00; display:flex; align-items:center; gap: 8px;\">\n <mat-icon>warning</mat-icon>\n <div style=\"flex:1;\">\n A chave prim\u00E1ria no servidor diverge da configura\u00E7\u00E3o atual.\n <span style=\"opacity:.85\">(config: {{ idField || 'id' }} | servidor: {{ serverIdField || 'id' }})</span>\n </div>\n <button mat-stroked-button color=\"primary\" type=\"button\" (click)=\"onReconcileIdField()\">Reconciliar</button>\n </div>\n\n <!-- Diverg\u00EAncia: serverHash -->\n <div *ngIf=\"schemaHashDiverges\" style=\"grid-column: 1 / -1; padding: 8px 12px; border-radius: 6px; background: #e6f4ff; color: #0b5aaa; display:flex; align-items:center; gap: 8px;\">\n <mat-icon>info</mat-icon>\n <div style=\"flex:1;\">\n O schema no servidor foi atualizado desde a \u00FAltima sincroniza\u00E7\u00E3o.\n </div>\n <button mat-stroked-button color=\"primary\" type=\"button\" (click)=\"onAcceptServerHash()\">Atualizar metadados</button>\n </div>\n </div>\n\n <div *ngSwitchCase=\"'overview'\" class=\"overview-grid\">\n <div class=\"overview-row\">\n <mat-form-field appearance=\"outline\" class=\"hs-field\">\n <mat-label>Scroll Horizontal</mat-label>\n <mat-select [(ngModel)]=\"horizontalScroll\" (ngModelChange)=\"onHorizontalScrollChange($event)\">\n <mat-option value=\"auto\">Auto (padr\u00E3o)</mat-option>\n <mat-option value=\"wrap\">Wrap (quebrar linhas)</mat-option>\n <mat-option value=\"none\">Host controla</mat-option>\n </mat-select>\n </mat-form-field>\n <div class=\"help small\">Controla como a tabela lida com largura horizontal e barra de rolagem.</div>\n </div>\n <behavior-config-editor\n [config]=\"editedConfig\"\n [resourcePath]=\"resourcePath\"\n (configChange)=\"onBehaviorConfigChange($event)\"\n (behaviorChange)=\"onBehaviorChange($event)\"\n ></behavior-config-editor>\n </div>\n\n <columns-config-editor\n *ngSwitchCase=\"'columns'\"\n [config]=\"editedConfig\"\n (configChange)=\"onColumnsConfigChange($event)\"\n (columnChange)=\"onColumnChange($event)\"\n ></columns-config-editor>\n\n <table-rules-editor\n *ngSwitchCase=\"'rules'\"\n [config]=\"editedConfig\"\n [resourcePath]=\"resourcePath\"\n (configChange)=\"onRulesConfigChange($event)\"\n ></table-rules-editor>\n\n <header-appearance-editor\n *ngSwitchCase=\"'header'\"\n [config]=\"editedConfig\"\n (configChange)=\"onColumnsConfigChange($event)\"\n ></header-appearance-editor>\n\n <toolbar-actions-editor\n *ngSwitchCase=\"'toolbar'\"\n [config]=\"editedConfig\"\n (configChange)=\"onToolbarActionsConfigChange($event)\"\n (toolbarActionsChange)=\"onToolbarActionsChange($event)\"\n ></toolbar-actions-editor>\n\n <!-- Aba extra para integra\u00E7\u00F5es CRUD (vis\u00EDvel quando em contexto CRUD) -->\n <crud-integration-editor\n #crudEditorRef\n *ngSwitchCase=\"'crud'\"\n [tableId]=\"crudContext?.tableId || 'default'\"\n [crudContext]=\"crudContext\"\n ></crud-integration-editor>\n\n <filter-settings\n *ngSwitchCase=\"'filters'\"\n [metadata]=\"columnMetas\"\n [settings]=\"\n editedConfig.behavior?.filtering?.advancedFilters?.settings\n \"\n (settingsChange)=\"onFilterSettingsChange($event)\"\n ></filter-settings>\n\n <messages-localization-editor\n *ngSwitchCase=\"'messages'\"\n [config]=\"editedConfig\"\n (configChange)=\"onMessagesLocalizationConfigChange($event)\"\n (messagesLocalizationChange)=\"\n onMessagesLocalizationChange($event)\n \"\n ></messages-localization-editor>\n\n <confirm-dialog-appearance-editor\n *ngSwitchCase=\"'dialogs'\"\n [config]=\"editedConfig\"\n (configChange)=\"onJsonConfigChange($event)\"\n ></confirm-dialog-appearance-editor>\n\n\n <json-config-editor\n *ngSwitchCase=\"'json'\"\n [config]=\"editedConfig\"\n (configChange)=\"onJsonConfigChange($event)\"\n (editorEvent)=\"onJsonEditorEvent($event)\"\n ></json-config-editor>\n </ng-container>\n </div>\n </mat-tab>\n </mat-tab-group>\n<div class=\"config-editor-status\" *ngIf=\"statusMessage\">\n <span\n class=\"status-text\"\n [class.error]=\"hasErrors\"\n [class.success]=\"hasSuccess\"\n >{{ statusMessage }}</span\n >\n</div>\n", styles: ["@charset \"UTF-8\";.config-tabs{flex:1 1 auto;display:flex;flex-direction:column}.config-tabs .mat-mdc-tab{min-width:120px}.config-tabs .mat-mdc-tab-body-wrapper,.config-tabs .mat-mdc-tab-group-container{flex:1 1 auto;min-height:0}.config-tabs .mat-mdc-tab-body-content{height:100%;min-height:0;overflow:visible}.tab-content{display:flex;flex-direction:column;flex:1 1 auto;min-height:0;padding:8px 8px 56px;box-sizing:border-box;overflow:visible}.overview-grid{display:grid;grid-template-columns:1fr;gap:12px}.overview-grid .overview-row{display:grid;grid-template-columns:280px 1fr;align-items:end;gap:12px}.overview-grid .overview-row .help.small{opacity:.75;font-size:12px}.educational-card{margin-bottom:24px;background:var(--mat-sys-surface-container-low);border-left:4px solid var(--mat-sys-primary);flex-shrink:0}.config-editor-status{padding:12px 16px;margin-top:auto;border-top:1px solid rgba(0,0,0,.12);background:var(--mat-sys-surface-container);flex-shrink:0;position:relative}.status-text{font-size:.875rem;line-height:1.2}.status-text.error{color:var(--mat-sys-error)}.status-text.success{color:var(--mat-sys-primary)}@media (max-width: 768px){.tab-content{padding:8px}.config-editor-status{padding:12px 16px}:host{display:flex;flex-direction:column;flex:1 1 auto;min-height:0}}\n"] }]
|
|
19479
19489
|
}], ctorParameters: () => [{ type: i0.ChangeDetectorRef }, { type: i1$3.TableConfigService }, { type: undefined, decorators: [{
|
|
19480
19490
|
type: Inject,
|
|
19481
19491
|
args: [SETTINGS_PANEL_DATA]
|
|
@@ -19589,6 +19599,8 @@ class PraxisFilter {
|
|
|
19589
19599
|
changeDebounceMs = 300;
|
|
19590
19600
|
/** Controla a exibição do botão de configurações dentro do filtro */
|
|
19591
19601
|
showFilterSettings = false;
|
|
19602
|
+
/** Mostrar campo de busca genérico quando não houver Quick configurado */
|
|
19603
|
+
showQuickFallback;
|
|
19592
19604
|
/** Data used to render the summary card when mode resolves to 'card'. */
|
|
19593
19605
|
summary;
|
|
19594
19606
|
/** Custom template to render the summary card; receives the summary as $implicit. */
|
|
@@ -19606,7 +19618,7 @@ class PraxisFilter {
|
|
|
19606
19618
|
/** Mostrar rótulos dos toggles na área de ações */
|
|
19607
19619
|
showToggleLabels = true;
|
|
19608
19620
|
/** Config da grade dos alwaysVisible */
|
|
19609
|
-
alwaysMinWidth =
|
|
19621
|
+
alwaysMinWidth = 240; // px (largura mínima padrão por campo)
|
|
19610
19622
|
alwaysColsMd = 2;
|
|
19611
19623
|
alwaysColsLg = 3;
|
|
19612
19624
|
/** Tag theming */
|
|
@@ -19762,6 +19774,20 @@ class PraxisFilter {
|
|
|
19762
19774
|
return undefined;
|
|
19763
19775
|
}
|
|
19764
19776
|
})();
|
|
19777
|
+
/** Decide se o bloco Quick deve ser exibido (heurística + preferência) */
|
|
19778
|
+
showQuickBar() {
|
|
19779
|
+
if (this.quickField || this.quickFieldMeta)
|
|
19780
|
+
return true;
|
|
19781
|
+
if (this.showQuickFallback === true)
|
|
19782
|
+
return true;
|
|
19783
|
+
const hasAlwaysCfg = Array.isArray(this.alwaysVisibleFields) && this.alwaysVisibleFields.length > 0;
|
|
19784
|
+
if (!this.schemaMetas || this.schemaMetas.length === 0) {
|
|
19785
|
+
return !hasAlwaysCfg;
|
|
19786
|
+
}
|
|
19787
|
+
const hasAlways = (this.alwaysVisibleMetas?.length || 0) > 0;
|
|
19788
|
+
const hasToggles = (this.toggleMetas?.length || 0) > 0;
|
|
19789
|
+
return !(hasAlways || hasToggles);
|
|
19790
|
+
}
|
|
19765
19791
|
loadSavedTagsFromStorage() {
|
|
19766
19792
|
try {
|
|
19767
19793
|
if (!this.configKey)
|
|
@@ -19804,6 +19830,9 @@ class PraxisFilter {
|
|
|
19804
19830
|
if (this.allowSaveTags === undefined && cfg.allowSaveTags !== undefined) {
|
|
19805
19831
|
this.allowSaveTags = cfg.allowSaveTags;
|
|
19806
19832
|
}
|
|
19833
|
+
if (this.showQuickFallback === undefined && cfg.showQuickFallback !== undefined) {
|
|
19834
|
+
this.showQuickFallback = !!cfg.showQuickFallback;
|
|
19835
|
+
}
|
|
19807
19836
|
if (this.changeDebounceMs === 300 && cfg.changeDebounceMs !== undefined) {
|
|
19808
19837
|
this.changeDebounceMs = cfg.changeDebounceMs;
|
|
19809
19838
|
}
|
|
@@ -20465,9 +20494,19 @@ class PraxisFilter {
|
|
|
20465
20494
|
this.alwaysForm.valueChanges
|
|
20466
20495
|
.pipe(debounceTime$1(this.changeDebounceMs), takeUntil$1(this.alwaysFormReset$), takeUntilDestroyed(this.destroyRef))
|
|
20467
20496
|
.subscribe((val) => this.advancedChange$.next(val));
|
|
20468
|
-
|
|
20497
|
+
let advancedMetas = metas
|
|
20469
20498
|
.filter((m) => m.name !== this.quickField && !this.alwaysVisibleFields?.includes(m.name))
|
|
20470
20499
|
.map((m) => ({ ...m, updateOn: 'change' }));
|
|
20500
|
+
// Quando o painel avançado abre em modal/gaveta, habilitar touchUi nos campos de data
|
|
20501
|
+
if (this.advancedOpenMode === 'modal' || this.advancedOpenMode === 'drawer') {
|
|
20502
|
+
advancedMetas = advancedMetas.map((m) => {
|
|
20503
|
+
const ct = m.controlType;
|
|
20504
|
+
if (ct === 'date' || ct === 'dateRange' || ct === 'dateTime' || ct === 'dateTimeRange') {
|
|
20505
|
+
return { ...m, touchUi: true };
|
|
20506
|
+
}
|
|
20507
|
+
return m;
|
|
20508
|
+
});
|
|
20509
|
+
}
|
|
20471
20510
|
if (advancedMetas.length) {
|
|
20472
20511
|
// Única linha com várias colunas: melhora responsividade via wrap no formulário filho
|
|
20473
20512
|
this.advancedConfig = {
|
|
@@ -20606,9 +20645,15 @@ class PraxisFilter {
|
|
|
20606
20645
|
this.autoSummaryData = undefined;
|
|
20607
20646
|
return;
|
|
20608
20647
|
}
|
|
20609
|
-
const maxBadges =
|
|
20610
|
-
const badges = entries.slice(0, maxBadges).map(([k, v]) =>
|
|
20648
|
+
const maxBadges = 5;
|
|
20649
|
+
const badges = entries.slice(0, maxBadges).map(([k, v]) => {
|
|
20650
|
+
const label = this.getFieldLabel(k) || k;
|
|
20651
|
+
return `${label}=${this.formatValueForBadge(k, v)}`;
|
|
20652
|
+
});
|
|
20611
20653
|
const extra = entries.length > maxBadges ? ` +${entries.length - maxBadges}` : '';
|
|
20654
|
+
if (entries.length > maxBadges) {
|
|
20655
|
+
badges.push(`+${entries.length - maxBadges}`);
|
|
20656
|
+
}
|
|
20612
20657
|
this.autoSummaryData = {
|
|
20613
20658
|
count: entries.length,
|
|
20614
20659
|
dto: { ...this.dto },
|
|
@@ -20623,17 +20668,71 @@ class PraxisFilter {
|
|
|
20623
20668
|
badges: this.autoSummaryData?.badges?.map((b) => (() => b)) ?? [],
|
|
20624
20669
|
};
|
|
20625
20670
|
}
|
|
20626
|
-
|
|
20671
|
+
/** Salva o estado atual dos filtros como um atalho (tag) do usuário */
|
|
20672
|
+
saveCurrentAsTag() {
|
|
20673
|
+
try {
|
|
20674
|
+
const dto = { ...(this.advancedForm?.getRawValue?.() || this.dto || {}) };
|
|
20675
|
+
if (!Object.keys(dto).length)
|
|
20676
|
+
return;
|
|
20677
|
+
const label = prompt(this.i18nLabels.saveAsShortcut || 'Salvar como atalho', '') || '';
|
|
20678
|
+
if (!label.trim())
|
|
20679
|
+
return;
|
|
20680
|
+
const tag = { id: Date.now().toString(), label: label.trim(), patch: dto };
|
|
20681
|
+
this.savedTags.push(tag);
|
|
20682
|
+
this.persistTags();
|
|
20683
|
+
this.updateDisplayedTags();
|
|
20684
|
+
}
|
|
20685
|
+
catch { }
|
|
20686
|
+
}
|
|
20687
|
+
formatValueForBadge(fieldName, v) {
|
|
20627
20688
|
if (v === null || v === undefined)
|
|
20628
20689
|
return '';
|
|
20690
|
+
// Array: traduz item a item
|
|
20629
20691
|
if (Array.isArray(v))
|
|
20630
|
-
return v.join(',');
|
|
20692
|
+
return v.map((it) => this.formatValueForBadge(fieldName, it)).join(',');
|
|
20693
|
+
// Try map via options (enum/select) when available
|
|
20694
|
+
const opt = this.getOptionText(fieldName, v);
|
|
20695
|
+
if (opt)
|
|
20696
|
+
return opt;
|
|
20697
|
+
// Boolean in pt-BR
|
|
20698
|
+
if (typeof v === 'boolean')
|
|
20699
|
+
return v ? 'Sim' : 'Não';
|
|
20631
20700
|
if (v instanceof Date)
|
|
20632
20701
|
return v.toISOString().slice(0, 10);
|
|
20633
20702
|
if (typeof v === 'object')
|
|
20634
20703
|
return JSON.stringify(v);
|
|
20635
20704
|
return String(v);
|
|
20636
20705
|
}
|
|
20706
|
+
/**
|
|
20707
|
+
* Resolve a user-friendly label for a filter key using the loaded FieldMetadata.
|
|
20708
|
+
* Falls back to the key itself when metadata is not available.
|
|
20709
|
+
*/
|
|
20710
|
+
getFieldLabel(name) {
|
|
20711
|
+
// Prefer schemaMetas when available
|
|
20712
|
+
const metas = this.schemaMetas || this.advancedConfig?.fieldMetadata || [];
|
|
20713
|
+
try {
|
|
20714
|
+
const found = metas.find((m) => m?.name === name);
|
|
20715
|
+
return found?.label || undefined;
|
|
20716
|
+
}
|
|
20717
|
+
catch {
|
|
20718
|
+
return undefined;
|
|
20719
|
+
}
|
|
20720
|
+
}
|
|
20721
|
+
/** Resolve option display text from FieldMetadata.options, when present */
|
|
20722
|
+
getOptionText(name, value) {
|
|
20723
|
+
const metas = this.schemaMetas || this.advancedConfig?.fieldMetadata || [];
|
|
20724
|
+
try {
|
|
20725
|
+
const found = metas.find((m) => m?.name === name);
|
|
20726
|
+
const opts = found?.options;
|
|
20727
|
+
if (!opts || !opts.length)
|
|
20728
|
+
return undefined;
|
|
20729
|
+
const match = opts.find((o) => (o?.value === value) || (String(o?.value) === String(value)));
|
|
20730
|
+
return match?.text;
|
|
20731
|
+
}
|
|
20732
|
+
catch {
|
|
20733
|
+
return undefined;
|
|
20734
|
+
}
|
|
20735
|
+
}
|
|
20637
20736
|
// Helper A11y: label do botão Avançado com contagem
|
|
20638
20737
|
getAdvancedAriaLabel() {
|
|
20639
20738
|
const count = this.activeFiltersCount || 0;
|
|
@@ -21212,7 +21311,7 @@ class PraxisFilter {
|
|
|
21212
21311
|
}
|
|
21213
21312
|
}
|
|
21214
21313
|
async openAdvancedModal() {
|
|
21215
|
-
const { FilterFormDialogHostComponent } = await import('./praxisui-table-filter-form-dialog-host.component-
|
|
21314
|
+
const { FilterFormDialogHostComponent } = await import('./praxisui-table-filter-form-dialog-host.component-Du_IEq0W.mjs');
|
|
21216
21315
|
const ref = this.dialog.open(FilterFormDialogHostComponent, {
|
|
21217
21316
|
width: '780px',
|
|
21218
21317
|
maxWidth: '96vw',
|
|
@@ -21220,6 +21319,7 @@ class PraxisFilter {
|
|
|
21220
21319
|
formId: this.formId,
|
|
21221
21320
|
resourcePath: this.resourcePath,
|
|
21222
21321
|
config: this.advancedConfig,
|
|
21322
|
+
initialDto: this.advancedForm?.getRawValue?.() || this.dto || {},
|
|
21223
21323
|
schemaLoading: this.schemaLoading,
|
|
21224
21324
|
},
|
|
21225
21325
|
});
|
|
@@ -21234,6 +21334,23 @@ class PraxisFilter {
|
|
|
21234
21334
|
await this.openAdvancedModal();
|
|
21235
21335
|
return;
|
|
21236
21336
|
}
|
|
21337
|
+
// Ensure schema/advancedConfig before opening the drawer to avoid undefined config
|
|
21338
|
+
if (!this.advancedConfig) {
|
|
21339
|
+
if (!this.schemaLoading)
|
|
21340
|
+
this.loadSchema();
|
|
21341
|
+
await new Promise((resolve) => {
|
|
21342
|
+
const start = Date.now();
|
|
21343
|
+
const tick = () => {
|
|
21344
|
+
if (this.advancedConfig)
|
|
21345
|
+
return resolve();
|
|
21346
|
+
// Safety timeout (2s) to prevent infinite waits in case of backend errors
|
|
21347
|
+
if (Date.now() - start > 2000)
|
|
21348
|
+
return resolve();
|
|
21349
|
+
setTimeout(tick, 50);
|
|
21350
|
+
};
|
|
21351
|
+
tick();
|
|
21352
|
+
});
|
|
21353
|
+
}
|
|
21237
21354
|
const initialDto = this.advancedForm?.getRawValue?.() || this.dto || {};
|
|
21238
21355
|
this.filterDrawerAdapter.open({
|
|
21239
21356
|
resourcePath: this.resourcePath,
|
|
@@ -21300,6 +21417,7 @@ class PraxisFilter {
|
|
|
21300
21417
|
overlayVariant: this.overlayVariant,
|
|
21301
21418
|
overlayBackdrop: this.overlayBackdrop,
|
|
21302
21419
|
advancedOpenMode: this.advancedOpenMode,
|
|
21420
|
+
showQuickFallback: this.showQuickFallback,
|
|
21303
21421
|
};
|
|
21304
21422
|
this.filterConfig.save(this.configKey, config);
|
|
21305
21423
|
}
|
|
@@ -21405,7 +21523,7 @@ class PraxisFilter {
|
|
|
21405
21523
|
}
|
|
21406
21524
|
}
|
|
21407
21525
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: PraxisFilter, deps: [{ token: i1$3.GenericCrudService }, { token: CONFIG_STORAGE }, { token: i0.DestroyRef }, { token: FilterConfigService }, { token: i3$2.SettingsPanelService }, { token: i2$1.MatSnackBar }, { token: i1$2.MatDialog }, { token: i0.ChangeDetectorRef }, { token: i1$3.DynamicFormService }, { token: i1$3.SchemaNormalizerService }], target: i0.ɵɵFactoryTarget.Component });
|
|
21408
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.1.4", type: PraxisFilter, isStandalone: true, selector: "praxis-filter", inputs: { resourcePath: "resourcePath", formId: "formId", mode: "mode", notifyIfOutdated: "notifyIfOutdated", snoozeMs: "snoozeMs", autoOpenSettingsOnOutdated: "autoOpenSettingsOnOutdated", editModeEnabled: "editModeEnabled", value: "value", quickField: "quickField", alwaysVisibleFields: "alwaysVisibleFields", tags: "tags", allowSaveTags: "allowSaveTags", persistenceKey: "persistenceKey", i18n: "i18n", changeDebounceMs: "changeDebounceMs", showFilterSettings: "showFilterSettings", summary: "summary", summaryTemplate: "summaryTemplate", summaryMap: "summaryMap", autoSummary: "autoSummary", confirmTagDelete: "confirmTagDelete", debugLayout: "debugLayout", placeBooleansInActions: "placeBooleansInActions", showToggleLabels: "showToggleLabels", alwaysMinWidth: "alwaysMinWidth", alwaysColsMd: "alwaysColsMd", alwaysColsLg: "alwaysColsLg", tagColor: "tagColor", tagVariant: "tagVariant", tagButtonColor: "tagButtonColor", actionsButtonColor: "actionsButtonColor", actionsVariant: "actionsVariant", overlayVariant: "overlayVariant", overlayBackdrop: "overlayBackdrop", advancedOpenMode: "advancedOpenMode" }, outputs: { submit: "submit", change: "change", clear: "clear", modeChange: "modeChange", requestSearch: "requestSearch", tagsChange: "tagsChange", metaChanged: "metaChanged", schemaStatusChange: "schemaStatusChange" }, host: { listeners: { "window:resize": "onWindowResize()", "document:keydown": "onGlobalKeydown($event)" }, properties: { "class.debug-layout": "debugLayout", "style.--pfx-always-min": "alwaysMinWidth + \"px\"", "style.--pfx-always-cols-md": "alwaysColsMd", "style.--pfx-always-cols-lg": "alwaysColsLg" } }, viewQueries: [{ propertyName: "anchorRef", first: true, predicate: ["anchorRef"], descendants: true, read: CdkOverlayOrigin }, { propertyName: "quickHostRef", first: true, predicate: ["quickHostRef"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<ng-container *ngIf=\"modeState === 'filter'; else summaryCard\">\n <mat-progress-bar *ngIf=\"saving\" mode=\"indeterminate\"></mat-progress-bar>\n\n <form class=\"praxis-filter-bar\" [class.is-open]=\"advancedOpen\" (submit)=\"onSubmit(); $event.preventDefault()\">\n <!-- QUICK FIELD -->\n <div class=\"quick-field\" *ngIf=\"quickFieldMeta; else fallbackQuick\">\n <div class=\"filter-anchor quick-shell\" #anchorRef=\"cdkOverlayOrigin\" cdkOverlayOrigin>\n\n <!-- din\u00E2mico: envolvido por host para garantir layout flex correto -->\n <div *ngIf=\"quickFieldMode === 'dynamic'\" class=\"quick-field-host\" #quickHostRef\n dynamicFieldLoader\n [fields]=\"quickFieldMetaArray\"\n [formGroup]=\"quickForm\"\n (componentsCreated)=\"onQuickComponents($event)\"\n (fieldCreated)=\"onQuickFieldCreated($event)\">\n </div>\n\n <!-- fallback (com meta) \u2014 sem suffix, s\u00F3 o input -->\n <mat-form-field *ngIf=\"quickFieldMode === 'fallback'\"\n appearance=\"outline\"\n floatLabel=\"always\"\n class=\"fallback-quick-field\">\n <mat-label>{{ quickFieldMeta.label || quickField }}</mat-label>\n <input matInput [formControl]=\"quickControl\"\n [type]=\"getQuickInputType()\"\n [attr.inputmode]=\"getQuickInputMode()\"\n [attr.aria-label]=\"quickFieldMeta.label || quickField\"\n (keydown.escape)=\"onQuickClear()\"\n (keypress)=\"onQuickNumericKeypress($event)\"\n (blur)=\"onQuickBlurFormat()\">\n </mat-form-field>\n\n \n </div>\n </div>\n\n\n <!-- QUICK \u201Cfalso\u201D (quando n\u00E3o h\u00E1 meta) -->\n <ng-template #fallbackQuick>\n <div class=\"filter-anchor quick-shell\" #anchorRef=\"cdkOverlayOrigin\" cdkOverlayOrigin>\n <mat-form-field appearance=\"outline\" floatLabel=\"always\" class=\"fallback-quick-field\">\n <mat-label>{{ i18nLabels.searchPlaceholder }}</mat-label>\n <input matInput [formControl]=\"quickControl\"\n [attr.aria-label]=\"i18nLabels.searchPlaceholder\"\n (keydown.escape)=\"onQuickClear()\" />\n </mat-form-field>\n </div>\n </ng-template>\n\n <!-- A\u00C7\u00D5ES INLINE (fixas \u00E0 direita da barra) -->\n <div class=\"inline-actions\" [class.actions-outlined]=\"actionsVariant==='outlined'\">\n <!-- Toggles/booleans simples realocados para a barra de a\u00E7\u00F5es -->\n <div class=\"inline-toggles\" *ngIf=\"toggleMetas.length\">\n <ng-container dynamicFieldLoader [fields]=\"toggleMetas\" [formGroup]=\"alwaysForm\"\n (componentsCreated)=\"onToggleComponents($event)\"></ng-container>\n </div>\n <button mat-icon-button [color]=\"actionsButtonColor==='basic'? null : actionsButtonColor\" type=\"button\" *ngIf=\"quickHasValue()\"\n (click)=\"onQuickClear()\" [attr.aria-label]=\"i18nLabels.clear\">\n <mat-icon [praxisIcon]=\"'close'\"></mat-icon>\n </button>\n <button mat-icon-button [color]=\"actionsButtonColor==='basic'? null : actionsButtonColor\" type=\"button\" (click)=\"onSubmit()\" [attr.aria-label]=\"i18nLabels.apply\">\n <mat-icon [praxisIcon]=\"'search'\"></mat-icon>\n </button>\n <button mat-icon-button [color]=\"actionsButtonColor==='basic'? null : actionsButtonColor\" type=\"button\"\n [matBadge]=\"activeFiltersCount\"\n [matBadgeHidden]=\"!activeFiltersCount\"\n matBadgeSize=\"small\"\n matBadgeColor=\"primary\"\n [matBadgeOverlap]=\"false\"\n (click)=\"toggleAdvanced()\"\n [attr.aria-label]=\"getAdvancedAriaLabel()\"\n [attr.aria-expanded]=\"advancedOpen\"\n [attr.aria-controls]=\"advancedPanelId\">\n <mat-icon [praxisIcon]=\"'tune'\"></mat-icon>\n </button>\n <button mat-icon-button [color]=\"actionsButtonColor==='basic'? null : actionsButtonColor\" type=\"button\" (click)=\"openSettings()\" *ngIf=\"showFilterSettings\"\n [matBadge]=\"schemaOutdated ? '!' : ''\"\n [matBadgeHidden]=\"!schemaOutdated\"\n matBadgeColor=\"warn\" matBadgeSize=\"small\" matBadgePosition=\"above after\"\n [matTooltip]=\"schemaOutdated ? 'Schema do servidor mudou \u2014 Reconciliar' : i18nLabels.settings\"\n matTooltipPosition=\"below\">\n <mat-icon [praxisIcon]=\"'settings'\"></mat-icon>\n </button>\n </div>\n\n <!-- campos sempre vis\u00EDveis (se houver) -->\n <div class=\"always-fields\" *ngIf=\"alwaysVisibleMetas.length\">\n <ng-container dynamicFieldLoader [fields]=\"alwaysVisibleMetas\" [formGroup]=\"alwaysForm\"\n (componentsCreated)=\"onAlwaysComponents($event)\"></ng-container>\n </div>\n\n <!-- acessibilidade -->\n <span class=\"sr-only\" aria-live=\"polite\">\n {{ activeFiltersCount ? (activeFiltersCount + ' filtros ativos') : '' }}\n </span>\n <button type=\"submit\" class=\"hidden-submit\" aria-hidden=\"true\" tabindex=\"-1\"></button>\n </form>\n\n <!-- tags -->\n <div class=\"praxis-filter-tags\" *ngIf=\"displayedTags.length\" [class.outlined]=\"tagVariant==='outlined'\">\n <mat-chip-set>\n <mat-chip *ngFor=\"let tag of displayedTags\"\n [color]=\"tagColor === 'basic' ? null : tagColor\"\n (click)=\"applyTag(tag)\" (keydown.enter)=\"applyTag(tag)\"\n tabindex=\"0\" role=\"button\">\n <ng-container *ngIf=\"editingTagId !== tag.id; else editChip\">\n <span class=\"chip-label\">{{ tag.label }}</span>\n <span class=\"chip-actions\" *ngIf=\"isUserTag(tag)\">\n <button mat-icon-button [color]=\"tagButtonColor === 'basic' ? null : tagButtonColor\"\n (click)=\"startEditTag(tag, $event)\" aria-label=\"edit tag\">\n <mat-icon>edit</mat-icon>\n </button>\n <button mat-icon-button [color]=\"tagButtonColor === 'basic' ? null : tagButtonColor\"\n (click)=\"deleteTag(tag)\" aria-label=\"remove tag\">\n <mat-icon>close</mat-icon>\n </button>\n </span>\n </ng-container>\n <ng-template #editChip>\n <input matInput class=\"chip-editor\" [formControl]=\"editingTagLabel\"\n (keydown.enter)=\"commitEditTag(tag, $event)\" (keydown.escape)=\"cancelEditTag($event)\" (click)=\"$event.stopPropagation()\" />\n <button mat-button color=\"primary\" (click)=\"commitEditTag(tag, $event)\">{{ i18nLabels.save }}</button>\n <button mat-button (click)=\"cancelEditTag($event)\">{{ i18nLabels.cancel }}</button>\n </ng-template>\n </mat-chip>\n </mat-chip-set>\n </div>\n\n <!-- OVERLAY -->\n <ng-container *ngIf=\"overlayOrigin\">\n <ng-template cdkConnectedOverlay\n [cdkConnectedOverlayOrigin]=\"overlayOrigin!\"\n [cdkConnectedOverlayOpen]=\"advancedOpen\"\n [cdkConnectedOverlayHasBackdrop]=\"overlayBackdrop\"\n [cdkConnectedOverlayBackdropClass]=\"'praxis-overlay-backdrop'\"\n [cdkConnectedOverlayPositions]=\"overlayPositions\"\n [cdkConnectedOverlayFlexibleDimensions]=\"true\"\n [cdkConnectedOverlayPush]=\"true\"\n [cdkConnectedOverlayOffsetY]=\"8\"\n [cdkConnectedOverlayLockPosition]=\"true\"\n [cdkConnectedOverlayWidth]=\"overlayWidth\"\n [cdkConnectedOverlayPanelClass]=\"['praxis-filter-overlay', isMobile ? 'mobile' : '', overlayVariant === 'frosted' ? 'frosted' : '']\"\n (overlayOutsideClick)=\"onOverlayOutsideClick($event)\"\n (backdropClick)=\"onOverlayDetach()\"\n (detach)=\"onOverlayDetach()\">\n <div class=\"praxis-filter-advanced\" (keydown.escape)=\"toggleAdvanced()\" role=\"dialog\" aria-modal=\"true\" [attr.id]=\"advancedPanelId\">\n <div class=\"advanced-body\">\n <mat-progress-bar *ngIf=\"schemaLoading\" mode=\"indeterminate\"></mat-progress-bar>\n <p *ngIf=\"schemaError\" class=\"schema-error\">\n {{ i18nLabels.errorLoadingFilters }}\n <button mat-button type=\"button\" (click)=\"loadSchema()\">{{ i18nLabels.retry }}</button>\n </p>\n <praxis-filter-form *ngIf=\"!schemaLoading && !schemaError && advancedConfig\"\n [formId]=\"formId\" [resourcePath]=\"resourcePath\" [mode]=\"'edit'\" [config]=\"advancedConfig\"\n (formReady)=\"onAdvancedReady($event)\" (valueChange)=\"onAdvancedChange($event)\"\n (validityChange)=\"onAdvancedValidityChange($event)\" (submit)=\"onAdvancedSubmit($event)\">\n </praxis-filter-form>\n <p *ngIf=\"!schemaLoading && !schemaError && !advancedConfig\">{{ i18nLabels.noData }}</p>\n </div>\n <div class=\"advanced-actions\" *ngIf=\"!schemaLoading && !schemaError && advancedConfig\">\n <button mat-raised-button color=\"primary\" type=\"button\"\n (click)=\"onAdvancedSubmit({ formData: (advancedForm?.getRawValue?.() || {}) })\"\n [disabled]=\"!advancedValid\">\n {{ i18nLabels.apply }}\n </button>\n <button mat-button type=\"button\" (click)=\"onClear()\">{{ i18nLabels.clear }}</button>\n </div>\n </div>\n </ng-template>\n </ng-container>\n</ng-container>\n\n<!-- resumo -->\n<ng-template #summaryCard>\n <div class=\"praxis-filter-card\" (keydown.escape)=\"onClear()\">\n <div class=\"summary-header\">\n <img *ngIf=\"currentSummaryMap?.avatar?.(currentSummary)\" [src]=\"currentSummaryMap?.avatar?.(currentSummary)\"\n class=\"summary-avatar\" alt=\"\" />\n <div class=\"summary-text\">\n <div class=\"summary-title\">{{ currentSummaryMap?.title?.(currentSummary) || '' }}</div>\n <div class=\"summary-subtitle\" *ngIf=\"currentSummaryMap?.subtitle\">{{ currentSummaryMap?.subtitle?.(currentSummary) }}</div>\n </div>\n </div>\n <div class=\"summary-badges\" *ngIf=\"currentSummaryMap?.badges?.length\">\n <span *ngFor=\"let b of currentSummaryMap!.badges\">{{ b(currentSummary) }}</span>\n </div>\n <div class=\"card-actions\">\n <button mat-button type=\"button\" (click)=\"switchToFilter()\">{{ i18nLabels.edit }}</button>\n <button mat-button type=\"button\" (click)=\"onClear()\">{{ i18nLabels.clear }}</button>\n </div>\n </div>\n</ng-template>\n", styles: ["@charset \"UTF-8\";:root{--pfx-filter-h: 40px;--pfx-filter-align-offset: 2px;--pfx-gap-x: 16px;--pfx-gap-y: 12px;--pfx-quick-pad-top: 5px;--pfx-quick-pad-left: 12px;--pfx-advanced-pad-x: 24px;--pfx-field-min: 280px;--pfx-quick-bg: var(--surface-2, #232a32);--pfx-quick-border: var(--pfx-surface-border, rgba(255,255,255,.08));--pfx-quick-radius: 12px}.praxis-filter-bar{display:grid;width:100%;grid-template-columns:1fr auto;grid-template-areas:\"quick actions\" \"always always\";column-gap:0;row-gap:8px;align-items:center}:host.debug-layout{background-image:repeating-linear-gradient(to right,rgba(147,197,253,.08) 0,rgba(147,197,253,.08) 1px,transparent 1px,transparent var(--pfx-gap-x)),repeating-linear-gradient(to bottom,rgba(163,230,53,.08) 0,rgba(163,230,53,.08) 1px,transparent 1px,transparent 8px)}:host.debug-layout .praxis-filter-bar{outline:1px dashed #f59e0b}:host.debug-layout .quick-shell{outline:1px dashed #3b82f6}:host.debug-layout .always-fields{outline:1px dashed #22c55e}:host.debug-layout .praxis-filter-overlay .praxis-filter-advanced{outline:2px solid #a855f7}.quick-field{grid-area:quick;min-width:280px;align-self:center}.inline-actions{grid-area:actions;justify-self:end}.always-fields{grid-area:always}.quick-shell{min-height:var(--pfx-filter-h);padding:0 0 0 var(--pfx-quick-pad-left);display:flex;align-items:center;flex-wrap:nowrap;gap:6px;overflow:hidden;background:var(--pfx-quick-bg);border:1px solid var(--pfx-quick-border);border-right:none;border-radius:var(--pfx-quick-radius) 0 0 var(--pfx-quick-radius)}.quick-shell>*{flex:1 1 auto;min-width:0}.quick-field-host{display:contents}:host ::ng-deep .quick-shell .mat-mdc-form-field{width:100%!important;flex:1 1 auto}:host ::ng-deep .quick-shell .mat-mdc-form-field{margin:0!important}:host ::ng-deep .quick-shell pdx-text-input,:host ::ng-deep .quick-shell pdx-select,:host ::ng-deep .quick-shell pdx-date-input,:host ::ng-deep .quick-shell pdx-auto-complete{flex:1 1 auto;min-width:0;display:block}.inline-actions{flex:0 0 auto;display:flex;gap:4px;align-self:start;white-space:nowrap;height:var(--pfx-filter-h);align-items:center;background:var(--pfx-quick-bg);border:1px solid var(--pfx-quick-border);border-left:none;border-radius:0 var(--pfx-quick-radius) var(--pfx-quick-radius) 0;padding-right:4px;margin-left:-1px}.inline-actions.actions-outlined button.mat-mdc-icon-button{border:1px solid var(--pfx-quick-border);border-radius:50%}.inline-actions .mat-mdc-icon-button{width:36px;height:36px}.inline-actions mat-icon{width:20px;height:20px;font-size:20px}.fallback-quick-field{height:var(--pfx-filter-h);display:flex;align-items:center}:host ::ng-deep .fallback-quick-field .mat-mdc-text-field-wrapper.mdc-text-field--outlined{height:var(--pfx-filter-h);align-items:center;padding-top:var(--pfx-quick-pad-top)}:host ::ng-deep .quick-shell .mat-mdc-text-field-wrapper.mdc-text-field--outlined{min-height:var(--pfx-filter-h);align-items:center;padding-top:var(--pfx-quick-pad-top)}:host ::ng-deep .quick-shell .mat-mdc-form-field-infix{min-height:var(--pfx-filter-h)}:host ::ng-deep .quick-shell .mat-mdc-select-trigger{height:var(--pfx-filter-h);align-items:center}:host ::ng-deep .quick-shell .mat-mdc-form-field-subscript-wrapper{display:none}:host ::ng-deep .quick-shell .mdc-line-ripple{display:none!important}.always-fields{display:grid;grid-template-columns:repeat(auto-fit,minmax(var(--pfx-always-min, 300px),1fr));gap:8px}:host ::ng-deep .always-fields .mat-mdc-text-field-wrapper.mdc-text-field--outlined{min-height:var(--pfx-filter-h);align-items:center}:host ::ng-deep .always-fields .mat-mdc-form-field-infix{min-height:var(--pfx-filter-h)}:host ::ng-deep .always-fields .mat-mdc-select-trigger{height:var(--pfx-filter-h);align-items:center}:host ::ng-deep .always-fields .mat-mdc-form-field{width:100%}.praxis-filter-tags{display:flex;flex-wrap:wrap;gap:6px}.praxis-filter-tags mat-chip{border-radius:16px;padding:0 6px}.praxis-filter-tags .chip-actions{display:inline-flex;align-items:center;gap:2px;margin-left:4px}.chip-editor{width:140px;margin-right:8px}.praxis-filter-tags.outlined mat-chip{background:transparent!important;border:1px solid var(--pfx-quick-border)}.praxis-filter-advanced{display:flex;flex-direction:column;min-width:400px;max-width:90vw;min-height:260px;max-height:80vh;margin-top:25px;margin-right:15px;margin-left:25px;background:var(--md-sys-color-surface-container, #2a3038)!important;background-color:var(--md-sys-color-surface-container, #2a3038)!important;background:color-mix(in srgb,var(--md-sys-color-surface-container, #2a3038),transparent 6%)!important;color:var(--md-sys-color-on-surface, #e6eaf2);border:1px solid var(--border-color);border-radius:12px;box-shadow:0 8px 24px #00000052,0 2px 8px #0000002e}.praxis-filter-overlay.mobile .praxis-filter-advanced{height:100vh;max-height:100vh}:host ::ng-deep .praxis-overlay-backdrop{background:#0006;-webkit-backdrop-filter:blur(2px);backdrop-filter:blur(2px)}.advanced-body{padding:var(--pfx-gap-y) var(--pfx-advanced-pad-x) 72px;overflow:auto;flex:1 1 auto;overscroll-behavior:contain}:host ::ng-deep .praxis-filter-advanced .praxis-filter-form .filter-row{display:grid!important;grid-template-columns:repeat(auto-fit,minmax(var(--pfx-field-min),1fr));gap:var(--pfx-gap-y) var(--pfx-gap-x)}:host ::ng-deep .praxis-filter-advanced .praxis-filter-form .filter-column{min-width:0}:host ::ng-deep .praxis-filter-advanced .praxis-filter-form .filter-column .mat-mdc-form-field{width:100%}.advanced-actions{position:sticky;bottom:0;z-index:2;display:flex;justify-content:flex-end;gap:8px;padding:var(--pfx-gap-y) var(--pfx-advanced-pad-x);background:var(--md-sys-color-surface-container, #2a3038)!important;background-color:var(--md-sys-color-surface-container, #2a3038)!important;background:color-mix(in srgb,var(--md-sys-color-surface-container, #2a3038),transparent 0%)!important;border-top:1px solid var(--border-color);box-shadow:0 -1px #0000002e}.advanced-actions .mat-mdc-button-base{height:40px}.advanced-actions .mat-mdc-raised-button.mat-primary{background:var(--md-sys-color-primary);color:var(--md-sys-color-on-primary)}:host ::ng-deep .praxis-filter-advanced .mat-mdc-text-field-wrapper.mdc-text-field--outlined{--mdc-outlined-text-field-outline-color: var(--border-color);--mdc-outlined-text-field-hover-outline-color: var(--border-color-hover);--mdc-outlined-text-field-focus-outline-color: var(--md-sys-color-primary);--mdc-outlined-text-field-label-text-color: var(--md-sys-color-on-surface-variant);--mdc-outlined-text-field-input-text-color: var(--md-sys-color-on-surface);--mdc-outlined-text-field-container-color: var(--md-sys-color-surface-container, #2a3038);--mdc-outlined-text-field-container-color: color-mix(in srgb, var(--md-sys-color-surface-container, #2a3038), transparent 90%)}:host ::ng-deep .praxis-filter-advanced .mat-mdc-select-trigger,:host ::ng-deep .praxis-filter-advanced .mat-mdc-form-field-subscript-wrapper,:host ::ng-deep .praxis-filter-advanced .mat-mdc-form-field-infix{color:var(--md-sys-color-on-surface)}@media (min-width: 600px){.always-fields{grid-template-columns:repeat(var(--pfx-always-cols-md, 2),minmax(0,1fr))}:host ::ng-deep .praxis-filter-advanced .praxis-filter-form .filter-row{grid-template-columns:repeat(2,minmax(0,1fr))}}@media (min-width: 960px){.always-fields{grid-template-columns:repeat(var(--pfx-always-cols-lg, 3),minmax(0,1fr))}}.inline-toggles{display:flex;align-items:center;gap:8px;margin:0 4px 0 6px}:host ::ng-deep .inline-actions .mat-mdc-slide-toggle{height:var(--pfx-filter-h);display:flex;align-items:center}:host ::ng-deep .inline-actions .mat-mdc-slide-toggle .mdc-form-field{align-items:center}::ng-deep .praxis-filter-overlay .praxis-filter-advanced .praxis-filter-form .filter-row{display:grid!important;gap:var(--pfx-gap-y, 1px) var(--pfx-gap-x, 6px)}@media (min-width: 600px){::ng-deep .praxis-filter-overlay .praxis-filter-advanced .praxis-filter-form .filter-row{grid-template-columns:repeat(2,minmax(0,1fr))}}.sr-only{position:absolute!important;width:1px!important;height:1px!important;margin:-1px!important;overflow:hidden!important;clip:rect(0,0,0,0)!important}.hidden-submit{position:absolute!important;width:0!important;height:0!important;padding:0!important;margin:0!important;border:0!important;opacity:0!important;pointer-events:none!important;clip:rect(0 0 0 0)!important;clip-path:inset(50%)!important;overflow:hidden!important}:host ::ng-deep .inline-actions [matBadge] .mat-badge-content{top:-6px;right:-6px}.praxis-filter-bar :where(.mat-mdc-slide-toggle .mdc-switch__icons){display:none!important}.praxis-filter-bar{--mdc-switch-unselected-icon-size: 0px;--mdc-switch-selected-icon-size: 0px}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { 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.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i3$1.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i3$1.MatLabel, selector: "mat-label" }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i6.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: 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: "ngmodule", type: MatChipsModule }, { kind: "component", type: i11.MatChip, selector: "mat-basic-chip, [mat-basic-chip], mat-chip, [mat-chip]", inputs: ["role", "id", "aria-label", "aria-description", "value", "color", "removable", "highlighted", "disableRipple", "disabled"], outputs: ["removed", "destroyed"], exportAs: ["matChip"] }, { kind: "component", type: i11.MatChipSet, selector: "mat-chip-set", inputs: ["disabled", "role", "tabIndex"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i4.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "directive", type: PraxisIconDirective, selector: "mat-icon[praxisIcon]", inputs: ["praxisIcon"] }, { kind: "ngmodule", type: MatBadgeModule }, { kind: "directive", type: i15.MatBadge, selector: "[matBadge]", inputs: ["matBadgeColor", "matBadgeOverlap", "matBadgeDisabled", "matBadgePosition", "matBadge", "matBadgeDescription", "matBadgeSize", "matBadgeHidden"] }, { kind: "ngmodule", type: MatProgressBarModule }, { kind: "component", type: i14$1.MatProgressBar, selector: "mat-progress-bar", inputs: ["color", "value", "bufferValue", "mode"], outputs: ["animationEnd"], exportAs: ["matProgressBar"] }, { kind: "ngmodule", type: MatSnackBarModule }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i10.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "directive", type: DynamicFieldLoaderDirective, selector: "[dynamicFieldLoader]", inputs: ["fields", "formGroup", "enableExternalControlBinding", "itemTemplate", "readonlyMode", "disabledMode", "presentationMode", "visible", "canvasMode"], outputs: ["componentsCreated", "fieldCreated", "fieldDestroyed", "canvasMouseEnter", "canvasMouseLeave", "canvasClick"] }, { kind: "component", type: PraxisFilterForm, selector: "praxis-filter-form", inputs: ["config", "formId", "resourcePath", "mode"], outputs: ["formReady", "valueChange", "submit", "validityChange"] }, { kind: "ngmodule", type: OverlayModule }, { kind: "directive", type: i19.CdkConnectedOverlay, selector: "[cdk-connected-overlay], [connected-overlay], [cdkConnectedOverlay]", inputs: ["cdkConnectedOverlayOrigin", "cdkConnectedOverlayPositions", "cdkConnectedOverlayPositionStrategy", "cdkConnectedOverlayOffsetX", "cdkConnectedOverlayOffsetY", "cdkConnectedOverlayWidth", "cdkConnectedOverlayHeight", "cdkConnectedOverlayMinWidth", "cdkConnectedOverlayMinHeight", "cdkConnectedOverlayBackdropClass", "cdkConnectedOverlayPanelClass", "cdkConnectedOverlayViewportMargin", "cdkConnectedOverlayScrollStrategy", "cdkConnectedOverlayOpen", "cdkConnectedOverlayDisableClose", "cdkConnectedOverlayTransformOriginOn", "cdkConnectedOverlayHasBackdrop", "cdkConnectedOverlayLockPosition", "cdkConnectedOverlayFlexibleDimensions", "cdkConnectedOverlayGrowAfterOpen", "cdkConnectedOverlayPush", "cdkConnectedOverlayDisposeOnNavigation"], outputs: ["backdropClick", "positionChange", "attach", "detach", "overlayKeydown", "overlayOutsideClick"], exportAs: ["cdkConnectedOverlay"] }, { kind: "directive", type: i19.CdkOverlayOrigin, selector: "[cdk-overlay-origin], [overlay-origin], [cdkOverlayOrigin]", exportAs: ["cdkOverlayOrigin"] }, { kind: "ngmodule", type: MatDialogModule }] });
|
|
21526
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.1.4", type: PraxisFilter, isStandalone: true, selector: "praxis-filter", inputs: { resourcePath: "resourcePath", formId: "formId", mode: "mode", notifyIfOutdated: "notifyIfOutdated", snoozeMs: "snoozeMs", autoOpenSettingsOnOutdated: "autoOpenSettingsOnOutdated", editModeEnabled: "editModeEnabled", value: "value", quickField: "quickField", alwaysVisibleFields: "alwaysVisibleFields", tags: "tags", allowSaveTags: "allowSaveTags", persistenceKey: "persistenceKey", i18n: "i18n", changeDebounceMs: "changeDebounceMs", showFilterSettings: "showFilterSettings", showQuickFallback: "showQuickFallback", summary: "summary", summaryTemplate: "summaryTemplate", summaryMap: "summaryMap", autoSummary: "autoSummary", confirmTagDelete: "confirmTagDelete", debugLayout: "debugLayout", placeBooleansInActions: "placeBooleansInActions", showToggleLabels: "showToggleLabels", alwaysMinWidth: "alwaysMinWidth", alwaysColsMd: "alwaysColsMd", alwaysColsLg: "alwaysColsLg", tagColor: "tagColor", tagVariant: "tagVariant", tagButtonColor: "tagButtonColor", actionsButtonColor: "actionsButtonColor", actionsVariant: "actionsVariant", overlayVariant: "overlayVariant", overlayBackdrop: "overlayBackdrop", advancedOpenMode: "advancedOpenMode" }, outputs: { submit: "submit", change: "change", clear: "clear", modeChange: "modeChange", requestSearch: "requestSearch", tagsChange: "tagsChange", metaChanged: "metaChanged", schemaStatusChange: "schemaStatusChange" }, host: { listeners: { "window:resize": "onWindowResize()", "document:keydown": "onGlobalKeydown($event)" }, properties: { "class.debug-layout": "debugLayout", "style.--pfx-always-min": "alwaysMinWidth + \"px\"", "style.--pfx-always-cols-md": "alwaysColsMd", "style.--pfx-always-cols-lg": "alwaysColsLg" } }, viewQueries: [{ propertyName: "anchorRef", first: true, predicate: ["anchorRef"], descendants: true, read: CdkOverlayOrigin }, { propertyName: "quickHostRef", first: true, predicate: ["quickHostRef"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<ng-container *ngIf=\"modeState === 'filter'; else summaryCard\">\n <mat-progress-bar *ngIf=\"saving\" mode=\"indeterminate\"></mat-progress-bar>\n\n <form class=\"praxis-filter-bar\" [class.is-open]=\"advancedOpen\" (submit)=\"onSubmit(); $event.preventDefault()\">\n <!-- QUICK FIELD (oculto quando n\u00E3o h\u00E1 Quick e existem campos sempre vis\u00EDveis, salvo override) -->\n <ng-container *ngIf=\"showQuickBar(); else noQuick\">\n <div class=\"quick-field\" *ngIf=\"quickFieldMeta; else fallbackQuick\">\n <div class=\"filter-anchor quick-shell\" #anchorRef=\"cdkOverlayOrigin\" cdkOverlayOrigin>\n\n <!-- din\u00E2mico: envolvido por host para garantir layout flex correto -->\n <div *ngIf=\"quickFieldMode === 'dynamic'\" class=\"quick-field-host\" #quickHostRef\n dynamicFieldLoader\n [fields]=\"quickFieldMetaArray\"\n [formGroup]=\"quickForm\"\n (componentsCreated)=\"onQuickComponents($event)\"\n (fieldCreated)=\"onQuickFieldCreated($event)\">\n </div>\n\n <!-- fallback (com meta) \u2014 sem suffix, s\u00F3 o input -->\n <mat-form-field *ngIf=\"quickFieldMode === 'fallback'\"\n appearance=\"outline\"\n floatLabel=\"always\"\n class=\"fallback-quick-field\">\n <mat-label>{{ quickFieldMeta.label || quickField }}</mat-label>\n <input matInput [formControl]=\"quickControl\"\n [type]=\"getQuickInputType()\"\n [attr.inputmode]=\"getQuickInputMode()\"\n [attr.aria-label]=\"quickFieldMeta.label || quickField\"\n (keydown.escape)=\"onQuickClear()\"\n (keypress)=\"onQuickNumericKeypress($event)\"\n (blur)=\"onQuickBlurFormat()\">\n </mat-form-field>\n\n \n </div>\n </div>\n\n\n <!-- QUICK \u201Cfalso\u201D (quando n\u00E3o h\u00E1 meta) -->\n <ng-template #fallbackQuick>\n <div class=\"filter-anchor quick-shell\" #anchorRef=\"cdkOverlayOrigin\" cdkOverlayOrigin>\n <mat-form-field appearance=\"outline\" floatLabel=\"always\" class=\"fallback-quick-field\">\n <mat-label>{{ i18nLabels.searchPlaceholder }}</mat-label>\n <input matInput [formControl]=\"quickControl\"\n [attr.aria-label]=\"i18nLabels.searchPlaceholder\"\n (keydown.escape)=\"onQuickClear()\" />\n </mat-form-field>\n </div>\n </ng-template>\n </ng-container>\n\n <ng-template #noQuick></ng-template>\n\n <!-- A\u00C7\u00D5ES INLINE (fixas \u00E0 direita da barra) -->\n <div class=\"inline-actions\" [class.actions-outlined]=\"actionsVariant==='outlined'\">\n <!-- Anchor de overlay quando n\u00E3o h\u00E1 Quick -->\n <div *ngIf=\"!showQuickBar()\" class=\"actions-anchor\" #anchorRef=\"cdkOverlayOrigin\" cdkOverlayOrigin></div>\n <!-- Toggles/booleans simples realocados para a barra de a\u00E7\u00F5es -->\n <div class=\"inline-toggles\" *ngIf=\"toggleMetas.length\">\n <ng-container dynamicFieldLoader [fields]=\"toggleMetas\" [formGroup]=\"alwaysForm\"\n (componentsCreated)=\"onToggleComponents($event)\"></ng-container>\n </div>\n <button mat-icon-button [color]=\"actionsButtonColor==='basic'? null : actionsButtonColor\" type=\"button\" *ngIf=\"quickHasValue()\"\n (click)=\"onQuickClear()\" [attr.aria-label]=\"i18nLabels.clear\">\n <mat-icon [praxisIcon]=\"'close'\"></mat-icon>\n </button>\n <button mat-icon-button [color]=\"actionsButtonColor==='basic'? null : actionsButtonColor\" type=\"button\" (click)=\"onSubmit()\" [attr.aria-label]=\"i18nLabels.apply\">\n <mat-icon [praxisIcon]=\"'search'\"></mat-icon>\n </button>\n <button mat-icon-button [color]=\"actionsButtonColor==='basic'? null : actionsButtonColor\" type=\"button\"\n [matBadge]=\"activeFiltersCount\"\n [matBadgeHidden]=\"!activeFiltersCount\"\n matBadgeSize=\"small\"\n matBadgeColor=\"primary\"\n [matBadgeOverlap]=\"false\"\n (click)=\"toggleAdvanced()\"\n [attr.aria-label]=\"getAdvancedAriaLabel()\"\n [attr.aria-expanded]=\"advancedOpen\"\n [attr.aria-controls]=\"advancedPanelId\">\n <mat-icon [praxisIcon]=\"'tune'\"></mat-icon>\n </button>\n <button mat-icon-button [color]=\"actionsButtonColor==='basic'? null : actionsButtonColor\" type=\"button\" (click)=\"openSettings()\" *ngIf=\"showFilterSettings\"\n [matBadge]=\"schemaOutdated ? '!' : ''\"\n [matBadgeHidden]=\"!schemaOutdated\"\n matBadgeColor=\"warn\" matBadgeSize=\"small\" matBadgePosition=\"above after\"\n [matTooltip]=\"schemaOutdated ? 'Schema do servidor mudou \u2014 Reconciliar' : i18nLabels.settings\"\n matTooltipPosition=\"below\">\n <mat-icon [praxisIcon]=\"'settings'\"></mat-icon>\n </button>\n </div>\n\n <!-- campos sempre vis\u00EDveis (se houver) -->\n <div class=\"always-fields\" *ngIf=\"alwaysVisibleMetas.length\">\n <ng-container dynamicFieldLoader [fields]=\"alwaysVisibleMetas\" [formGroup]=\"alwaysForm\"\n (componentsCreated)=\"onAlwaysComponents($event)\"></ng-container>\n </div>\n\n <!-- acessibilidade -->\n <span class=\"sr-only\" aria-live=\"polite\">\n {{ activeFiltersCount ? (activeFiltersCount + ' filtros ativos') : '' }}\n </span>\n <button type=\"submit\" class=\"hidden-submit\" aria-hidden=\"true\" tabindex=\"-1\"></button>\n </form>\n\n <!-- tags -->\n <div class=\"praxis-filter-tags\" *ngIf=\"displayedTags.length\" [class.outlined]=\"tagVariant==='outlined'\">\n <mat-chip-set>\n <mat-chip *ngFor=\"let tag of displayedTags\"\n [color]=\"tagColor === 'basic' ? null : tagColor\"\n (click)=\"applyTag(tag)\" (keydown.enter)=\"applyTag(tag)\"\n tabindex=\"0\" role=\"button\">\n <ng-container *ngIf=\"editingTagId !== tag.id; else editChip\">\n <span class=\"chip-label\">{{ tag.label }}</span>\n <span class=\"chip-actions\" *ngIf=\"isUserTag(tag)\">\n <button mat-icon-button [color]=\"tagButtonColor === 'basic' ? null : tagButtonColor\"\n (click)=\"startEditTag(tag, $event)\" aria-label=\"edit tag\">\n <mat-icon>edit</mat-icon>\n </button>\n <button mat-icon-button [color]=\"tagButtonColor === 'basic' ? null : tagButtonColor\"\n (click)=\"deleteTag(tag)\" aria-label=\"remove tag\">\n <mat-icon>close</mat-icon>\n </button>\n </span>\n </ng-container>\n <ng-template #editChip>\n <input matInput class=\"chip-editor\" [formControl]=\"editingTagLabel\"\n (keydown.enter)=\"commitEditTag(tag, $event)\" (keydown.escape)=\"cancelEditTag($event)\" (click)=\"$event.stopPropagation()\" />\n <button mat-button color=\"primary\" (click)=\"commitEditTag(tag, $event)\">{{ i18nLabels.save }}</button>\n <button mat-button (click)=\"cancelEditTag($event)\">{{ i18nLabels.cancel }}</button>\n </ng-template>\n </mat-chip>\n </mat-chip-set>\n </div>\n\n <!-- OVERLAY -->\n <ng-container *ngIf=\"overlayOrigin\">\n <ng-template cdkConnectedOverlay\n [cdkConnectedOverlayOrigin]=\"overlayOrigin!\"\n [cdkConnectedOverlayOpen]=\"advancedOpen\"\n [cdkConnectedOverlayHasBackdrop]=\"overlayBackdrop\"\n [cdkConnectedOverlayBackdropClass]=\"'praxis-overlay-backdrop'\"\n [cdkConnectedOverlayPositions]=\"overlayPositions\"\n [cdkConnectedOverlayFlexibleDimensions]=\"true\"\n [cdkConnectedOverlayPush]=\"true\"\n [cdkConnectedOverlayOffsetY]=\"8\"\n [cdkConnectedOverlayLockPosition]=\"true\"\n [cdkConnectedOverlayWidth]=\"overlayWidth\"\n [cdkConnectedOverlayPanelClass]=\"['praxis-filter-overlay', isMobile ? 'mobile' : '', overlayVariant === 'frosted' ? 'frosted' : '']\"\n (overlayOutsideClick)=\"onOverlayOutsideClick($event)\"\n (backdropClick)=\"onOverlayDetach()\"\n (detach)=\"onOverlayDetach()\">\n <div class=\"praxis-filter-advanced\" (keydown.escape)=\"toggleAdvanced()\" (keydown.enter)=\"onAdvancedSubmit({ formData: (advancedForm?.getRawValue?.() || {}) })\" role=\"dialog\" aria-modal=\"true\" [attr.id]=\"advancedPanelId\">\n <div class=\"advanced-body\">\n <mat-progress-bar *ngIf=\"schemaLoading\" mode=\"indeterminate\"></mat-progress-bar>\n <p *ngIf=\"schemaError\" class=\"schema-error\">\n {{ i18nLabels.errorLoadingFilters }}\n <button mat-button type=\"button\" (click)=\"loadSchema()\">{{ i18nLabels.retry }}</button>\n </p>\n <praxis-filter-form *ngIf=\"!schemaLoading && !schemaError && advancedConfig\"\n [formId]=\"formId\" [resourcePath]=\"resourcePath\" [mode]=\"'edit'\" [config]=\"advancedConfig\"\n (formReady)=\"onAdvancedReady($event)\" (valueChange)=\"onAdvancedChange($event)\"\n (validityChange)=\"onAdvancedValidityChange($event)\" (submit)=\"onAdvancedSubmit($event)\">\n </praxis-filter-form>\n <p *ngIf=\"!schemaLoading && !schemaError && !advancedConfig\">{{ i18nLabels.noData }}</p>\n </div>\n <div class=\"advanced-actions\" *ngIf=\"!schemaLoading && !schemaError && advancedConfig\">\n <button mat-button type=\"button\" *ngIf=\"allowSaveTags && activeFiltersCount\" (click)=\"saveCurrentAsTag()\">\n {{ i18nLabels.saveAsShortcut }}\n </button>\n <button mat-raised-button color=\"primary\" type=\"button\"\n (click)=\"onAdvancedSubmit({ formData: (advancedForm?.getRawValue?.() || {}) })\"\n [disabled]=\"!advancedValid\">\n {{ i18nLabels.apply }}\n </button>\n <button mat-button type=\"button\" (click)=\"onClear()\">{{ i18nLabels.clear }}</button>\n </div>\n </div>\n </ng-template>\n </ng-container>\n</ng-container>\n\n<!-- resumo -->\n<ng-template #summaryCard>\n <div class=\"praxis-filter-card\" (keydown.escape)=\"onClear()\">\n <div class=\"summary-header\">\n <img *ngIf=\"currentSummaryMap?.avatar?.(currentSummary)\" [src]=\"currentSummaryMap?.avatar?.(currentSummary)\"\n class=\"summary-avatar\" alt=\"\" />\n <div class=\"summary-text\">\n <div class=\"summary-title\">{{ currentSummaryMap?.title?.(currentSummary) || '' }}</div>\n <div class=\"summary-subtitle\" *ngIf=\"currentSummaryMap?.subtitle\">{{ currentSummaryMap?.subtitle?.(currentSummary) }}</div>\n </div>\n </div>\n <div class=\"summary-badges\" *ngIf=\"currentSummaryMap?.badges?.length\">\n <span *ngFor=\"let b of currentSummaryMap!.badges\">{{ b(currentSummary) }}</span>\n </div>\n <div class=\"card-actions\">\n <button mat-button type=\"button\" (click)=\"switchToFilter()\">{{ i18nLabels.edit }}</button>\n <button mat-button type=\"button\" (click)=\"onClear()\">{{ i18nLabels.clear }}</button>\n </div>\n </div>\n</ng-template>\n", styles: ["@charset \"UTF-8\";:root{--pfx-filter-h: 40px;--pfx-filter-align-offset: 2px;--pfx-gap-x: 16px;--pfx-gap-y: 12px;--pfx-quick-pad-top: 5px;--pfx-quick-pad-left: 12px;--pfx-advanced-pad-x: 24px;--pfx-field-min: 280px;--pfx-quick-bg: var(--surface-2, #232a32);--pfx-quick-border: var(--pfx-surface-border, rgba(255,255,255,.08));--pfx-quick-radius: 12px}.praxis-filter-bar{display:grid;width:100%;grid-template-columns:1fr auto;grid-template-areas:\"quick actions\" \"always always\";column-gap:0;row-gap:8px;align-items:center}:host.debug-layout{background-image:repeating-linear-gradient(to right,rgba(147,197,253,.08) 0,rgba(147,197,253,.08) 1px,transparent 1px,transparent var(--pfx-gap-x)),repeating-linear-gradient(to bottom,rgba(163,230,53,.08) 0,rgba(163,230,53,.08) 1px,transparent 1px,transparent 8px)}:host.debug-layout .praxis-filter-bar{outline:1px dashed #f59e0b}:host.debug-layout .quick-shell{outline:1px dashed #3b82f6}:host.debug-layout .always-fields{outline:1px dashed #22c55e}:host.debug-layout .praxis-filter-overlay .praxis-filter-advanced{outline:2px solid #a855f7}.quick-field{grid-area:quick;min-width:280px;align-self:center}.inline-actions{grid-area:actions;justify-self:end}.always-fields{grid-area:always}.inline-actions .actions-anchor{width:0;height:0;overflow:hidden}.quick-shell{min-height:var(--pfx-filter-h);padding:0 0 0 var(--pfx-quick-pad-left);display:flex;align-items:center;flex-wrap:nowrap;gap:6px;overflow:hidden;background:var(--pfx-quick-bg);border:1px solid var(--pfx-quick-border);border-right:none;border-radius:var(--pfx-quick-radius) 0 0 var(--pfx-quick-radius)}.quick-shell>*{flex:1 1 auto;min-width:0}.quick-field-host{display:contents}:host ::ng-deep .quick-shell .mat-mdc-form-field{width:100%!important;flex:1 1 auto}:host ::ng-deep .quick-shell .mat-mdc-form-field{margin:0!important}:host ::ng-deep .quick-shell pdx-text-input,:host ::ng-deep .quick-shell pdx-select,:host ::ng-deep .quick-shell pdx-date-input,:host ::ng-deep .quick-shell pdx-auto-complete{flex:1 1 auto;min-width:0;display:block}.inline-actions{flex:0 0 auto;display:flex;gap:4px;align-self:start;white-space:nowrap;height:var(--pfx-filter-h);align-items:center;background:var(--pfx-quick-bg);border:1px solid var(--pfx-quick-border);border-left:none;border-radius:0 var(--pfx-quick-radius) var(--pfx-quick-radius) 0;padding-right:4px;margin-left:-1px}.inline-actions.actions-outlined button.mat-mdc-icon-button{border:1px solid var(--pfx-quick-border);border-radius:50%}.inline-actions .mat-mdc-icon-button{width:36px;height:36px}.inline-actions mat-icon{width:20px;height:20px;font-size:20px}.fallback-quick-field{height:var(--pfx-filter-h);display:flex;align-items:center}:host ::ng-deep .fallback-quick-field .mat-mdc-text-field-wrapper.mdc-text-field--outlined{height:var(--pfx-filter-h);align-items:center;padding-top:var(--pfx-quick-pad-top)}:host ::ng-deep .quick-shell .mat-mdc-text-field-wrapper.mdc-text-field--outlined{min-height:var(--pfx-filter-h);align-items:center;padding-top:var(--pfx-quick-pad-top)}:host ::ng-deep .quick-shell .mat-mdc-form-field-infix{min-height:var(--pfx-filter-h);padding-top:8px}:host ::ng-deep .quick-shell .mat-mdc-select-trigger{height:var(--pfx-filter-h);align-items:center}:host ::ng-deep .quick-shell .mat-mdc-form-field-subscript-wrapper{display:none}:host ::ng-deep .quick-shell .mdc-line-ripple{display:none!important}.always-fields{display:grid;grid-template-columns:repeat(auto-fit,minmax(var(--pfx-always-min, 300px),1fr));gap:8px}:host ::ng-deep .always-fields .mat-mdc-text-field-wrapper.mdc-text-field--outlined{min-height:var(--pfx-filter-h);align-items:center}:host ::ng-deep .always-fields .mat-mdc-form-field-infix{min-height:var(--pfx-filter-h)}:host ::ng-deep .always-fields .mat-mdc-select-trigger{height:var(--pfx-filter-h);align-items:center}:host ::ng-deep .always-fields .mat-mdc-form-field{width:100%}.praxis-filter-tags{display:flex;flex-wrap:wrap;gap:6px}.praxis-filter-tags mat-chip{border-radius:16px;padding:0 6px}.praxis-filter-tags .chip-actions{display:inline-flex;align-items:center;gap:2px;margin-left:4px}.chip-editor{width:140px;margin-right:8px}.praxis-filter-tags.outlined mat-chip{background:transparent!important;border:1px solid var(--pfx-quick-border)}.praxis-filter-advanced{display:flex;flex-direction:column;min-width:400px;max-width:90vw;min-height:260px;max-height:80vh;margin-top:25px;margin-right:15px;margin-left:25px;background:var(--md-sys-color-surface-container, #2a3038)!important;background-color:var(--md-sys-color-surface-container, #2a3038)!important;background:color-mix(in srgb,var(--md-sys-color-surface-container, #2a3038),transparent 6%)!important;color:var(--md-sys-color-on-surface, #e6eaf2);border:1px solid var(--border-color);border-radius:12px;box-shadow:0 8px 24px #00000052,0 2px 8px #0000002e}.praxis-filter-overlay.mobile .praxis-filter-advanced{height:100vh;max-height:100vh}:host ::ng-deep .praxis-overlay-backdrop{background:#0006;-webkit-backdrop-filter:blur(2px);backdrop-filter:blur(2px)}.advanced-body{padding:var(--pfx-gap-y) var(--pfx-advanced-pad-x) 72px;overflow:auto;flex:1 1 auto;overscroll-behavior:contain}:host ::ng-deep .praxis-filter-advanced .praxis-filter-form .filter-row{display:grid!important;grid-template-columns:repeat(auto-fit,minmax(var(--pfx-field-min),1fr));gap:var(--pfx-gap-y) var(--pfx-gap-x)}:host ::ng-deep .praxis-filter-advanced .praxis-filter-form .filter-column{min-width:0}:host ::ng-deep .praxis-filter-advanced .praxis-filter-form .filter-column .mat-mdc-form-field{width:100%}.advanced-actions{position:sticky;bottom:0;z-index:2;display:flex;justify-content:flex-end;gap:8px;padding:var(--pfx-gap-y) var(--pfx-advanced-pad-x);background:var(--md-sys-color-surface-container, #2a3038)!important;background-color:var(--md-sys-color-surface-container, #2a3038)!important;background:color-mix(in srgb,var(--md-sys-color-surface-container, #2a3038),transparent 0%)!important;border-top:1px solid var(--border-color);box-shadow:0 -1px #0000002e}.advanced-actions .mat-mdc-button-base{height:40px}.advanced-actions .mat-mdc-raised-button.mat-primary{background:var(--md-sys-color-primary);color:var(--md-sys-color-on-primary)}:host ::ng-deep .praxis-filter-advanced .mat-mdc-text-field-wrapper.mdc-text-field--outlined{--mdc-outlined-text-field-outline-color: var(--border-color);--mdc-outlined-text-field-hover-outline-color: var(--border-color-hover);--mdc-outlined-text-field-focus-outline-color: var(--md-sys-color-primary);--mdc-outlined-text-field-label-text-color: var(--md-sys-color-on-surface-variant);--mdc-outlined-text-field-input-text-color: var(--md-sys-color-on-surface);--mdc-outlined-text-field-container-color: var(--md-sys-color-surface-container, #2a3038);--mdc-outlined-text-field-container-color: color-mix(in srgb, var(--md-sys-color-surface-container, #2a3038), transparent 90%)}:host ::ng-deep .praxis-filter-advanced .mat-mdc-select-trigger,:host ::ng-deep .praxis-filter-advanced .mat-mdc-form-field-subscript-wrapper,:host ::ng-deep .praxis-filter-advanced .mat-mdc-form-field-infix{color:var(--md-sys-color-on-surface)}@media (min-width: 600px){.always-fields{grid-template-columns:repeat(var(--pfx-always-cols-md, 2),minmax(0,1fr))}:host ::ng-deep .praxis-filter-advanced .praxis-filter-form .filter-row{grid-template-columns:repeat(2,minmax(0,1fr))}}@media (min-width: 960px){.always-fields{grid-template-columns:repeat(var(--pfx-always-cols-lg, 3),minmax(0,1fr))}}.inline-toggles{display:flex;align-items:center;gap:8px;margin:0 4px 0 6px}:host ::ng-deep .inline-actions .mat-mdc-slide-toggle{height:var(--pfx-filter-h);display:flex;align-items:center}:host ::ng-deep .inline-actions .mat-mdc-slide-toggle .mdc-form-field{align-items:center}::ng-deep .praxis-filter-overlay .praxis-filter-advanced .praxis-filter-form .filter-row{display:grid!important;gap:var(--pfx-gap-y, 1px) var(--pfx-gap-x, 6px)}@media (min-width: 600px){::ng-deep .praxis-filter-overlay .praxis-filter-advanced .praxis-filter-form .filter-row{grid-template-columns:repeat(2,minmax(0,1fr))}}.sr-only{position:absolute!important;width:1px!important;height:1px!important;margin:-1px!important;overflow:hidden!important;clip:rect(0,0,0,0)!important}.hidden-submit{position:absolute!important;width:0!important;height:0!important;padding:0!important;margin:0!important;border:0!important;opacity:0!important;pointer-events:none!important;clip:rect(0 0 0 0)!important;clip-path:inset(50%)!important;overflow:hidden!important}:host ::ng-deep .inline-actions [matBadge] .mat-badge-content{top:-6px;right:-6px}.praxis-filter-bar :where(.mat-mdc-slide-toggle .mdc-switch__icons){display:none!important}.praxis-filter-bar{--mdc-switch-unselected-icon-size: 0px;--mdc-switch-selected-icon-size: 0px;--pfx-always-min: 240px}.praxis-filter-card{display:flex;flex-direction:column;gap:6px;padding:8px 12px;border-radius:12px;border:1px solid var(--pfx-quick-border);background:var(--pfx-quick-bg);color:var(--md-sys-color-on-surface, #2B2A28)}.praxis-filter-card .summary-header{display:flex;align-items:center;gap:10px}.praxis-filter-card .summary-avatar{width:32px;height:32px;border-radius:50%;object-fit:cover}.praxis-filter-card .summary-title{font-weight:600}.praxis-filter-card .summary-subtitle{opacity:.8;font-size:.875rem}.praxis-filter-card .summary-badges{display:flex;flex-wrap:wrap;gap:6px}.praxis-filter-card .summary-badges span{display:inline-flex;align-items:center;padding:2px 8px;border-radius:999px;background:color-mix(in oklab,var(--md-sys-color-primary, #3FBCA5),transparent 88%);border:1px solid color-mix(in oklab,var(--md-sys-color-primary, #3FBCA5),transparent 70%);color:var(--md-sys-color-on-surface, #2B2A28);font-size:12px}.praxis-filter-card .card-actions{display:flex;gap:8px}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { 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.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i3$1.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i3$1.MatLabel, selector: "mat-label" }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i6.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: 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: "ngmodule", type: MatChipsModule }, { kind: "component", type: i11.MatChip, selector: "mat-basic-chip, [mat-basic-chip], mat-chip, [mat-chip]", inputs: ["role", "id", "aria-label", "aria-description", "value", "color", "removable", "highlighted", "disableRipple", "disabled"], outputs: ["removed", "destroyed"], exportAs: ["matChip"] }, { kind: "component", type: i11.MatChipSet, selector: "mat-chip-set", inputs: ["disabled", "role", "tabIndex"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i4.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "directive", type: PraxisIconDirective, selector: "mat-icon[praxisIcon]", inputs: ["praxisIcon"] }, { kind: "ngmodule", type: MatBadgeModule }, { kind: "directive", type: i15.MatBadge, selector: "[matBadge]", inputs: ["matBadgeColor", "matBadgeOverlap", "matBadgeDisabled", "matBadgePosition", "matBadge", "matBadgeDescription", "matBadgeSize", "matBadgeHidden"] }, { kind: "ngmodule", type: MatProgressBarModule }, { kind: "component", type: i14$1.MatProgressBar, selector: "mat-progress-bar", inputs: ["color", "value", "bufferValue", "mode"], outputs: ["animationEnd"], exportAs: ["matProgressBar"] }, { kind: "ngmodule", type: MatSnackBarModule }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i10.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "directive", type: DynamicFieldLoaderDirective, selector: "[dynamicFieldLoader]", inputs: ["fields", "formGroup", "enableExternalControlBinding", "itemTemplate", "readonlyMode", "disabledMode", "presentationMode", "visible", "canvasMode"], outputs: ["componentsCreated", "fieldCreated", "fieldDestroyed", "canvasMouseEnter", "canvasMouseLeave", "canvasClick"] }, { kind: "component", type: PraxisFilterForm, selector: "praxis-filter-form", inputs: ["config", "formId", "resourcePath", "mode"], outputs: ["formReady", "valueChange", "submit", "validityChange"] }, { kind: "ngmodule", type: OverlayModule }, { kind: "directive", type: i19.CdkConnectedOverlay, selector: "[cdk-connected-overlay], [connected-overlay], [cdkConnectedOverlay]", inputs: ["cdkConnectedOverlayOrigin", "cdkConnectedOverlayPositions", "cdkConnectedOverlayPositionStrategy", "cdkConnectedOverlayOffsetX", "cdkConnectedOverlayOffsetY", "cdkConnectedOverlayWidth", "cdkConnectedOverlayHeight", "cdkConnectedOverlayMinWidth", "cdkConnectedOverlayMinHeight", "cdkConnectedOverlayBackdropClass", "cdkConnectedOverlayPanelClass", "cdkConnectedOverlayViewportMargin", "cdkConnectedOverlayScrollStrategy", "cdkConnectedOverlayOpen", "cdkConnectedOverlayDisableClose", "cdkConnectedOverlayTransformOriginOn", "cdkConnectedOverlayHasBackdrop", "cdkConnectedOverlayLockPosition", "cdkConnectedOverlayFlexibleDimensions", "cdkConnectedOverlayGrowAfterOpen", "cdkConnectedOverlayPush", "cdkConnectedOverlayDisposeOnNavigation"], outputs: ["backdropClick", "positionChange", "attach", "detach", "overlayKeydown", "overlayOutsideClick"], exportAs: ["cdkConnectedOverlay"] }, { kind: "directive", type: i19.CdkOverlayOrigin, selector: "[cdk-overlay-origin], [overlay-origin], [cdkOverlayOrigin]", exportAs: ["cdkOverlayOrigin"] }, { kind: "ngmodule", type: MatDialogModule }] });
|
|
21409
21527
|
}
|
|
21410
21528
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: PraxisFilter, decorators: [{
|
|
21411
21529
|
type: Component,
|
|
@@ -21431,7 +21549,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.4", ngImpor
|
|
|
21431
21549
|
'[style.--pfx-always-min]': 'alwaysMinWidth + "px"',
|
|
21432
21550
|
'[style.--pfx-always-cols-md]': 'alwaysColsMd',
|
|
21433
21551
|
'[style.--pfx-always-cols-lg]': 'alwaysColsLg',
|
|
21434
|
-
}, template: "<ng-container *ngIf=\"modeState === 'filter'; else summaryCard\">\n <mat-progress-bar *ngIf=\"saving\" mode=\"indeterminate\"></mat-progress-bar>\n\n <form class=\"praxis-filter-bar\" [class.is-open]=\"advancedOpen\" (submit)=\"onSubmit(); $event.preventDefault()\">\n <!-- QUICK FIELD -->\n <div class=\"quick-field\" *ngIf=\"quickFieldMeta; else fallbackQuick\">\n <div class=\"filter-anchor quick-shell\" #anchorRef=\"cdkOverlayOrigin\" cdkOverlayOrigin>\n\n <!-- din\u00E2mico: envolvido por host para garantir layout flex correto -->\n <div *ngIf=\"quickFieldMode === 'dynamic'\" class=\"quick-field-host\" #quickHostRef\n dynamicFieldLoader\n [fields]=\"quickFieldMetaArray\"\n [formGroup]=\"quickForm\"\n (componentsCreated)=\"onQuickComponents($event)\"\n (fieldCreated)=\"onQuickFieldCreated($event)\">\n </div>\n\n <!-- fallback (com meta) \u2014 sem suffix, s\u00F3 o input -->\n <mat-form-field *ngIf=\"quickFieldMode === 'fallback'\"\n appearance=\"outline\"\n floatLabel=\"always\"\n class=\"fallback-quick-field\">\n <mat-label>{{ quickFieldMeta.label || quickField }}</mat-label>\n <input matInput [formControl]=\"quickControl\"\n [type]=\"getQuickInputType()\"\n [attr.inputmode]=\"getQuickInputMode()\"\n [attr.aria-label]=\"quickFieldMeta.label || quickField\"\n (keydown.escape)=\"onQuickClear()\"\n (keypress)=\"onQuickNumericKeypress($event)\"\n (blur)=\"onQuickBlurFormat()\">\n </mat-form-field>\n\n \n </div>\n </div>\n\n\n <!-- QUICK \u201Cfalso\u201D (quando n\u00E3o h\u00E1 meta) -->\n <ng-template #fallbackQuick>\n <div class=\"filter-anchor quick-shell\" #anchorRef=\"cdkOverlayOrigin\" cdkOverlayOrigin>\n <mat-form-field appearance=\"outline\" floatLabel=\"always\" class=\"fallback-quick-field\">\n <mat-label>{{ i18nLabels.searchPlaceholder }}</mat-label>\n <input matInput [formControl]=\"quickControl\"\n [attr.aria-label]=\"i18nLabels.searchPlaceholder\"\n (keydown.escape)=\"onQuickClear()\" />\n </mat-form-field>\n </div>\n </ng-template>\n\n <!-- A\u00C7\u00D5ES INLINE (fixas \u00E0 direita da barra) -->\n <div class=\"inline-actions\" [class.actions-outlined]=\"actionsVariant==='outlined'\">\n <!-- Toggles/booleans simples realocados para a barra de a\u00E7\u00F5es -->\n <div class=\"inline-toggles\" *ngIf=\"toggleMetas.length\">\n <ng-container dynamicFieldLoader [fields]=\"toggleMetas\" [formGroup]=\"alwaysForm\"\n (componentsCreated)=\"onToggleComponents($event)\"></ng-container>\n </div>\n <button mat-icon-button [color]=\"actionsButtonColor==='basic'? null : actionsButtonColor\" type=\"button\" *ngIf=\"quickHasValue()\"\n (click)=\"onQuickClear()\" [attr.aria-label]=\"i18nLabels.clear\">\n <mat-icon [praxisIcon]=\"'close'\"></mat-icon>\n </button>\n <button mat-icon-button [color]=\"actionsButtonColor==='basic'? null : actionsButtonColor\" type=\"button\" (click)=\"onSubmit()\" [attr.aria-label]=\"i18nLabels.apply\">\n <mat-icon [praxisIcon]=\"'search'\"></mat-icon>\n </button>\n <button mat-icon-button [color]=\"actionsButtonColor==='basic'? null : actionsButtonColor\" type=\"button\"\n [matBadge]=\"activeFiltersCount\"\n [matBadgeHidden]=\"!activeFiltersCount\"\n matBadgeSize=\"small\"\n matBadgeColor=\"primary\"\n [matBadgeOverlap]=\"false\"\n (click)=\"toggleAdvanced()\"\n [attr.aria-label]=\"getAdvancedAriaLabel()\"\n [attr.aria-expanded]=\"advancedOpen\"\n [attr.aria-controls]=\"advancedPanelId\">\n <mat-icon [praxisIcon]=\"'tune'\"></mat-icon>\n </button>\n <button mat-icon-button [color]=\"actionsButtonColor==='basic'? null : actionsButtonColor\" type=\"button\" (click)=\"openSettings()\" *ngIf=\"showFilterSettings\"\n [matBadge]=\"schemaOutdated ? '!' : ''\"\n [matBadgeHidden]=\"!schemaOutdated\"\n matBadgeColor=\"warn\" matBadgeSize=\"small\" matBadgePosition=\"above after\"\n [matTooltip]=\"schemaOutdated ? 'Schema do servidor mudou \u2014 Reconciliar' : i18nLabels.settings\"\n matTooltipPosition=\"below\">\n <mat-icon [praxisIcon]=\"'settings'\"></mat-icon>\n </button>\n </div>\n\n <!-- campos sempre vis\u00EDveis (se houver) -->\n <div class=\"always-fields\" *ngIf=\"alwaysVisibleMetas.length\">\n <ng-container dynamicFieldLoader [fields]=\"alwaysVisibleMetas\" [formGroup]=\"alwaysForm\"\n (componentsCreated)=\"onAlwaysComponents($event)\"></ng-container>\n </div>\n\n <!-- acessibilidade -->\n <span class=\"sr-only\" aria-live=\"polite\">\n {{ activeFiltersCount ? (activeFiltersCount + ' filtros ativos') : '' }}\n </span>\n <button type=\"submit\" class=\"hidden-submit\" aria-hidden=\"true\" tabindex=\"-1\"></button>\n </form>\n\n <!-- tags -->\n <div class=\"praxis-filter-tags\" *ngIf=\"displayedTags.length\" [class.outlined]=\"tagVariant==='outlined'\">\n <mat-chip-set>\n <mat-chip *ngFor=\"let tag of displayedTags\"\n [color]=\"tagColor === 'basic' ? null : tagColor\"\n (click)=\"applyTag(tag)\" (keydown.enter)=\"applyTag(tag)\"\n tabindex=\"0\" role=\"button\">\n <ng-container *ngIf=\"editingTagId !== tag.id; else editChip\">\n <span class=\"chip-label\">{{ tag.label }}</span>\n <span class=\"chip-actions\" *ngIf=\"isUserTag(tag)\">\n <button mat-icon-button [color]=\"tagButtonColor === 'basic' ? null : tagButtonColor\"\n (click)=\"startEditTag(tag, $event)\" aria-label=\"edit tag\">\n <mat-icon>edit</mat-icon>\n </button>\n <button mat-icon-button [color]=\"tagButtonColor === 'basic' ? null : tagButtonColor\"\n (click)=\"deleteTag(tag)\" aria-label=\"remove tag\">\n <mat-icon>close</mat-icon>\n </button>\n </span>\n </ng-container>\n <ng-template #editChip>\n <input matInput class=\"chip-editor\" [formControl]=\"editingTagLabel\"\n (keydown.enter)=\"commitEditTag(tag, $event)\" (keydown.escape)=\"cancelEditTag($event)\" (click)=\"$event.stopPropagation()\" />\n <button mat-button color=\"primary\" (click)=\"commitEditTag(tag, $event)\">{{ i18nLabels.save }}</button>\n <button mat-button (click)=\"cancelEditTag($event)\">{{ i18nLabels.cancel }}</button>\n </ng-template>\n </mat-chip>\n </mat-chip-set>\n </div>\n\n <!-- OVERLAY -->\n <ng-container *ngIf=\"overlayOrigin\">\n <ng-template cdkConnectedOverlay\n [cdkConnectedOverlayOrigin]=\"overlayOrigin!\"\n [cdkConnectedOverlayOpen]=\"advancedOpen\"\n [cdkConnectedOverlayHasBackdrop]=\"overlayBackdrop\"\n [cdkConnectedOverlayBackdropClass]=\"'praxis-overlay-backdrop'\"\n [cdkConnectedOverlayPositions]=\"overlayPositions\"\n [cdkConnectedOverlayFlexibleDimensions]=\"true\"\n [cdkConnectedOverlayPush]=\"true\"\n [cdkConnectedOverlayOffsetY]=\"8\"\n [cdkConnectedOverlayLockPosition]=\"true\"\n [cdkConnectedOverlayWidth]=\"overlayWidth\"\n [cdkConnectedOverlayPanelClass]=\"['praxis-filter-overlay', isMobile ? 'mobile' : '', overlayVariant === 'frosted' ? 'frosted' : '']\"\n (overlayOutsideClick)=\"onOverlayOutsideClick($event)\"\n (backdropClick)=\"onOverlayDetach()\"\n (detach)=\"onOverlayDetach()\">\n <div class=\"praxis-filter-advanced\" (keydown.escape)=\"toggleAdvanced()\" role=\"dialog\" aria-modal=\"true\" [attr.id]=\"advancedPanelId\">\n <div class=\"advanced-body\">\n <mat-progress-bar *ngIf=\"schemaLoading\" mode=\"indeterminate\"></mat-progress-bar>\n <p *ngIf=\"schemaError\" class=\"schema-error\">\n {{ i18nLabels.errorLoadingFilters }}\n <button mat-button type=\"button\" (click)=\"loadSchema()\">{{ i18nLabels.retry }}</button>\n </p>\n <praxis-filter-form *ngIf=\"!schemaLoading && !schemaError && advancedConfig\"\n [formId]=\"formId\" [resourcePath]=\"resourcePath\" [mode]=\"'edit'\" [config]=\"advancedConfig\"\n (formReady)=\"onAdvancedReady($event)\" (valueChange)=\"onAdvancedChange($event)\"\n (validityChange)=\"onAdvancedValidityChange($event)\" (submit)=\"onAdvancedSubmit($event)\">\n </praxis-filter-form>\n <p *ngIf=\"!schemaLoading && !schemaError && !advancedConfig\">{{ i18nLabels.noData }}</p>\n </div>\n <div class=\"advanced-actions\" *ngIf=\"!schemaLoading && !schemaError && advancedConfig\">\n <button mat-raised-button color=\"primary\" type=\"button\"\n (click)=\"onAdvancedSubmit({ formData: (advancedForm?.getRawValue?.() || {}) })\"\n [disabled]=\"!advancedValid\">\n {{ i18nLabels.apply }}\n </button>\n <button mat-button type=\"button\" (click)=\"onClear()\">{{ i18nLabels.clear }}</button>\n </div>\n </div>\n </ng-template>\n </ng-container>\n</ng-container>\n\n<!-- resumo -->\n<ng-template #summaryCard>\n <div class=\"praxis-filter-card\" (keydown.escape)=\"onClear()\">\n <div class=\"summary-header\">\n <img *ngIf=\"currentSummaryMap?.avatar?.(currentSummary)\" [src]=\"currentSummaryMap?.avatar?.(currentSummary)\"\n class=\"summary-avatar\" alt=\"\" />\n <div class=\"summary-text\">\n <div class=\"summary-title\">{{ currentSummaryMap?.title?.(currentSummary) || '' }}</div>\n <div class=\"summary-subtitle\" *ngIf=\"currentSummaryMap?.subtitle\">{{ currentSummaryMap?.subtitle?.(currentSummary) }}</div>\n </div>\n </div>\n <div class=\"summary-badges\" *ngIf=\"currentSummaryMap?.badges?.length\">\n <span *ngFor=\"let b of currentSummaryMap!.badges\">{{ b(currentSummary) }}</span>\n </div>\n <div class=\"card-actions\">\n <button mat-button type=\"button\" (click)=\"switchToFilter()\">{{ i18nLabels.edit }}</button>\n <button mat-button type=\"button\" (click)=\"onClear()\">{{ i18nLabels.clear }}</button>\n </div>\n </div>\n</ng-template>\n", styles: ["@charset \"UTF-8\";:root{--pfx-filter-h: 40px;--pfx-filter-align-offset: 2px;--pfx-gap-x: 16px;--pfx-gap-y: 12px;--pfx-quick-pad-top: 5px;--pfx-quick-pad-left: 12px;--pfx-advanced-pad-x: 24px;--pfx-field-min: 280px;--pfx-quick-bg: var(--surface-2, #232a32);--pfx-quick-border: var(--pfx-surface-border, rgba(255,255,255,.08));--pfx-quick-radius: 12px}.praxis-filter-bar{display:grid;width:100%;grid-template-columns:1fr auto;grid-template-areas:\"quick actions\" \"always always\";column-gap:0;row-gap:8px;align-items:center}:host.debug-layout{background-image:repeating-linear-gradient(to right,rgba(147,197,253,.08) 0,rgba(147,197,253,.08) 1px,transparent 1px,transparent var(--pfx-gap-x)),repeating-linear-gradient(to bottom,rgba(163,230,53,.08) 0,rgba(163,230,53,.08) 1px,transparent 1px,transparent 8px)}:host.debug-layout .praxis-filter-bar{outline:1px dashed #f59e0b}:host.debug-layout .quick-shell{outline:1px dashed #3b82f6}:host.debug-layout .always-fields{outline:1px dashed #22c55e}:host.debug-layout .praxis-filter-overlay .praxis-filter-advanced{outline:2px solid #a855f7}.quick-field{grid-area:quick;min-width:280px;align-self:center}.inline-actions{grid-area:actions;justify-self:end}.always-fields{grid-area:always}.quick-shell{min-height:var(--pfx-filter-h);padding:0 0 0 var(--pfx-quick-pad-left);display:flex;align-items:center;flex-wrap:nowrap;gap:6px;overflow:hidden;background:var(--pfx-quick-bg);border:1px solid var(--pfx-quick-border);border-right:none;border-radius:var(--pfx-quick-radius) 0 0 var(--pfx-quick-radius)}.quick-shell>*{flex:1 1 auto;min-width:0}.quick-field-host{display:contents}:host ::ng-deep .quick-shell .mat-mdc-form-field{width:100%!important;flex:1 1 auto}:host ::ng-deep .quick-shell .mat-mdc-form-field{margin:0!important}:host ::ng-deep .quick-shell pdx-text-input,:host ::ng-deep .quick-shell pdx-select,:host ::ng-deep .quick-shell pdx-date-input,:host ::ng-deep .quick-shell pdx-auto-complete{flex:1 1 auto;min-width:0;display:block}.inline-actions{flex:0 0 auto;display:flex;gap:4px;align-self:start;white-space:nowrap;height:var(--pfx-filter-h);align-items:center;background:var(--pfx-quick-bg);border:1px solid var(--pfx-quick-border);border-left:none;border-radius:0 var(--pfx-quick-radius) var(--pfx-quick-radius) 0;padding-right:4px;margin-left:-1px}.inline-actions.actions-outlined button.mat-mdc-icon-button{border:1px solid var(--pfx-quick-border);border-radius:50%}.inline-actions .mat-mdc-icon-button{width:36px;height:36px}.inline-actions mat-icon{width:20px;height:20px;font-size:20px}.fallback-quick-field{height:var(--pfx-filter-h);display:flex;align-items:center}:host ::ng-deep .fallback-quick-field .mat-mdc-text-field-wrapper.mdc-text-field--outlined{height:var(--pfx-filter-h);align-items:center;padding-top:var(--pfx-quick-pad-top)}:host ::ng-deep .quick-shell .mat-mdc-text-field-wrapper.mdc-text-field--outlined{min-height:var(--pfx-filter-h);align-items:center;padding-top:var(--pfx-quick-pad-top)}:host ::ng-deep .quick-shell .mat-mdc-form-field-infix{min-height:var(--pfx-filter-h)}:host ::ng-deep .quick-shell .mat-mdc-select-trigger{height:var(--pfx-filter-h);align-items:center}:host ::ng-deep .quick-shell .mat-mdc-form-field-subscript-wrapper{display:none}:host ::ng-deep .quick-shell .mdc-line-ripple{display:none!important}.always-fields{display:grid;grid-template-columns:repeat(auto-fit,minmax(var(--pfx-always-min, 300px),1fr));gap:8px}:host ::ng-deep .always-fields .mat-mdc-text-field-wrapper.mdc-text-field--outlined{min-height:var(--pfx-filter-h);align-items:center}:host ::ng-deep .always-fields .mat-mdc-form-field-infix{min-height:var(--pfx-filter-h)}:host ::ng-deep .always-fields .mat-mdc-select-trigger{height:var(--pfx-filter-h);align-items:center}:host ::ng-deep .always-fields .mat-mdc-form-field{width:100%}.praxis-filter-tags{display:flex;flex-wrap:wrap;gap:6px}.praxis-filter-tags mat-chip{border-radius:16px;padding:0 6px}.praxis-filter-tags .chip-actions{display:inline-flex;align-items:center;gap:2px;margin-left:4px}.chip-editor{width:140px;margin-right:8px}.praxis-filter-tags.outlined mat-chip{background:transparent!important;border:1px solid var(--pfx-quick-border)}.praxis-filter-advanced{display:flex;flex-direction:column;min-width:400px;max-width:90vw;min-height:260px;max-height:80vh;margin-top:25px;margin-right:15px;margin-left:25px;background:var(--md-sys-color-surface-container, #2a3038)!important;background-color:var(--md-sys-color-surface-container, #2a3038)!important;background:color-mix(in srgb,var(--md-sys-color-surface-container, #2a3038),transparent 6%)!important;color:var(--md-sys-color-on-surface, #e6eaf2);border:1px solid var(--border-color);border-radius:12px;box-shadow:0 8px 24px #00000052,0 2px 8px #0000002e}.praxis-filter-overlay.mobile .praxis-filter-advanced{height:100vh;max-height:100vh}:host ::ng-deep .praxis-overlay-backdrop{background:#0006;-webkit-backdrop-filter:blur(2px);backdrop-filter:blur(2px)}.advanced-body{padding:var(--pfx-gap-y) var(--pfx-advanced-pad-x) 72px;overflow:auto;flex:1 1 auto;overscroll-behavior:contain}:host ::ng-deep .praxis-filter-advanced .praxis-filter-form .filter-row{display:grid!important;grid-template-columns:repeat(auto-fit,minmax(var(--pfx-field-min),1fr));gap:var(--pfx-gap-y) var(--pfx-gap-x)}:host ::ng-deep .praxis-filter-advanced .praxis-filter-form .filter-column{min-width:0}:host ::ng-deep .praxis-filter-advanced .praxis-filter-form .filter-column .mat-mdc-form-field{width:100%}.advanced-actions{position:sticky;bottom:0;z-index:2;display:flex;justify-content:flex-end;gap:8px;padding:var(--pfx-gap-y) var(--pfx-advanced-pad-x);background:var(--md-sys-color-surface-container, #2a3038)!important;background-color:var(--md-sys-color-surface-container, #2a3038)!important;background:color-mix(in srgb,var(--md-sys-color-surface-container, #2a3038),transparent 0%)!important;border-top:1px solid var(--border-color);box-shadow:0 -1px #0000002e}.advanced-actions .mat-mdc-button-base{height:40px}.advanced-actions .mat-mdc-raised-button.mat-primary{background:var(--md-sys-color-primary);color:var(--md-sys-color-on-primary)}:host ::ng-deep .praxis-filter-advanced .mat-mdc-text-field-wrapper.mdc-text-field--outlined{--mdc-outlined-text-field-outline-color: var(--border-color);--mdc-outlined-text-field-hover-outline-color: var(--border-color-hover);--mdc-outlined-text-field-focus-outline-color: var(--md-sys-color-primary);--mdc-outlined-text-field-label-text-color: var(--md-sys-color-on-surface-variant);--mdc-outlined-text-field-input-text-color: var(--md-sys-color-on-surface);--mdc-outlined-text-field-container-color: var(--md-sys-color-surface-container, #2a3038);--mdc-outlined-text-field-container-color: color-mix(in srgb, var(--md-sys-color-surface-container, #2a3038), transparent 90%)}:host ::ng-deep .praxis-filter-advanced .mat-mdc-select-trigger,:host ::ng-deep .praxis-filter-advanced .mat-mdc-form-field-subscript-wrapper,:host ::ng-deep .praxis-filter-advanced .mat-mdc-form-field-infix{color:var(--md-sys-color-on-surface)}@media (min-width: 600px){.always-fields{grid-template-columns:repeat(var(--pfx-always-cols-md, 2),minmax(0,1fr))}:host ::ng-deep .praxis-filter-advanced .praxis-filter-form .filter-row{grid-template-columns:repeat(2,minmax(0,1fr))}}@media (min-width: 960px){.always-fields{grid-template-columns:repeat(var(--pfx-always-cols-lg, 3),minmax(0,1fr))}}.inline-toggles{display:flex;align-items:center;gap:8px;margin:0 4px 0 6px}:host ::ng-deep .inline-actions .mat-mdc-slide-toggle{height:var(--pfx-filter-h);display:flex;align-items:center}:host ::ng-deep .inline-actions .mat-mdc-slide-toggle .mdc-form-field{align-items:center}::ng-deep .praxis-filter-overlay .praxis-filter-advanced .praxis-filter-form .filter-row{display:grid!important;gap:var(--pfx-gap-y, 1px) var(--pfx-gap-x, 6px)}@media (min-width: 600px){::ng-deep .praxis-filter-overlay .praxis-filter-advanced .praxis-filter-form .filter-row{grid-template-columns:repeat(2,minmax(0,1fr))}}.sr-only{position:absolute!important;width:1px!important;height:1px!important;margin:-1px!important;overflow:hidden!important;clip:rect(0,0,0,0)!important}.hidden-submit{position:absolute!important;width:0!important;height:0!important;padding:0!important;margin:0!important;border:0!important;opacity:0!important;pointer-events:none!important;clip:rect(0 0 0 0)!important;clip-path:inset(50%)!important;overflow:hidden!important}:host ::ng-deep .inline-actions [matBadge] .mat-badge-content{top:-6px;right:-6px}.praxis-filter-bar :where(.mat-mdc-slide-toggle .mdc-switch__icons){display:none!important}.praxis-filter-bar{--mdc-switch-unselected-icon-size: 0px;--mdc-switch-selected-icon-size: 0px}\n"] }]
|
|
21552
|
+
}, template: "<ng-container *ngIf=\"modeState === 'filter'; else summaryCard\">\n <mat-progress-bar *ngIf=\"saving\" mode=\"indeterminate\"></mat-progress-bar>\n\n <form class=\"praxis-filter-bar\" [class.is-open]=\"advancedOpen\" (submit)=\"onSubmit(); $event.preventDefault()\">\n <!-- QUICK FIELD (oculto quando n\u00E3o h\u00E1 Quick e existem campos sempre vis\u00EDveis, salvo override) -->\n <ng-container *ngIf=\"showQuickBar(); else noQuick\">\n <div class=\"quick-field\" *ngIf=\"quickFieldMeta; else fallbackQuick\">\n <div class=\"filter-anchor quick-shell\" #anchorRef=\"cdkOverlayOrigin\" cdkOverlayOrigin>\n\n <!-- din\u00E2mico: envolvido por host para garantir layout flex correto -->\n <div *ngIf=\"quickFieldMode === 'dynamic'\" class=\"quick-field-host\" #quickHostRef\n dynamicFieldLoader\n [fields]=\"quickFieldMetaArray\"\n [formGroup]=\"quickForm\"\n (componentsCreated)=\"onQuickComponents($event)\"\n (fieldCreated)=\"onQuickFieldCreated($event)\">\n </div>\n\n <!-- fallback (com meta) \u2014 sem suffix, s\u00F3 o input -->\n <mat-form-field *ngIf=\"quickFieldMode === 'fallback'\"\n appearance=\"outline\"\n floatLabel=\"always\"\n class=\"fallback-quick-field\">\n <mat-label>{{ quickFieldMeta.label || quickField }}</mat-label>\n <input matInput [formControl]=\"quickControl\"\n [type]=\"getQuickInputType()\"\n [attr.inputmode]=\"getQuickInputMode()\"\n [attr.aria-label]=\"quickFieldMeta.label || quickField\"\n (keydown.escape)=\"onQuickClear()\"\n (keypress)=\"onQuickNumericKeypress($event)\"\n (blur)=\"onQuickBlurFormat()\">\n </mat-form-field>\n\n \n </div>\n </div>\n\n\n <!-- QUICK \u201Cfalso\u201D (quando n\u00E3o h\u00E1 meta) -->\n <ng-template #fallbackQuick>\n <div class=\"filter-anchor quick-shell\" #anchorRef=\"cdkOverlayOrigin\" cdkOverlayOrigin>\n <mat-form-field appearance=\"outline\" floatLabel=\"always\" class=\"fallback-quick-field\">\n <mat-label>{{ i18nLabels.searchPlaceholder }}</mat-label>\n <input matInput [formControl]=\"quickControl\"\n [attr.aria-label]=\"i18nLabels.searchPlaceholder\"\n (keydown.escape)=\"onQuickClear()\" />\n </mat-form-field>\n </div>\n </ng-template>\n </ng-container>\n\n <ng-template #noQuick></ng-template>\n\n <!-- A\u00C7\u00D5ES INLINE (fixas \u00E0 direita da barra) -->\n <div class=\"inline-actions\" [class.actions-outlined]=\"actionsVariant==='outlined'\">\n <!-- Anchor de overlay quando n\u00E3o h\u00E1 Quick -->\n <div *ngIf=\"!showQuickBar()\" class=\"actions-anchor\" #anchorRef=\"cdkOverlayOrigin\" cdkOverlayOrigin></div>\n <!-- Toggles/booleans simples realocados para a barra de a\u00E7\u00F5es -->\n <div class=\"inline-toggles\" *ngIf=\"toggleMetas.length\">\n <ng-container dynamicFieldLoader [fields]=\"toggleMetas\" [formGroup]=\"alwaysForm\"\n (componentsCreated)=\"onToggleComponents($event)\"></ng-container>\n </div>\n <button mat-icon-button [color]=\"actionsButtonColor==='basic'? null : actionsButtonColor\" type=\"button\" *ngIf=\"quickHasValue()\"\n (click)=\"onQuickClear()\" [attr.aria-label]=\"i18nLabels.clear\">\n <mat-icon [praxisIcon]=\"'close'\"></mat-icon>\n </button>\n <button mat-icon-button [color]=\"actionsButtonColor==='basic'? null : actionsButtonColor\" type=\"button\" (click)=\"onSubmit()\" [attr.aria-label]=\"i18nLabels.apply\">\n <mat-icon [praxisIcon]=\"'search'\"></mat-icon>\n </button>\n <button mat-icon-button [color]=\"actionsButtonColor==='basic'? null : actionsButtonColor\" type=\"button\"\n [matBadge]=\"activeFiltersCount\"\n [matBadgeHidden]=\"!activeFiltersCount\"\n matBadgeSize=\"small\"\n matBadgeColor=\"primary\"\n [matBadgeOverlap]=\"false\"\n (click)=\"toggleAdvanced()\"\n [attr.aria-label]=\"getAdvancedAriaLabel()\"\n [attr.aria-expanded]=\"advancedOpen\"\n [attr.aria-controls]=\"advancedPanelId\">\n <mat-icon [praxisIcon]=\"'tune'\"></mat-icon>\n </button>\n <button mat-icon-button [color]=\"actionsButtonColor==='basic'? null : actionsButtonColor\" type=\"button\" (click)=\"openSettings()\" *ngIf=\"showFilterSettings\"\n [matBadge]=\"schemaOutdated ? '!' : ''\"\n [matBadgeHidden]=\"!schemaOutdated\"\n matBadgeColor=\"warn\" matBadgeSize=\"small\" matBadgePosition=\"above after\"\n [matTooltip]=\"schemaOutdated ? 'Schema do servidor mudou \u2014 Reconciliar' : i18nLabels.settings\"\n matTooltipPosition=\"below\">\n <mat-icon [praxisIcon]=\"'settings'\"></mat-icon>\n </button>\n </div>\n\n <!-- campos sempre vis\u00EDveis (se houver) -->\n <div class=\"always-fields\" *ngIf=\"alwaysVisibleMetas.length\">\n <ng-container dynamicFieldLoader [fields]=\"alwaysVisibleMetas\" [formGroup]=\"alwaysForm\"\n (componentsCreated)=\"onAlwaysComponents($event)\"></ng-container>\n </div>\n\n <!-- acessibilidade -->\n <span class=\"sr-only\" aria-live=\"polite\">\n {{ activeFiltersCount ? (activeFiltersCount + ' filtros ativos') : '' }}\n </span>\n <button type=\"submit\" class=\"hidden-submit\" aria-hidden=\"true\" tabindex=\"-1\"></button>\n </form>\n\n <!-- tags -->\n <div class=\"praxis-filter-tags\" *ngIf=\"displayedTags.length\" [class.outlined]=\"tagVariant==='outlined'\">\n <mat-chip-set>\n <mat-chip *ngFor=\"let tag of displayedTags\"\n [color]=\"tagColor === 'basic' ? null : tagColor\"\n (click)=\"applyTag(tag)\" (keydown.enter)=\"applyTag(tag)\"\n tabindex=\"0\" role=\"button\">\n <ng-container *ngIf=\"editingTagId !== tag.id; else editChip\">\n <span class=\"chip-label\">{{ tag.label }}</span>\n <span class=\"chip-actions\" *ngIf=\"isUserTag(tag)\">\n <button mat-icon-button [color]=\"tagButtonColor === 'basic' ? null : tagButtonColor\"\n (click)=\"startEditTag(tag, $event)\" aria-label=\"edit tag\">\n <mat-icon>edit</mat-icon>\n </button>\n <button mat-icon-button [color]=\"tagButtonColor === 'basic' ? null : tagButtonColor\"\n (click)=\"deleteTag(tag)\" aria-label=\"remove tag\">\n <mat-icon>close</mat-icon>\n </button>\n </span>\n </ng-container>\n <ng-template #editChip>\n <input matInput class=\"chip-editor\" [formControl]=\"editingTagLabel\"\n (keydown.enter)=\"commitEditTag(tag, $event)\" (keydown.escape)=\"cancelEditTag($event)\" (click)=\"$event.stopPropagation()\" />\n <button mat-button color=\"primary\" (click)=\"commitEditTag(tag, $event)\">{{ i18nLabels.save }}</button>\n <button mat-button (click)=\"cancelEditTag($event)\">{{ i18nLabels.cancel }}</button>\n </ng-template>\n </mat-chip>\n </mat-chip-set>\n </div>\n\n <!-- OVERLAY -->\n <ng-container *ngIf=\"overlayOrigin\">\n <ng-template cdkConnectedOverlay\n [cdkConnectedOverlayOrigin]=\"overlayOrigin!\"\n [cdkConnectedOverlayOpen]=\"advancedOpen\"\n [cdkConnectedOverlayHasBackdrop]=\"overlayBackdrop\"\n [cdkConnectedOverlayBackdropClass]=\"'praxis-overlay-backdrop'\"\n [cdkConnectedOverlayPositions]=\"overlayPositions\"\n [cdkConnectedOverlayFlexibleDimensions]=\"true\"\n [cdkConnectedOverlayPush]=\"true\"\n [cdkConnectedOverlayOffsetY]=\"8\"\n [cdkConnectedOverlayLockPosition]=\"true\"\n [cdkConnectedOverlayWidth]=\"overlayWidth\"\n [cdkConnectedOverlayPanelClass]=\"['praxis-filter-overlay', isMobile ? 'mobile' : '', overlayVariant === 'frosted' ? 'frosted' : '']\"\n (overlayOutsideClick)=\"onOverlayOutsideClick($event)\"\n (backdropClick)=\"onOverlayDetach()\"\n (detach)=\"onOverlayDetach()\">\n <div class=\"praxis-filter-advanced\" (keydown.escape)=\"toggleAdvanced()\" (keydown.enter)=\"onAdvancedSubmit({ formData: (advancedForm?.getRawValue?.() || {}) })\" role=\"dialog\" aria-modal=\"true\" [attr.id]=\"advancedPanelId\">\n <div class=\"advanced-body\">\n <mat-progress-bar *ngIf=\"schemaLoading\" mode=\"indeterminate\"></mat-progress-bar>\n <p *ngIf=\"schemaError\" class=\"schema-error\">\n {{ i18nLabels.errorLoadingFilters }}\n <button mat-button type=\"button\" (click)=\"loadSchema()\">{{ i18nLabels.retry }}</button>\n </p>\n <praxis-filter-form *ngIf=\"!schemaLoading && !schemaError && advancedConfig\"\n [formId]=\"formId\" [resourcePath]=\"resourcePath\" [mode]=\"'edit'\" [config]=\"advancedConfig\"\n (formReady)=\"onAdvancedReady($event)\" (valueChange)=\"onAdvancedChange($event)\"\n (validityChange)=\"onAdvancedValidityChange($event)\" (submit)=\"onAdvancedSubmit($event)\">\n </praxis-filter-form>\n <p *ngIf=\"!schemaLoading && !schemaError && !advancedConfig\">{{ i18nLabels.noData }}</p>\n </div>\n <div class=\"advanced-actions\" *ngIf=\"!schemaLoading && !schemaError && advancedConfig\">\n <button mat-button type=\"button\" *ngIf=\"allowSaveTags && activeFiltersCount\" (click)=\"saveCurrentAsTag()\">\n {{ i18nLabels.saveAsShortcut }}\n </button>\n <button mat-raised-button color=\"primary\" type=\"button\"\n (click)=\"onAdvancedSubmit({ formData: (advancedForm?.getRawValue?.() || {}) })\"\n [disabled]=\"!advancedValid\">\n {{ i18nLabels.apply }}\n </button>\n <button mat-button type=\"button\" (click)=\"onClear()\">{{ i18nLabels.clear }}</button>\n </div>\n </div>\n </ng-template>\n </ng-container>\n</ng-container>\n\n<!-- resumo -->\n<ng-template #summaryCard>\n <div class=\"praxis-filter-card\" (keydown.escape)=\"onClear()\">\n <div class=\"summary-header\">\n <img *ngIf=\"currentSummaryMap?.avatar?.(currentSummary)\" [src]=\"currentSummaryMap?.avatar?.(currentSummary)\"\n class=\"summary-avatar\" alt=\"\" />\n <div class=\"summary-text\">\n <div class=\"summary-title\">{{ currentSummaryMap?.title?.(currentSummary) || '' }}</div>\n <div class=\"summary-subtitle\" *ngIf=\"currentSummaryMap?.subtitle\">{{ currentSummaryMap?.subtitle?.(currentSummary) }}</div>\n </div>\n </div>\n <div class=\"summary-badges\" *ngIf=\"currentSummaryMap?.badges?.length\">\n <span *ngFor=\"let b of currentSummaryMap!.badges\">{{ b(currentSummary) }}</span>\n </div>\n <div class=\"card-actions\">\n <button mat-button type=\"button\" (click)=\"switchToFilter()\">{{ i18nLabels.edit }}</button>\n <button mat-button type=\"button\" (click)=\"onClear()\">{{ i18nLabels.clear }}</button>\n </div>\n </div>\n</ng-template>\n", styles: ["@charset \"UTF-8\";:root{--pfx-filter-h: 40px;--pfx-filter-align-offset: 2px;--pfx-gap-x: 16px;--pfx-gap-y: 12px;--pfx-quick-pad-top: 5px;--pfx-quick-pad-left: 12px;--pfx-advanced-pad-x: 24px;--pfx-field-min: 280px;--pfx-quick-bg: var(--surface-2, #232a32);--pfx-quick-border: var(--pfx-surface-border, rgba(255,255,255,.08));--pfx-quick-radius: 12px}.praxis-filter-bar{display:grid;width:100%;grid-template-columns:1fr auto;grid-template-areas:\"quick actions\" \"always always\";column-gap:0;row-gap:8px;align-items:center}:host.debug-layout{background-image:repeating-linear-gradient(to right,rgba(147,197,253,.08) 0,rgba(147,197,253,.08) 1px,transparent 1px,transparent var(--pfx-gap-x)),repeating-linear-gradient(to bottom,rgba(163,230,53,.08) 0,rgba(163,230,53,.08) 1px,transparent 1px,transparent 8px)}:host.debug-layout .praxis-filter-bar{outline:1px dashed #f59e0b}:host.debug-layout .quick-shell{outline:1px dashed #3b82f6}:host.debug-layout .always-fields{outline:1px dashed #22c55e}:host.debug-layout .praxis-filter-overlay .praxis-filter-advanced{outline:2px solid #a855f7}.quick-field{grid-area:quick;min-width:280px;align-self:center}.inline-actions{grid-area:actions;justify-self:end}.always-fields{grid-area:always}.inline-actions .actions-anchor{width:0;height:0;overflow:hidden}.quick-shell{min-height:var(--pfx-filter-h);padding:0 0 0 var(--pfx-quick-pad-left);display:flex;align-items:center;flex-wrap:nowrap;gap:6px;overflow:hidden;background:var(--pfx-quick-bg);border:1px solid var(--pfx-quick-border);border-right:none;border-radius:var(--pfx-quick-radius) 0 0 var(--pfx-quick-radius)}.quick-shell>*{flex:1 1 auto;min-width:0}.quick-field-host{display:contents}:host ::ng-deep .quick-shell .mat-mdc-form-field{width:100%!important;flex:1 1 auto}:host ::ng-deep .quick-shell .mat-mdc-form-field{margin:0!important}:host ::ng-deep .quick-shell pdx-text-input,:host ::ng-deep .quick-shell pdx-select,:host ::ng-deep .quick-shell pdx-date-input,:host ::ng-deep .quick-shell pdx-auto-complete{flex:1 1 auto;min-width:0;display:block}.inline-actions{flex:0 0 auto;display:flex;gap:4px;align-self:start;white-space:nowrap;height:var(--pfx-filter-h);align-items:center;background:var(--pfx-quick-bg);border:1px solid var(--pfx-quick-border);border-left:none;border-radius:0 var(--pfx-quick-radius) var(--pfx-quick-radius) 0;padding-right:4px;margin-left:-1px}.inline-actions.actions-outlined button.mat-mdc-icon-button{border:1px solid var(--pfx-quick-border);border-radius:50%}.inline-actions .mat-mdc-icon-button{width:36px;height:36px}.inline-actions mat-icon{width:20px;height:20px;font-size:20px}.fallback-quick-field{height:var(--pfx-filter-h);display:flex;align-items:center}:host ::ng-deep .fallback-quick-field .mat-mdc-text-field-wrapper.mdc-text-field--outlined{height:var(--pfx-filter-h);align-items:center;padding-top:var(--pfx-quick-pad-top)}:host ::ng-deep .quick-shell .mat-mdc-text-field-wrapper.mdc-text-field--outlined{min-height:var(--pfx-filter-h);align-items:center;padding-top:var(--pfx-quick-pad-top)}:host ::ng-deep .quick-shell .mat-mdc-form-field-infix{min-height:var(--pfx-filter-h);padding-top:8px}:host ::ng-deep .quick-shell .mat-mdc-select-trigger{height:var(--pfx-filter-h);align-items:center}:host ::ng-deep .quick-shell .mat-mdc-form-field-subscript-wrapper{display:none}:host ::ng-deep .quick-shell .mdc-line-ripple{display:none!important}.always-fields{display:grid;grid-template-columns:repeat(auto-fit,minmax(var(--pfx-always-min, 300px),1fr));gap:8px}:host ::ng-deep .always-fields .mat-mdc-text-field-wrapper.mdc-text-field--outlined{min-height:var(--pfx-filter-h);align-items:center}:host ::ng-deep .always-fields .mat-mdc-form-field-infix{min-height:var(--pfx-filter-h)}:host ::ng-deep .always-fields .mat-mdc-select-trigger{height:var(--pfx-filter-h);align-items:center}:host ::ng-deep .always-fields .mat-mdc-form-field{width:100%}.praxis-filter-tags{display:flex;flex-wrap:wrap;gap:6px}.praxis-filter-tags mat-chip{border-radius:16px;padding:0 6px}.praxis-filter-tags .chip-actions{display:inline-flex;align-items:center;gap:2px;margin-left:4px}.chip-editor{width:140px;margin-right:8px}.praxis-filter-tags.outlined mat-chip{background:transparent!important;border:1px solid var(--pfx-quick-border)}.praxis-filter-advanced{display:flex;flex-direction:column;min-width:400px;max-width:90vw;min-height:260px;max-height:80vh;margin-top:25px;margin-right:15px;margin-left:25px;background:var(--md-sys-color-surface-container, #2a3038)!important;background-color:var(--md-sys-color-surface-container, #2a3038)!important;background:color-mix(in srgb,var(--md-sys-color-surface-container, #2a3038),transparent 6%)!important;color:var(--md-sys-color-on-surface, #e6eaf2);border:1px solid var(--border-color);border-radius:12px;box-shadow:0 8px 24px #00000052,0 2px 8px #0000002e}.praxis-filter-overlay.mobile .praxis-filter-advanced{height:100vh;max-height:100vh}:host ::ng-deep .praxis-overlay-backdrop{background:#0006;-webkit-backdrop-filter:blur(2px);backdrop-filter:blur(2px)}.advanced-body{padding:var(--pfx-gap-y) var(--pfx-advanced-pad-x) 72px;overflow:auto;flex:1 1 auto;overscroll-behavior:contain}:host ::ng-deep .praxis-filter-advanced .praxis-filter-form .filter-row{display:grid!important;grid-template-columns:repeat(auto-fit,minmax(var(--pfx-field-min),1fr));gap:var(--pfx-gap-y) var(--pfx-gap-x)}:host ::ng-deep .praxis-filter-advanced .praxis-filter-form .filter-column{min-width:0}:host ::ng-deep .praxis-filter-advanced .praxis-filter-form .filter-column .mat-mdc-form-field{width:100%}.advanced-actions{position:sticky;bottom:0;z-index:2;display:flex;justify-content:flex-end;gap:8px;padding:var(--pfx-gap-y) var(--pfx-advanced-pad-x);background:var(--md-sys-color-surface-container, #2a3038)!important;background-color:var(--md-sys-color-surface-container, #2a3038)!important;background:color-mix(in srgb,var(--md-sys-color-surface-container, #2a3038),transparent 0%)!important;border-top:1px solid var(--border-color);box-shadow:0 -1px #0000002e}.advanced-actions .mat-mdc-button-base{height:40px}.advanced-actions .mat-mdc-raised-button.mat-primary{background:var(--md-sys-color-primary);color:var(--md-sys-color-on-primary)}:host ::ng-deep .praxis-filter-advanced .mat-mdc-text-field-wrapper.mdc-text-field--outlined{--mdc-outlined-text-field-outline-color: var(--border-color);--mdc-outlined-text-field-hover-outline-color: var(--border-color-hover);--mdc-outlined-text-field-focus-outline-color: var(--md-sys-color-primary);--mdc-outlined-text-field-label-text-color: var(--md-sys-color-on-surface-variant);--mdc-outlined-text-field-input-text-color: var(--md-sys-color-on-surface);--mdc-outlined-text-field-container-color: var(--md-sys-color-surface-container, #2a3038);--mdc-outlined-text-field-container-color: color-mix(in srgb, var(--md-sys-color-surface-container, #2a3038), transparent 90%)}:host ::ng-deep .praxis-filter-advanced .mat-mdc-select-trigger,:host ::ng-deep .praxis-filter-advanced .mat-mdc-form-field-subscript-wrapper,:host ::ng-deep .praxis-filter-advanced .mat-mdc-form-field-infix{color:var(--md-sys-color-on-surface)}@media (min-width: 600px){.always-fields{grid-template-columns:repeat(var(--pfx-always-cols-md, 2),minmax(0,1fr))}:host ::ng-deep .praxis-filter-advanced .praxis-filter-form .filter-row{grid-template-columns:repeat(2,minmax(0,1fr))}}@media (min-width: 960px){.always-fields{grid-template-columns:repeat(var(--pfx-always-cols-lg, 3),minmax(0,1fr))}}.inline-toggles{display:flex;align-items:center;gap:8px;margin:0 4px 0 6px}:host ::ng-deep .inline-actions .mat-mdc-slide-toggle{height:var(--pfx-filter-h);display:flex;align-items:center}:host ::ng-deep .inline-actions .mat-mdc-slide-toggle .mdc-form-field{align-items:center}::ng-deep .praxis-filter-overlay .praxis-filter-advanced .praxis-filter-form .filter-row{display:grid!important;gap:var(--pfx-gap-y, 1px) var(--pfx-gap-x, 6px)}@media (min-width: 600px){::ng-deep .praxis-filter-overlay .praxis-filter-advanced .praxis-filter-form .filter-row{grid-template-columns:repeat(2,minmax(0,1fr))}}.sr-only{position:absolute!important;width:1px!important;height:1px!important;margin:-1px!important;overflow:hidden!important;clip:rect(0,0,0,0)!important}.hidden-submit{position:absolute!important;width:0!important;height:0!important;padding:0!important;margin:0!important;border:0!important;opacity:0!important;pointer-events:none!important;clip:rect(0 0 0 0)!important;clip-path:inset(50%)!important;overflow:hidden!important}:host ::ng-deep .inline-actions [matBadge] .mat-badge-content{top:-6px;right:-6px}.praxis-filter-bar :where(.mat-mdc-slide-toggle .mdc-switch__icons){display:none!important}.praxis-filter-bar{--mdc-switch-unselected-icon-size: 0px;--mdc-switch-selected-icon-size: 0px;--pfx-always-min: 240px}.praxis-filter-card{display:flex;flex-direction:column;gap:6px;padding:8px 12px;border-radius:12px;border:1px solid var(--pfx-quick-border);background:var(--pfx-quick-bg);color:var(--md-sys-color-on-surface, #2B2A28)}.praxis-filter-card .summary-header{display:flex;align-items:center;gap:10px}.praxis-filter-card .summary-avatar{width:32px;height:32px;border-radius:50%;object-fit:cover}.praxis-filter-card .summary-title{font-weight:600}.praxis-filter-card .summary-subtitle{opacity:.8;font-size:.875rem}.praxis-filter-card .summary-badges{display:flex;flex-wrap:wrap;gap:6px}.praxis-filter-card .summary-badges span{display:inline-flex;align-items:center;padding:2px 8px;border-radius:999px;background:color-mix(in oklab,var(--md-sys-color-primary, #3FBCA5),transparent 88%);border:1px solid color-mix(in oklab,var(--md-sys-color-primary, #3FBCA5),transparent 70%);color:var(--md-sys-color-on-surface, #2B2A28);font-size:12px}.praxis-filter-card .card-actions{display:flex;gap:8px}\n"] }]
|
|
21435
21553
|
}], ctorParameters: () => [{ type: i1$3.GenericCrudService }, { type: undefined, decorators: [{
|
|
21436
21554
|
type: Inject,
|
|
21437
21555
|
args: [CONFIG_STORAGE]
|
|
@@ -21469,6 +21587,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.4", ngImpor
|
|
|
21469
21587
|
type: Input
|
|
21470
21588
|
}], showFilterSettings: [{
|
|
21471
21589
|
type: Input
|
|
21590
|
+
}], showQuickFallback: [{
|
|
21591
|
+
type: Input
|
|
21472
21592
|
}], summary: [{
|
|
21473
21593
|
type: Input
|
|
21474
21594
|
}], summaryTemplate: [{
|
|
@@ -22812,13 +22932,39 @@ class PraxisTable {
|
|
|
22812
22932
|
}
|
|
22813
22933
|
catch { }
|
|
22814
22934
|
}
|
|
22935
|
+
resolvePagingStrategy() {
|
|
22936
|
+
const raw = this.config.behavior?.pagination?.strategy;
|
|
22937
|
+
if (raw === 'client' || raw === 'server')
|
|
22938
|
+
return raw;
|
|
22939
|
+
// Default to server when using remote resource and not explicitly configured
|
|
22940
|
+
return this.resourcePath ? 'server' : 'client';
|
|
22941
|
+
}
|
|
22942
|
+
resolveSortingStrategy() {
|
|
22943
|
+
const raw = this.config.behavior?.sorting?.strategy;
|
|
22944
|
+
if (raw === 'client' || raw === 'server')
|
|
22945
|
+
return raw;
|
|
22946
|
+
// Default to server when using remote resource and not explicitly configured
|
|
22947
|
+
return this.resourcePath ? 'server' : 'client';
|
|
22948
|
+
}
|
|
22815
22949
|
applyDataSourceSettings() {
|
|
22816
|
-
const paginationStrategy = this.
|
|
22817
|
-
const sortingStrategy = this.
|
|
22950
|
+
const paginationStrategy = this.resolvePagingStrategy();
|
|
22951
|
+
const sortingStrategy = this.resolveSortingStrategy();
|
|
22818
22952
|
const isServerPaging = paginationStrategy === 'server';
|
|
22819
22953
|
const isServerSorting = sortingStrategy === 'server';
|
|
22954
|
+
// Sync internal page size with config so server requests match UI paginator
|
|
22955
|
+
try {
|
|
22956
|
+
const cfgSize = this.getPaginationPageSize();
|
|
22957
|
+
if (typeof cfgSize === 'number' && cfgSize > 0) {
|
|
22958
|
+
this.pageSize = cfgSize;
|
|
22959
|
+
}
|
|
22960
|
+
}
|
|
22961
|
+
catch { }
|
|
22820
22962
|
if (this.paginator) {
|
|
22821
22963
|
this.paginator.length = this.getPaginationLength();
|
|
22964
|
+
try {
|
|
22965
|
+
this.paginator.pageSize = this.pageSize;
|
|
22966
|
+
}
|
|
22967
|
+
catch { }
|
|
22822
22968
|
// Only connect MatTableDataSource paginator when doing client-side paging
|
|
22823
22969
|
this.dataSource.paginator = isServerPaging ? null : this.paginator;
|
|
22824
22970
|
}
|
|
@@ -23023,7 +23169,7 @@ class PraxisTable {
|
|
|
23023
23169
|
// Fall back to inference only if API type is not available or invalid
|
|
23024
23170
|
apiType = this.inferFieldTypeFromFieldName(field.name);
|
|
23025
23171
|
}
|
|
23026
|
-
|
|
23172
|
+
const col = {
|
|
23027
23173
|
field: field.name,
|
|
23028
23174
|
header: field.label ?? field.name,
|
|
23029
23175
|
order: field.order,
|
|
@@ -23034,6 +23180,47 @@ class PraxisTable {
|
|
|
23034
23180
|
_originalApiType: apiType,
|
|
23035
23181
|
_isApiField: true,
|
|
23036
23182
|
};
|
|
23183
|
+
// Auto-renderers: map known UI controls to richer cell renderers on first bootstrap
|
|
23184
|
+
// - Avatar: when backend marks controlType 'avatar' (x-ui) or field name matches avatar-like patterns
|
|
23185
|
+
try {
|
|
23186
|
+
this.applyAutoRenderer(field, col);
|
|
23187
|
+
}
|
|
23188
|
+
catch { }
|
|
23189
|
+
return col;
|
|
23190
|
+
}
|
|
23191
|
+
/**
|
|
23192
|
+
* Apply automatic renderer hints based on schema field metadata.
|
|
23193
|
+
* Runs only on initial bootstrap (when columns are derived from schema).
|
|
23194
|
+
*/
|
|
23195
|
+
applyAutoRenderer(field, col) {
|
|
23196
|
+
if (!field || !col)
|
|
23197
|
+
return;
|
|
23198
|
+
// Do not override explicit renderer if any (defensive; initial columns have none)
|
|
23199
|
+
if (col.renderer && col.renderer.type)
|
|
23200
|
+
return;
|
|
23201
|
+
const ctl = (field.controlType || '').toString().trim().toLowerCase();
|
|
23202
|
+
const fname = (field.name || '').toString();
|
|
23203
|
+
const lname = fname.toLowerCase();
|
|
23204
|
+
const isAvatarByControl = ctl === 'avatar';
|
|
23205
|
+
if (isAvatarByControl) {
|
|
23206
|
+
// Derive initials from common name fields; leave altField undefined to avoid brittle coupling
|
|
23207
|
+
const initialsExpr = "= (row.nomeCompleto || row.nome || row.fullName || row.name || row.title || '').trim().split(/\\s+/).slice(0,2).map(p => p[0] || '').join('').toUpperCase()";
|
|
23208
|
+
col.renderer = {
|
|
23209
|
+
type: 'avatar',
|
|
23210
|
+
avatar: {
|
|
23211
|
+
srcField: fname,
|
|
23212
|
+
// altField intentionally omitted; rely on initialsExpr + title attr if provided later
|
|
23213
|
+
initialsExpr,
|
|
23214
|
+
shape: 'circle',
|
|
23215
|
+
size: 32,
|
|
23216
|
+
},
|
|
23217
|
+
};
|
|
23218
|
+
// Sensible defaults for avatar column
|
|
23219
|
+
col.align = col.align || 'center';
|
|
23220
|
+
if (!col.width)
|
|
23221
|
+
col.width = '56px';
|
|
23222
|
+
return;
|
|
23223
|
+
}
|
|
23037
23224
|
}
|
|
23038
23225
|
/**
|
|
23039
23226
|
* Check if a value is a valid ColumnDataType
|
|
@@ -23170,6 +23357,13 @@ class PraxisTable {
|
|
|
23170
23357
|
if (this.paginator) {
|
|
23171
23358
|
this.paginator.length = page.totalElements;
|
|
23172
23359
|
}
|
|
23360
|
+
// Keep config pagination length in sync for template bindings
|
|
23361
|
+
try {
|
|
23362
|
+
const beh = this.config.behavior || (this.config.behavior = {});
|
|
23363
|
+
const pag = beh.pagination || (beh.pagination = {});
|
|
23364
|
+
pag.totalItems = page.totalElements;
|
|
23365
|
+
}
|
|
23366
|
+
catch { }
|
|
23173
23367
|
},
|
|
23174
23368
|
error: (err) => {
|
|
23175
23369
|
console.error('[PraxisTable] Data load error', err);
|
|
@@ -24062,7 +24256,7 @@ class PraxisTable {
|
|
|
24062
24256
|
this.dataSubject.complete();
|
|
24063
24257
|
}
|
|
24064
24258
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: PraxisTable, deps: [{ token: i1$3.GenericCrudService }, { token: i0.ChangeDetectorRef }, { token: i3$2.SettingsPanelService }, { token: DataFormattingService }, { token: CONFIG_STORAGE }, { token: CONNECTION_STORAGE }, { token: TableDefaultsProvider }, { token: i2$1.MatSnackBar }, { token: FilterConfigService }, { token: i7$2.PraxisDialog }, { token: i0.ElementRef }, { token: i1$3.GlobalConfigService }], target: i0.ɵɵFactoryTarget.Component });
|
|
24065
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.1.4", type: PraxisTable, isStandalone: true, selector: "praxis-table", inputs: { config: "config", resourcePath: "resourcePath", filterCriteria: "filterCriteria", notifyIfOutdated: "notifyIfOutdated", snoozeMs: "snoozeMs", autoOpenSettingsOnOutdated: "autoOpenSettingsOnOutdated", showToolbar: "showToolbar", toolbarV2: "toolbarV2", autoDelete: "autoDelete", editModeEnabled: "editModeEnabled", dense: "dense", tableId: "tableId", debugLayout: "debugLayout", horizontalScroll: "horizontalScroll", crudContext: "crudContext", idField: "idField" }, outputs: { rowClick: "rowClick", rowAction: "rowAction", toolbarAction: "toolbarAction", bulkAction: "bulkAction", rowDoubleClick: "rowDoubleClick", schemaStatusChange: "schemaStatusChange", metadataChange: "metadataChange", beforeDelete: "beforeDelete", afterDelete: "afterDelete", deleteError: "deleteError", beforeBulkDelete: "beforeBulkDelete", afterBulkDelete: "afterBulkDelete", bulkDeleteError: "bulkDeleteError" }, host: { properties: { "class.debug-layout": "debugLayout", "class.density-compact": "config?.appearance?.density === 'compact'", "class.density-comfortable": "config?.appearance?.density === 'comfortable'", "class.density-spacious": "config?.appearance?.density === 'spacious'", "class.row-borders": "config?.appearance?.borders?.showRowBorders !== false", "class.col-borders": "!!config?.appearance?.borders?.showColumnBorders" } }, queries: [{ propertyName: "projectedFilter", first: true, predicate: PraxisFilter, descendants: true }], viewQueries: [{ propertyName: "paginator", first: true, predicate: MatPaginator, descendants: true }, { propertyName: "sort", first: true, predicate: MatSort, descendants: true }, { propertyName: "actionsHeaderCell", first: true, predicate: ["actionsHeaderCell"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<praxis-empty-state-card\n *ngIf=\"!resourcePath\"\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<!-- Error State with Quick Connect CTA -->\n<div class=\"ptable-error\" *ngIf=\"resourcePath && (schemaError || dataError)\" style=\"display:flex; align-items:center; gap:12px; padding:12px; border:1px solid var(--md-sys-color-error, #b00020); border-radius:8px; margin: 8px 0;\">\n <mat-icon color=\"warn\" aria-hidden=\"true\">error</mat-icon>\n <div style=\"flex:1\">\n <div style=\"font-weight:600\">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 <button mat-stroked-button (click)=\"retryData()\" *ngIf=\"!schemaError\">Tentar novamente</button>\n <button mat-stroked-button (click)=\"reloadSchema()\" *ngIf=\"schemaError\">Recarregar colunas</button>\n </div>\n\n<!-- Inline banner for schema change (only in edit mode) -->\n<div *ngIf=\"shouldShowOutdatedInline()\" 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 <ng-container *ngIf=\"resourcePath && !schemaError && !dataError && toolbarV2; else legacyHeader\">\n <div class=\"praxis-table-header\" [class.debug-layout]=\"debugLayout\" [class.edit-mode]=\"editModeEnabled\" *ngIf=\"showToolbar || editModeEnabled\">\n <praxis-table-toolbar\n *ngIf=\"showToolbar\"\n [config]=\"config\"\n [debugLayout]=\"debugLayout\"\n (toolbarAction)=\"onToolbarAction($event)\"\n (reset)=\"onResetPreferences()\"\n >\n <praxis-filter\n *ngIf=\"\n resourcePath &&\n config.behavior?.filtering?.advancedFilters?.enabled &&\n !projectedFilter\n \"\n advancedFilter\n [resourcePath]=\"resourcePath\"\n [formId]=\"tableId + '-filter'\"\n [editModeEnabled]=\"editModeEnabled\"\n [quickField]=\"\n config.behavior?.filtering?.advancedFilters?.settings?.quickField\n \"\n [alwaysVisibleFields]=\"\n config.behavior?.filtering?.advancedFilters?.settings\n ?.alwaysVisibleFields\n \"\n [allowSaveTags]=\"\n config.behavior?.filtering?.advancedFilters?.settings\n ?.allowSaveTags\n \"\n [changeDebounceMs]=\"\n config.behavior?.filtering?.advancedFilters?.settings\n ?.changeDebounceMs ?? 300\n \"\n [i18n]=\"getFilterI18n()\"\n [mode]=\"\n config.behavior?.filtering?.advancedFilters?.settings?.mode ??\n 'auto'\n \"\n [debugLayout]=\"debugLayout\"\n [showFilterSettings]=\"!editModeEnabled\"\n (submit)=\"onAdvancedFilterSubmit($event)\"\n (clear)=\"onAdvancedFilterClear()\"\n ></praxis-filter>\n <ng-content select=\"[advancedFilter]\" />\n <ng-content select=\"[toolbar]\" />\n <button end-actions mat-icon-button color=\"primary\" data-role=\"table-settings\" *ngIf=\"editModeEnabled\"\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 </praxis-table-toolbar>\n <!-- Render a minimal settings button when toolbar is hidden but edit mode is enabled -->\n <div class=\"ptable-header-actions\" *ngIf=\"!showToolbar && editModeEnabled\">\n <button mat-icon-button color=\"primary\" (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 <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 </div>\n \n </div>\n</ng-container>\n<ng-template #legacyHeader>\n <ng-container *ngIf=\"resourcePath && !schemaError && !dataError\">\n <praxis-table-toolbar\n *ngIf=\"showToolbar\"\n [config]=\"config\"\n [debugLayout]=\"debugLayout\"\n (toolbarAction)=\"onToolbarAction($event)\"\n (reset)=\"onResetPreferences()\"\n >\n <praxis-filter\n *ngIf=\"\n resourcePath &&\n config.behavior?.filtering?.advancedFilters?.enabled &&\n !projectedFilter\n \"\n advancedFilter\n [resourcePath]=\"resourcePath\"\n [formId]=\"tableId + '-filter'\"\n [editModeEnabled]=\"editModeEnabled\"\n [quickField]=\"\n config.behavior?.filtering?.advancedFilters?.settings?.quickField\n \"\n [alwaysVisibleFields]=\"\n config.behavior?.filtering?.advancedFilters?.settings\n ?.alwaysVisibleFields\n \"\n [allowSaveTags]=\"\n config.behavior?.filtering?.advancedFilters?.settings?.allowSaveTags\n \"\n [changeDebounceMs]=\"\n config.behavior?.filtering?.advancedFilters?.settings\n ?.changeDebounceMs ?? 300\n \"\n [i18n]=\"getFilterI18n()\"\n [mode]=\"\n config.behavior?.filtering?.advancedFilters?.settings?.mode ??\n 'auto'\n \"\n [debugLayout]=\"debugLayout\"\n [showFilterSettings]=\"!editModeEnabled\"\n (submit)=\"onAdvancedFilterSubmit($event)\"\n (clear)=\"onAdvancedFilterClear()\"\n ></praxis-filter>\n <ng-content select=\"[advancedFilter]\" />\n <ng-content select=\"[toolbar]\" />\n <button end-actions mat-icon-button color=\"primary\" *ngIf=\"editModeEnabled\"\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 </praxis-table-toolbar>\n <!-- Legacy header: settings button when toolbar hidden -->\n <div class=\"ptable-header-actions\" *ngIf=\"!showToolbar && editModeEnabled\">\n <button mat-icon-button color=\"primary\" data-role=\"table-settings\" (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 </ng-container>\n \n</ng-template>\n<div class=\"px-scroll-viewport\"\n [class.scroll-auto]=\"horizontalScroll === 'auto'\"\n [class.scroll-wrap]=\"horizontalScroll === 'wrap'\"\n [class.scroll-none]=\"horizontalScroll === 'none'\">\n\n<table\n *ngIf=\"resourcePath && !schemaError && !dataError\"\n mat-table\n [dataSource]=\"dataSource\"\n matSort\n (matSortChange)=\"onSortChange($event)\"\n [matSortDisabled]=\"!getSortingEnabled()\"\n class=\"mat-elevation-z8\"\n>\n <ng-container\n *ngIf=\"config.behavior?.selection?.enabled\"\n matColumnDef=\"_select\"\n >\n <th mat-header-cell *matHeaderCellDef>\n <mat-checkbox\n (change)=\"masterToggle()\"\n [checked]=\"isAllSelected()\"\n [indeterminate]=\"selection.hasValue() && !isAllSelected()\"\n ></mat-checkbox>\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 <ng-container\n *ngFor=\"let column of visibleColumns\"\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 [disabled]=\"!getSortingEnabled() || column.sortable === false\"\n [style.text-align]=\"column.align\"\n [style.width]=\"column.width\"\n [attr.style]=\"column.headerStyle\"\n >\n {{ column.header }}\n </th>\n <td\n mat-cell\n *matCellDef=\"let element\"\n [style.text-align]=\"column.align\"\n [style.width]=\"column.width\"\n [attr.style]=\"column.style\"\n [ngClass]=\"getCellClasses(element, column)\"\n [ngStyle]=\"getCellNgStyle(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 <mat-icon *ngIf=\"getBadgeIcon(element, column) as bi\" 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 <mat-icon *ngIf=\"getButtonIcon(element, column) as bi\">{{ 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 <mat-icon *ngIf=\"getButtonIcon(element, column) as bi\">{{ 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 <mat-icon *ngIf=\"getButtonIcon(element, column) as bi\">{{ 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 <mat-icon *ngIf=\"getChipIcon(element, column) as ci\" 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.%]=\"getProgressValue(element, column)\" [style.background]=\"getProgressColor(element, column) || null\"></div>\n <div class=\"pfx-progress-label\" *ngIf=\"getProgressShowLabel(element, column)\">{{ getProgressValue(element, column) }}%</div>\n </div>\n </ng-container>\n\n <!-- Avatar renderer -->\n <ng-container *ngSwitchCase=\"'avatar'\">\n <ng-container *ngIf=\"getAvatarSrc(element, column) as asrc; else initials\">\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 </ng-container>\n <ng-template #initials>\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 </ng-template>\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.id, element, $event)\" [disabled]=\"!it.__visible\" >\n <mat-icon *ngIf=\"it.icon\">{{ it.icon }}</mat-icon>\n <span>{{ it.label }}</span>\n </button>\n </mat-menu>\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))\"><mat-icon *ngIf=\"getBadgeIcon(element, asItemColumn(column, it)) as bi\" 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)\"><mat-icon *ngIf=\"getButtonIcon(element, asItemColumn(column, it)) as bi\">{{ 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)\"><mat-icon *ngIf=\"getButtonIcon(element, asItemColumn(column, it)) as bi\">{{ 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)\"><mat-icon *ngIf=\"getButtonIcon(element, asItemColumn(column, it)) as bi\">{{ 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))\"><mat-icon *ngIf=\"getChipIcon(element, asItemColumn(column, it)) as ci\" 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.%]=\"getProgressValue(element, asItemColumn(column, it))\" [style.background]=\"getProgressColor(element, asItemColumn(column, it)) || null\"></div><div class=\"pfx-progress-label\" *ngIf=\"getProgressShowLabel(element, asItemColumn(column, it))\">{{ getProgressValue(element, asItemColumn(column, it)) }}%</div></div>\n </ng-container>\n <ng-container *ngSwitchCase=\"'avatar'\">\n <ng-container *ngIf=\"getAvatarSrc(element, asItemColumn(column, it)) as asrc; else initials_comp\">\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 </ng-container>\n <ng-template #initials_comp>\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 </ng-template>\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.id, element, $event)\" [disabled]=\"!mi.__visible\"><mat-icon *ngIf=\"mi.icon\">{{ mi.icon }}</mat-icon><span>{{ mi.label }}</span></button>\n </mat-menu>\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\">{{ getCellValue(element, column) }}</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 </td>\n </ng-container>\n <ng-container *ngIf=\"config.actions?.row?.enabled\" 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]=\"config.actions?.row?.width\" 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 <mat-icon *ngIf=\"getActionsHeaderIcon() as hi\" [praxisIcon]=\"hi\"></mat-icon>\n <span class=\"label\" *ngIf=\"getActionsHeaderLabel() as hl\">{{ 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]=\"config.actions?.row?.width\"\n >\n <div class=\"praxis-actions-cell__content\">\n <!-- A\u00E7\u00F5es inline -->\n <!-- Inline actions: icons mode -->\n <ng-container *ngIf=\"config.actions?.row?.display === 'icons' || !config.actions?.row?.display\">\n <ng-container *ngFor=\"let a of getInlineRowActions(row); trackBy: trackAction\">\n <button\n mat-icon-button\n class=\"praxis-icon-btn\"\n [disabled]=\"isActionDisabled(a, row)\"\n (click)=\"onRowAction(getActionId(a), row, $event)\"\n [matTooltip]=\"a.label || getActionId(a)\"\n matTooltipPosition=\"above\"\n matTooltipClass=\"praxis-tooltip\"\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 </ng-container>\n </ng-container>\n\n <!-- Inline actions: buttons mode (show label + icon) -->\n <ng-container *ngIf=\"config.actions?.row?.display === 'buttons'\">\n <ng-container *ngFor=\"let a of getInlineRowActions(row); trackBy: trackAction\">\n <button\n mat-flat-button\n class=\"praxis-row-btn\"\n [disabled]=\"isActionDisabled(a, row)\"\n (click)=\"onRowAction(getActionId(a), row, $event)\"\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 </ng-container>\n </ng-container>\n\n <!-- Menu de overflow -->\n <button\n mat-icon-button\n class=\"praxis-icon-btn praxis-more-btn\"\n *ngIf=\"hasOverflowRowActions(row)\"\n [matMenuTriggerFor]=\"rowMoreMenu\"\n [color]=\"getRowMenuButtonColor() || null\"\n aria-label=\"Mais a\u00E7\u00F5es\"\n >\n <mat-icon [praxisIcon]=\"getRowMenuIcon()\"></mat-icon>\n </button>\n <mat-menu #rowMoreMenu=\"matMenu\" xPosition=\"before\">\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)\"\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 </mat-menu>\n </div>\n </td>\n </ng-container>\n\n <tr mat-header-row *matHeaderRowDef=\"displayedColumns\"></tr>\n <ng-container *ngIf=\"!isVirtualized()\">\n <tr\n mat-row\n *matRowDef=\"let row; let i = index; columns: displayedColumns\"\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)\"\n (dblclick)=\"onRowDoubleClicked(row, i)\"\n ></tr>\n </ng-container>\n</table>\n\n<!-- Virtual rows path (header preserved above) -->\n<ng-container *ngIf=\"resourcePath && !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]=\"getVirtMinHeightStyle()\"\n >\n <table class=\"mat-mdc-table mat-elevation-z8\" [style.width]=\"horizontalScroll === 'auto' ? 'max-content' : '100%'\">\n <tbody>\n <tr class=\"mat-mdc-row\"\n *cdkVirtualFor=\"let row of dataSource.data; let i = index; trackBy: trackByRow\"\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)\"\n (dblclick)=\"onRowDoubleClicked(row, i)\">\n <!-- Selection column -->\n <td class=\"mat-mdc-cell\" *ngIf=\"config.behavior?.selection?.enabled\">\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 <td class=\"mat-mdc-cell\"\n *ngFor=\"let column of visibleColumns\"\n [style.text-align]=\"column.align\"\n [style.width]=\"column.width\"\n [attr.style]=\"column.style\"\n [ngClass]=\"getCellClasses(row, column)\"\n [ngStyle]=\"getCellNgStyle(row, column)\">\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 <mat-icon *ngIf=\"getBadgeIcon(row, column) as bi\" 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 </td>\n\n <!-- Actions column -->\n <td class=\"mat-mdc-cell praxis-actions-cell\" *ngIf=\"config.actions?.row?.enabled\" [class.dense]=\"dense\" [style.width]=\"config.actions?.row?.width\">\n <div class=\"praxis-actions-cell__content\">\n <ng-container *ngIf=\"config.actions?.row?.display === 'icons' || !config.actions?.row?.display\">\n <ng-container *ngFor=\"let a of getInlineRowActions(row); trackBy: trackAction\">\n <button mat-icon-button class=\"praxis-icon-btn\"\n [disabled]=\"isActionDisabled(a, row)\"\n (click)=\"onRowAction(getActionId(a), row, $event)\"\n [matTooltip]=\"a.label || getActionId(a)\"\n matTooltipPosition=\"above\"\n matTooltipClass=\"praxis-tooltip\"\n [attr.aria-label]=\"a.label || getActionId(a)\"\n [color]=\"a.color || null\">\n <mat-icon [praxisIcon]=\"a.icon\"></mat-icon>\n </button>\n </ng-container>\n </ng-container>\n <ng-container *ngIf=\"config.actions?.row?.display === 'buttons'\">\n <ng-container *ngFor=\"let a of getInlineRowActions(row); trackBy: trackAction\">\n <button mat-flat-button class=\"praxis-row-btn\"\n [disabled]=\"isActionDisabled(a, row)\"\n (click)=\"onRowAction(getActionId(a), row, $event)\"\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 </ng-container>\n </ng-container>\n <button mat-icon-button class=\"praxis-icon-btn praxis-more-btn\"\n *ngIf=\"hasOverflowRowActions(row)\"\n [matMenuTriggerFor]=\"rowMoreMenuV\"\n [color]=\"getRowMenuButtonColor() || null\"\n aria-label=\"Mais a\u00E7\u00F5es\">\n <mat-icon [praxisIcon]=\"getRowMenuIcon()\"></mat-icon>\n </button>\n <mat-menu #rowMoreMenuV=\"matMenu\" xPosition=\"before\">\n <ng-container *ngFor=\"let a of getOverflowRowActions(row); trackBy: trackAction\">\n <button mat-menu-item (click)=\"onRowAction(getActionId(a), row, $event)\" [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 </mat-menu>\n </div>\n </td>\n </tr>\n </tbody>\n </table>\n </cdk-virtual-scroll-viewport>\n</ng-container>\n\n</div>\n<!-- Paginadores (top/bottom) -->\n<mat-paginator\n *ngIf=\"resourcePath && !schemaError && !dataError && getPaginationEnabled() && (config.behavior?.pagination?.position === 'top' || config.behavior?.pagination?.position === 'both')\"\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<mat-paginator\n *ngIf=\"resourcePath && !schemaError && !dataError && getPaginationEnabled() && (config.behavior?.pagination?.position === 'bottom' || config.behavior?.pagination?.position === 'both' || !config.behavior?.pagination?.position)\"\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", styles: ["@charset \"UTF-8\";table{width:100%}.praxis-actions-cell{height:100%;padding-inline:12px;white-space:nowrap}:host.density-compact{--p-header-padding: 8px 12px;--p-actions-btn-size: 32px;--p-actions-icon-size: 18px}:host.density-comfortable{--p-header-padding: 12px 16px;--p-actions-btn-size: 40px;--p-actions-icon-size: 22px}:host.density-spacious{--p-header-padding: 16px 20px;--p-actions-btn-size: 44px;--p-actions-icon-size: 24px}:host.density-compact ::ng-deep .mat-mdc-cell{padding:8px 12px}:host.density-comfortable ::ng-deep .mat-mdc-cell{padding:12px 16px}:host.density-spacious ::ng-deep .mat-mdc-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%}.praxis-actions-cell.dense .praxis-actions-cell__content{gap:6px}.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, rgba(255, 255, 255, .06))}.praxis-icon-btn:focus-visible{outline:2px solid var(--primary, #48a1ff);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-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-icon-btn.destructive mat-icon{color:#ff6b6b}.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.debug-layout,:host.debug-layout .praxis-table-header{outline:2px dashed #ff4d4f;border-radius:8px}:host.debug-layout ::ng-deep .praxis-filter-bar{outline:1px dashed #f59e0b}:host.debug-layout ::ng-deep .quick-shell{outline:1px dashed #3b82f6}:host.debug-layout ::ng-deep .always-fields{outline:1px dashed #22c55e}:host.debug-layout ::ng-deep .praxis-filter-overlay .praxis-filter-advanced{outline:2px solid #a855f7}:host.debug-layout ::ng-deep .mat-mdc-table{outline:1px dashed #94a3b8}.praxis-table-header>praxis-table-toolbar{flex:1 0 100%}:host{--p-table-header-bg: var(--md-sys-color-surface-container-highest, #1d1d1f);--p-table-header-fg: var(--md-sys-color-on-surface, #e8f3f1);--p-table-border-color: var(--md-sys-color-outline-variant, rgba(255, 255, 255, .12));--p-table-row-even-bg: var(--md-sys-color-surface-container, rgba(255, 255, 255, .04));--p-table-row-hover-bg: color-mix(in srgb, var(--md-sys-color-primary, #3f51b5) 10%, transparent);--p-table-row-selected-bg: var(--md-sys-color-primary-container, rgba(63,81,181,.14));--p-table-badge-soft-primary-bg: color-mix(in srgb, var(--mat-sys-primary, var(--md-sys-color-primary)) 16%, transparent);--p-table-badge-soft-primary-fg: var(--mat-sys-primary, var(--md-sys-color-primary));--p-table-badge-soft-accent-bg: color-mix(in srgb, var(--mat-sys-secondary, var(--md-sys-color-secondary, #ff4081)) 14%, transparent);--p-table-badge-soft-accent-fg: var(--mat-sys-secondary, var(--md-sys-color-secondary, #ff4081));--p-table-badge-soft-warn-bg: color-mix(in srgb, var(--mat-sys-error, var(--md-sys-color-error, #f44336)) 14%, transparent);--p-table-badge-soft-warn-fg: var(--mat-sys-error, var(--md-sys-color-error, #f44336));--p-table-state-success-bg: color-mix(in srgb, var(--mat-sys-tertiary, var(--md-sys-color-tertiary, #388E3C)) 16%, transparent);--p-table-state-success-fg: var(--md-sys-color-on-surface, #c8e6c9);--p-table-state-warning-bg: color-mix(in srgb, var(--md-sys-color-secondary, #FFA000) 18%, transparent);--p-table-state-warning-fg: var(--md-sys-color-on-surface, #ffe0b2);--p-table-state-danger-bg: color-mix(in srgb, var(--md-sys-color-error, #e53935) 18%, transparent);--p-table-state-danger-fg: var(--md-sys-color-on-surface, #ffcdd2);--p-table-state-highlight-bg: color-mix(in srgb, var(--md-sys-color-primary, #2196f3) 16%, transparent);--p-table-state-highlight-fg: var(--md-sys-color-on-surface, #bbdefb)}:host ::ng-deep .mat-mdc-table{background:var(--md-sys-color-surface-container-highest, #1d1d1f);border-radius:12px;width:100%}:host [data-role=table-settings].mat-mdc-icon-button{--mdc-icon-button-icon-color: var(--mat-sys-primary, var(--md-sys-color-primary, #3f51b5));color:var(--mat-sys-primary, var(--md-sys-color-primary, #3f51b5))}.pfx-link{color:var(--mat-sys-primary, #3f51b5);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(--mat-sys-outline-variant);color:var(--mat-sys-on-surface)}.pfx-chip--filled-primary{background:var(--mat-sys-primary);color:var(--mat-sys-on-primary)}.pfx-chip--filled-accent{background:var(--mat-sys-secondary, #ff4081);color:#fff}.pfx-chip--filled-warn{background:var(--mat-sys-error, #f44336);color:#fff}.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(--mat-sys-surface-container-highest, rgba(255, 255, 255, .08));border-radius:4px;overflow:hidden;display:inline-block;vertical-align:middle}.pfx-progress-bar{height:100%;background:var(--mat-sys-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(--mat-sys-surface-container, #2a2a2e);color:var(--mat-sys-on-surface, #eee);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;scrollbar-gutter:stable}.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:1;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}.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 .mat-mdc-cell{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}:host ::ng-deep .mat-mdc-row:hover{background:var(--p-table-row-hover-bg)}:host ::ng-deep .mat-mdc-row:nth-child(2n){background:var(--p-table-row-even-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-info-banner{display:flex;gap:12px;align-items:center;padding:8px 12px;margin:8px 0;border-radius:8px;border:1px solid var(--mat-sys-primary, var(--md-sys-color-primary, #1a73e8));background:color-mix(in srgb,var(--mat-sys-primary, var(--md-sys-color-primary, #1a73e8)) 10%,transparent)}.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, #2a2a2a);border:1px solid var(--md-sys-color-outline-variant, rgba(0, 0, 0, .08))}.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(--mat-sys-primary, #3f51b5);color:var(--mat-sys-on-primary, #fff)}.pfx-badge--filled-accent{background:var(--mat-sys-secondary, #ff4081);color:var(--mat-sys-on-secondary, #fff)}.pfx-badge--filled-warn{background:var(--mat-sys-error, #f44336);color:var(--mat-sys-on-error, #fff)}.pfx-badge--outlined{background:transparent;border-color:var(--mat-sys-outline-variant, rgba(255, 255, 255, .24));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: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "directive", type: i1.NgSwitch, selector: "[ngSwitch]", inputs: ["ngSwitch"] }, { kind: "directive", type: i1.NgSwitchCase, selector: "[ngSwitchCase]", inputs: ["ngSwitchCase"] }, { kind: "directive", type: i1.NgSwitchDefault, selector: "[ngSwitchDefault]" }, { 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: 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: "ngmodule", type: MatPaginatorModule }, { kind: "component", type: i11$1.MatPaginator, selector: "mat-paginator", inputs: ["color", "pageIndex", "length", "pageSize", "pageSizeOptions", "hidePageSize", "showFirstLastButtons", "selectConfig", "disabled"], outputs: ["page"], exportAs: ["matPaginator"] }, { kind: "ngmodule", type: MatSortModule }, { kind: "directive", type: i12.MatSort, selector: "[matSort]", inputs: ["matSortActive", "matSortStart", "matSortDirection", "matSortDisableClear", "matSortDisabled"], outputs: ["matSortChange"], exportAs: ["matSort"] }, { kind: "component", type: i12.MatSortHeader, selector: "[mat-sort-header]", inputs: ["mat-sort-header", "arrowPosition", "start", "disabled", "sortActionDescription", "disableClear"], exportAs: ["matSortHeader"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i4.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatMenuModule }, { kind: "component", type: i5.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: i5.MatMenuItem, selector: "[mat-menu-item]", inputs: ["role", "disabled", "disableRipple"], exportAs: ["matMenuItem"] }, { kind: "directive", type: i5.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: 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: MatTooltipModule }, { kind: "directive", type: i10.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "ngmodule", type: MatSnackBarModule }, { 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: MatBadgeModule }, { kind: "directive", type: i15.MatBadge, selector: "[matBadge]", inputs: ["matBadgeColor", "matBadgeOverlap", "matBadgeDisabled", "matBadgePosition", "matBadge", "matBadgeDescription", "matBadgeSize", "matBadgeHidden"] }, { kind: "ngmodule", type: ScrollingModule }, { kind: "directive", type: i19.ɵɵCdkFixedSizeVirtualScroll, selector: "cdk-virtual-scroll-viewport[itemSize]", inputs: ["itemSize", "minBufferPx", "maxBufferPx"] }, { kind: "directive", type: i19.ɵɵCdkVirtualForOf, selector: "[cdkVirtualFor][cdkVirtualForOf]", inputs: ["cdkVirtualForOf", "cdkVirtualForTrackBy", "cdkVirtualForTemplate", "cdkVirtualForTemplateCacheSize"] }, { kind: "component", type: i19.ɵɵCdkVirtualScrollViewport, selector: "cdk-virtual-scroll-viewport", inputs: ["orientation", "appendOnly"], outputs: ["scrolledIndexChange"] }, { kind: "component", type: PraxisTableToolbar, selector: "praxis-table-toolbar", inputs: ["config", "debugLayout"], outputs: ["toolbarAction", "reset"] }, { kind: "component", type: PraxisFilter, selector: "praxis-filter", inputs: ["resourcePath", "formId", "mode", "notifyIfOutdated", "snoozeMs", "autoOpenSettingsOnOutdated", "editModeEnabled", "value", "quickField", "alwaysVisibleFields", "tags", "allowSaveTags", "persistenceKey", "i18n", "changeDebounceMs", "showFilterSettings", "summary", "summaryTemplate", "summaryMap", "autoSummary", "confirmTagDelete", "debugLayout", "placeBooleansInActions", "showToggleLabels", "alwaysMinWidth", "alwaysColsMd", "alwaysColsLg", "tagColor", "tagVariant", "tagButtonColor", "actionsButtonColor", "actionsVariant", "overlayVariant", "overlayBackdrop", "advancedOpenMode"], outputs: ["submit", "change", "clear", "modeChange", "requestSearch", "tagsChange", "metaChanged", "schemaStatusChange"] }, { kind: "directive", type: PraxisIconDirective, selector: "mat-icon[praxisIcon]", inputs: ["praxisIcon"] }, { kind: "component", type: EmptyStateCardComponent, selector: "praxis-empty-state-card", inputs: ["icon", "title", "description", "primaryAction", "secondaryActions", "inline"] }] });
|
|
24259
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.1.4", type: PraxisTable, isStandalone: true, selector: "praxis-table", inputs: { config: "config", resourcePath: "resourcePath", filterCriteria: "filterCriteria", notifyIfOutdated: "notifyIfOutdated", snoozeMs: "snoozeMs", autoOpenSettingsOnOutdated: "autoOpenSettingsOnOutdated", showToolbar: "showToolbar", toolbarV2: "toolbarV2", autoDelete: "autoDelete", editModeEnabled: "editModeEnabled", dense: "dense", tableId: "tableId", debugLayout: "debugLayout", horizontalScroll: "horizontalScroll", crudContext: "crudContext", idField: "idField" }, outputs: { rowClick: "rowClick", rowAction: "rowAction", toolbarAction: "toolbarAction", bulkAction: "bulkAction", rowDoubleClick: "rowDoubleClick", schemaStatusChange: "schemaStatusChange", metadataChange: "metadataChange", beforeDelete: "beforeDelete", afterDelete: "afterDelete", deleteError: "deleteError", beforeBulkDelete: "beforeBulkDelete", afterBulkDelete: "afterBulkDelete", bulkDeleteError: "bulkDeleteError" }, host: { properties: { "class.debug-layout": "debugLayout", "class.density-compact": "config?.appearance?.density === 'compact'", "class.density-comfortable": "config?.appearance?.density === 'comfortable'", "class.density-spacious": "config?.appearance?.density === 'spacious'", "class.row-borders": "config?.appearance?.borders?.showRowBorders !== false", "class.col-borders": "!!config?.appearance?.borders?.showColumnBorders" } }, queries: [{ propertyName: "projectedFilter", first: true, predicate: PraxisFilter, descendants: true }], viewQueries: [{ propertyName: "paginator", first: true, predicate: MatPaginator, descendants: true }, { propertyName: "sort", first: true, predicate: MatSort, descendants: true }, { propertyName: "actionsHeaderCell", first: true, predicate: ["actionsHeaderCell"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<praxis-empty-state-card\n *ngIf=\"!resourcePath\"\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<!-- Error State with Quick Connect CTA -->\n<div class=\"ptable-error\" *ngIf=\"resourcePath && (schemaError || dataError)\" style=\"display:flex; align-items:center; gap:12px; padding:12px; border:1px solid var(--md-sys-color-error, #b00020); border-radius:8px; margin: 8px 0;\">\n <mat-icon color=\"warn\" aria-hidden=\"true\">error</mat-icon>\n <div style=\"flex:1\">\n <div style=\"font-weight:600\">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 <button mat-stroked-button (click)=\"retryData()\" *ngIf=\"!schemaError\">Tentar novamente</button>\n <button mat-stroked-button (click)=\"reloadSchema()\" *ngIf=\"schemaError\">Recarregar colunas</button>\n </div>\n\n<!-- Inline banner for schema change (only in edit mode) -->\n<div *ngIf=\"shouldShowOutdatedInline()\" 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 <ng-container *ngIf=\"resourcePath && !schemaError && !dataError && toolbarV2; else legacyHeader\">\n <div class=\"praxis-table-header\" [class.debug-layout]=\"debugLayout\" [class.edit-mode]=\"editModeEnabled\" *ngIf=\"showToolbar || editModeEnabled\">\n <praxis-table-toolbar\n *ngIf=\"showToolbar\"\n [config]=\"config\"\n [debugLayout]=\"debugLayout\"\n (toolbarAction)=\"onToolbarAction($event)\"\n (reset)=\"onResetPreferences()\"\n >\n <praxis-filter\n *ngIf=\"\n resourcePath &&\n config.behavior?.filtering?.advancedFilters?.enabled &&\n !projectedFilter\n \"\n advancedFilter\n [resourcePath]=\"resourcePath\"\n [formId]=\"tableId + '-filter'\"\n [editModeEnabled]=\"editModeEnabled\"\n [quickField]=\"\n config.behavior?.filtering?.advancedFilters?.settings?.quickField\n \"\n [alwaysVisibleFields]=\"\n config.behavior?.filtering?.advancedFilters?.settings\n ?.alwaysVisibleFields\n \"\n [allowSaveTags]=\"\n config.behavior?.filtering?.advancedFilters?.settings\n ?.allowSaveTags\n \"\n [changeDebounceMs]=\"\n config.behavior?.filtering?.advancedFilters?.settings\n ?.changeDebounceMs ?? 300\n \"\n [i18n]=\"getFilterI18n()\"\n [mode]=\"\n config.behavior?.filtering?.advancedFilters?.settings?.mode ??\n 'auto'\n \"\n [debugLayout]=\"debugLayout\"\n [showFilterSettings]=\"editModeEnabled\"\n (submit)=\"onAdvancedFilterSubmit($event)\"\n (clear)=\"onAdvancedFilterClear()\"\n ></praxis-filter>\n <ng-content select=\"[advancedFilter]\" />\n <ng-content select=\"[toolbar]\" />\n <button end-actions mat-icon-button color=\"primary\" data-role=\"table-settings\" *ngIf=\"editModeEnabled\"\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 </praxis-table-toolbar>\n <!-- Render a minimal settings button when toolbar is hidden but edit mode is enabled -->\n <div class=\"ptable-header-actions\" *ngIf=\"!showToolbar && editModeEnabled\">\n <button mat-icon-button color=\"primary\" (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 <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 </div>\n \n </div>\n</ng-container>\n<ng-template #legacyHeader>\n <ng-container *ngIf=\"resourcePath && !schemaError && !dataError\">\n <praxis-table-toolbar\n *ngIf=\"showToolbar\"\n [config]=\"config\"\n [debugLayout]=\"debugLayout\"\n (toolbarAction)=\"onToolbarAction($event)\"\n (reset)=\"onResetPreferences()\"\n >\n <praxis-filter\n *ngIf=\"\n resourcePath &&\n config.behavior?.filtering?.advancedFilters?.enabled &&\n !projectedFilter\n \"\n advancedFilter\n [resourcePath]=\"resourcePath\"\n [formId]=\"tableId + '-filter'\"\n [editModeEnabled]=\"editModeEnabled\"\n [quickField]=\"\n config.behavior?.filtering?.advancedFilters?.settings?.quickField\n \"\n [alwaysVisibleFields]=\"\n config.behavior?.filtering?.advancedFilters?.settings\n ?.alwaysVisibleFields\n \"\n [allowSaveTags]=\"\n config.behavior?.filtering?.advancedFilters?.settings?.allowSaveTags\n \"\n [changeDebounceMs]=\"\n config.behavior?.filtering?.advancedFilters?.settings\n ?.changeDebounceMs ?? 300\n \"\n [i18n]=\"getFilterI18n()\"\n [mode]=\"\n config.behavior?.filtering?.advancedFilters?.settings?.mode ??\n 'auto'\n \"\n [debugLayout]=\"debugLayout\"\n [showFilterSettings]=\"editModeEnabled\"\n (submit)=\"onAdvancedFilterSubmit($event)\"\n (clear)=\"onAdvancedFilterClear()\"\n ></praxis-filter>\n <ng-content select=\"[advancedFilter]\" />\n <ng-content select=\"[toolbar]\" />\n <button end-actions mat-icon-button color=\"primary\" *ngIf=\"editModeEnabled\"\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 </praxis-table-toolbar>\n <!-- Legacy header: settings button when toolbar hidden -->\n <div class=\"ptable-header-actions\" *ngIf=\"!showToolbar && editModeEnabled\">\n <button mat-icon-button color=\"primary\" data-role=\"table-settings\" (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 </ng-container>\n \n</ng-template>\n<div class=\"px-scroll-viewport\"\n [class.scroll-auto]=\"horizontalScroll === 'auto'\"\n [class.scroll-wrap]=\"horizontalScroll === 'wrap'\"\n [class.scroll-none]=\"horizontalScroll === 'none'\">\n\n<table\n *ngIf=\"resourcePath && !schemaError && !dataError\"\n mat-table\n [dataSource]=\"dataSource\"\n matSort\n (matSortChange)=\"onSortChange($event)\"\n [matSortDisabled]=\"!getSortingEnabled()\"\n class=\"mat-elevation-z8\"\n>\n <ng-container\n *ngIf=\"config.behavior?.selection?.enabled\"\n matColumnDef=\"_select\"\n >\n <th mat-header-cell *matHeaderCellDef>\n <mat-checkbox\n (change)=\"masterToggle()\"\n [checked]=\"isAllSelected()\"\n [indeterminate]=\"selection.hasValue() && !isAllSelected()\"\n ></mat-checkbox>\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 <ng-container\n *ngFor=\"let column of visibleColumns\"\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 [disabled]=\"!getSortingEnabled() || column.sortable === false\"\n [style.text-align]=\"column.align\"\n [style.width]=\"column.width\"\n [attr.style]=\"column.headerStyle\"\n >\n {{ column.header }}\n </th>\n <td\n mat-cell\n *matCellDef=\"let element\"\n [style.text-align]=\"column.align\"\n [style.width]=\"column.width\"\n [attr.style]=\"column.style\"\n [ngClass]=\"getCellClasses(element, column)\"\n [ngStyle]=\"getCellNgStyle(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 <mat-icon *ngIf=\"getBadgeIcon(element, column) as bi\" 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 <mat-icon *ngIf=\"getButtonIcon(element, column) as bi\">{{ 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 <mat-icon *ngIf=\"getButtonIcon(element, column) as bi\">{{ 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 <mat-icon *ngIf=\"getButtonIcon(element, column) as bi\">{{ 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 <mat-icon *ngIf=\"getChipIcon(element, column) as ci\" 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.%]=\"getProgressValue(element, column)\" [style.background]=\"getProgressColor(element, column) || null\"></div>\n <div class=\"pfx-progress-label\" *ngIf=\"getProgressShowLabel(element, column)\">{{ getProgressValue(element, column) }}%</div>\n </div>\n </ng-container>\n\n <!-- Avatar renderer -->\n <ng-container *ngSwitchCase=\"'avatar'\">\n <ng-container *ngIf=\"getAvatarSrc(element, column) as asrc; else initials\">\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 </ng-container>\n <ng-template #initials>\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 </ng-template>\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.id, element, $event)\" [disabled]=\"!it.__visible\" >\n <mat-icon *ngIf=\"it.icon\">{{ it.icon }}</mat-icon>\n <span>{{ it.label }}</span>\n </button>\n </mat-menu>\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))\"><mat-icon *ngIf=\"getBadgeIcon(element, asItemColumn(column, it)) as bi\" 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)\"><mat-icon *ngIf=\"getButtonIcon(element, asItemColumn(column, it)) as bi\">{{ 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)\"><mat-icon *ngIf=\"getButtonIcon(element, asItemColumn(column, it)) as bi\">{{ 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)\"><mat-icon *ngIf=\"getButtonIcon(element, asItemColumn(column, it)) as bi\">{{ 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))\"><mat-icon *ngIf=\"getChipIcon(element, asItemColumn(column, it)) as ci\" 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.%]=\"getProgressValue(element, asItemColumn(column, it))\" [style.background]=\"getProgressColor(element, asItemColumn(column, it)) || null\"></div><div class=\"pfx-progress-label\" *ngIf=\"getProgressShowLabel(element, asItemColumn(column, it))\">{{ getProgressValue(element, asItemColumn(column, it)) }}%</div></div>\n </ng-container>\n <ng-container *ngSwitchCase=\"'avatar'\">\n <ng-container *ngIf=\"getAvatarSrc(element, asItemColumn(column, it)) as asrc; else initials_comp\">\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 </ng-container>\n <ng-template #initials_comp>\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 </ng-template>\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.id, element, $event)\" [disabled]=\"!mi.__visible\"><mat-icon *ngIf=\"mi.icon\">{{ mi.icon }}</mat-icon><span>{{ mi.label }}</span></button>\n </mat-menu>\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\">{{ getCellValue(element, column) }}</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 </td>\n </ng-container>\n <ng-container *ngIf=\"config.actions?.row?.enabled\" 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]=\"config.actions?.row?.width\" 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 <mat-icon *ngIf=\"getActionsHeaderIcon() as hi\" [praxisIcon]=\"hi\"></mat-icon>\n <span class=\"label\" *ngIf=\"getActionsHeaderLabel() as hl\">{{ 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]=\"config.actions?.row?.width\"\n >\n <div class=\"praxis-actions-cell__content\">\n <!-- A\u00E7\u00F5es inline -->\n <!-- Inline actions: icons mode -->\n <ng-container *ngIf=\"config.actions?.row?.display === 'icons' || !config.actions?.row?.display\">\n <ng-container *ngFor=\"let a of getInlineRowActions(row); trackBy: trackAction\">\n <button\n mat-icon-button\n class=\"praxis-icon-btn\"\n [disabled]=\"isActionDisabled(a, row)\"\n (click)=\"onRowAction(getActionId(a), row, $event)\"\n [matTooltip]=\"a.label || getActionId(a)\"\n matTooltipPosition=\"above\"\n matTooltipClass=\"praxis-tooltip\"\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 </ng-container>\n </ng-container>\n\n <!-- Inline actions: buttons mode (show label + icon) -->\n <ng-container *ngIf=\"config.actions?.row?.display === 'buttons'\">\n <ng-container *ngFor=\"let a of getInlineRowActions(row); trackBy: trackAction\">\n <button\n mat-flat-button\n class=\"praxis-row-btn\"\n [disabled]=\"isActionDisabled(a, row)\"\n (click)=\"onRowAction(getActionId(a), row, $event)\"\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 </ng-container>\n </ng-container>\n\n <!-- Menu de overflow -->\n <button\n mat-icon-button\n class=\"praxis-icon-btn praxis-more-btn\"\n *ngIf=\"hasOverflowRowActions(row)\"\n [matMenuTriggerFor]=\"rowMoreMenu\"\n [color]=\"getRowMenuButtonColor() || null\"\n aria-label=\"Mais a\u00E7\u00F5es\"\n >\n <mat-icon [praxisIcon]=\"getRowMenuIcon()\"></mat-icon>\n </button>\n <mat-menu #rowMoreMenu=\"matMenu\" xPosition=\"before\">\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)\"\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 </mat-menu>\n </div>\n </td>\n </ng-container>\n\n <tr mat-header-row *matHeaderRowDef=\"displayedColumns\"></tr>\n <ng-container *ngIf=\"!isVirtualized()\">\n <tr\n mat-row\n *matRowDef=\"let row; let i = index; columns: displayedColumns\"\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)\"\n (dblclick)=\"onRowDoubleClicked(row, i)\"\n ></tr>\n </ng-container>\n</table>\n\n<!-- Virtual rows path (header preserved above) -->\n<ng-container *ngIf=\"resourcePath && !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]=\"getVirtMinHeightStyle()\"\n >\n <table class=\"mat-mdc-table mat-elevation-z8\" [style.width]=\"horizontalScroll === 'auto' ? 'max-content' : '100%'\">\n <tbody>\n <tr class=\"mat-mdc-row\"\n *cdkVirtualFor=\"let row of dataSource.data; let i = index; trackBy: trackByRow\"\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)\"\n (dblclick)=\"onRowDoubleClicked(row, i)\">\n <!-- Selection column -->\n <td class=\"mat-mdc-cell\" *ngIf=\"config.behavior?.selection?.enabled\">\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 <td class=\"mat-mdc-cell\"\n *ngFor=\"let column of visibleColumns\"\n [style.text-align]=\"column.align\"\n [style.width]=\"column.width\"\n [attr.style]=\"column.style\"\n [ngClass]=\"getCellClasses(row, column)\"\n [ngStyle]=\"getCellNgStyle(row, column)\">\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 <mat-icon *ngIf=\"getBadgeIcon(row, column) as bi\" 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 </td>\n\n <!-- Actions column -->\n <td class=\"mat-mdc-cell praxis-actions-cell\" *ngIf=\"config.actions?.row?.enabled\" [class.dense]=\"dense\" [style.width]=\"config.actions?.row?.width\">\n <div class=\"praxis-actions-cell__content\">\n <ng-container *ngIf=\"config.actions?.row?.display === 'icons' || !config.actions?.row?.display\">\n <ng-container *ngFor=\"let a of getInlineRowActions(row); trackBy: trackAction\">\n <button mat-icon-button class=\"praxis-icon-btn\"\n [disabled]=\"isActionDisabled(a, row)\"\n (click)=\"onRowAction(getActionId(a), row, $event)\"\n [matTooltip]=\"a.label || getActionId(a)\"\n matTooltipPosition=\"above\"\n matTooltipClass=\"praxis-tooltip\"\n [attr.aria-label]=\"a.label || getActionId(a)\"\n [color]=\"a.color || null\">\n <mat-icon [praxisIcon]=\"a.icon\"></mat-icon>\n </button>\n </ng-container>\n </ng-container>\n <ng-container *ngIf=\"config.actions?.row?.display === 'buttons'\">\n <ng-container *ngFor=\"let a of getInlineRowActions(row); trackBy: trackAction\">\n <button mat-flat-button class=\"praxis-row-btn\"\n [disabled]=\"isActionDisabled(a, row)\"\n (click)=\"onRowAction(getActionId(a), row, $event)\"\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 </ng-container>\n </ng-container>\n <button mat-icon-button class=\"praxis-icon-btn praxis-more-btn\"\n *ngIf=\"hasOverflowRowActions(row)\"\n [matMenuTriggerFor]=\"rowMoreMenuV\"\n [color]=\"getRowMenuButtonColor() || null\"\n aria-label=\"Mais a\u00E7\u00F5es\">\n <mat-icon [praxisIcon]=\"getRowMenuIcon()\"></mat-icon>\n </button>\n <mat-menu #rowMoreMenuV=\"matMenu\" xPosition=\"before\">\n <ng-container *ngFor=\"let a of getOverflowRowActions(row); trackBy: trackAction\">\n <button mat-menu-item (click)=\"onRowAction(getActionId(a), row, $event)\" [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 </mat-menu>\n </div>\n </td>\n </tr>\n </tbody>\n </table>\n </cdk-virtual-scroll-viewport>\n</ng-container>\n\n</div>\n<!-- Paginadores (top/bottom) -->\n<mat-paginator\n *ngIf=\"resourcePath && !schemaError && !dataError && getPaginationEnabled() && (config.behavior?.pagination?.position === 'top' || config.behavior?.pagination?.position === 'both')\"\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<mat-paginator\n *ngIf=\"resourcePath && !schemaError && !dataError && getPaginationEnabled() && (config.behavior?.pagination?.position === 'bottom' || config.behavior?.pagination?.position === 'both' || !config.behavior?.pagination?.position)\"\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", styles: ["@charset \"UTF-8\";table{width:100%}.praxis-actions-cell{height:100%;padding-inline:12px;white-space:nowrap}:host.density-compact{--p-header-padding: 8px 12px;--p-actions-btn-size: 32px;--p-actions-icon-size: 18px}:host.density-comfortable{--p-header-padding: 12px 16px;--p-actions-btn-size: 40px;--p-actions-icon-size: 22px}:host.density-spacious{--p-header-padding: 16px 20px;--p-actions-btn-size: 44px;--p-actions-icon-size: 24px}:host.density-compact ::ng-deep .mat-mdc-cell{padding:8px 12px}:host.density-comfortable ::ng-deep .mat-mdc-cell{padding:12px 16px}:host.density-spacious ::ng-deep .mat-mdc-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%}.praxis-actions-cell.dense .praxis-actions-cell__content{gap:6px}.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, rgba(255, 255, 255, .06))}.praxis-icon-btn:focus-visible{outline:2px solid var(--primary, #48a1ff);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-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-icon-btn.destructive mat-icon{color:#ff6b6b}.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.debug-layout,:host.debug-layout .praxis-table-header{outline:2px dashed #ff4d4f;border-radius:8px}:host.debug-layout ::ng-deep .praxis-filter-bar{outline:1px dashed #f59e0b}:host.debug-layout ::ng-deep .quick-shell{outline:1px dashed #3b82f6}:host.debug-layout ::ng-deep .always-fields{outline:1px dashed #22c55e}:host.debug-layout ::ng-deep .praxis-filter-overlay .praxis-filter-advanced{outline:2px solid #a855f7}:host.debug-layout ::ng-deep .mat-mdc-table{outline:1px dashed #94a3b8}.praxis-table-header>praxis-table-toolbar{flex:1 0 100%}:host{--p-table-header-bg: var(--md-sys-color-surface-container-highest, #1d1d1f);--p-table-header-fg: var(--md-sys-color-on-surface, #e8f3f1);--p-table-border-color: var(--md-sys-color-outline-variant, rgba(255, 255, 255, .12));--p-table-row-even-bg: var(--md-sys-color-surface-container, rgba(255, 255, 255, .04));--p-table-row-hover-bg: color-mix(in srgb, var(--md-sys-color-primary, #3f51b5) 10%, transparent);--p-table-row-selected-bg: var(--md-sys-color-primary-container, rgba(63,81,181,.14));--p-table-badge-soft-primary-bg: color-mix(in srgb, var(--mat-sys-primary, var(--md-sys-color-primary)) 16%, transparent);--p-table-badge-soft-primary-fg: var(--mat-sys-primary, var(--md-sys-color-primary));--p-table-badge-soft-accent-bg: color-mix(in srgb, var(--mat-sys-secondary, var(--md-sys-color-secondary, #ff4081)) 14%, transparent);--p-table-badge-soft-accent-fg: var(--mat-sys-secondary, var(--md-sys-color-secondary, #ff4081));--p-table-badge-soft-warn-bg: color-mix(in srgb, var(--mat-sys-error, var(--md-sys-color-error, #f44336)) 14%, transparent);--p-table-badge-soft-warn-fg: var(--mat-sys-error, var(--md-sys-color-error, #f44336));--p-table-state-success-bg: color-mix(in srgb, var(--mat-sys-tertiary, var(--md-sys-color-tertiary, #388E3C)) 16%, transparent);--p-table-state-success-fg: var(--md-sys-color-on-surface, #c8e6c9);--p-table-state-warning-bg: color-mix(in srgb, var(--md-sys-color-secondary, #FFA000) 18%, transparent);--p-table-state-warning-fg: var(--md-sys-color-on-surface, #ffe0b2);--p-table-state-danger-bg: color-mix(in srgb, var(--md-sys-color-error, #e53935) 18%, transparent);--p-table-state-danger-fg: var(--md-sys-color-on-surface, #ffcdd2);--p-table-state-highlight-bg: color-mix(in srgb, var(--md-sys-color-primary, #2196f3) 16%, transparent);--p-table-state-highlight-fg: var(--md-sys-color-on-surface, #bbdefb)}:host ::ng-deep .mat-mdc-table{background:var(--md-sys-color-surface-container-highest, #1d1d1f);border-radius:12px;width:100%}:host [data-role=table-settings].mat-mdc-icon-button{--mdc-icon-button-icon-color: var(--mat-sys-primary, var(--md-sys-color-primary, #3f51b5));color:var(--mat-sys-primary, var(--md-sys-color-primary, #3f51b5))}.pfx-link{color:var(--mat-sys-primary, #3f51b5);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(--mat-sys-outline-variant);color:var(--mat-sys-on-surface)}.pfx-chip--filled-primary{background:var(--mat-sys-primary);color:var(--mat-sys-on-primary)}.pfx-chip--filled-accent{background:var(--mat-sys-secondary, #ff4081);color:#fff}.pfx-chip--filled-warn{background:var(--mat-sys-error, #f44336);color:#fff}.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(--mat-sys-surface-container-highest, rgba(255, 255, 255, .08));border-radius:4px;overflow:hidden;display:inline-block;vertical-align:middle}.pfx-progress-bar{height:100%;background:var(--mat-sys-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(--mat-sys-surface-container, #2a2a2e);color:var(--mat-sys-on-surface, #eee);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;scrollbar-gutter:stable}.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:1;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}.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 .mat-mdc-cell{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}:host ::ng-deep .mat-mdc-row:hover{background:var(--p-table-row-hover-bg)}: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.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-info-banner{display:flex;gap:12px;align-items:center;padding:8px 12px;margin:8px 0;border-radius:8px;border:1px solid var(--mat-sys-primary, var(--md-sys-color-primary, #1a73e8));background:color-mix(in srgb,var(--mat-sys-primary, var(--md-sys-color-primary, #1a73e8)) 10%,transparent)}.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, #2a2a2a);border:1px solid var(--md-sys-color-outline-variant, rgba(0, 0, 0, .08))}.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(--mat-sys-primary, #3f51b5);color:var(--mat-sys-on-primary, #fff)}.pfx-badge--filled-accent{background:var(--mat-sys-secondary, #ff4081);color:var(--mat-sys-on-secondary, #fff)}.pfx-badge--filled-warn{background:var(--mat-sys-error, #f44336);color:var(--mat-sys-on-error, #fff)}.pfx-badge--outlined{background:transparent;border-color:var(--mat-sys-outline-variant, rgba(255, 255, 255, .24));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: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "directive", type: i1.NgSwitch, selector: "[ngSwitch]", inputs: ["ngSwitch"] }, { kind: "directive", type: i1.NgSwitchCase, selector: "[ngSwitchCase]", inputs: ["ngSwitchCase"] }, { kind: "directive", type: i1.NgSwitchDefault, selector: "[ngSwitchDefault]" }, { 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: 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: "ngmodule", type: MatPaginatorModule }, { kind: "component", type: i11$1.MatPaginator, selector: "mat-paginator", inputs: ["color", "pageIndex", "length", "pageSize", "pageSizeOptions", "hidePageSize", "showFirstLastButtons", "selectConfig", "disabled"], outputs: ["page"], exportAs: ["matPaginator"] }, { kind: "ngmodule", type: MatSortModule }, { kind: "directive", type: i12.MatSort, selector: "[matSort]", inputs: ["matSortActive", "matSortStart", "matSortDirection", "matSortDisableClear", "matSortDisabled"], outputs: ["matSortChange"], exportAs: ["matSort"] }, { kind: "component", type: i12.MatSortHeader, selector: "[mat-sort-header]", inputs: ["mat-sort-header", "arrowPosition", "start", "disabled", "sortActionDescription", "disableClear"], exportAs: ["matSortHeader"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i4.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatMenuModule }, { kind: "component", type: i5.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: i5.MatMenuItem, selector: "[mat-menu-item]", inputs: ["role", "disabled", "disableRipple"], exportAs: ["matMenuItem"] }, { kind: "directive", type: i5.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: 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: MatTooltipModule }, { kind: "directive", type: i10.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "ngmodule", type: MatSnackBarModule }, { 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: MatBadgeModule }, { kind: "directive", type: i15.MatBadge, selector: "[matBadge]", inputs: ["matBadgeColor", "matBadgeOverlap", "matBadgeDisabled", "matBadgePosition", "matBadge", "matBadgeDescription", "matBadgeSize", "matBadgeHidden"] }, { kind: "ngmodule", type: ScrollingModule }, { kind: "directive", type: i19.ɵɵCdkFixedSizeVirtualScroll, selector: "cdk-virtual-scroll-viewport[itemSize]", inputs: ["itemSize", "minBufferPx", "maxBufferPx"] }, { kind: "directive", type: i19.ɵɵCdkVirtualForOf, selector: "[cdkVirtualFor][cdkVirtualForOf]", inputs: ["cdkVirtualForOf", "cdkVirtualForTrackBy", "cdkVirtualForTemplate", "cdkVirtualForTemplateCacheSize"] }, { kind: "component", type: i19.ɵɵCdkVirtualScrollViewport, selector: "cdk-virtual-scroll-viewport", inputs: ["orientation", "appendOnly"], outputs: ["scrolledIndexChange"] }, { kind: "component", type: PraxisTableToolbar, selector: "praxis-table-toolbar", inputs: ["config", "debugLayout"], outputs: ["toolbarAction", "reset"] }, { kind: "component", type: PraxisFilter, selector: "praxis-filter", inputs: ["resourcePath", "formId", "mode", "notifyIfOutdated", "snoozeMs", "autoOpenSettingsOnOutdated", "editModeEnabled", "value", "quickField", "alwaysVisibleFields", "tags", "allowSaveTags", "persistenceKey", "i18n", "changeDebounceMs", "showFilterSettings", "showQuickFallback", "summary", "summaryTemplate", "summaryMap", "autoSummary", "confirmTagDelete", "debugLayout", "placeBooleansInActions", "showToggleLabels", "alwaysMinWidth", "alwaysColsMd", "alwaysColsLg", "tagColor", "tagVariant", "tagButtonColor", "actionsButtonColor", "actionsVariant", "overlayVariant", "overlayBackdrop", "advancedOpenMode"], outputs: ["submit", "change", "clear", "modeChange", "requestSearch", "tagsChange", "metaChanged", "schemaStatusChange"] }, { kind: "directive", type: PraxisIconDirective, selector: "mat-icon[praxisIcon]", inputs: ["praxisIcon"] }, { kind: "component", type: EmptyStateCardComponent, selector: "praxis-empty-state-card", inputs: ["icon", "title", "description", "primaryAction", "secondaryActions", "inline"] }] });
|
|
24066
24260
|
}
|
|
24067
24261
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.4", ngImport: i0, type: PraxisTable, decorators: [{
|
|
24068
24262
|
type: Component,
|
|
@@ -24093,7 +24287,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.4", ngImpor
|
|
|
24093
24287
|
// Quick borders toggles (rows/columns)
|
|
24094
24288
|
"[class.row-borders]": "config?.appearance?.borders?.showRowBorders !== false",
|
|
24095
24289
|
"[class.col-borders]": "!!config?.appearance?.borders?.showColumnBorders",
|
|
24096
|
-
}, template: "<praxis-empty-state-card\n *ngIf=\"!resourcePath\"\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<!-- Error State with Quick Connect CTA -->\n<div class=\"ptable-error\" *ngIf=\"resourcePath && (schemaError || dataError)\" style=\"display:flex; align-items:center; gap:12px; padding:12px; border:1px solid var(--md-sys-color-error, #b00020); border-radius:8px; margin: 8px 0;\">\n <mat-icon color=\"warn\" aria-hidden=\"true\">error</mat-icon>\n <div style=\"flex:1\">\n <div style=\"font-weight:600\">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 <button mat-stroked-button (click)=\"retryData()\" *ngIf=\"!schemaError\">Tentar novamente</button>\n <button mat-stroked-button (click)=\"reloadSchema()\" *ngIf=\"schemaError\">Recarregar colunas</button>\n </div>\n\n<!-- Inline banner for schema change (only in edit mode) -->\n<div *ngIf=\"shouldShowOutdatedInline()\" 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 <ng-container *ngIf=\"resourcePath && !schemaError && !dataError && toolbarV2; else legacyHeader\">\n <div class=\"praxis-table-header\" [class.debug-layout]=\"debugLayout\" [class.edit-mode]=\"editModeEnabled\" *ngIf=\"showToolbar || editModeEnabled\">\n <praxis-table-toolbar\n *ngIf=\"showToolbar\"\n [config]=\"config\"\n [debugLayout]=\"debugLayout\"\n (toolbarAction)=\"onToolbarAction($event)\"\n (reset)=\"onResetPreferences()\"\n >\n <praxis-filter\n *ngIf=\"\n resourcePath &&\n config.behavior?.filtering?.advancedFilters?.enabled &&\n !projectedFilter\n \"\n advancedFilter\n [resourcePath]=\"resourcePath\"\n [formId]=\"tableId + '-filter'\"\n [editModeEnabled]=\"editModeEnabled\"\n [quickField]=\"\n config.behavior?.filtering?.advancedFilters?.settings?.quickField\n \"\n [alwaysVisibleFields]=\"\n config.behavior?.filtering?.advancedFilters?.settings\n ?.alwaysVisibleFields\n \"\n [allowSaveTags]=\"\n config.behavior?.filtering?.advancedFilters?.settings\n ?.allowSaveTags\n \"\n [changeDebounceMs]=\"\n config.behavior?.filtering?.advancedFilters?.settings\n ?.changeDebounceMs ?? 300\n \"\n [i18n]=\"getFilterI18n()\"\n [mode]=\"\n config.behavior?.filtering?.advancedFilters?.settings?.mode ??\n 'auto'\n \"\n [debugLayout]=\"debugLayout\"\n [showFilterSettings]=\"!editModeEnabled\"\n (submit)=\"onAdvancedFilterSubmit($event)\"\n (clear)=\"onAdvancedFilterClear()\"\n ></praxis-filter>\n <ng-content select=\"[advancedFilter]\" />\n <ng-content select=\"[toolbar]\" />\n <button end-actions mat-icon-button color=\"primary\" data-role=\"table-settings\" *ngIf=\"editModeEnabled\"\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 </praxis-table-toolbar>\n <!-- Render a minimal settings button when toolbar is hidden but edit mode is enabled -->\n <div class=\"ptable-header-actions\" *ngIf=\"!showToolbar && editModeEnabled\">\n <button mat-icon-button color=\"primary\" (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 <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 </div>\n \n </div>\n</ng-container>\n<ng-template #legacyHeader>\n <ng-container *ngIf=\"resourcePath && !schemaError && !dataError\">\n <praxis-table-toolbar\n *ngIf=\"showToolbar\"\n [config]=\"config\"\n [debugLayout]=\"debugLayout\"\n (toolbarAction)=\"onToolbarAction($event)\"\n (reset)=\"onResetPreferences()\"\n >\n <praxis-filter\n *ngIf=\"\n resourcePath &&\n config.behavior?.filtering?.advancedFilters?.enabled &&\n !projectedFilter\n \"\n advancedFilter\n [resourcePath]=\"resourcePath\"\n [formId]=\"tableId + '-filter'\"\n [editModeEnabled]=\"editModeEnabled\"\n [quickField]=\"\n config.behavior?.filtering?.advancedFilters?.settings?.quickField\n \"\n [alwaysVisibleFields]=\"\n config.behavior?.filtering?.advancedFilters?.settings\n ?.alwaysVisibleFields\n \"\n [allowSaveTags]=\"\n config.behavior?.filtering?.advancedFilters?.settings?.allowSaveTags\n \"\n [changeDebounceMs]=\"\n config.behavior?.filtering?.advancedFilters?.settings\n ?.changeDebounceMs ?? 300\n \"\n [i18n]=\"getFilterI18n()\"\n [mode]=\"\n config.behavior?.filtering?.advancedFilters?.settings?.mode ??\n 'auto'\n \"\n [debugLayout]=\"debugLayout\"\n [showFilterSettings]=\"!editModeEnabled\"\n (submit)=\"onAdvancedFilterSubmit($event)\"\n (clear)=\"onAdvancedFilterClear()\"\n ></praxis-filter>\n <ng-content select=\"[advancedFilter]\" />\n <ng-content select=\"[toolbar]\" />\n <button end-actions mat-icon-button color=\"primary\" *ngIf=\"editModeEnabled\"\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 </praxis-table-toolbar>\n <!-- Legacy header: settings button when toolbar hidden -->\n <div class=\"ptable-header-actions\" *ngIf=\"!showToolbar && editModeEnabled\">\n <button mat-icon-button color=\"primary\" data-role=\"table-settings\" (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 </ng-container>\n \n</ng-template>\n<div class=\"px-scroll-viewport\"\n [class.scroll-auto]=\"horizontalScroll === 'auto'\"\n [class.scroll-wrap]=\"horizontalScroll === 'wrap'\"\n [class.scroll-none]=\"horizontalScroll === 'none'\">\n\n<table\n *ngIf=\"resourcePath && !schemaError && !dataError\"\n mat-table\n [dataSource]=\"dataSource\"\n matSort\n (matSortChange)=\"onSortChange($event)\"\n [matSortDisabled]=\"!getSortingEnabled()\"\n class=\"mat-elevation-z8\"\n>\n <ng-container\n *ngIf=\"config.behavior?.selection?.enabled\"\n matColumnDef=\"_select\"\n >\n <th mat-header-cell *matHeaderCellDef>\n <mat-checkbox\n (change)=\"masterToggle()\"\n [checked]=\"isAllSelected()\"\n [indeterminate]=\"selection.hasValue() && !isAllSelected()\"\n ></mat-checkbox>\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 <ng-container\n *ngFor=\"let column of visibleColumns\"\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 [disabled]=\"!getSortingEnabled() || column.sortable === false\"\n [style.text-align]=\"column.align\"\n [style.width]=\"column.width\"\n [attr.style]=\"column.headerStyle\"\n >\n {{ column.header }}\n </th>\n <td\n mat-cell\n *matCellDef=\"let element\"\n [style.text-align]=\"column.align\"\n [style.width]=\"column.width\"\n [attr.style]=\"column.style\"\n [ngClass]=\"getCellClasses(element, column)\"\n [ngStyle]=\"getCellNgStyle(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 <mat-icon *ngIf=\"getBadgeIcon(element, column) as bi\" 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 <mat-icon *ngIf=\"getButtonIcon(element, column) as bi\">{{ 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 <mat-icon *ngIf=\"getButtonIcon(element, column) as bi\">{{ 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 <mat-icon *ngIf=\"getButtonIcon(element, column) as bi\">{{ 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 <mat-icon *ngIf=\"getChipIcon(element, column) as ci\" 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.%]=\"getProgressValue(element, column)\" [style.background]=\"getProgressColor(element, column) || null\"></div>\n <div class=\"pfx-progress-label\" *ngIf=\"getProgressShowLabel(element, column)\">{{ getProgressValue(element, column) }}%</div>\n </div>\n </ng-container>\n\n <!-- Avatar renderer -->\n <ng-container *ngSwitchCase=\"'avatar'\">\n <ng-container *ngIf=\"getAvatarSrc(element, column) as asrc; else initials\">\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 </ng-container>\n <ng-template #initials>\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 </ng-template>\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.id, element, $event)\" [disabled]=\"!it.__visible\" >\n <mat-icon *ngIf=\"it.icon\">{{ it.icon }}</mat-icon>\n <span>{{ it.label }}</span>\n </button>\n </mat-menu>\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))\"><mat-icon *ngIf=\"getBadgeIcon(element, asItemColumn(column, it)) as bi\" 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)\"><mat-icon *ngIf=\"getButtonIcon(element, asItemColumn(column, it)) as bi\">{{ 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)\"><mat-icon *ngIf=\"getButtonIcon(element, asItemColumn(column, it)) as bi\">{{ 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)\"><mat-icon *ngIf=\"getButtonIcon(element, asItemColumn(column, it)) as bi\">{{ 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))\"><mat-icon *ngIf=\"getChipIcon(element, asItemColumn(column, it)) as ci\" 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.%]=\"getProgressValue(element, asItemColumn(column, it))\" [style.background]=\"getProgressColor(element, asItemColumn(column, it)) || null\"></div><div class=\"pfx-progress-label\" *ngIf=\"getProgressShowLabel(element, asItemColumn(column, it))\">{{ getProgressValue(element, asItemColumn(column, it)) }}%</div></div>\n </ng-container>\n <ng-container *ngSwitchCase=\"'avatar'\">\n <ng-container *ngIf=\"getAvatarSrc(element, asItemColumn(column, it)) as asrc; else initials_comp\">\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 </ng-container>\n <ng-template #initials_comp>\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 </ng-template>\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.id, element, $event)\" [disabled]=\"!mi.__visible\"><mat-icon *ngIf=\"mi.icon\">{{ mi.icon }}</mat-icon><span>{{ mi.label }}</span></button>\n </mat-menu>\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\">{{ getCellValue(element, column) }}</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 </td>\n </ng-container>\n <ng-container *ngIf=\"config.actions?.row?.enabled\" 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]=\"config.actions?.row?.width\" 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 <mat-icon *ngIf=\"getActionsHeaderIcon() as hi\" [praxisIcon]=\"hi\"></mat-icon>\n <span class=\"label\" *ngIf=\"getActionsHeaderLabel() as hl\">{{ 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]=\"config.actions?.row?.width\"\n >\n <div class=\"praxis-actions-cell__content\">\n <!-- A\u00E7\u00F5es inline -->\n <!-- Inline actions: icons mode -->\n <ng-container *ngIf=\"config.actions?.row?.display === 'icons' || !config.actions?.row?.display\">\n <ng-container *ngFor=\"let a of getInlineRowActions(row); trackBy: trackAction\">\n <button\n mat-icon-button\n class=\"praxis-icon-btn\"\n [disabled]=\"isActionDisabled(a, row)\"\n (click)=\"onRowAction(getActionId(a), row, $event)\"\n [matTooltip]=\"a.label || getActionId(a)\"\n matTooltipPosition=\"above\"\n matTooltipClass=\"praxis-tooltip\"\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 </ng-container>\n </ng-container>\n\n <!-- Inline actions: buttons mode (show label + icon) -->\n <ng-container *ngIf=\"config.actions?.row?.display === 'buttons'\">\n <ng-container *ngFor=\"let a of getInlineRowActions(row); trackBy: trackAction\">\n <button\n mat-flat-button\n class=\"praxis-row-btn\"\n [disabled]=\"isActionDisabled(a, row)\"\n (click)=\"onRowAction(getActionId(a), row, $event)\"\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 </ng-container>\n </ng-container>\n\n <!-- Menu de overflow -->\n <button\n mat-icon-button\n class=\"praxis-icon-btn praxis-more-btn\"\n *ngIf=\"hasOverflowRowActions(row)\"\n [matMenuTriggerFor]=\"rowMoreMenu\"\n [color]=\"getRowMenuButtonColor() || null\"\n aria-label=\"Mais a\u00E7\u00F5es\"\n >\n <mat-icon [praxisIcon]=\"getRowMenuIcon()\"></mat-icon>\n </button>\n <mat-menu #rowMoreMenu=\"matMenu\" xPosition=\"before\">\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)\"\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 </mat-menu>\n </div>\n </td>\n </ng-container>\n\n <tr mat-header-row *matHeaderRowDef=\"displayedColumns\"></tr>\n <ng-container *ngIf=\"!isVirtualized()\">\n <tr\n mat-row\n *matRowDef=\"let row; let i = index; columns: displayedColumns\"\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)\"\n (dblclick)=\"onRowDoubleClicked(row, i)\"\n ></tr>\n </ng-container>\n</table>\n\n<!-- Virtual rows path (header preserved above) -->\n<ng-container *ngIf=\"resourcePath && !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]=\"getVirtMinHeightStyle()\"\n >\n <table class=\"mat-mdc-table mat-elevation-z8\" [style.width]=\"horizontalScroll === 'auto' ? 'max-content' : '100%'\">\n <tbody>\n <tr class=\"mat-mdc-row\"\n *cdkVirtualFor=\"let row of dataSource.data; let i = index; trackBy: trackByRow\"\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)\"\n (dblclick)=\"onRowDoubleClicked(row, i)\">\n <!-- Selection column -->\n <td class=\"mat-mdc-cell\" *ngIf=\"config.behavior?.selection?.enabled\">\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 <td class=\"mat-mdc-cell\"\n *ngFor=\"let column of visibleColumns\"\n [style.text-align]=\"column.align\"\n [style.width]=\"column.width\"\n [attr.style]=\"column.style\"\n [ngClass]=\"getCellClasses(row, column)\"\n [ngStyle]=\"getCellNgStyle(row, column)\">\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 <mat-icon *ngIf=\"getBadgeIcon(row, column) as bi\" 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 </td>\n\n <!-- Actions column -->\n <td class=\"mat-mdc-cell praxis-actions-cell\" *ngIf=\"config.actions?.row?.enabled\" [class.dense]=\"dense\" [style.width]=\"config.actions?.row?.width\">\n <div class=\"praxis-actions-cell__content\">\n <ng-container *ngIf=\"config.actions?.row?.display === 'icons' || !config.actions?.row?.display\">\n <ng-container *ngFor=\"let a of getInlineRowActions(row); trackBy: trackAction\">\n <button mat-icon-button class=\"praxis-icon-btn\"\n [disabled]=\"isActionDisabled(a, row)\"\n (click)=\"onRowAction(getActionId(a), row, $event)\"\n [matTooltip]=\"a.label || getActionId(a)\"\n matTooltipPosition=\"above\"\n matTooltipClass=\"praxis-tooltip\"\n [attr.aria-label]=\"a.label || getActionId(a)\"\n [color]=\"a.color || null\">\n <mat-icon [praxisIcon]=\"a.icon\"></mat-icon>\n </button>\n </ng-container>\n </ng-container>\n <ng-container *ngIf=\"config.actions?.row?.display === 'buttons'\">\n <ng-container *ngFor=\"let a of getInlineRowActions(row); trackBy: trackAction\">\n <button mat-flat-button class=\"praxis-row-btn\"\n [disabled]=\"isActionDisabled(a, row)\"\n (click)=\"onRowAction(getActionId(a), row, $event)\"\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 </ng-container>\n </ng-container>\n <button mat-icon-button class=\"praxis-icon-btn praxis-more-btn\"\n *ngIf=\"hasOverflowRowActions(row)\"\n [matMenuTriggerFor]=\"rowMoreMenuV\"\n [color]=\"getRowMenuButtonColor() || null\"\n aria-label=\"Mais a\u00E7\u00F5es\">\n <mat-icon [praxisIcon]=\"getRowMenuIcon()\"></mat-icon>\n </button>\n <mat-menu #rowMoreMenuV=\"matMenu\" xPosition=\"before\">\n <ng-container *ngFor=\"let a of getOverflowRowActions(row); trackBy: trackAction\">\n <button mat-menu-item (click)=\"onRowAction(getActionId(a), row, $event)\" [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 </mat-menu>\n </div>\n </td>\n </tr>\n </tbody>\n </table>\n </cdk-virtual-scroll-viewport>\n</ng-container>\n\n</div>\n<!-- Paginadores (top/bottom) -->\n<mat-paginator\n *ngIf=\"resourcePath && !schemaError && !dataError && getPaginationEnabled() && (config.behavior?.pagination?.position === 'top' || config.behavior?.pagination?.position === 'both')\"\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<mat-paginator\n *ngIf=\"resourcePath && !schemaError && !dataError && getPaginationEnabled() && (config.behavior?.pagination?.position === 'bottom' || config.behavior?.pagination?.position === 'both' || !config.behavior?.pagination?.position)\"\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", styles: ["@charset \"UTF-8\";table{width:100%}.praxis-actions-cell{height:100%;padding-inline:12px;white-space:nowrap}:host.density-compact{--p-header-padding: 8px 12px;--p-actions-btn-size: 32px;--p-actions-icon-size: 18px}:host.density-comfortable{--p-header-padding: 12px 16px;--p-actions-btn-size: 40px;--p-actions-icon-size: 22px}:host.density-spacious{--p-header-padding: 16px 20px;--p-actions-btn-size: 44px;--p-actions-icon-size: 24px}:host.density-compact ::ng-deep .mat-mdc-cell{padding:8px 12px}:host.density-comfortable ::ng-deep .mat-mdc-cell{padding:12px 16px}:host.density-spacious ::ng-deep .mat-mdc-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%}.praxis-actions-cell.dense .praxis-actions-cell__content{gap:6px}.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, rgba(255, 255, 255, .06))}.praxis-icon-btn:focus-visible{outline:2px solid var(--primary, #48a1ff);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-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-icon-btn.destructive mat-icon{color:#ff6b6b}.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.debug-layout,:host.debug-layout .praxis-table-header{outline:2px dashed #ff4d4f;border-radius:8px}:host.debug-layout ::ng-deep .praxis-filter-bar{outline:1px dashed #f59e0b}:host.debug-layout ::ng-deep .quick-shell{outline:1px dashed #3b82f6}:host.debug-layout ::ng-deep .always-fields{outline:1px dashed #22c55e}:host.debug-layout ::ng-deep .praxis-filter-overlay .praxis-filter-advanced{outline:2px solid #a855f7}:host.debug-layout ::ng-deep .mat-mdc-table{outline:1px dashed #94a3b8}.praxis-table-header>praxis-table-toolbar{flex:1 0 100%}:host{--p-table-header-bg: var(--md-sys-color-surface-container-highest, #1d1d1f);--p-table-header-fg: var(--md-sys-color-on-surface, #e8f3f1);--p-table-border-color: var(--md-sys-color-outline-variant, rgba(255, 255, 255, .12));--p-table-row-even-bg: var(--md-sys-color-surface-container, rgba(255, 255, 255, .04));--p-table-row-hover-bg: color-mix(in srgb, var(--md-sys-color-primary, #3f51b5) 10%, transparent);--p-table-row-selected-bg: var(--md-sys-color-primary-container, rgba(63,81,181,.14));--p-table-badge-soft-primary-bg: color-mix(in srgb, var(--mat-sys-primary, var(--md-sys-color-primary)) 16%, transparent);--p-table-badge-soft-primary-fg: var(--mat-sys-primary, var(--md-sys-color-primary));--p-table-badge-soft-accent-bg: color-mix(in srgb, var(--mat-sys-secondary, var(--md-sys-color-secondary, #ff4081)) 14%, transparent);--p-table-badge-soft-accent-fg: var(--mat-sys-secondary, var(--md-sys-color-secondary, #ff4081));--p-table-badge-soft-warn-bg: color-mix(in srgb, var(--mat-sys-error, var(--md-sys-color-error, #f44336)) 14%, transparent);--p-table-badge-soft-warn-fg: var(--mat-sys-error, var(--md-sys-color-error, #f44336));--p-table-state-success-bg: color-mix(in srgb, var(--mat-sys-tertiary, var(--md-sys-color-tertiary, #388E3C)) 16%, transparent);--p-table-state-success-fg: var(--md-sys-color-on-surface, #c8e6c9);--p-table-state-warning-bg: color-mix(in srgb, var(--md-sys-color-secondary, #FFA000) 18%, transparent);--p-table-state-warning-fg: var(--md-sys-color-on-surface, #ffe0b2);--p-table-state-danger-bg: color-mix(in srgb, var(--md-sys-color-error, #e53935) 18%, transparent);--p-table-state-danger-fg: var(--md-sys-color-on-surface, #ffcdd2);--p-table-state-highlight-bg: color-mix(in srgb, var(--md-sys-color-primary, #2196f3) 16%, transparent);--p-table-state-highlight-fg: var(--md-sys-color-on-surface, #bbdefb)}:host ::ng-deep .mat-mdc-table{background:var(--md-sys-color-surface-container-highest, #1d1d1f);border-radius:12px;width:100%}:host [data-role=table-settings].mat-mdc-icon-button{--mdc-icon-button-icon-color: var(--mat-sys-primary, var(--md-sys-color-primary, #3f51b5));color:var(--mat-sys-primary, var(--md-sys-color-primary, #3f51b5))}.pfx-link{color:var(--mat-sys-primary, #3f51b5);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(--mat-sys-outline-variant);color:var(--mat-sys-on-surface)}.pfx-chip--filled-primary{background:var(--mat-sys-primary);color:var(--mat-sys-on-primary)}.pfx-chip--filled-accent{background:var(--mat-sys-secondary, #ff4081);color:#fff}.pfx-chip--filled-warn{background:var(--mat-sys-error, #f44336);color:#fff}.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(--mat-sys-surface-container-highest, rgba(255, 255, 255, .08));border-radius:4px;overflow:hidden;display:inline-block;vertical-align:middle}.pfx-progress-bar{height:100%;background:var(--mat-sys-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(--mat-sys-surface-container, #2a2a2e);color:var(--mat-sys-on-surface, #eee);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;scrollbar-gutter:stable}.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:1;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}.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 .mat-mdc-cell{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}:host ::ng-deep .mat-mdc-row:hover{background:var(--p-table-row-hover-bg)}:host ::ng-deep .mat-mdc-row:nth-child(2n){background:var(--p-table-row-even-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-info-banner{display:flex;gap:12px;align-items:center;padding:8px 12px;margin:8px 0;border-radius:8px;border:1px solid var(--mat-sys-primary, var(--md-sys-color-primary, #1a73e8));background:color-mix(in srgb,var(--mat-sys-primary, var(--md-sys-color-primary, #1a73e8)) 10%,transparent)}.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, #2a2a2a);border:1px solid var(--md-sys-color-outline-variant, rgba(0, 0, 0, .08))}.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(--mat-sys-primary, #3f51b5);color:var(--mat-sys-on-primary, #fff)}.pfx-badge--filled-accent{background:var(--mat-sys-secondary, #ff4081);color:var(--mat-sys-on-secondary, #fff)}.pfx-badge--filled-warn{background:var(--mat-sys-error, #f44336);color:var(--mat-sys-on-error, #fff)}.pfx-badge--outlined{background:transparent;border-color:var(--mat-sys-outline-variant, rgba(255, 255, 255, .24));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"] }]
|
|
24290
|
+
}, template: "<praxis-empty-state-card\n *ngIf=\"!resourcePath\"\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<!-- Error State with Quick Connect CTA -->\n<div class=\"ptable-error\" *ngIf=\"resourcePath && (schemaError || dataError)\" style=\"display:flex; align-items:center; gap:12px; padding:12px; border:1px solid var(--md-sys-color-error, #b00020); border-radius:8px; margin: 8px 0;\">\n <mat-icon color=\"warn\" aria-hidden=\"true\">error</mat-icon>\n <div style=\"flex:1\">\n <div style=\"font-weight:600\">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 <button mat-stroked-button (click)=\"retryData()\" *ngIf=\"!schemaError\">Tentar novamente</button>\n <button mat-stroked-button (click)=\"reloadSchema()\" *ngIf=\"schemaError\">Recarregar colunas</button>\n </div>\n\n<!-- Inline banner for schema change (only in edit mode) -->\n<div *ngIf=\"shouldShowOutdatedInline()\" 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 <ng-container *ngIf=\"resourcePath && !schemaError && !dataError && toolbarV2; else legacyHeader\">\n <div class=\"praxis-table-header\" [class.debug-layout]=\"debugLayout\" [class.edit-mode]=\"editModeEnabled\" *ngIf=\"showToolbar || editModeEnabled\">\n <praxis-table-toolbar\n *ngIf=\"showToolbar\"\n [config]=\"config\"\n [debugLayout]=\"debugLayout\"\n (toolbarAction)=\"onToolbarAction($event)\"\n (reset)=\"onResetPreferences()\"\n >\n <praxis-filter\n *ngIf=\"\n resourcePath &&\n config.behavior?.filtering?.advancedFilters?.enabled &&\n !projectedFilter\n \"\n advancedFilter\n [resourcePath]=\"resourcePath\"\n [formId]=\"tableId + '-filter'\"\n [editModeEnabled]=\"editModeEnabled\"\n [quickField]=\"\n config.behavior?.filtering?.advancedFilters?.settings?.quickField\n \"\n [alwaysVisibleFields]=\"\n config.behavior?.filtering?.advancedFilters?.settings\n ?.alwaysVisibleFields\n \"\n [allowSaveTags]=\"\n config.behavior?.filtering?.advancedFilters?.settings\n ?.allowSaveTags\n \"\n [changeDebounceMs]=\"\n config.behavior?.filtering?.advancedFilters?.settings\n ?.changeDebounceMs ?? 300\n \"\n [i18n]=\"getFilterI18n()\"\n [mode]=\"\n config.behavior?.filtering?.advancedFilters?.settings?.mode ??\n 'auto'\n \"\n [debugLayout]=\"debugLayout\"\n [showFilterSettings]=\"editModeEnabled\"\n (submit)=\"onAdvancedFilterSubmit($event)\"\n (clear)=\"onAdvancedFilterClear()\"\n ></praxis-filter>\n <ng-content select=\"[advancedFilter]\" />\n <ng-content select=\"[toolbar]\" />\n <button end-actions mat-icon-button color=\"primary\" data-role=\"table-settings\" *ngIf=\"editModeEnabled\"\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 </praxis-table-toolbar>\n <!-- Render a minimal settings button when toolbar is hidden but edit mode is enabled -->\n <div class=\"ptable-header-actions\" *ngIf=\"!showToolbar && editModeEnabled\">\n <button mat-icon-button color=\"primary\" (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 <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 </div>\n \n </div>\n</ng-container>\n<ng-template #legacyHeader>\n <ng-container *ngIf=\"resourcePath && !schemaError && !dataError\">\n <praxis-table-toolbar\n *ngIf=\"showToolbar\"\n [config]=\"config\"\n [debugLayout]=\"debugLayout\"\n (toolbarAction)=\"onToolbarAction($event)\"\n (reset)=\"onResetPreferences()\"\n >\n <praxis-filter\n *ngIf=\"\n resourcePath &&\n config.behavior?.filtering?.advancedFilters?.enabled &&\n !projectedFilter\n \"\n advancedFilter\n [resourcePath]=\"resourcePath\"\n [formId]=\"tableId + '-filter'\"\n [editModeEnabled]=\"editModeEnabled\"\n [quickField]=\"\n config.behavior?.filtering?.advancedFilters?.settings?.quickField\n \"\n [alwaysVisibleFields]=\"\n config.behavior?.filtering?.advancedFilters?.settings\n ?.alwaysVisibleFields\n \"\n [allowSaveTags]=\"\n config.behavior?.filtering?.advancedFilters?.settings?.allowSaveTags\n \"\n [changeDebounceMs]=\"\n config.behavior?.filtering?.advancedFilters?.settings\n ?.changeDebounceMs ?? 300\n \"\n [i18n]=\"getFilterI18n()\"\n [mode]=\"\n config.behavior?.filtering?.advancedFilters?.settings?.mode ??\n 'auto'\n \"\n [debugLayout]=\"debugLayout\"\n [showFilterSettings]=\"editModeEnabled\"\n (submit)=\"onAdvancedFilterSubmit($event)\"\n (clear)=\"onAdvancedFilterClear()\"\n ></praxis-filter>\n <ng-content select=\"[advancedFilter]\" />\n <ng-content select=\"[toolbar]\" />\n <button end-actions mat-icon-button color=\"primary\" *ngIf=\"editModeEnabled\"\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 </praxis-table-toolbar>\n <!-- Legacy header: settings button when toolbar hidden -->\n <div class=\"ptable-header-actions\" *ngIf=\"!showToolbar && editModeEnabled\">\n <button mat-icon-button color=\"primary\" data-role=\"table-settings\" (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 </ng-container>\n \n</ng-template>\n<div class=\"px-scroll-viewport\"\n [class.scroll-auto]=\"horizontalScroll === 'auto'\"\n [class.scroll-wrap]=\"horizontalScroll === 'wrap'\"\n [class.scroll-none]=\"horizontalScroll === 'none'\">\n\n<table\n *ngIf=\"resourcePath && !schemaError && !dataError\"\n mat-table\n [dataSource]=\"dataSource\"\n matSort\n (matSortChange)=\"onSortChange($event)\"\n [matSortDisabled]=\"!getSortingEnabled()\"\n class=\"mat-elevation-z8\"\n>\n <ng-container\n *ngIf=\"config.behavior?.selection?.enabled\"\n matColumnDef=\"_select\"\n >\n <th mat-header-cell *matHeaderCellDef>\n <mat-checkbox\n (change)=\"masterToggle()\"\n [checked]=\"isAllSelected()\"\n [indeterminate]=\"selection.hasValue() && !isAllSelected()\"\n ></mat-checkbox>\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 <ng-container\n *ngFor=\"let column of visibleColumns\"\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 [disabled]=\"!getSortingEnabled() || column.sortable === false\"\n [style.text-align]=\"column.align\"\n [style.width]=\"column.width\"\n [attr.style]=\"column.headerStyle\"\n >\n {{ column.header }}\n </th>\n <td\n mat-cell\n *matCellDef=\"let element\"\n [style.text-align]=\"column.align\"\n [style.width]=\"column.width\"\n [attr.style]=\"column.style\"\n [ngClass]=\"getCellClasses(element, column)\"\n [ngStyle]=\"getCellNgStyle(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 <mat-icon *ngIf=\"getBadgeIcon(element, column) as bi\" 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 <mat-icon *ngIf=\"getButtonIcon(element, column) as bi\">{{ 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 <mat-icon *ngIf=\"getButtonIcon(element, column) as bi\">{{ 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 <mat-icon *ngIf=\"getButtonIcon(element, column) as bi\">{{ 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 <mat-icon *ngIf=\"getChipIcon(element, column) as ci\" 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.%]=\"getProgressValue(element, column)\" [style.background]=\"getProgressColor(element, column) || null\"></div>\n <div class=\"pfx-progress-label\" *ngIf=\"getProgressShowLabel(element, column)\">{{ getProgressValue(element, column) }}%</div>\n </div>\n </ng-container>\n\n <!-- Avatar renderer -->\n <ng-container *ngSwitchCase=\"'avatar'\">\n <ng-container *ngIf=\"getAvatarSrc(element, column) as asrc; else initials\">\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 </ng-container>\n <ng-template #initials>\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 </ng-template>\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.id, element, $event)\" [disabled]=\"!it.__visible\" >\n <mat-icon *ngIf=\"it.icon\">{{ it.icon }}</mat-icon>\n <span>{{ it.label }}</span>\n </button>\n </mat-menu>\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))\"><mat-icon *ngIf=\"getBadgeIcon(element, asItemColumn(column, it)) as bi\" 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)\"><mat-icon *ngIf=\"getButtonIcon(element, asItemColumn(column, it)) as bi\">{{ 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)\"><mat-icon *ngIf=\"getButtonIcon(element, asItemColumn(column, it)) as bi\">{{ 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)\"><mat-icon *ngIf=\"getButtonIcon(element, asItemColumn(column, it)) as bi\">{{ 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))\"><mat-icon *ngIf=\"getChipIcon(element, asItemColumn(column, it)) as ci\" 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.%]=\"getProgressValue(element, asItemColumn(column, it))\" [style.background]=\"getProgressColor(element, asItemColumn(column, it)) || null\"></div><div class=\"pfx-progress-label\" *ngIf=\"getProgressShowLabel(element, asItemColumn(column, it))\">{{ getProgressValue(element, asItemColumn(column, it)) }}%</div></div>\n </ng-container>\n <ng-container *ngSwitchCase=\"'avatar'\">\n <ng-container *ngIf=\"getAvatarSrc(element, asItemColumn(column, it)) as asrc; else initials_comp\">\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 </ng-container>\n <ng-template #initials_comp>\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 </ng-template>\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.id, element, $event)\" [disabled]=\"!mi.__visible\"><mat-icon *ngIf=\"mi.icon\">{{ mi.icon }}</mat-icon><span>{{ mi.label }}</span></button>\n </mat-menu>\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\">{{ getCellValue(element, column) }}</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 </td>\n </ng-container>\n <ng-container *ngIf=\"config.actions?.row?.enabled\" 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]=\"config.actions?.row?.width\" 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 <mat-icon *ngIf=\"getActionsHeaderIcon() as hi\" [praxisIcon]=\"hi\"></mat-icon>\n <span class=\"label\" *ngIf=\"getActionsHeaderLabel() as hl\">{{ 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]=\"config.actions?.row?.width\"\n >\n <div class=\"praxis-actions-cell__content\">\n <!-- A\u00E7\u00F5es inline -->\n <!-- Inline actions: icons mode -->\n <ng-container *ngIf=\"config.actions?.row?.display === 'icons' || !config.actions?.row?.display\">\n <ng-container *ngFor=\"let a of getInlineRowActions(row); trackBy: trackAction\">\n <button\n mat-icon-button\n class=\"praxis-icon-btn\"\n [disabled]=\"isActionDisabled(a, row)\"\n (click)=\"onRowAction(getActionId(a), row, $event)\"\n [matTooltip]=\"a.label || getActionId(a)\"\n matTooltipPosition=\"above\"\n matTooltipClass=\"praxis-tooltip\"\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 </ng-container>\n </ng-container>\n\n <!-- Inline actions: buttons mode (show label + icon) -->\n <ng-container *ngIf=\"config.actions?.row?.display === 'buttons'\">\n <ng-container *ngFor=\"let a of getInlineRowActions(row); trackBy: trackAction\">\n <button\n mat-flat-button\n class=\"praxis-row-btn\"\n [disabled]=\"isActionDisabled(a, row)\"\n (click)=\"onRowAction(getActionId(a), row, $event)\"\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 </ng-container>\n </ng-container>\n\n <!-- Menu de overflow -->\n <button\n mat-icon-button\n class=\"praxis-icon-btn praxis-more-btn\"\n *ngIf=\"hasOverflowRowActions(row)\"\n [matMenuTriggerFor]=\"rowMoreMenu\"\n [color]=\"getRowMenuButtonColor() || null\"\n aria-label=\"Mais a\u00E7\u00F5es\"\n >\n <mat-icon [praxisIcon]=\"getRowMenuIcon()\"></mat-icon>\n </button>\n <mat-menu #rowMoreMenu=\"matMenu\" xPosition=\"before\">\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)\"\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 </mat-menu>\n </div>\n </td>\n </ng-container>\n\n <tr mat-header-row *matHeaderRowDef=\"displayedColumns\"></tr>\n <ng-container *ngIf=\"!isVirtualized()\">\n <tr\n mat-row\n *matRowDef=\"let row; let i = index; columns: displayedColumns\"\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)\"\n (dblclick)=\"onRowDoubleClicked(row, i)\"\n ></tr>\n </ng-container>\n</table>\n\n<!-- Virtual rows path (header preserved above) -->\n<ng-container *ngIf=\"resourcePath && !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]=\"getVirtMinHeightStyle()\"\n >\n <table class=\"mat-mdc-table mat-elevation-z8\" [style.width]=\"horizontalScroll === 'auto' ? 'max-content' : '100%'\">\n <tbody>\n <tr class=\"mat-mdc-row\"\n *cdkVirtualFor=\"let row of dataSource.data; let i = index; trackBy: trackByRow\"\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)\"\n (dblclick)=\"onRowDoubleClicked(row, i)\">\n <!-- Selection column -->\n <td class=\"mat-mdc-cell\" *ngIf=\"config.behavior?.selection?.enabled\">\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 <td class=\"mat-mdc-cell\"\n *ngFor=\"let column of visibleColumns\"\n [style.text-align]=\"column.align\"\n [style.width]=\"column.width\"\n [attr.style]=\"column.style\"\n [ngClass]=\"getCellClasses(row, column)\"\n [ngStyle]=\"getCellNgStyle(row, column)\">\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 <mat-icon *ngIf=\"getBadgeIcon(row, column) as bi\" 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 </td>\n\n <!-- Actions column -->\n <td class=\"mat-mdc-cell praxis-actions-cell\" *ngIf=\"config.actions?.row?.enabled\" [class.dense]=\"dense\" [style.width]=\"config.actions?.row?.width\">\n <div class=\"praxis-actions-cell__content\">\n <ng-container *ngIf=\"config.actions?.row?.display === 'icons' || !config.actions?.row?.display\">\n <ng-container *ngFor=\"let a of getInlineRowActions(row); trackBy: trackAction\">\n <button mat-icon-button class=\"praxis-icon-btn\"\n [disabled]=\"isActionDisabled(a, row)\"\n (click)=\"onRowAction(getActionId(a), row, $event)\"\n [matTooltip]=\"a.label || getActionId(a)\"\n matTooltipPosition=\"above\"\n matTooltipClass=\"praxis-tooltip\"\n [attr.aria-label]=\"a.label || getActionId(a)\"\n [color]=\"a.color || null\">\n <mat-icon [praxisIcon]=\"a.icon\"></mat-icon>\n </button>\n </ng-container>\n </ng-container>\n <ng-container *ngIf=\"config.actions?.row?.display === 'buttons'\">\n <ng-container *ngFor=\"let a of getInlineRowActions(row); trackBy: trackAction\">\n <button mat-flat-button class=\"praxis-row-btn\"\n [disabled]=\"isActionDisabled(a, row)\"\n (click)=\"onRowAction(getActionId(a), row, $event)\"\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 </ng-container>\n </ng-container>\n <button mat-icon-button class=\"praxis-icon-btn praxis-more-btn\"\n *ngIf=\"hasOverflowRowActions(row)\"\n [matMenuTriggerFor]=\"rowMoreMenuV\"\n [color]=\"getRowMenuButtonColor() || null\"\n aria-label=\"Mais a\u00E7\u00F5es\">\n <mat-icon [praxisIcon]=\"getRowMenuIcon()\"></mat-icon>\n </button>\n <mat-menu #rowMoreMenuV=\"matMenu\" xPosition=\"before\">\n <ng-container *ngFor=\"let a of getOverflowRowActions(row); trackBy: trackAction\">\n <button mat-menu-item (click)=\"onRowAction(getActionId(a), row, $event)\" [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 </mat-menu>\n </div>\n </td>\n </tr>\n </tbody>\n </table>\n </cdk-virtual-scroll-viewport>\n</ng-container>\n\n</div>\n<!-- Paginadores (top/bottom) -->\n<mat-paginator\n *ngIf=\"resourcePath && !schemaError && !dataError && getPaginationEnabled() && (config.behavior?.pagination?.position === 'top' || config.behavior?.pagination?.position === 'both')\"\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<mat-paginator\n *ngIf=\"resourcePath && !schemaError && !dataError && getPaginationEnabled() && (config.behavior?.pagination?.position === 'bottom' || config.behavior?.pagination?.position === 'both' || !config.behavior?.pagination?.position)\"\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", styles: ["@charset \"UTF-8\";table{width:100%}.praxis-actions-cell{height:100%;padding-inline:12px;white-space:nowrap}:host.density-compact{--p-header-padding: 8px 12px;--p-actions-btn-size: 32px;--p-actions-icon-size: 18px}:host.density-comfortable{--p-header-padding: 12px 16px;--p-actions-btn-size: 40px;--p-actions-icon-size: 22px}:host.density-spacious{--p-header-padding: 16px 20px;--p-actions-btn-size: 44px;--p-actions-icon-size: 24px}:host.density-compact ::ng-deep .mat-mdc-cell{padding:8px 12px}:host.density-comfortable ::ng-deep .mat-mdc-cell{padding:12px 16px}:host.density-spacious ::ng-deep .mat-mdc-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%}.praxis-actions-cell.dense .praxis-actions-cell__content{gap:6px}.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, rgba(255, 255, 255, .06))}.praxis-icon-btn:focus-visible{outline:2px solid var(--primary, #48a1ff);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-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-icon-btn.destructive mat-icon{color:#ff6b6b}.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.debug-layout,:host.debug-layout .praxis-table-header{outline:2px dashed #ff4d4f;border-radius:8px}:host.debug-layout ::ng-deep .praxis-filter-bar{outline:1px dashed #f59e0b}:host.debug-layout ::ng-deep .quick-shell{outline:1px dashed #3b82f6}:host.debug-layout ::ng-deep .always-fields{outline:1px dashed #22c55e}:host.debug-layout ::ng-deep .praxis-filter-overlay .praxis-filter-advanced{outline:2px solid #a855f7}:host.debug-layout ::ng-deep .mat-mdc-table{outline:1px dashed #94a3b8}.praxis-table-header>praxis-table-toolbar{flex:1 0 100%}:host{--p-table-header-bg: var(--md-sys-color-surface-container-highest, #1d1d1f);--p-table-header-fg: var(--md-sys-color-on-surface, #e8f3f1);--p-table-border-color: var(--md-sys-color-outline-variant, rgba(255, 255, 255, .12));--p-table-row-even-bg: var(--md-sys-color-surface-container, rgba(255, 255, 255, .04));--p-table-row-hover-bg: color-mix(in srgb, var(--md-sys-color-primary, #3f51b5) 10%, transparent);--p-table-row-selected-bg: var(--md-sys-color-primary-container, rgba(63,81,181,.14));--p-table-badge-soft-primary-bg: color-mix(in srgb, var(--mat-sys-primary, var(--md-sys-color-primary)) 16%, transparent);--p-table-badge-soft-primary-fg: var(--mat-sys-primary, var(--md-sys-color-primary));--p-table-badge-soft-accent-bg: color-mix(in srgb, var(--mat-sys-secondary, var(--md-sys-color-secondary, #ff4081)) 14%, transparent);--p-table-badge-soft-accent-fg: var(--mat-sys-secondary, var(--md-sys-color-secondary, #ff4081));--p-table-badge-soft-warn-bg: color-mix(in srgb, var(--mat-sys-error, var(--md-sys-color-error, #f44336)) 14%, transparent);--p-table-badge-soft-warn-fg: var(--mat-sys-error, var(--md-sys-color-error, #f44336));--p-table-state-success-bg: color-mix(in srgb, var(--mat-sys-tertiary, var(--md-sys-color-tertiary, #388E3C)) 16%, transparent);--p-table-state-success-fg: var(--md-sys-color-on-surface, #c8e6c9);--p-table-state-warning-bg: color-mix(in srgb, var(--md-sys-color-secondary, #FFA000) 18%, transparent);--p-table-state-warning-fg: var(--md-sys-color-on-surface, #ffe0b2);--p-table-state-danger-bg: color-mix(in srgb, var(--md-sys-color-error, #e53935) 18%, transparent);--p-table-state-danger-fg: var(--md-sys-color-on-surface, #ffcdd2);--p-table-state-highlight-bg: color-mix(in srgb, var(--md-sys-color-primary, #2196f3) 16%, transparent);--p-table-state-highlight-fg: var(--md-sys-color-on-surface, #bbdefb)}:host ::ng-deep .mat-mdc-table{background:var(--md-sys-color-surface-container-highest, #1d1d1f);border-radius:12px;width:100%}:host [data-role=table-settings].mat-mdc-icon-button{--mdc-icon-button-icon-color: var(--mat-sys-primary, var(--md-sys-color-primary, #3f51b5));color:var(--mat-sys-primary, var(--md-sys-color-primary, #3f51b5))}.pfx-link{color:var(--mat-sys-primary, #3f51b5);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(--mat-sys-outline-variant);color:var(--mat-sys-on-surface)}.pfx-chip--filled-primary{background:var(--mat-sys-primary);color:var(--mat-sys-on-primary)}.pfx-chip--filled-accent{background:var(--mat-sys-secondary, #ff4081);color:#fff}.pfx-chip--filled-warn{background:var(--mat-sys-error, #f44336);color:#fff}.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(--mat-sys-surface-container-highest, rgba(255, 255, 255, .08));border-radius:4px;overflow:hidden;display:inline-block;vertical-align:middle}.pfx-progress-bar{height:100%;background:var(--mat-sys-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(--mat-sys-surface-container, #2a2a2e);color:var(--mat-sys-on-surface, #eee);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;scrollbar-gutter:stable}.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:1;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}.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 .mat-mdc-cell{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}:host ::ng-deep .mat-mdc-row:hover{background:var(--p-table-row-hover-bg)}: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.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-info-banner{display:flex;gap:12px;align-items:center;padding:8px 12px;margin:8px 0;border-radius:8px;border:1px solid var(--mat-sys-primary, var(--md-sys-color-primary, #1a73e8));background:color-mix(in srgb,var(--mat-sys-primary, var(--md-sys-color-primary, #1a73e8)) 10%,transparent)}.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, #2a2a2a);border:1px solid var(--md-sys-color-outline-variant, rgba(0, 0, 0, .08))}.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(--mat-sys-primary, #3f51b5);color:var(--mat-sys-on-primary, #fff)}.pfx-badge--filled-accent{background:var(--mat-sys-secondary, #ff4081);color:var(--mat-sys-on-secondary, #fff)}.pfx-badge--filled-warn{background:var(--mat-sys-error, #f44336);color:var(--mat-sys-on-error, #fff)}.pfx-badge--outlined{background:transparent;border-color:var(--mat-sys-outline-variant, rgba(255, 255, 255, .24));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"] }]
|
|
24097
24291
|
}], ctorParameters: () => [{ type: i1$3.GenericCrudService }, { type: i0.ChangeDetectorRef }, { type: i3$2.SettingsPanelService }, { type: DataFormattingService }, { type: undefined, decorators: [{
|
|
24098
24292
|
type: Inject,
|
|
24099
24293
|
args: [CONFIG_STORAGE]
|