@praxisui/table 10.0.0-rc.30 → 10.0.0-rc.32
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/ai/component-registry.json +2 -2
- package/fesm2022/praxisui-table-authoring.mjs +7 -1
- package/fesm2022/{praxisui-table-praxisui-table-Dg1mPimH.mjs → praxisui-table-praxisui-table-CWOg6JDN.mjs} +249 -37
- package/fesm2022/{praxisui-table-table-agentic-authoring-turn-flow-B2nHomHJ.mjs → praxisui-table-table-agentic-authoring-turn-flow-EvaZNCNd.mjs} +1 -1
- package/fesm2022/{praxisui-table-table-ai.adapter-D0gEqzlb.mjs → praxisui-table-table-ai.adapter-DqlbvUHe.mjs} +1 -1
- package/fesm2022/praxisui-table.mjs +1 -1
- package/package.json +10 -10
- package/types/praxisui-table.d.ts +19 -6
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": "1.0.0",
|
|
3
|
-
"generatedAt": "2026-10-
|
|
3
|
+
"generatedAt": "2026-10-17T14:44:09.509Z",
|
|
4
4
|
"packageName": "@praxisui/table",
|
|
5
|
-
"packageVersion": "10.0.0-rc.
|
|
5
|
+
"packageVersion": "10.0.0-rc.32",
|
|
6
6
|
"sourceRegistry": "praxis-component-registry-ingestion",
|
|
7
7
|
"sourceRegistryVersion": "1.0.0",
|
|
8
8
|
"componentCount": 3,
|
|
@@ -423,7 +423,13 @@ function toTableDetailCardGridContentNode(node) {
|
|
|
423
423
|
return node;
|
|
424
424
|
const type = String(node?.['type'] || '').trim();
|
|
425
425
|
if (type === 'cardGrid') {
|
|
426
|
-
const
|
|
426
|
+
const firstCard = Array.isArray(node['cards']) ? node['cards'][0] : undefined;
|
|
427
|
+
const firstList = Array.isArray(firstCard?.content)
|
|
428
|
+
? firstCard.content
|
|
429
|
+
: Array.isArray(firstCard?.items)
|
|
430
|
+
? firstCard.items
|
|
431
|
+
: undefined;
|
|
432
|
+
const first = firstList?.[0];
|
|
427
433
|
return first ? toTableDetailCardGridContentNode(structuredClone(first)) : null;
|
|
428
434
|
}
|
|
429
435
|
if (type !== 'value')
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
2
|
import { input, inject, computed, ChangeDetectionStrategy, Component, output, signal, InjectionToken, EventEmitter, ElementRef, Output, Input, ViewChild, Optional, Inject, LOCALE_ID, Injectable, Injector, HostListener, Directive, ChangeDetectorRef, DestroyRef, ENVIRONMENT_INITIALIZER, effect, booleanAttribute, HostBinding, ContentChild, TemplateRef, ViewContainerRef, numberAttribute } from '@angular/core';
|
|
3
3
|
import * as i1 from '@praxisui/core';
|
|
4
|
-
import { PraxisI18nService, BulkOperationClientService, isBulkExecutionTerminal, LoggerService, createCorporateLoggerConfig, ConsoleLoggerSink, PraxisJsonLogicService, resolveResourceAvailabilityReasonKey, RESOURCE_DISCOVERY_I18N_CONFIG, RESOURCE_DISCOVERY_I18N_NAMESPACE, PraxisIconDirective, PraxisIconButtonComponent, SafeExpressionEvaluator, API_URL, EnterpriseRuntimeContextService, buildApiUrl, ResourceDiscoveryService, renderPraxisPresentationVisualizationHtml, createDefaultTableConfig,
|
|
4
|
+
import { PraxisI18nService, BulkOperationClientService, isBulkExecutionTerminal, LoggerService, createCorporateLoggerConfig, ConsoleLoggerSink, PraxisJsonLogicService, resolveResourceAvailabilityReasonKey, RESOURCE_DISCOVERY_I18N_CONFIG, RESOURCE_DISCOVERY_I18N_NAMESPACE, PraxisIconDirective, PraxisIconButtonComponent, SafeExpressionEvaluator, API_URL, EnterpriseRuntimeContextService, buildApiUrl, ResourceDiscoveryService, renderPraxisPresentationVisualizationHtml, createDefaultTableConfig, deepMerge as deepMerge$1, ASYNC_CONFIG_STORAGE, providePraxisI18nConfig, INLINE_FILTER_CONTROL_TYPES, INLINE_FILTER_CONTROL_TYPE_VALUES, FieldControlType, normalizeControlTypeToken, resolveControlTypeAlias, INLINE_FILTER_ALIAS_TOKENS, SCHEMA_METADATA_CLIENT_OPTIONS, GlobalConfigService, buildSchemaId, MemoryCacheAdapter, LocalStorageCacheAdapter, SchemaMetadataClient, mapFieldDefinitionsToMetadata, resolveInlineFilterControlType, fetchWithETag, serializeEntityLookupValueForPayload, GenericCrudService, SchemaNormalizerService, ResourceQuickConnectComponent, ComponentMetadataRegistry, AnalyticsStatsRequestBuilderService, normalizePraxisDataQueryContext, normalizeUnknownError, PraxisRuntimeComponentObservationRegistryService, PRAXIS_TABLE_DETAIL_INLINE_RENDERERS, BulkSyncStateService, PRAXIS_TABLE_DETAIL_INLINE_NODE_RESOLVERS, PRAXIS_TABLE_DETAIL_RESOURCE_RESOLVER, PraxisWidgetEventBus, PraxisCollectionExportService, fillUndefined, translateResourceAvailabilityReason, ResourceSurfaceOpenAdapterService, ResourceActionOpenAdapterService, CrudOperationResolutionService, SURFACE_OPEN_PRESETS, SURFACE_DRAWER_REF, assertPraxisCollectionExportArtifact, PRAXIS_LOADING_CTX, resolveColumnTypeFromFieldDefinition as resolveColumnTypeFromFieldDefinition$1, isPraxisPresentationVisualizationTableSafe as isPraxisPresentationVisualizationTableSafe$1, resolveTextMaskFormatFromFieldDefinition as resolveTextMaskFormatFromFieldDefinition$1, translateResourceDiscoveryText, supportsImplicitValuePresentation, resolveValuePresentation, resolvePraxisMicroVisualizationTone, resolveResourceIdentityContract, materializeResourceIdentity, translateUnavailableWorkflowMessage, CONNECTION_STORAGE, PRAXIS_LOADING_RENDERER, EmptyStateCardComponent, getPraxisTableCellVisualizationGuidance, getPraxisTableCellVisualizationConstraint, isTableConfigV2, normalizePraxisPresentationVisualization, PRAXIS_GLOBAL_ACTION_CATALOG, SURFACE_OPEN_I18N_NAMESPACE, isRequiredGlobalActionPayloadMissing, getGlobalActionUiSchema, getRequiredGlobalActionPayloadKeys, hasMeaningfulGlobalActionPayloadValue, SurfaceOpenActionEditorComponent, SURFACE_OPEN_I18N_CONFIG, PraxisJsonLogicError, GLOBAL_ACTION_CATALOG, validateGlobalActionRefs, getGlobalActionCatalog, TableConfigService } from '@praxisui/core';
|
|
5
5
|
import * as i1$3 from '@angular/common/http';
|
|
6
6
|
import { HttpErrorResponse, HttpClient, HttpContext } from '@angular/common/http';
|
|
7
7
|
import * as i3 from '@angular/material/button';
|
|
@@ -7649,6 +7649,7 @@ class TableDefaultsProvider {
|
|
|
7649
7649
|
}
|
|
7650
7650
|
/**
|
|
7651
7651
|
* Returns default configuration for a given table identifier.
|
|
7652
|
+
* Precedence inside defaults: GlobalConfig.table > createDefaultTableConfig().
|
|
7652
7653
|
* @param tableId Table identifier
|
|
7653
7654
|
*/
|
|
7654
7655
|
getDefaults(_tableId) {
|
|
@@ -7664,11 +7665,17 @@ class TableDefaultsProvider {
|
|
|
7664
7665
|
const g = this.global.getTable();
|
|
7665
7666
|
if (!g)
|
|
7666
7667
|
return base;
|
|
7667
|
-
|
|
7668
|
-
|
|
7669
|
-
|
|
7670
|
-
|
|
7671
|
-
merged.
|
|
7668
|
+
const merged = deepMerge$1(base, g);
|
|
7669
|
+
if (g.filteringUi) {
|
|
7670
|
+
merged.behavior = merged.behavior || {};
|
|
7671
|
+
merged.behavior.filtering = merged.behavior.filtering || {};
|
|
7672
|
+
merged.behavior.filtering.advancedFilters =
|
|
7673
|
+
merged.behavior.filtering.advancedFilters || { enabled: false };
|
|
7674
|
+
const currentSettings = (merged.behavior.filtering.advancedFilters.settings || {});
|
|
7675
|
+
merged.behavior.filtering.advancedFilters.settings = {
|
|
7676
|
+
...g.filteringUi,
|
|
7677
|
+
...currentSettings,
|
|
7678
|
+
};
|
|
7672
7679
|
}
|
|
7673
7680
|
return merged;
|
|
7674
7681
|
}
|
|
@@ -19981,7 +19988,13 @@ function toTableDetailCardGridContentNode(node) {
|
|
|
19981
19988
|
return node;
|
|
19982
19989
|
const type = String(node?.['type'] || '').trim();
|
|
19983
19990
|
if (type === 'cardGrid') {
|
|
19984
|
-
const
|
|
19991
|
+
const firstCard = Array.isArray(node['cards']) ? node['cards'][0] : undefined;
|
|
19992
|
+
const firstList = Array.isArray(firstCard?.content)
|
|
19993
|
+
? firstCard.content
|
|
19994
|
+
: Array.isArray(firstCard?.items)
|
|
19995
|
+
? firstCard.items
|
|
19996
|
+
: undefined;
|
|
19997
|
+
const first = firstList?.[0];
|
|
19985
19998
|
return first ? toTableDetailCardGridContentNode(structuredClone(first)) : null;
|
|
19986
19999
|
}
|
|
19987
20000
|
if (type !== 'value')
|
|
@@ -21035,7 +21048,10 @@ class PraxisTable {
|
|
|
21035
21048
|
'audit-warning': 'audit-review',
|
|
21036
21049
|
'sync-warning': 'sync-pending',
|
|
21037
21050
|
};
|
|
21038
|
-
|
|
21051
|
+
static ngAcceptInputType_config;
|
|
21052
|
+
config = { columns: [] };
|
|
21053
|
+
hostInputConfig;
|
|
21054
|
+
persistedUserConfig;
|
|
21039
21055
|
resourcePath;
|
|
21040
21056
|
data = null;
|
|
21041
21057
|
tableId;
|
|
@@ -21050,11 +21066,29 @@ class PraxisTable {
|
|
|
21050
21066
|
autoOpenSettingsOnOutdated = false;
|
|
21051
21067
|
crudContext;
|
|
21052
21068
|
filterCriteria = {};
|
|
21053
|
-
|
|
21069
|
+
filterCriteriaChange = new EventEmitter();
|
|
21070
|
+
_filterTeleport = false;
|
|
21071
|
+
set filterTeleport(value) {
|
|
21072
|
+
if (this._filterTeleport === value)
|
|
21073
|
+
return;
|
|
21074
|
+
this._filterTeleport = value;
|
|
21075
|
+
this.setShowToolbar(this.shouldExposeToolbar(), true);
|
|
21076
|
+
}
|
|
21077
|
+
get filterTeleport() {
|
|
21078
|
+
return this._filterTeleport;
|
|
21079
|
+
}
|
|
21054
21080
|
widgetId;
|
|
21055
|
-
|
|
21081
|
+
filterTemplateSignal = signal(undefined, ...(ngDevMode ? [{ debugName: "filterTemplateSignal" }] : /* istanbul ignore next */ []));
|
|
21082
|
+
_filterBarTemplate;
|
|
21083
|
+
set filterBarTemplate(tpl) {
|
|
21084
|
+
this._filterBarTemplate = tpl;
|
|
21085
|
+
this.filterTemplateSignal.set(tpl);
|
|
21086
|
+
}
|
|
21087
|
+
get filterBarTemplate() {
|
|
21088
|
+
return this._filterBarTemplate;
|
|
21089
|
+
}
|
|
21056
21090
|
get filterTemplate() {
|
|
21057
|
-
return this.
|
|
21091
|
+
return this.filterTemplateSignal();
|
|
21058
21092
|
}
|
|
21059
21093
|
widgetEventBus = inject(PraxisWidgetEventBus, { optional: true });
|
|
21060
21094
|
queryContext = null;
|
|
@@ -23056,6 +23090,40 @@ class PraxisTable {
|
|
|
23056
23090
|
}
|
|
23057
23091
|
catch { }
|
|
23058
23092
|
}
|
|
23093
|
+
recomposeEffectiveTableConfig() {
|
|
23094
|
+
const existingColumns = Array.isArray(this.config?.columns)
|
|
23095
|
+
? [...this.config.columns]
|
|
23096
|
+
: [];
|
|
23097
|
+
const baseInput = this.hostInputConfig
|
|
23098
|
+
? this.clonePlainObject(this.hostInputConfig)
|
|
23099
|
+
: { columns: [] };
|
|
23100
|
+
if (this.persistedUserConfig) {
|
|
23101
|
+
const storedClone = this.clonePlainObject(this.persistedUserConfig);
|
|
23102
|
+
this.config = this.mergePersistedTableConfigWithInput(storedClone, baseInput);
|
|
23103
|
+
}
|
|
23104
|
+
else {
|
|
23105
|
+
this.config = baseInput;
|
|
23106
|
+
}
|
|
23107
|
+
const globalTable = this.global?.getTable?.();
|
|
23108
|
+
this.hostDeclaredAppearanceDensity =
|
|
23109
|
+
this.hasDeclaredAppearanceDensity(this.persistedUserConfig) ||
|
|
23110
|
+
this.hasDeclaredAppearanceDensity(this.hostInputConfig) ||
|
|
23111
|
+
this.hasDeclaredAppearanceDensity(globalTable);
|
|
23112
|
+
this.hostDeclaredAppearanceSpacing =
|
|
23113
|
+
this.hasDeclaredAppearanceSection(this.persistedUserConfig, 'spacing') ||
|
|
23114
|
+
this.hasDeclaredAppearanceSection(this.hostInputConfig, 'spacing') ||
|
|
23115
|
+
this.hasDeclaredAppearanceSection(globalTable, 'spacing');
|
|
23116
|
+
this.hostDeclaredAppearanceTypography =
|
|
23117
|
+
this.hasDeclaredAppearanceSection(this.persistedUserConfig, 'typography') ||
|
|
23118
|
+
this.hasDeclaredAppearanceSection(this.hostInputConfig, 'typography') ||
|
|
23119
|
+
this.hasDeclaredAppearanceSection(globalTable, 'typography');
|
|
23120
|
+
this.ensureConfigDefaults();
|
|
23121
|
+
if ((!Array.isArray(this.config.columns) || this.config.columns.length === 0) &&
|
|
23122
|
+
existingColumns.length > 0 &&
|
|
23123
|
+
(this.usesSchemaColumnProjection(this.config) || this.isRemoteMode())) {
|
|
23124
|
+
this.config.columns = existingColumns;
|
|
23125
|
+
}
|
|
23126
|
+
}
|
|
23059
23127
|
hasDeclaredAppearanceDensity(config) {
|
|
23060
23128
|
const appearance = config?.appearance;
|
|
23061
23129
|
return !!appearance && Object.prototype.hasOwnProperty.call(appearance, 'density');
|
|
@@ -23301,11 +23369,19 @@ class PraxisTable {
|
|
|
23301
23369
|
return false;
|
|
23302
23370
|
if (config.toolbar?.visible)
|
|
23303
23371
|
return true;
|
|
23372
|
+
if (typeof config.toolbar?.title === 'string' && config.toolbar.title.trim().length > 0)
|
|
23373
|
+
return true;
|
|
23374
|
+
if (typeof config.toolbar?.subtitle === 'string' && config.toolbar.subtitle.trim().length > 0)
|
|
23375
|
+
return true;
|
|
23304
23376
|
if (config.export?.enabled)
|
|
23305
23377
|
return true;
|
|
23306
23378
|
if (config.actions?.bulk?.enabled)
|
|
23307
23379
|
return true;
|
|
23308
|
-
if (this.isAdvancedFiltersEffectivelyEnabled(config))
|
|
23380
|
+
if (!this.filterTeleport && this.isAdvancedFiltersEffectivelyEnabled(config))
|
|
23381
|
+
return true;
|
|
23382
|
+
if (this.getConfiguredQuickFilters().length > 0)
|
|
23383
|
+
return true;
|
|
23384
|
+
if ((this.activeCrossFilters?.length ?? 0) > 0)
|
|
23309
23385
|
return true;
|
|
23310
23386
|
return (config.toolbar?.actions?.length ?? 0) > 0;
|
|
23311
23387
|
}
|
|
@@ -23959,7 +24035,7 @@ class PraxisTable {
|
|
|
23959
24035
|
if (this.aiAdapter || this.aiAdapterLoadStarted)
|
|
23960
24036
|
return;
|
|
23961
24037
|
this.aiAdapterLoadStarted = true;
|
|
23962
|
-
import('./praxisui-table-table-ai.adapter-
|
|
24038
|
+
import('./praxisui-table-table-ai.adapter-DqlbvUHe.mjs')
|
|
23963
24039
|
.then(({ TableAiAdapter }) => {
|
|
23964
24040
|
if (!this.isAiAssistantEnabled()) {
|
|
23965
24041
|
this.aiAssistantOpenAfterAdapterLoad = false;
|
|
@@ -24731,7 +24807,7 @@ class PraxisTable {
|
|
|
24731
24807
|
initializeAiAssistantController() {
|
|
24732
24808
|
if (!this.aiAdapter || this.aiAssistantController)
|
|
24733
24809
|
return;
|
|
24734
|
-
import('./praxisui-table-table-agentic-authoring-turn-flow-
|
|
24810
|
+
import('./praxisui-table-table-agentic-authoring-turn-flow-EvaZNCNd.mjs')
|
|
24735
24811
|
.then(({ TableAgenticAuthoringTurnFlow }) => {
|
|
24736
24812
|
if (this.aiAssistantController || !this.aiAdapter)
|
|
24737
24813
|
return;
|
|
@@ -25601,6 +25677,8 @@ class PraxisTable {
|
|
|
25601
25677
|
};
|
|
25602
25678
|
this.queryContextClear.emit(clearEvent);
|
|
25603
25679
|
this.queryContextChange.emit(this.queryContext);
|
|
25680
|
+
this.filterCriteriaChange.emit({ ...this.getEffectiveEditableFilterCriteria() });
|
|
25681
|
+
this.setShowToolbar(this.shouldExposeToolbar(), true);
|
|
25604
25682
|
// Host-mediated widgetEvent for composition runtime
|
|
25605
25683
|
this.widgetEvent.emit({
|
|
25606
25684
|
ownerWidgetKey: this.componentInstanceId || this.tableId || undefined,
|
|
@@ -25659,6 +25737,8 @@ class PraxisTable {
|
|
|
25659
25737
|
};
|
|
25660
25738
|
this.queryContextClear.emit(clearEvent);
|
|
25661
25739
|
this.queryContextChange.emit(this.queryContext);
|
|
25740
|
+
this.filterCriteriaChange.emit({ ...this.getEffectiveEditableFilterCriteria() });
|
|
25741
|
+
this.setShowToolbar(this.shouldExposeToolbar(), true);
|
|
25662
25742
|
this.widgetEvent.emit({
|
|
25663
25743
|
ownerWidgetKey: this.componentInstanceId || this.tableId || undefined,
|
|
25664
25744
|
sourceComponentId: 'praxis-table',
|
|
@@ -25804,8 +25884,11 @@ class PraxisTable {
|
|
|
25804
25884
|
ref.saved$.subscribe(apply);
|
|
25805
25885
|
}
|
|
25806
25886
|
async ngOnInit() {
|
|
25887
|
+
if (!this.hostInputConfig && this.config) {
|
|
25888
|
+
this.hostInputConfig = this.clonePlainObject(this.config);
|
|
25889
|
+
}
|
|
25807
25890
|
// Ensure config exists before any awaited operations to avoid template errors
|
|
25808
|
-
this.
|
|
25891
|
+
this.recomposeEffectiveTableConfig();
|
|
25809
25892
|
this.enforceUnsupportedFeatureGuards();
|
|
25810
25893
|
this.syncPaginatorIntl();
|
|
25811
25894
|
this.setShowToolbar(this.shouldExposeToolbar(), true);
|
|
@@ -25821,6 +25904,21 @@ class PraxisTable {
|
|
|
25821
25904
|
}
|
|
25822
25905
|
}));
|
|
25823
25906
|
}
|
|
25907
|
+
if (this.global?.configChanges$) {
|
|
25908
|
+
this.subscriptions.push(this.global.configChanges$.subscribe(() => {
|
|
25909
|
+
this.recomposeEffectiveTableConfig();
|
|
25910
|
+
this.enforceUnsupportedFeatureGuards();
|
|
25911
|
+
this.syncPaginatorIntl();
|
|
25912
|
+
this.syncHorizontalScrollFromAppearanceConfig();
|
|
25913
|
+
this.setShowToolbar(this.shouldExposeToolbar(), true);
|
|
25914
|
+
this.applyAppearanceVariables();
|
|
25915
|
+
this.cdr.markForCheck();
|
|
25916
|
+
}));
|
|
25917
|
+
}
|
|
25918
|
+
try {
|
|
25919
|
+
await this.global?.ready?.();
|
|
25920
|
+
}
|
|
25921
|
+
catch { }
|
|
25824
25922
|
// Resolve global fallback for schema prefs
|
|
25825
25923
|
try {
|
|
25826
25924
|
await this.resolveSchemaPrefs();
|
|
@@ -25851,14 +25949,8 @@ class PraxisTable {
|
|
|
25851
25949
|
try {
|
|
25852
25950
|
const storedConfig = await firstValueFrom(this.asyncConfigStorage.loadConfig(cfgKey));
|
|
25853
25951
|
if (storedConfig) {
|
|
25854
|
-
this.
|
|
25855
|
-
|
|
25856
|
-
this.hostDeclaredAppearanceSpacing =
|
|
25857
|
-
this.hostDeclaredAppearanceSpacing || this.hasDeclaredAppearanceSection(storedConfig, 'spacing');
|
|
25858
|
-
this.hostDeclaredAppearanceTypography =
|
|
25859
|
-
this.hostDeclaredAppearanceTypography || this.hasDeclaredAppearanceSection(storedConfig, 'typography');
|
|
25860
|
-
this.config = this.mergePersistedTableConfigWithInput(storedConfig, this.config);
|
|
25861
|
-
this.ensureConfigDefaults();
|
|
25952
|
+
this.persistedUserConfig = this.clonePlainObject(storedConfig);
|
|
25953
|
+
this.recomposeEffectiveTableConfig();
|
|
25862
25954
|
this.enforceUnsupportedFeatureGuards();
|
|
25863
25955
|
this.setupColumns();
|
|
25864
25956
|
this.cdr.markForCheck();
|
|
@@ -25883,8 +25975,8 @@ class PraxisTable {
|
|
|
25883
25975
|
}
|
|
25884
25976
|
}
|
|
25885
25977
|
catch { }
|
|
25886
|
-
//
|
|
25887
|
-
this.
|
|
25978
|
+
// Recompose effective config after GlobalConfig.ready() and persisted user config hydration
|
|
25979
|
+
this.recomposeEffectiveTableConfig();
|
|
25888
25980
|
this.resetDetailRuntimeForConfig();
|
|
25889
25981
|
this.syncPaginatorIntl();
|
|
25890
25982
|
// ngOnInit is async and Angular does not await it before ngAfterContentInit.
|
|
@@ -25908,6 +26000,7 @@ class PraxisTable {
|
|
|
25908
26000
|
resetPageSizeOverride: true,
|
|
25909
26001
|
});
|
|
25910
26002
|
this.applyDataSourceSettings();
|
|
26003
|
+
this.applyAppearanceVariables();
|
|
25911
26004
|
if (this.isAiAssistantEnabled()) {
|
|
25912
26005
|
this.ensureAiAdapterLoaded();
|
|
25913
26006
|
}
|
|
@@ -25938,10 +26031,24 @@ class PraxisTable {
|
|
|
25938
26031
|
this.localPageSizeRuntimeOverride = false;
|
|
25939
26032
|
}
|
|
25940
26033
|
if (changes['config']?.currentValue && this.config) {
|
|
25941
|
-
this.
|
|
25942
|
-
|
|
25943
|
-
this.
|
|
26034
|
+
this.hostInputConfig = this.clonePlainObject(changes['config'].currentValue);
|
|
26035
|
+
const globalTable = this.global?.getTable?.();
|
|
26036
|
+
this.hostDeclaredAppearanceDensity =
|
|
26037
|
+
this.hasDeclaredAppearanceDensity(this.persistedUserConfig) ||
|
|
26038
|
+
this.hasDeclaredAppearanceDensity(changes['config'].currentValue) ||
|
|
26039
|
+
this.hasDeclaredAppearanceDensity(globalTable);
|
|
26040
|
+
this.hostDeclaredAppearanceSpacing =
|
|
26041
|
+
this.hasDeclaredAppearanceSection(this.persistedUserConfig, 'spacing') ||
|
|
26042
|
+
this.hasDeclaredAppearanceSection(changes['config'].currentValue, 'spacing') ||
|
|
26043
|
+
this.hasDeclaredAppearanceSection(globalTable, 'spacing');
|
|
26044
|
+
this.hostDeclaredAppearanceTypography =
|
|
26045
|
+
this.hasDeclaredAppearanceSection(this.persistedUserConfig, 'typography') ||
|
|
26046
|
+
this.hasDeclaredAppearanceSection(changes['config'].currentValue, 'typography') ||
|
|
26047
|
+
this.hasDeclaredAppearanceSection(globalTable, 'typography');
|
|
25944
26048
|
this.config = this.reconcileTableConfigInputChange(changes['config'].previousValue, changes['config'].currentValue);
|
|
26049
|
+
if (this.persistedUserConfig) {
|
|
26050
|
+
this.persistedUserConfig = this.clonePlainObject(this.config);
|
|
26051
|
+
}
|
|
25945
26052
|
}
|
|
25946
26053
|
this.ensureConfigDefaults();
|
|
25947
26054
|
this.enforceUnsupportedFeatureGuards();
|
|
@@ -26081,6 +26188,16 @@ class PraxisTable {
|
|
|
26081
26188
|
shouldFetchRemoteDataForQueryChanges(changes) {
|
|
26082
26189
|
if (!this.isRemoteMode())
|
|
26083
26190
|
return false;
|
|
26191
|
+
if (changes['filterCriteria'] &&
|
|
26192
|
+
!changes['queryContext'] &&
|
|
26193
|
+
this.lastAppliedFilterCriteria !== null) {
|
|
26194
|
+
const incoming = normalizePraxisFilterCriteriaRecord(changes['filterCriteria'].currentValue);
|
|
26195
|
+
const prevApplied = this.lastAppliedFilterCriteria;
|
|
26196
|
+
this.lastAppliedFilterCriteria = null;
|
|
26197
|
+
if (this.hasEquivalentFilterCriteria(incoming, prevApplied)) {
|
|
26198
|
+
return false;
|
|
26199
|
+
}
|
|
26200
|
+
}
|
|
26084
26201
|
if (this.hasInitialized)
|
|
26085
26202
|
return true;
|
|
26086
26203
|
const queryChanges = [changes['filterCriteria'], changes['queryContext']];
|
|
@@ -28362,8 +28479,13 @@ class PraxisTable {
|
|
|
28362
28479
|
return false;
|
|
28363
28480
|
if (visibleFieldNames.has(name))
|
|
28364
28481
|
return false;
|
|
28365
|
-
if (name.startsWith('_')
|
|
28482
|
+
if (name.startsWith('_')
|
|
28483
|
+
|| name === 'id'
|
|
28484
|
+
|| name === '__v'
|
|
28485
|
+
|| name === 'version'
|
|
28486
|
+
|| name === 'resourceVersion') {
|
|
28366
28487
|
return false;
|
|
28488
|
+
}
|
|
28367
28489
|
if (this.isSensitiveAiAssistantField(name))
|
|
28368
28490
|
return false;
|
|
28369
28491
|
return true;
|
|
@@ -29055,7 +29177,7 @@ class PraxisTable {
|
|
|
29055
29177
|
childKeys.push('items');
|
|
29056
29178
|
}
|
|
29057
29179
|
if (type === 'tab' || type === 'card') {
|
|
29058
|
-
childKeys.push('content');
|
|
29180
|
+
childKeys.push('content', 'items');
|
|
29059
29181
|
}
|
|
29060
29182
|
for (const childKey of childKeys) {
|
|
29061
29183
|
const rawChildren = clone[childKey];
|
|
@@ -32289,6 +32411,7 @@ class PraxisTable {
|
|
|
32289
32411
|
this.clearQuickFilterRuntimeState();
|
|
32290
32412
|
this.applyAdvancedFilterCriteria(editableCriteria, 'advanced-filter-submit');
|
|
32291
32413
|
this.syncQuickFilterStateFromEffectiveCriteria();
|
|
32414
|
+
this.filterCriteriaChange.emit({ ...this.filterCriteria });
|
|
32292
32415
|
if (this.widgetEventBus) {
|
|
32293
32416
|
this.widgetEventBus.publish({
|
|
32294
32417
|
sourceWidgetId: this.widgetId || this.tableId,
|
|
@@ -32305,6 +32428,7 @@ class PraxisTable {
|
|
|
32305
32428
|
this.clearQuickFilterRuntimeState();
|
|
32306
32429
|
this.applyAdvancedFilterCriteria({}, 'advanced-filter-clear');
|
|
32307
32430
|
this.syncQuickFilterStateFromEffectiveCriteria();
|
|
32431
|
+
this.filterCriteriaChange.emit({});
|
|
32308
32432
|
if (this.widgetEventBus) {
|
|
32309
32433
|
this.widgetEventBus.publish({
|
|
32310
32434
|
sourceWidgetId: this.widgetId || this.tableId,
|
|
@@ -32336,6 +32460,7 @@ class PraxisTable {
|
|
|
32336
32460
|
this.activeQuickFilterId = id;
|
|
32337
32461
|
this.activeQuickFilterCriteria = {};
|
|
32338
32462
|
this.applyAdvancedFilterCriteria({}, 'quick-filter-apply');
|
|
32463
|
+
this.filterCriteriaChange.emit({});
|
|
32339
32464
|
return;
|
|
32340
32465
|
}
|
|
32341
32466
|
const current = normalizePraxisFilterCriteriaRecord(this.filterCriteria);
|
|
@@ -32353,12 +32478,14 @@ class PraxisTable {
|
|
|
32353
32478
|
this.clearQuickFilterRuntimeState();
|
|
32354
32479
|
this.applyAdvancedFilterCriteria(cleanedBase, 'quick-filter-clear');
|
|
32355
32480
|
this.syncQuickFilterStateFromEffectiveCriteria();
|
|
32481
|
+
this.filterCriteriaChange.emit({ ...this.filterCriteria });
|
|
32356
32482
|
return;
|
|
32357
32483
|
}
|
|
32358
32484
|
this.quickFilterBaseCriteria = cleanedBase;
|
|
32359
32485
|
this.activeQuickFilterId = id;
|
|
32360
32486
|
this.activeQuickFilterCriteria = { ...cleanedBase, ...patch };
|
|
32361
32487
|
this.applyAdvancedFilterCriteria(this.activeQuickFilterCriteria, 'quick-filter-apply');
|
|
32488
|
+
this.filterCriteriaChange.emit({ ...this.filterCriteria });
|
|
32362
32489
|
}
|
|
32363
32490
|
getConfiguredQuickFilters() {
|
|
32364
32491
|
const filters = this.config?.toolbar?.filters;
|
|
@@ -32501,6 +32628,7 @@ class PraxisTable {
|
|
|
32501
32628
|
};
|
|
32502
32629
|
this.queryContextClear?.emit(clearEvent);
|
|
32503
32630
|
this.queryContextChange?.emit(this.queryContext);
|
|
32631
|
+
this.filterCriteriaChange.emit({ ...this.getEffectiveEditableFilterCriteria() });
|
|
32504
32632
|
this.widgetEvent?.emit({
|
|
32505
32633
|
ownerWidgetKey: this.componentInstanceId || this.tableId || undefined,
|
|
32506
32634
|
sourceComponentId: 'praxis-table',
|
|
@@ -32556,8 +32684,15 @@ class PraxisTable {
|
|
|
32556
32684
|
}
|
|
32557
32685
|
hasEquivalentFilterCriteria(left, right) {
|
|
32558
32686
|
const canonicalize = (value) => {
|
|
32559
|
-
if (Array.isArray(value))
|
|
32560
|
-
|
|
32687
|
+
if (Array.isArray(value)) {
|
|
32688
|
+
const items = value.map(canonicalize);
|
|
32689
|
+
if (items.length === 2 &&
|
|
32690
|
+
typeof items[0] === 'number' &&
|
|
32691
|
+
typeof items[1] === 'number') {
|
|
32692
|
+
return { end: items[1], start: items[0] };
|
|
32693
|
+
}
|
|
32694
|
+
return items;
|
|
32695
|
+
}
|
|
32561
32696
|
if (!value || typeof value !== 'object')
|
|
32562
32697
|
return value;
|
|
32563
32698
|
return Object.keys(value)
|
|
@@ -32569,8 +32704,10 @@ class PraxisTable {
|
|
|
32569
32704
|
};
|
|
32570
32705
|
return JSON.stringify(canonicalize(left)) === JSON.stringify(canonicalize(right));
|
|
32571
32706
|
}
|
|
32707
|
+
lastAppliedFilterCriteria = null;
|
|
32572
32708
|
applyAdvancedFilterCriteria(criteria, reason = 'external-api') {
|
|
32573
32709
|
this.setAdvancedFilterCriteria(criteria);
|
|
32710
|
+
this.lastAppliedFilterCriteria = { ...this.filterCriteria };
|
|
32574
32711
|
this.applyExpansionCollapsePolicy('filterChange');
|
|
32575
32712
|
this.clearCellAnimationChangeState();
|
|
32576
32713
|
this.pageIndex = 0;
|
|
@@ -33056,6 +33193,7 @@ class PraxisTable {
|
|
|
33056
33193
|
const compactConfig = this.toPortableTableConfig(plan.canonicalConfig);
|
|
33057
33194
|
const cfg = this.attachRuntimeMetadataToEditorConfig(compactConfig, plan.metadata?.attachServerMeta === true && !shouldReloadSchema, plan.persistence?.saveConfig === true);
|
|
33058
33195
|
if (plan.persistence?.saveConfig) {
|
|
33196
|
+
this.persistedUserConfig = this.clonePlainObject(cfg);
|
|
33059
33197
|
const cfgKey = this.tableConfigKey();
|
|
33060
33198
|
if (cfgKey) {
|
|
33061
33199
|
this.saveConfigWithAck(cfgKey, cfg, 'table-settings-save', {
|
|
@@ -33224,8 +33362,27 @@ class PraxisTable {
|
|
|
33224
33362
|
onResetPersistenceSettled(false, 'reset-filter-config');
|
|
33225
33363
|
});
|
|
33226
33364
|
}
|
|
33365
|
+
this.persistedUserConfig = undefined;
|
|
33227
33366
|
const defaults = this.tableDefaultsProvider.getDefaults(this.tableId);
|
|
33228
|
-
this.
|
|
33367
|
+
const restoredConfig = this.hostInputConfig
|
|
33368
|
+
? fillUndefined(this.clonePlainObject(this.hostInputConfig), defaults)
|
|
33369
|
+
: defaults;
|
|
33370
|
+
if ((!Array.isArray(restoredConfig.columns) || restoredConfig.columns.length === 0) &&
|
|
33371
|
+
this.schemaColumnFieldsSnapshot.length > 0 &&
|
|
33372
|
+
(this.usesSchemaColumnProjection(restoredConfig) || this.isRemoteMode())) {
|
|
33373
|
+
restoredConfig.columns = this.projectSchemaColumns(this.schemaColumnFieldsSnapshot, restoredConfig.columnProjection);
|
|
33374
|
+
}
|
|
33375
|
+
const globalTable = this.global?.getTable?.();
|
|
33376
|
+
this.hostDeclaredAppearanceDensity =
|
|
33377
|
+
this.hasDeclaredAppearanceDensity(this.hostInputConfig) ||
|
|
33378
|
+
this.hasDeclaredAppearanceDensity(globalTable);
|
|
33379
|
+
this.hostDeclaredAppearanceSpacing =
|
|
33380
|
+
this.hasDeclaredAppearanceSection(this.hostInputConfig, 'spacing') ||
|
|
33381
|
+
this.hasDeclaredAppearanceSection(globalTable, 'spacing');
|
|
33382
|
+
this.hostDeclaredAppearanceTypography =
|
|
33383
|
+
this.hasDeclaredAppearanceSection(this.hostInputConfig, 'typography') ||
|
|
33384
|
+
this.hasDeclaredAppearanceSection(globalTable, 'typography');
|
|
33385
|
+
this.applyTableConfig(restoredConfig);
|
|
33229
33386
|
if (operationCount === 0) {
|
|
33230
33387
|
this.showResetSuccessFeedback(successTrigger);
|
|
33231
33388
|
}
|
|
@@ -34799,6 +34956,7 @@ class PraxisTable {
|
|
|
34799
34956
|
.subscribe({
|
|
34800
34957
|
next: () => {
|
|
34801
34958
|
acknowledged = true;
|
|
34959
|
+
this.persistedUserConfig = this.clonePlainObject(payload);
|
|
34802
34960
|
if (applyReconciledConfigOnSuccess) {
|
|
34803
34961
|
this.config = payload;
|
|
34804
34962
|
this.runColumnResizeLayoutMutation(() => this.setupColumns());
|
|
@@ -35098,7 +35256,11 @@ class PraxisTable {
|
|
|
35098
35256
|
this.config?.toolbar?.filters?.enabled !== false &&
|
|
35099
35257
|
(!this.config?.toolbar?.filters?.quickFilters || this.config.toolbar.filters.quickFilters.length === 0)) {
|
|
35100
35258
|
const toolbar = this.ensureToolbarConfigForRuntime();
|
|
35101
|
-
|
|
35259
|
+
const globalShowAdvanced = this.global?.getTable?.()?.toolbar?.filters?.showAdvancedButton;
|
|
35260
|
+
toolbar.filters = toolbar.filters || {
|
|
35261
|
+
enabled: true,
|
|
35262
|
+
showAdvancedButton: typeof globalShowAdvanced === 'boolean' ? globalShowAdvanced : true,
|
|
35263
|
+
};
|
|
35102
35264
|
toolbar.filters.quickFilters = [...discoveredQuickFilters];
|
|
35103
35265
|
if (toolbar.filters.enabled === undefined) {
|
|
35104
35266
|
toolbar.filters.enabled = true;
|
|
@@ -38300,8 +38462,56 @@ class PraxisTable {
|
|
|
38300
38462
|
}, { dedupeKey: 'praxis-table:expansion:virtualization-fail-closed' });
|
|
38301
38463
|
return false;
|
|
38302
38464
|
}
|
|
38465
|
+
if (!this.hasComplementarySchemaExpansionFields()) {
|
|
38466
|
+
return false;
|
|
38467
|
+
}
|
|
38303
38468
|
return true;
|
|
38304
38469
|
}
|
|
38470
|
+
hasComplementarySchemaExpansionFields() {
|
|
38471
|
+
const rawMode = String(this.getDetailConfig()?.source?.mode
|
|
38472
|
+
|| this.getExpansionConfig()?.source
|
|
38473
|
+
|| this.getExpansionConfig()?.mode
|
|
38474
|
+
|| (this.getExpansionConfig()?.enabled && !this.getDetailConfig()?.source?.inlineSchema ? 'schema' : 'inline')).trim();
|
|
38475
|
+
if (rawMode !== 'schema')
|
|
38476
|
+
return true;
|
|
38477
|
+
if (this.getExpansionFallbackMode() !== 'none')
|
|
38478
|
+
return true;
|
|
38479
|
+
const schemaFields = this.schemaColumnFieldsSnapshot && this.schemaColumnFieldsSnapshot.length > 0
|
|
38480
|
+
? this.schemaColumnFieldsSnapshot
|
|
38481
|
+
: this.schemaFieldsSnapshot && this.schemaFieldsSnapshot.length > 0
|
|
38482
|
+
? this.schemaFieldsSnapshot
|
|
38483
|
+
: null;
|
|
38484
|
+
if (!schemaFields || schemaFields.length === 0)
|
|
38485
|
+
return true;
|
|
38486
|
+
const visibleFieldNames = new Set();
|
|
38487
|
+
const activeColumns = this.visibleColumns && this.visibleColumns.length > 0
|
|
38488
|
+
? this.visibleColumns
|
|
38489
|
+
: (this.config?.columns || []).filter((col) => col && col.visible !== false);
|
|
38490
|
+
for (const col of activeColumns) {
|
|
38491
|
+
if (col?.field)
|
|
38492
|
+
visibleFieldNames.add(col.field);
|
|
38493
|
+
}
|
|
38494
|
+
const idField = this.getIdField();
|
|
38495
|
+
if (idField)
|
|
38496
|
+
visibleFieldNames.add(idField);
|
|
38497
|
+
return schemaFields.some((f) => {
|
|
38498
|
+
const name = String(f?.name || '').trim();
|
|
38499
|
+
if (!name)
|
|
38500
|
+
return false;
|
|
38501
|
+
if (visibleFieldNames.has(name))
|
|
38502
|
+
return false;
|
|
38503
|
+
if (name.startsWith('_')
|
|
38504
|
+
|| name === 'id'
|
|
38505
|
+
|| name === '__v'
|
|
38506
|
+
|| name === 'version'
|
|
38507
|
+
|| name === 'resourceVersion') {
|
|
38508
|
+
return false;
|
|
38509
|
+
}
|
|
38510
|
+
if (this.isSensitiveAiAssistantField(name))
|
|
38511
|
+
return false;
|
|
38512
|
+
return true;
|
|
38513
|
+
});
|
|
38514
|
+
}
|
|
38305
38515
|
enforceAppearanceSchemaGuards() {
|
|
38306
38516
|
const appearance = (this.config?.appearance || {});
|
|
38307
38517
|
if (!appearance || typeof appearance !== 'object')
|
|
@@ -42266,7 +42476,7 @@ class PraxisTable {
|
|
|
42266
42476
|
this.removeViewportChangeListeners = null;
|
|
42267
42477
|
}
|
|
42268
42478
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: PraxisTable, deps: [{ token: i0.ChangeDetectorRef }, { token: i3$2.SettingsPanelService }, { token: i1.GenericCrudService }, { token: TableDefaultsProvider }, { token: FilterConfigService }, { token: DataFormattingService }, { token: i6$1.PraxisDialog }, { token: i4$2.MatSnackBar }, { token: ASYNC_CONFIG_STORAGE }, { token: CONNECTION_STORAGE }, { token: i0.ElementRef }, { token: i1.GlobalConfigService }, { token: i0.Injector }, { token: i1.ComponentKeyService }, { token: i1.LoadingOrchestrator }, { token: i1.GlobalActionService }, { token: i1.EnterpriseRuntimeContextService, optional: true }, { token: PRAXIS_LOADING_RENDERER, optional: true }, { token: i8$1.ActivatedRoute, optional: true }, { token: i1.LoggerService, optional: true }, { token: AnalyticsTableStatsApiService, optional: true }], target: i0.ɵɵFactoryTarget.Component });
|
|
42269
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.14", type: PraxisTable, isStandalone: true, selector: "praxis-table", inputs: { config: "config", resourcePath: "resourcePath", data: "data", tableId: "tableId", componentInstanceId: "componentInstanceId", configPersistenceStrategy: "configPersistenceStrategy", title: "title", subtitle: "subtitle", icon: "icon", autoDelete: "autoDelete", notifyIfOutdated: "notifyIfOutdated", snoozeMs: "snoozeMs", autoOpenSettingsOnOutdated: "autoOpenSettingsOnOutdated", crudContext: "crudContext", filterCriteria: "filterCriteria", filterTeleport: ["filterTeleport", "filterTeleport", booleanAttribute], widgetId: "widgetId", queryContext: "queryContext", aiContext: "aiContext", aiAssistantVoiceInputMode: "aiAssistantVoiceInputMode", aiAssistantVoiceLanguage: "aiAssistantVoiceLanguage", horizontalScroll: "horizontalScroll", enableCustomization: ["enableCustomization", "enableCustomization", booleanAttribute], authoringCapability: "authoringCapability", dense: "dense" }, outputs: { queryContextClear: "queryContextClear", queryContextChange: "queryContextChange", rowClick: "rowClick", widgetEvent: "widgetEvent", resourceEvent: "resourceEvent", rowDoubleClick: "rowDoubleClick", rowExpansionChange: "rowExpansionChange", rowAction: "rowAction", toolbarAction: "toolbarAction", bulkAction: "bulkAction", exportAction: "exportAction", columnReorder: "columnReorder", columnReorderAttempt: "columnReorderAttempt", columnResize: "columnResize", beforeDelete: "beforeDelete", afterDelete: "afterDelete", deleteError: "deleteError", beforeBulkDelete: "beforeBulkDelete", afterBulkDelete: "afterBulkDelete", bulkDeleteError: "bulkDeleteError", schemaStatusChange: "schemaStatusChange", configChange: "configChange", metadataChange: "metadataChange", loadingStateChange: "loadingStateChange", collectionLinksChange: "collectionLinksChange", selectionChange: "selectionChange", drawerOpen: "drawerOpen", drawerClose: "drawerClose", drawerTabChange: "drawerTabChange" }, host: { properties: { "class.density-compact": "this.hostDensityCompactClass", "class.density-comfortable": "this.hostDensityComfortableClass", "class.density-spacious": "this.hostDensitySpaciousClass", "class.row-borders": "this.hostRowBordersClass", "class.col-borders": "this.hostColumnBordersClass" } }, providers: [
|
|
42479
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.14", type: PraxisTable, isStandalone: true, selector: "praxis-table", inputs: { config: "config", resourcePath: "resourcePath", data: "data", tableId: "tableId", componentInstanceId: "componentInstanceId", configPersistenceStrategy: "configPersistenceStrategy", title: "title", subtitle: "subtitle", icon: "icon", autoDelete: "autoDelete", notifyIfOutdated: "notifyIfOutdated", snoozeMs: "snoozeMs", autoOpenSettingsOnOutdated: "autoOpenSettingsOnOutdated", crudContext: "crudContext", filterCriteria: "filterCriteria", filterTeleport: ["filterTeleport", "filterTeleport", booleanAttribute], widgetId: "widgetId", queryContext: "queryContext", aiContext: "aiContext", aiAssistantVoiceInputMode: "aiAssistantVoiceInputMode", aiAssistantVoiceLanguage: "aiAssistantVoiceLanguage", horizontalScroll: "horizontalScroll", enableCustomization: ["enableCustomization", "enableCustomization", booleanAttribute], authoringCapability: "authoringCapability", dense: "dense" }, outputs: { filterCriteriaChange: "filterCriteriaChange", queryContextClear: "queryContextClear", queryContextChange: "queryContextChange", rowClick: "rowClick", widgetEvent: "widgetEvent", resourceEvent: "resourceEvent", rowDoubleClick: "rowDoubleClick", rowExpansionChange: "rowExpansionChange", rowAction: "rowAction", toolbarAction: "toolbarAction", bulkAction: "bulkAction", exportAction: "exportAction", columnReorder: "columnReorder", columnReorderAttempt: "columnReorderAttempt", columnResize: "columnResize", beforeDelete: "beforeDelete", afterDelete: "afterDelete", deleteError: "deleteError", beforeBulkDelete: "beforeBulkDelete", afterBulkDelete: "afterBulkDelete", bulkDeleteError: "bulkDeleteError", schemaStatusChange: "schemaStatusChange", configChange: "configChange", metadataChange: "metadataChange", loadingStateChange: "loadingStateChange", collectionLinksChange: "collectionLinksChange", selectionChange: "selectionChange", drawerOpen: "drawerOpen", drawerClose: "drawerClose", drawerTabChange: "drawerTabChange" }, host: { properties: { "class.density-compact": "this.hostDensityCompactClass", "class.density-comfortable": "this.hostDensityComfortableClass", "class.density-spacious": "this.hostDensitySpaciousClass", "class.row-borders": "this.hostRowBordersClass", "class.col-borders": "this.hostColumnBordersClass" } }, providers: [
|
|
42270
42480
|
providePraxisI18nConfig(RESOURCE_DISCOVERY_I18N_CONFIG),
|
|
42271
42481
|
providePraxisI18nConfig(PRAXIS_TABLE_RUNTIME_I18N_CONFIG),
|
|
42272
42482
|
MatPaginatorIntl,
|
|
@@ -42365,6 +42575,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
|
|
|
42365
42575
|
type: Input
|
|
42366
42576
|
}], filterCriteria: [{
|
|
42367
42577
|
type: Input
|
|
42578
|
+
}], filterCriteriaChange: [{
|
|
42579
|
+
type: Output
|
|
42368
42580
|
}], filterTeleport: [{
|
|
42369
42581
|
type: Input,
|
|
42370
42582
|
args: [{ transform: booleanAttribute }]
|
|
@@ -73679,7 +73891,7 @@ class PraxisTableConfigEditor {
|
|
|
73679
73891
|
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.14", type: PraxisTableConfigEditor, isStandalone: true, selector: "praxis-table-config-editor", providers: [
|
|
73680
73892
|
TableConfigService,
|
|
73681
73893
|
providePraxisI18nConfig(PRAXIS_TABLE_EDITOR_I18N_CONFIG),
|
|
73682
|
-
], viewQueries: [{ propertyName: "filterSettingsEditor", first: true, predicate: ["tableFilterSettingsRef"], descendants: true }, { propertyName: "behaviorEditor", first: true, predicate: BehaviorConfigEditorComponent, descendants: true }, { propertyName: "detailEditor", first: true, predicate: TableDetailEditorComponent, descendants: true }, { propertyName: "rulesEditor", first: true, predicate: TableRulesEditorComponent, descendants: true }, { propertyName: "crudEditorSetter", first: true, predicate: ["crudEditorRef"], descendants: true }], ngImport: i0, template: "<div class=\"editor-section-selector\">\n <mat-form-field appearance=\"outline\" subscriptSizing=\"dynamic\">\n <mat-label>{{ tx('sections.selector', 'Editor section') }}</mat-label>\n <mat-select [(ngModel)]=\"activeSectionIndex\" data-testid=\"table-config-editor-sections\">\n @for (section of sections; track section.id; let index = $index) {\n <mat-option [value]=\"index\">{{ section.label }}</mat-option>\n }\n </mat-select>\n </mat-form-field>\n</div>\n<mat-tab-group [preserveContent]=\"true\" class=\"config-tabs\" [(selectedIndex)]=\"activeSectionIndex\">\n @for (section of sections; track section.id) {\n <mat-tab>\n <ng-template mat-tab-label>\n @if (section.icon) { <mat-icon [praxisIcon]=\"section.icon\"></mat-icon> }\n <span [attr.data-testid]=\"'config-tab-' + section.id\">{{ section.label }}</span>\n </ng-template>\n <div class=\"tab-content\">\n @switch (section.id) {\n @case ('connect') {\n <div class=\"connect-grid\">\n <mat-form-field appearance=\"outline\">\n <mat-label>{{ tx('connect.resource', 'Resource') }}</mat-label>\n <input matInput [(ngModel)]=\"resourcePath\" (ngModelChange)=\"onResourcePathChange($event)\" [placeholder]=\"tx('connect.resource.placeholder', 'e.g. employees')\" />\n <mat-icon matSuffix>link</mat-icon>\n </mat-form-field>\n <mat-form-field appearance=\"outline\">\n <mat-label>{{ tx('connect.primaryKey', 'Primary key') }}</mat-label>\n <input\n matInput\n [(ngModel)]=\"idField\"\n (ngModelChange)=\"onIdFieldChange($event)\"\n [matAutocomplete]=\"idFieldPicker\"\n [placeholder]=\"tx('connect.primaryKey.placeholder', 'e.g. id, uuid, code')\"\n />\n <mat-icon matSuffix>fingerprint</mat-icon>\n <mat-autocomplete\n #idFieldPicker=\"matAutocomplete\"\n (optionSelected)=\"onIdFieldOptionSelected($event.option.value)\"\n >\n @for (option of filteredIdFieldOptions; track option.name) {\n <mat-option [value]=\"option.name\">\n <span>{{ option.name }}</span>\n @if (option.label && option.label !== option.name) {\n <small> - {{ option.label }}</small>\n }\n </mat-option>\n }\n @if (filteredIdFieldOptions.length === 0) {\n <mat-option disabled>\n {{ tx('connect.primaryKey.empty', 'No matching field found.') }}\n </mat-option>\n }\n </mat-autocomplete>\n </mat-form-field>\n <p class=\"connect-note\">{{ tx('connect.note', 'Define the API resource and, when needed, the primary key.') }}</p>\n <!-- Diverg\u00EAncia: idField -->\n @if (idFieldDiverges) { <div class=\"alert alert--warning connect-alert\">\n <mat-icon class=\"alert__icon\">warning</mat-icon>\n <div class=\"alert__text connect-alert__text\">\n {{ tx('connect.serverPrimaryKeyDiverges', 'The primary key on the server differs from the current configuration.') }}\n <span class=\"connect-alert__meta\">(config: {{ idField || 'id' }} | servidor: {{ serverIdField || 'id' }})</span>\n </div>\n <button mat-stroked-button color=\"primary\" type=\"button\" (click)=\"onReconcileIdField()\">{{ tx('connect.reconcile', 'Reconcile') }}</button>\n </div> }\n <!-- Diverg\u00EAncia: serverHash -->\n @if (schemaHashDiverges) { <div class=\"alert alert--info connect-alert\">\n <mat-icon class=\"alert__icon\">info</mat-icon>\n <div class=\"alert__text connect-alert__text\">\n {{ tx('connect.schemaSnapshotDiverges', 'The saved schema snapshot differs from the current server schema.') }}\n </div>\n <button mat-stroked-button color=\"primary\" type=\"button\" (click)=\"onAcceptServerHash()\">{{ tx('connect.updateMetadata', 'Update metadata') }}</button>\n </div> }\n @if (!schemaHashDiverges && schemaSnapshotMissing) { <div class=\"alert alert--info connect-alert\">\n <mat-icon class=\"alert__icon\">info</mat-icon>\n <div class=\"alert__text connect-alert__text\">\n {{ tx('connect.schemaSnapshotMissing', 'A current schema exists on the server, but there is still no persisted snapshot for reconciliation.') }}\n </div>\n <button mat-stroked-button color=\"primary\" type=\"button\" (click)=\"onAcceptServerHash()\">{{ tx('connect.saveSnapshot', 'Save snapshot') }}</button>\n </div> }\n </div>\n }\n @case ('overview') {\n <div class=\"overview-grid\">\n <section class=\"responsive-settings\" aria-labelledby=\"table-responsive-title\">\n <div class=\"responsive-settings__heading\">\n <mat-icon aria-hidden=\"true\">devices</mat-icon>\n <h3 id=\"table-responsive-title\">{{ tx('overview.responsive.title', 'Narrow screens') }}</h3>\n </div>\n <p>{{ tx('overview.responsive.description', 'Choose how records appear when the table has less space.') }}</p>\n <mat-form-field appearance=\"outline\" subscriptSizing=\"dynamic\">\n <mat-label>{{ tx('overview.responsive.mode', 'Record layout') }}</mat-label>\n <mat-select [ngModel]=\"mobileCardMode\" (ngModelChange)=\"onMobileCardModeChange($event)\">\n <mat-option [value]=\"false\">{{ tx('overview.responsive.table', 'Table') }}</mat-option>\n <mat-option [value]=\"true\">{{ tx('overview.responsive.cards', 'Cards') }}</mat-option>\n </mat-select>\n </mat-form-field>\n @if (mobileCardMode) {\n <p class=\"responsive-settings__hint\">{{ tx('overview.responsive.cardsHint', 'Each record becomes a card with its visible columns. Selection and row actions remain available. Wider areas keep the table layout.') }}</p>\n <mat-form-field appearance=\"outline\" subscriptSizing=\"dynamic\">\n <mat-label>{{ tx('overview.responsive.breakpoint', 'Show cards at widths up to') }}</mat-label>\n <input matInput type=\"number\" min=\"1\" step=\"1\" required\n [ngModel]=\"mobileBreakpoint\" (ngModelChange)=\"onMobileBreakpointChange($event)\"\n [attr.aria-invalid]=\"mobileBreakpointInvalid\"\n aria-describedby=\"table-responsive-width-help\" />\n <span matTextSuffix>px</span>\n </mat-form-field>\n @if (mobileBreakpointInvalid) {\n <p class=\"responsive-settings__error\" role=\"alert\">{{ tx('overview.responsive.invalidWidth', 'Enter a positive whole number.') }}</p>\n }\n <p id=\"table-responsive-width-help\" class=\"responsive-settings__hint\">{{ tx('overview.responsive.widthHint', 'Uses the smaller width of the screen and the table area. Default: 768 px.') }}</p>\n <p class=\"responsive-settings__hint\">{{ tx('overview.responsive.virtualizationHint', 'Cards require standard rows. With virtual scrolling enabled, records remain in a table.') }}</p>\n }\n </section>\n <div class=\"overview-row\">\n <mat-form-field appearance=\"outline\" class=\"hs-field\">\n <mat-label>{{ tx('overview.horizontalScroll', 'Horizontal scroll') }}</mat-label>\n <mat-select [(ngModel)]=\"horizontalScroll\" (ngModelChange)=\"onHorizontalScrollChange($event)\">\n <mat-option value=\"auto\">{{ tx('overview.horizontalScroll.auto', 'Auto (default)') }}</mat-option>\n <mat-option value=\"wrap\">{{ tx('overview.horizontalScroll.wrap', 'Wrap') }}</mat-option>\n <mat-option value=\"none\">{{ tx('overview.horizontalScroll.none', 'Host controls') }}</mat-option>\n </mat-select>\n </mat-form-field>\n <div class=\"help small\">{{ tx('overview.horizontalScroll.help', 'Controls how the table handles horizontal width and scrollbar behavior.') }}</div>\n </div>\n @if (isEffectiveLocalMode()) { <div class=\"alert alert--info overview-mode-alert\">\n <mat-icon class=\"alert__icon\">info</mat-icon>\n <div class=\"alert__text\">\n {{ tx('overview.localModeActive', 'Effective local mode is active: server pagination and sorting strategies are blocked and persisted as client mode.') }}\n </div>\n </div> }\n <behavior-config-editor\n [config]=\"editedConfig\"\n [resourcePath]=\"resourcePath\"\n [forceClientStrategies]=\"isEffectiveLocalMode()\"\n (configChange)=\"onBehaviorConfigChange($event)\"\n (behaviorChange)=\"onBehaviorChange($event)\"\n ></behavior-config-editor>\n </div>\n }\n @case ('columns') {\n <columns-config-editor\n [config]=\"editedConfig\"\n [fieldMetadata]=\"getColumnAuthoringMetas()\"\n (configChange)=\"onColumnsConfigChange($event)\"\n (columnChange)=\"onColumnChange($event)\"\n ></columns-config-editor>\n }\n @case ('detail') {\n <praxis-table-detail-editor [config]=\"editedConfig\"\n (configChange)=\"onDetailConfigChange($event)\"\n (draftStateChange)=\"onDetailDraftStateChange($event)\"\n ></praxis-table-detail-editor>\n }\n @case ('rules') {\n <table-rules-editor\n [config]=\"editedConfig\"\n [resourcePath]=\"resourcePath\"\n (configChange)=\"onRulesConfigChange($event)\"\n ></table-rules-editor>\n }\n @case ('header') {\n <header-appearance-editor\n [config]=\"editedConfig\"\n (configChange)=\"onColumnsConfigChange($event)\"\n ></header-appearance-editor>\n }\n @case ('toolbar') {\n <toolbar-actions-editor\n [config]=\"editedConfig\"\n (configChange)=\"onToolbarActionsConfigChange($event)\"\n (toolbarActionsChange)=\"onToolbarActionsChange($event)\"\n (validationChange)=\"onSurfaceDraftValidationChange($event)\"\n ></toolbar-actions-editor>\n }\n <!-- Aba extra para integra\u00E7\u00F5es CRUD (vis\u00EDvel quando em contexto CRUD) -->\n @case ('crud') {\n <crud-integration-editor\n #crudEditorRef\n [tableId]=\"crudContext?.tableId || 'default'\"\n [crudContext]=\"crudContext\"\n [componentKeyId]=\"crudContext?.componentKeyId\"\n ></crud-integration-editor>\n }\n @case ('filters') {\n <div class=\"filters-authoring-stack\">\n <section\n class=\"responsive-settings toolbar-filters-region\"\n data-testid=\"table-unified-filter-region-section\"\n aria-labelledby=\"table-unified-filter-region-title\"\n >\n <div class=\"responsive-settings__heading\">\n <mat-icon aria-hidden=\"true\">filter_list</mat-icon>\n <h3 id=\"table-unified-filter-region-title\">\n {{ tx('filters.region.title', 'Regi\u00E3o \u00FAnica de filtros e escopos da toolbar') }}\n </h3>\n </div>\n <p class=\"responsive-settings__hint\">\n {{\n tx(\n 'filters.region.description',\n 'Centralize escopos r\u00E1pidos (Todos / Ativos / Inativos), busca e gaveta avan\u00E7ada na toolbar da tabela sem controles duplicados.'\n )\n }}\n </p>\n\n <div class=\"toolbar-filters-toggles\">\n <mat-form-field appearance=\"outline\" subscriptSizing=\"dynamic\">\n <mat-label>{{ tx('filters.region.enabled', 'Regi\u00E3o de filtros na toolbar') }}</mat-label>\n <mat-select\n [ngModel]=\"toolbarFiltersEnabled\"\n (ngModelChange)=\"onToolbarFiltersEnabledChange($event)\"\n data-testid=\"table-toolbar-filters-enabled-select\"\n >\n <mat-option [value]=\"true\">{{ tx('common.enabled', 'Ativada') }}</mat-option>\n <mat-option [value]=\"false\">{{ tx('common.disabled', 'Desativada') }}</mat-option>\n </mat-select>\n </mat-form-field>\n\n <mat-form-field appearance=\"outline\" subscriptSizing=\"dynamic\">\n <mat-label>{{ tx('filters.region.showQuickFilters', 'Exibir escopos r\u00E1pidos') }}</mat-label>\n <mat-select\n [ngModel]=\"toolbarShowQuickFilters\"\n (ngModelChange)=\"onToolbarShowQuickFiltersChange($event)\"\n data-testid=\"table-toolbar-show-quick-filters-select\"\n >\n <mat-option [value]=\"true\">{{ tx('common.yes', 'Sim') }}</mat-option>\n <mat-option [value]=\"false\">{{ tx('common.no', 'N\u00E3o') }}</mat-option>\n </mat-select>\n </mat-form-field>\n\n <mat-form-field appearance=\"outline\" subscriptSizing=\"dynamic\">\n <mat-label>{{ tx('filters.region.showAdvancedButton', 'Bot\u00E3o de gaveta avan\u00E7ada') }}</mat-label>\n <mat-select\n [ngModel]=\"toolbarShowAdvancedButton\"\n (ngModelChange)=\"onToolbarShowAdvancedButtonChange($event)\"\n data-testid=\"table-toolbar-show-advanced-button-select\"\n >\n <mat-option [value]=\"true\">{{ tx('common.yes', 'Sim') }}</mat-option>\n <mat-option [value]=\"false\">{{ tx('common.no', 'N\u00E3o') }}</mat-option>\n </mat-select>\n </mat-form-field>\n\n <mat-form-field appearance=\"outline\" subscriptSizing=\"dynamic\">\n <mat-label>{{ tx('filters.region.showAddButton', 'Bot\u00E3o \"Gerenciar campos\"') }}</mat-label>\n <mat-select\n [ngModel]=\"advancedFilterShowAddButton\"\n (ngModelChange)=\"onAdvancedFilterShowAddButtonChange($event)\"\n data-testid=\"table-toolbar-show-add-button-select\"\n >\n <mat-option [value]=\"true\">{{ tx('common.yes', 'Sim') }}</mat-option>\n <mat-option [value]=\"false\">{{ tx('common.no', 'N\u00E3o') }}</mat-option>\n </mat-select>\n </mat-form-field>\n\n <mat-form-field appearance=\"outline\" subscriptSizing=\"dynamic\">\n <mat-label>{{ tx('filters.region.showFilterSettings', 'Bot\u00E3o \"Configura\u00E7\u00F5es do filtro\"') }}</mat-label>\n <mat-select\n [ngModel]=\"advancedFilterShowFilterSettings\"\n (ngModelChange)=\"onAdvancedFilterShowFilterSettingsChange($event)\"\n data-testid=\"table-toolbar-show-filter-settings-select\"\n >\n <mat-option [value]=\"true\">{{ tx('common.yes', 'Sim') }}</mat-option>\n <mat-option [value]=\"false\">{{ tx('common.no', 'N\u00E3o') }}</mat-option>\n </mat-select>\n </mat-form-field>\n </div>\n\n @if (duplicatedQuickFilterInlineFields.length > 0) {\n <div\n class=\"alert alert--warning connect-alert\"\n data-testid=\"table-filter-duplicate-scope-warning\"\n >\n <mat-icon class=\"alert__icon\">warning</mat-icon>\n <div class=\"alert__text connect-alert__text\">\n {{\n tx(\n 'filters.region.duplicateWarning',\n 'Os campos abaixo j\u00E1 possuem escopos r\u00E1pidos na toolbar e tamb\u00E9m est\u00E3o nos filtros inline:'\n )\n }}\n <strong>{{ duplicatedQuickFilterInlineFields.join(', ') }}</strong>\n </div>\n <button\n mat-stroked-button\n color=\"primary\"\n type=\"button\"\n data-testid=\"table-filter-consolidate-duplicates-btn\"\n (click)=\"consolidateDuplicateInlineFilterFields()\"\n >\n {{ tx('filters.region.consolidateBtn', 'Consolidar nos escopos r\u00E1pidos') }}\n </button>\n </div>\n }\n\n <div class=\"quick-filters-header\">\n <strong>{{ tx('filters.quickFilters.heading', 'Escopos r\u00E1pidos (quickFilters)') }}</strong>\n <div class=\"quick-filters-actions\">\n <button\n mat-stroked-button\n type=\"button\"\n data-testid=\"table-quick-filters-preset-boolean-btn\"\n (click)=\"applyBooleanQuickFilterPreset()\"\n >\n {{ tx('filters.quickFilters.presetBoolean', 'Preset Todos / Ativos / Inativos') }}\n </button>\n <button\n mat-stroked-button\n color=\"primary\"\n type=\"button\"\n data-testid=\"table-quick-filters-add-btn\"\n (click)=\"addQuickFilterScope()\"\n >\n {{ tx('filters.quickFilters.add', 'Adicionar escopo') }}\n </button>\n </div>\n </div>\n\n @if (toolbarQuickFilters.length > 0) {\n <div class=\"quick-filters-list\" data-testid=\"table-quick-filters-list\">\n @for (qf of toolbarQuickFilters; track $index; let idx = $index) {\n <div class=\"quick-filter-row\" [attr.data-testid]=\"'table-quick-filter-row-' + idx\">\n <mat-form-field appearance=\"outline\" subscriptSizing=\"dynamic\">\n <mat-label>{{ tx('filters.quickFilters.id', 'ID') }}</mat-label>\n <input\n matInput\n [ngModel]=\"qf.id\"\n (ngModelChange)=\"updateQuickFilterMeta(idx, { id: $event })\"\n [attr.data-testid]=\"'table-quick-filter-id-' + idx\"\n />\n </mat-form-field>\n\n <mat-form-field appearance=\"outline\" subscriptSizing=\"dynamic\">\n <mat-label>{{ tx('filters.quickFilters.label', 'R\u00F3tulo') }}</mat-label>\n <input\n matInput\n [ngModel]=\"qf.label\"\n (ngModelChange)=\"updateQuickFilterMeta(idx, { label: $event })\"\n [attr.data-testid]=\"'table-quick-filter-label-' + idx\"\n />\n </mat-form-field>\n\n <mat-form-field appearance=\"outline\" subscriptSizing=\"dynamic\">\n <mat-label>{{ tx('filters.quickFilters.mode', 'Tipo de escopo') }}</mat-label>\n <mat-select\n [ngModel]=\"getQuickFilterMode(qf)\"\n (ngModelChange)=\"onQuickFilterModeChange(idx, $event)\"\n [attr.data-testid]=\"'table-quick-filter-mode-' + idx\"\n >\n <mat-option value=\"all\">{{ tx('filters.quickFilters.mode.all', 'Todos (limpar filtro)') }}</mat-option>\n <mat-option value=\"boolean\">{{ tx('filters.quickFilters.mode.boolean', 'Status booleano (Sim/N\u00E3o)') }}</mat-option>\n <mat-option value=\"equals\">{{ tx('filters.quickFilters.mode.equals', 'Campo igual a valor') }}</mat-option>\n </mat-select>\n </mat-form-field>\n\n @if (getQuickFilterMode(qf) !== 'all') {\n <mat-form-field appearance=\"outline\" subscriptSizing=\"dynamic\">\n <mat-label>{{ tx('filters.quickFilters.field', 'Campo') }}</mat-label>\n <input\n matInput\n [ngModel]=\"getQuickFilterField(qf)\"\n (ngModelChange)=\"onQuickFilterFieldChange(idx, $event)\"\n [attr.data-testid]=\"'table-quick-filter-field-' + idx\"\n />\n </mat-form-field>\n\n @if (getQuickFilterMode(qf) === 'boolean') {\n <mat-form-field appearance=\"outline\" subscriptSizing=\"dynamic\">\n <mat-label>{{ tx('filters.quickFilters.value', 'Valor') }}</mat-label>\n <mat-select\n [ngModel]=\"getQuickFilterValue(qf)\"\n (ngModelChange)=\"onQuickFilterValueChange(idx, $event)\"\n [attr.data-testid]=\"'table-quick-filter-bool-value-' + idx\"\n >\n <mat-option [value]=\"true\">{{ tx('common.boolean.true', 'Verdadeiro (true)') }}</mat-option>\n <mat-option [value]=\"false\">{{ tx('common.boolean.false', 'Falso (false)') }}</mat-option>\n </mat-select>\n </mat-form-field>\n } @else {\n <mat-form-field appearance=\"outline\" subscriptSizing=\"dynamic\">\n <mat-label>{{ tx('filters.quickFilters.value', 'Valor') }}</mat-label>\n <input\n matInput\n [ngModel]=\"getQuickFilterValue(qf)\"\n (ngModelChange)=\"onQuickFilterValueChange(idx, $event)\"\n [attr.data-testid]=\"'table-quick-filter-value-' + idx\"\n />\n </mat-form-field>\n }\n }\n\n <button\n mat-stroked-button\n color=\"warn\"\n type=\"button\"\n [attr.data-testid]=\"'table-quick-filter-remove-' + idx\"\n (click)=\"removeQuickFilterScope(idx)\"\n >\n {{ tx('common.remove', 'Remover') }}\n </button>\n </div>\n }\n </div>\n }\n </section>\n\n <filter-settings\n #tableFilterSettingsRef\n [metadata]=\"getFilterSettingsMetas()\"\n [metadataSource]=\"isUsingFilterDtoMetas() ? 'filter-dto' : 'columns'\"\n [metadataLoading]=\"filterDtoMetasLoading\"\n [metadataErrorMsg]=\"filterDtoMetasErrorMsg\"\n [settings]=\"\n editedConfig.behavior?.filtering?.advancedFilters?.settings\n \"\n (settingsChange)=\"onFilterSettingsChange($event)\"\n ></filter-settings>\n </div>\n }\n @case ('messages') {\n <messages-localization-editor\n [config]=\"editedConfig\"\n (configChange)=\"onMessagesLocalizationConfigChange($event)\"\n (messagesLocalizationChange)=\"\n onMessagesLocalizationChange($event)\n \"\n ></messages-localization-editor>\n }\n @case ('dialogs') {\n <confirm-dialog-appearance-editor\n [config]=\"editedConfig\"\n (configChange)=\"onJsonConfigChange($event)\"\n ></confirm-dialog-appearance-editor>\n }\n @case ('json') {\n <json-config-editor\n [document]=\"buildJsonAuthoringDocument()\"\n (documentChange)=\"onJsonConfigChange($event)\"\n (validationChange)=\"onJsonValidationChange($event)\"\n (editorEvent)=\"onJsonEditorEvent($event)\"\n ></json-config-editor>\n }\n }\n </div>\n </mat-tab>\n }\n</mat-tab-group>\n@if (statusMessage) { <div class=\"config-editor-status\">\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\";:host{display:block;min-width:0;container:praxis-authoring-editor/inline-size}.editor-section-selector{display:none;padding:var(--pfx-spacing-2, 8px)}.editor-section-selector mat-form-field{width:100%}@container praxis-authoring-editor (max-width: 768px){.editor-section-selector{display:block}::ng-deep .config-tabs>.mat-mdc-tab-header{display:none}}.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;min-width:0;grid-template-columns:minmax(0,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}.overview-mode-alert{align-items:center}.connect-grid{display:grid;gap:12px;padding:8px;grid-template-columns:minmax(0,1fr);align-items:start}.connect-note{grid-column:1/-1;margin:0;font-size:12px;color:var(--md-sys-color-on-surface-variant)}.connect-alert{grid-column:1/-1;align-items:center}.connect-alert__text{flex:1}.connect-alert__meta{opacity:.85}.educational-card{margin-bottom:24px;background:var(--md-sys-color-surface-container-low);border-left:4px solid var(--md-sys-color-primary);flex-shrink:0}.config-editor-status{padding:12px 16px;margin-top:auto;border-top:1px solid var(--md-sys-color-outline-variant);background:var(--md-sys-color-surface-container);flex-shrink:0;position:relative}.status-text{font-size:.875rem;line-height:1.2}.status-text.error{color:var(--md-sys-color-error)}.status-text.success{color:var(--md-sys-color-primary)}@media(max-width:768px){.tab-content{padding:8px 8px 72px}.config-editor-status{padding:12px 16px}.connect-grid{grid-template-columns:1fr}.overview-grid .overview-row{grid-template-columns:1fr;align-items:start}:host{display:flex;flex-direction:column;flex:1 1 auto;min-height:0}}.responsive-settings{display:grid;grid-template-columns:minmax(0,1fr);gap:12px;min-width:0;padding:16px;border:1px solid var(--md-sys-color-outline-variant);border-radius:var(--md-sys-shape-corner-medium, 12px);background:var(--md-sys-color-surface-container-low)}.responsive-settings__heading{display:flex;align-items:center;gap:8px}.responsive-settings h3,.responsive-settings p{margin:0}.responsive-settings h3{font-size:1rem;font-weight:600}.responsive-settings p{font-size:.875rem;line-height:1.5}.responsive-settings__hint{color:var(--md-sys-color-on-surface-variant)}.responsive-settings__error{color:var(--md-sys-color-error)}.responsive-settings mat-form-field{width:100%;min-width:0}.filters-authoring-stack{display:grid;grid-template-columns:minmax(0,1fr);gap:16px}.toolbar-filters-toggles{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:12px}.quick-filters-header{display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;gap:8px}.quick-filters-actions{display:flex;flex-wrap:wrap;gap:8px}.quick-filters-list{display:grid;gap:10px}.quick-filter-row{display:grid;grid-template-columns:repeat(auto-fit,minmax(140px,1fr));align-items:center;gap:8px;padding:10px;border:1px solid var(--md-sys-color-outline-variant);border-radius:8px;background:var(--md-sys-color-surface)}\n"], dependencies: [{ kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i7.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { 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: "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.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.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { 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.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: MatAutocompleteModule }, { kind: "component", type: i17$1.MatAutocomplete, selector: "mat-autocomplete", inputs: ["aria-label", "aria-labelledby", "displayWith", "autoActiveFirstOption", "autoSelectActiveOption", "requireSelection", "panelWidth", "disableRipple", "class", "hideSingleSelectionIndicator"], outputs: ["optionSelected", "opened", "closed", "optionActivated"], exportAs: ["matAutocomplete"] }, { kind: "component", type: i4.MatOption, selector: "mat-option", inputs: ["value", "id", "disabled"], outputs: ["onSelectionChange"], exportAs: ["matOption"] }, { kind: "directive", type: i17$1.MatAutocompleteTrigger, selector: "input[matAutocomplete], textarea[matAutocomplete]", inputs: ["matAutocomplete", "matAutocompletePosition", "matAutocompleteConnectedTo", "autocomplete", "matAutocompleteDisabled"], exportAs: ["matAutocompleteTrigger"] }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i2$1.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i2$1.MatLabel, selector: "mat-label" }, { kind: "directive", type: i2$1.MatSuffix, selector: "[matSuffix], [matIconSuffix], [matTextSuffix]", inputs: ["matTextSuffix"] }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i3$1.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: i4.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: "directive", type: PraxisIconDirective, selector: "mat-icon[praxisIcon]", inputs: ["praxisIcon"] }, { kind: "component", type: JsonConfigEditorComponent, selector: "json-config-editor", inputs: ["document"], outputs: ["documentChange", "validationChange", "editorEvent"] }, { kind: "component", type: ColumnsConfigEditorComponent, selector: "columns-config-editor", inputs: ["config", "readonly", "fieldMetadata"], outputs: ["configChange", "columnChange"] }, { kind: "component", type: BehaviorConfigEditorComponent, selector: "behavior-config-editor", inputs: ["config", "resourcePath", "forceClientStrategies"], 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", "validationChange", "toolbarActionsChange"] }, { kind: "component", type: MessagesLocalizationEditorComponent, selector: "messages-localization-editor", inputs: ["config"], outputs: ["configChange", "messagesLocalizationChange"] }, { kind: "component", type: FilterSettingsComponent, selector: "filter-settings", inputs: ["metadata", "metadataSource", "metadataLoading", "metadataErrorMsg", "settings", "configKey"], outputs: ["settingsChange"] }, { kind: "component", type: CrudIntegrationEditorComponent, selector: "crud-integration-editor", inputs: ["tableId", "crudContext", "componentKeyId"] }, { 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"] }, { kind: "component", type: TableDetailEditorComponent, selector: "praxis-table-detail-editor", inputs: ["config"], outputs: ["configChange", "draftStateChange"] }] });
|
|
73894
|
+
], viewQueries: [{ propertyName: "filterSettingsEditor", first: true, predicate: ["tableFilterSettingsRef"], descendants: true }, { propertyName: "behaviorEditor", first: true, predicate: BehaviorConfigEditorComponent, descendants: true }, { propertyName: "detailEditor", first: true, predicate: TableDetailEditorComponent, descendants: true }, { propertyName: "rulesEditor", first: true, predicate: TableRulesEditorComponent, descendants: true }, { propertyName: "crudEditorSetter", first: true, predicate: ["crudEditorRef"], descendants: true }], ngImport: i0, template: "<div class=\"editor-section-selector\">\n <mat-form-field appearance=\"outline\" subscriptSizing=\"dynamic\">\n <mat-label>{{ tx('sections.selector', 'Editor section') }}</mat-label>\n <mat-select [(ngModel)]=\"activeSectionIndex\" data-testid=\"table-config-editor-sections\">\n @for (section of sections; track section.id; let index = $index) {\n <mat-option [value]=\"index\">{{ section.label }}</mat-option>\n }\n </mat-select>\n </mat-form-field>\n</div>\n<mat-tab-group [preserveContent]=\"true\" class=\"config-tabs\" [(selectedIndex)]=\"activeSectionIndex\">\n @for (section of sections; track section.id) {\n <mat-tab>\n <ng-template mat-tab-label>\n @if (section.icon) { <mat-icon [praxisIcon]=\"section.icon\"></mat-icon> }\n <span [attr.data-testid]=\"'config-tab-' + section.id\">{{ section.label }}</span>\n </ng-template>\n <div class=\"tab-content\">\n @switch (section.id) {\n @case ('connect') {\n <div class=\"connect-grid\">\n <mat-form-field appearance=\"outline\">\n <mat-label>{{ tx('connect.resource', 'Resource') }}</mat-label>\n <input matInput [(ngModel)]=\"resourcePath\" (ngModelChange)=\"onResourcePathChange($event)\" [placeholder]=\"tx('connect.resource.placeholder', 'e.g. employees')\" />\n <mat-icon matSuffix>link</mat-icon>\n </mat-form-field>\n <mat-form-field appearance=\"outline\">\n <mat-label>{{ tx('connect.primaryKey', 'Primary key') }}</mat-label>\n <input\n matInput\n [(ngModel)]=\"idField\"\n (ngModelChange)=\"onIdFieldChange($event)\"\n [matAutocomplete]=\"idFieldPicker\"\n [placeholder]=\"tx('connect.primaryKey.placeholder', 'e.g. id, uuid, code')\"\n />\n <mat-icon matSuffix>fingerprint</mat-icon>\n <mat-autocomplete\n #idFieldPicker=\"matAutocomplete\"\n (optionSelected)=\"onIdFieldOptionSelected($event.option.value)\"\n >\n @for (option of filteredIdFieldOptions; track option.name) {\n <mat-option [value]=\"option.name\">\n <span>{{ option.name }}</span>\n @if (option.label && option.label !== option.name) {\n <small> - {{ option.label }}</small>\n }\n </mat-option>\n }\n @if (filteredIdFieldOptions.length === 0) {\n <mat-option disabled>\n {{ tx('connect.primaryKey.empty', 'No matching field found.') }}\n </mat-option>\n }\n </mat-autocomplete>\n </mat-form-field>\n <p class=\"connect-note\">{{ tx('connect.note', 'Define the API resource and, when needed, the primary key.') }}</p>\n <!-- Diverg\u00EAncia: idField -->\n @if (idFieldDiverges) { <div class=\"alert alert--warning connect-alert\">\n <mat-icon class=\"alert__icon\">warning</mat-icon>\n <div class=\"alert__text connect-alert__text\">\n {{ tx('connect.serverPrimaryKeyDiverges', 'The primary key on the server differs from the current configuration.') }}\n <span class=\"connect-alert__meta\">(config: {{ idField || 'id' }} | servidor: {{ serverIdField || 'id' }})</span>\n </div>\n <button mat-stroked-button color=\"primary\" type=\"button\" (click)=\"onReconcileIdField()\">{{ tx('connect.reconcile', 'Reconcile') }}</button>\n </div> }\n <!-- Diverg\u00EAncia: serverHash -->\n @if (schemaHashDiverges) { <div class=\"alert alert--info connect-alert\">\n <mat-icon class=\"alert__icon\">info</mat-icon>\n <div class=\"alert__text connect-alert__text\">\n {{ tx('connect.schemaSnapshotDiverges', 'The saved schema snapshot differs from the current server schema.') }}\n </div>\n <button mat-stroked-button color=\"primary\" type=\"button\" (click)=\"onAcceptServerHash()\">{{ tx('connect.updateMetadata', 'Update metadata') }}</button>\n </div> }\n @if (!schemaHashDiverges && schemaSnapshotMissing) { <div class=\"alert alert--info connect-alert\">\n <mat-icon class=\"alert__icon\">info</mat-icon>\n <div class=\"alert__text connect-alert__text\">\n {{ tx('connect.schemaSnapshotMissing', 'A current schema exists on the server, but there is still no persisted snapshot for reconciliation.') }}\n </div>\n <button mat-stroked-button color=\"primary\" type=\"button\" (click)=\"onAcceptServerHash()\">{{ tx('connect.saveSnapshot', 'Save snapshot') }}</button>\n </div> }\n </div>\n }\n @case ('overview') {\n <div class=\"overview-grid\">\n <section class=\"responsive-settings\" aria-labelledby=\"table-responsive-title\">\n <div class=\"responsive-settings__heading\">\n <mat-icon aria-hidden=\"true\">devices</mat-icon>\n <h3 id=\"table-responsive-title\">{{ tx('overview.responsive.title', 'Narrow screens') }}</h3>\n </div>\n <p>{{ tx('overview.responsive.description', 'Choose how records appear when the table has less space.') }}</p>\n <mat-form-field appearance=\"outline\" subscriptSizing=\"dynamic\">\n <mat-label>{{ tx('overview.responsive.mode', 'Record layout') }}</mat-label>\n <mat-select [ngModel]=\"mobileCardMode\" (ngModelChange)=\"onMobileCardModeChange($event)\">\n <mat-option [value]=\"false\">{{ tx('overview.responsive.table', 'Table') }}</mat-option>\n <mat-option [value]=\"true\">{{ tx('overview.responsive.cards', 'Cards') }}</mat-option>\n </mat-select>\n </mat-form-field>\n @if (mobileCardMode) {\n <p class=\"responsive-settings__hint\">{{ tx('overview.responsive.cardsHint', 'Each record becomes a card with its visible columns. Selection and row actions remain available. Wider areas keep the table layout.') }}</p>\n <mat-form-field appearance=\"outline\" subscriptSizing=\"dynamic\">\n <mat-label>{{ tx('overview.responsive.breakpoint', 'Show cards at widths up to') }}</mat-label>\n <input matInput type=\"number\" min=\"1\" step=\"1\" required\n [ngModel]=\"mobileBreakpoint\" (ngModelChange)=\"onMobileBreakpointChange($event)\"\n [attr.aria-invalid]=\"mobileBreakpointInvalid\"\n aria-describedby=\"table-responsive-width-help\" />\n <span matTextSuffix>px</span>\n </mat-form-field>\n @if (mobileBreakpointInvalid) {\n <p class=\"responsive-settings__error\" role=\"alert\">{{ tx('overview.responsive.invalidWidth', 'Enter a positive whole number.') }}</p>\n }\n <p id=\"table-responsive-width-help\" class=\"responsive-settings__hint\">{{ tx('overview.responsive.widthHint', 'Uses the smaller width of the screen and the table area. Default: 768 px.') }}</p>\n <p class=\"responsive-settings__hint\">{{ tx('overview.responsive.virtualizationHint', 'Cards require standard rows. With virtual scrolling enabled, records remain in a table.') }}</p>\n }\n </section>\n <div class=\"overview-row\">\n <mat-form-field appearance=\"outline\" class=\"hs-field\">\n <mat-label>{{ tx('overview.horizontalScroll', 'Horizontal scroll') }}</mat-label>\n <mat-select [(ngModel)]=\"horizontalScroll\" (ngModelChange)=\"onHorizontalScrollChange($event)\">\n <mat-option value=\"auto\">{{ tx('overview.horizontalScroll.auto', 'Auto (default)') }}</mat-option>\n <mat-option value=\"wrap\">{{ tx('overview.horizontalScroll.wrap', 'Wrap') }}</mat-option>\n <mat-option value=\"none\">{{ tx('overview.horizontalScroll.none', 'Host controls') }}</mat-option>\n </mat-select>\n </mat-form-field>\n <div class=\"help small\">{{ tx('overview.horizontalScroll.help', 'Controls how the table handles horizontal width and scrollbar behavior.') }}</div>\n </div>\n @if (isEffectiveLocalMode()) { <div class=\"alert alert--info overview-mode-alert\">\n <mat-icon class=\"alert__icon\">info</mat-icon>\n <div class=\"alert__text\">\n {{ tx('overview.localModeActive', 'Effective local mode is active: server pagination and sorting strategies are blocked and persisted as client mode.') }}\n </div>\n </div> }\n <behavior-config-editor\n [config]=\"editedConfig\"\n [resourcePath]=\"resourcePath\"\n [forceClientStrategies]=\"isEffectiveLocalMode()\"\n (configChange)=\"onBehaviorConfigChange($event)\"\n (behaviorChange)=\"onBehaviorChange($event)\"\n ></behavior-config-editor>\n </div>\n }\n @case ('columns') {\n <columns-config-editor\n [config]=\"editedConfig\"\n [fieldMetadata]=\"getColumnAuthoringMetas()\"\n (configChange)=\"onColumnsConfigChange($event)\"\n (columnChange)=\"onColumnChange($event)\"\n ></columns-config-editor>\n }\n @case ('detail') {\n <praxis-table-detail-editor [config]=\"editedConfig\"\n (configChange)=\"onDetailConfigChange($event)\"\n (draftStateChange)=\"onDetailDraftStateChange($event)\"\n ></praxis-table-detail-editor>\n }\n @case ('rules') {\n <table-rules-editor\n [config]=\"editedConfig\"\n [resourcePath]=\"resourcePath\"\n (configChange)=\"onRulesConfigChange($event)\"\n ></table-rules-editor>\n }\n @case ('header') {\n <header-appearance-editor\n [config]=\"editedConfig\"\n (configChange)=\"onColumnsConfigChange($event)\"\n ></header-appearance-editor>\n }\n @case ('toolbar') {\n <toolbar-actions-editor\n [config]=\"editedConfig\"\n (configChange)=\"onToolbarActionsConfigChange($event)\"\n (toolbarActionsChange)=\"onToolbarActionsChange($event)\"\n (validationChange)=\"onSurfaceDraftValidationChange($event)\"\n ></toolbar-actions-editor>\n }\n <!-- Aba extra para integra\u00E7\u00F5es CRUD (vis\u00EDvel quando em contexto CRUD) -->\n @case ('crud') {\n <crud-integration-editor\n #crudEditorRef\n [tableId]=\"crudContext?.tableId || 'default'\"\n [crudContext]=\"crudContext\"\n [componentKeyId]=\"crudContext?.componentKeyId\"\n ></crud-integration-editor>\n }\n @case ('filters') {\n <div class=\"filters-authoring-stack\">\n <section\n class=\"responsive-settings toolbar-filters-region\"\n data-testid=\"table-unified-filter-region-section\"\n aria-labelledby=\"table-unified-filter-region-title\"\n >\n <div class=\"responsive-settings__heading\">\n <mat-icon aria-hidden=\"true\">filter_list</mat-icon>\n <h3 id=\"table-unified-filter-region-title\">\n {{ tx('filters.region.title', 'Regi\u00E3o \u00FAnica de filtros e escopos da toolbar') }}\n </h3>\n </div>\n <p class=\"responsive-settings__hint\">\n {{\n tx(\n 'filters.region.description',\n 'Centralize escopos r\u00E1pidos (Todos / Ativos / Inativos), busca e gaveta avan\u00E7ada na toolbar da tabela sem controles duplicados.'\n )\n }}\n </p>\n\n <div class=\"toolbar-filters-toggles\">\n <mat-form-field appearance=\"outline\" subscriptSizing=\"dynamic\">\n <mat-label>{{ tx('filters.region.enabled', 'Regi\u00E3o de filtros na toolbar') }}</mat-label>\n <mat-select\n [ngModel]=\"toolbarFiltersEnabled\"\n (ngModelChange)=\"onToolbarFiltersEnabledChange($event)\"\n data-testid=\"table-toolbar-filters-enabled-select\"\n >\n <mat-option [value]=\"true\">{{ tx('common.enabled', 'Ativada') }}</mat-option>\n <mat-option [value]=\"false\">{{ tx('common.disabled', 'Desativada') }}</mat-option>\n </mat-select>\n </mat-form-field>\n\n <mat-form-field appearance=\"outline\" subscriptSizing=\"dynamic\">\n <mat-label>{{ tx('filters.region.showQuickFilters', 'Exibir escopos r\u00E1pidos') }}</mat-label>\n <mat-select\n [ngModel]=\"toolbarShowQuickFilters\"\n (ngModelChange)=\"onToolbarShowQuickFiltersChange($event)\"\n data-testid=\"table-toolbar-show-quick-filters-select\"\n >\n <mat-option [value]=\"true\">{{ tx('common.yes', 'Sim') }}</mat-option>\n <mat-option [value]=\"false\">{{ tx('common.no', 'N\u00E3o') }}</mat-option>\n </mat-select>\n </mat-form-field>\n\n <mat-form-field appearance=\"outline\" subscriptSizing=\"dynamic\">\n <mat-label>{{ tx('filters.region.showAdvancedButton', 'Bot\u00E3o de gaveta avan\u00E7ada') }}</mat-label>\n <mat-select\n [ngModel]=\"toolbarShowAdvancedButton\"\n (ngModelChange)=\"onToolbarShowAdvancedButtonChange($event)\"\n data-testid=\"table-toolbar-show-advanced-button-select\"\n >\n <mat-option [value]=\"true\">{{ tx('common.yes', 'Sim') }}</mat-option>\n <mat-option [value]=\"false\">{{ tx('common.no', 'N\u00E3o') }}</mat-option>\n </mat-select>\n </mat-form-field>\n\n <mat-form-field appearance=\"outline\" subscriptSizing=\"dynamic\">\n <mat-label>{{ tx('filters.region.showAddButton', 'Bot\u00E3o \"Gerenciar campos\"') }}</mat-label>\n <mat-select\n [ngModel]=\"advancedFilterShowAddButton\"\n (ngModelChange)=\"onAdvancedFilterShowAddButtonChange($event)\"\n data-testid=\"table-toolbar-show-add-button-select\"\n >\n <mat-option [value]=\"true\">{{ tx('common.yes', 'Sim') }}</mat-option>\n <mat-option [value]=\"false\">{{ tx('common.no', 'N\u00E3o') }}</mat-option>\n </mat-select>\n </mat-form-field>\n\n <mat-form-field appearance=\"outline\" subscriptSizing=\"dynamic\">\n <mat-label>{{ tx('filters.region.showFilterSettings', 'Bot\u00E3o \"Configura\u00E7\u00F5es do filtro\"') }}</mat-label>\n <mat-select\n [ngModel]=\"advancedFilterShowFilterSettings\"\n (ngModelChange)=\"onAdvancedFilterShowFilterSettingsChange($event)\"\n data-testid=\"table-toolbar-show-filter-settings-select\"\n >\n <mat-option [value]=\"true\">{{ tx('common.yes', 'Sim') }}</mat-option>\n <mat-option [value]=\"false\">{{ tx('common.no', 'N\u00E3o') }}</mat-option>\n </mat-select>\n </mat-form-field>\n </div>\n\n @if (duplicatedQuickFilterInlineFields.length > 0) {\n <div\n class=\"alert alert--warning connect-alert\"\n data-testid=\"table-filter-duplicate-scope-warning\"\n >\n <mat-icon class=\"alert__icon\">warning</mat-icon>\n <div class=\"alert__text connect-alert__text\">\n {{\n tx(\n 'filters.region.duplicateWarning',\n 'Os campos abaixo j\u00E1 possuem escopos r\u00E1pidos na toolbar e tamb\u00E9m est\u00E3o nos filtros inline:'\n )\n }}\n <strong>{{ duplicatedQuickFilterInlineFields.join(', ') }}</strong>\n </div>\n <button\n mat-stroked-button\n color=\"primary\"\n type=\"button\"\n data-testid=\"table-filter-consolidate-duplicates-btn\"\n (click)=\"consolidateDuplicateInlineFilterFields()\"\n >\n {{ tx('filters.region.consolidateBtn', 'Consolidar nos escopos r\u00E1pidos') }}\n </button>\n </div>\n }\n\n <div class=\"quick-filters-header\">\n <strong>{{ tx('filters.quickFilters.heading', 'Escopos r\u00E1pidos (quickFilters)') }}</strong>\n <div class=\"quick-filters-actions\">\n <button\n mat-stroked-button\n type=\"button\"\n data-testid=\"table-quick-filters-preset-boolean-btn\"\n (click)=\"applyBooleanQuickFilterPreset()\"\n >\n {{ tx('filters.quickFilters.presetBoolean', 'Preset Todos / Ativos / Inativos') }}\n </button>\n <button\n mat-stroked-button\n color=\"primary\"\n type=\"button\"\n data-testid=\"table-quick-filters-add-btn\"\n (click)=\"addQuickFilterScope()\"\n >\n {{ tx('filters.quickFilters.add', 'Adicionar escopo') }}\n </button>\n </div>\n </div>\n\n @if (toolbarQuickFilters.length > 0) {\n <div class=\"quick-filters-list\" data-testid=\"table-quick-filters-list\">\n @for (qf of toolbarQuickFilters; track $index; let idx = $index) {\n <div class=\"quick-filter-row\" [attr.data-testid]=\"'table-quick-filter-row-' + idx\">\n <mat-form-field appearance=\"outline\" subscriptSizing=\"dynamic\">\n <mat-label>{{ tx('filters.quickFilters.id', 'ID') }}</mat-label>\n <input\n matInput\n [ngModel]=\"qf.id\"\n (ngModelChange)=\"updateQuickFilterMeta(idx, { id: $event })\"\n [attr.data-testid]=\"'table-quick-filter-id-' + idx\"\n />\n </mat-form-field>\n\n <mat-form-field appearance=\"outline\" subscriptSizing=\"dynamic\">\n <mat-label>{{ tx('filters.quickFilters.label', 'R\u00F3tulo') }}</mat-label>\n <input\n matInput\n [ngModel]=\"qf.label\"\n (ngModelChange)=\"updateQuickFilterMeta(idx, { label: $event })\"\n [attr.data-testid]=\"'table-quick-filter-label-' + idx\"\n />\n </mat-form-field>\n\n <mat-form-field appearance=\"outline\" subscriptSizing=\"dynamic\">\n <mat-label>{{ tx('filters.quickFilters.mode', 'Tipo de escopo') }}</mat-label>\n <mat-select\n [ngModel]=\"getQuickFilterMode(qf)\"\n (ngModelChange)=\"onQuickFilterModeChange(idx, $event)\"\n [attr.data-testid]=\"'table-quick-filter-mode-' + idx\"\n >\n <mat-option value=\"all\">{{ tx('filters.quickFilters.mode.all', 'Todos (limpar filtro)') }}</mat-option>\n <mat-option value=\"boolean\">{{ tx('filters.quickFilters.mode.boolean', 'Status booleano (Sim/N\u00E3o)') }}</mat-option>\n <mat-option value=\"equals\">{{ tx('filters.quickFilters.mode.equals', 'Campo igual a valor') }}</mat-option>\n </mat-select>\n </mat-form-field>\n\n @if (getQuickFilterMode(qf) !== 'all') {\n <mat-form-field appearance=\"outline\" subscriptSizing=\"dynamic\">\n <mat-label>{{ tx('filters.quickFilters.field', 'Campo') }}</mat-label>\n <input\n matInput\n [ngModel]=\"getQuickFilterField(qf)\"\n (ngModelChange)=\"onQuickFilterFieldChange(idx, $event)\"\n [attr.data-testid]=\"'table-quick-filter-field-' + idx\"\n />\n </mat-form-field>\n\n @if (getQuickFilterMode(qf) === 'boolean') {\n <mat-form-field appearance=\"outline\" subscriptSizing=\"dynamic\">\n <mat-label>{{ tx('filters.quickFilters.value', 'Valor') }}</mat-label>\n <mat-select\n [ngModel]=\"getQuickFilterValue(qf)\"\n (ngModelChange)=\"onQuickFilterValueChange(idx, $event)\"\n [attr.data-testid]=\"'table-quick-filter-bool-value-' + idx\"\n >\n <mat-option [value]=\"true\">{{ tx('common.boolean.true', 'Verdadeiro (true)') }}</mat-option>\n <mat-option [value]=\"false\">{{ tx('common.boolean.false', 'Falso (false)') }}</mat-option>\n </mat-select>\n </mat-form-field>\n } @else {\n <mat-form-field appearance=\"outline\" subscriptSizing=\"dynamic\">\n <mat-label>{{ tx('filters.quickFilters.value', 'Valor') }}</mat-label>\n <input\n matInput\n [ngModel]=\"getQuickFilterValue(qf)\"\n (ngModelChange)=\"onQuickFilterValueChange(idx, $event)\"\n [attr.data-testid]=\"'table-quick-filter-value-' + idx\"\n />\n </mat-form-field>\n }\n }\n\n <button\n mat-stroked-button\n color=\"warn\"\n type=\"button\"\n [attr.data-testid]=\"'table-quick-filter-remove-' + idx\"\n (click)=\"removeQuickFilterScope(idx)\"\n >\n {{ tx('common.remove', 'Remover') }}\n </button>\n </div>\n }\n </div>\n }\n </section>\n\n <filter-settings\n #tableFilterSettingsRef\n [metadata]=\"getFilterSettingsMetas()\"\n [metadataSource]=\"isUsingFilterDtoMetas() ? 'filter-dto' : 'columns'\"\n [metadataLoading]=\"filterDtoMetasLoading\"\n [metadataErrorMsg]=\"filterDtoMetasErrorMsg\"\n [settings]=\"\n editedConfig.behavior?.filtering?.advancedFilters?.settings\n \"\n (settingsChange)=\"onFilterSettingsChange($event)\"\n ></filter-settings>\n </div>\n }\n @case ('messages') {\n <messages-localization-editor\n [config]=\"editedConfig\"\n (configChange)=\"onMessagesLocalizationConfigChange($event)\"\n (messagesLocalizationChange)=\"\n onMessagesLocalizationChange($event)\n \"\n ></messages-localization-editor>\n }\n @case ('dialogs') {\n <confirm-dialog-appearance-editor\n [config]=\"editedConfig\"\n (configChange)=\"onJsonConfigChange($event)\"\n ></confirm-dialog-appearance-editor>\n }\n @case ('json') {\n <json-config-editor\n [document]=\"buildJsonAuthoringDocument()\"\n (documentChange)=\"onJsonConfigChange($event)\"\n (validationChange)=\"onJsonValidationChange($event)\"\n (editorEvent)=\"onJsonEditorEvent($event)\"\n ></json-config-editor>\n }\n }\n </div>\n </mat-tab>\n }\n</mat-tab-group>\n@if (statusMessage) { <div class=\"config-editor-status\">\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\";:host{display:block;min-width:0;container:praxis-authoring-editor/inline-size}.editor-section-selector{display:block;padding:var(--pfx-spacing-2, 8px)}.editor-section-selector mat-form-field{width:100%}@container praxis-authoring-editor (max-width: 768px){.editor-section-selector{display:block}::ng-deep .config-tabs>.mat-mdc-tab-header{display:none}}.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;min-width:0;grid-template-columns:minmax(0,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}.overview-mode-alert{align-items:center}.connect-grid{display:grid;gap:12px;padding:8px;grid-template-columns:minmax(0,1fr);align-items:start}.connect-note{grid-column:1/-1;margin:0;font-size:12px;color:var(--md-sys-color-on-surface-variant)}.connect-alert{grid-column:1/-1;align-items:center}.connect-alert__text{flex:1}.connect-alert__meta{opacity:.85}.educational-card{margin-bottom:24px;background:var(--md-sys-color-surface-container-low);border-left:4px solid var(--md-sys-color-primary);flex-shrink:0}.config-editor-status{padding:12px 16px;margin-top:auto;border-top:1px solid var(--md-sys-color-outline-variant);background:var(--md-sys-color-surface-container);flex-shrink:0;position:relative}.status-text{font-size:.875rem;line-height:1.2}.status-text.error{color:var(--md-sys-color-error)}.status-text.success{color:var(--md-sys-color-primary)}@media(max-width:768px){.tab-content{padding:8px 8px 72px}.config-editor-status{padding:12px 16px}.connect-grid{grid-template-columns:1fr}.overview-grid .overview-row{grid-template-columns:1fr;align-items:start}:host{display:flex;flex-direction:column;flex:1 1 auto;min-height:0}}.responsive-settings{display:grid;grid-template-columns:minmax(0,1fr);gap:12px;min-width:0;padding:16px;border:1px solid var(--md-sys-color-outline-variant);border-radius:var(--md-sys-shape-corner-medium, 12px);background:var(--md-sys-color-surface-container-low)}.responsive-settings__heading{display:flex;align-items:center;gap:8px}.responsive-settings h3,.responsive-settings p{margin:0}.responsive-settings h3{font-size:1rem;font-weight:600}.responsive-settings p{font-size:.875rem;line-height:1.5}.responsive-settings__hint{color:var(--md-sys-color-on-surface-variant)}.responsive-settings__error{color:var(--md-sys-color-error)}.responsive-settings mat-form-field{width:100%;min-width:0}.filters-authoring-stack{display:grid;grid-template-columns:minmax(0,1fr);gap:16px}.toolbar-filters-toggles{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:12px}.quick-filters-header{display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;gap:8px}.quick-filters-actions{display:flex;flex-wrap:wrap;gap:8px}.quick-filters-list{display:grid;gap:10px}.quick-filter-row{display:grid;grid-template-columns:repeat(auto-fit,minmax(140px,1fr));align-items:center;gap:8px;padding:10px;border:1px solid var(--md-sys-color-outline-variant);border-radius:8px;background:var(--md-sys-color-surface)}\n"], dependencies: [{ kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i7.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { 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: "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.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.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { 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.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: MatAutocompleteModule }, { kind: "component", type: i17$1.MatAutocomplete, selector: "mat-autocomplete", inputs: ["aria-label", "aria-labelledby", "displayWith", "autoActiveFirstOption", "autoSelectActiveOption", "requireSelection", "panelWidth", "disableRipple", "class", "hideSingleSelectionIndicator"], outputs: ["optionSelected", "opened", "closed", "optionActivated"], exportAs: ["matAutocomplete"] }, { kind: "component", type: i4.MatOption, selector: "mat-option", inputs: ["value", "id", "disabled"], outputs: ["onSelectionChange"], exportAs: ["matOption"] }, { kind: "directive", type: i17$1.MatAutocompleteTrigger, selector: "input[matAutocomplete], textarea[matAutocomplete]", inputs: ["matAutocomplete", "matAutocompletePosition", "matAutocompleteConnectedTo", "autocomplete", "matAutocompleteDisabled"], exportAs: ["matAutocompleteTrigger"] }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i2$1.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i2$1.MatLabel, selector: "mat-label" }, { kind: "directive", type: i2$1.MatSuffix, selector: "[matSuffix], [matIconSuffix], [matTextSuffix]", inputs: ["matTextSuffix"] }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i3$1.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: i4.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: "directive", type: PraxisIconDirective, selector: "mat-icon[praxisIcon]", inputs: ["praxisIcon"] }, { kind: "component", type: JsonConfigEditorComponent, selector: "json-config-editor", inputs: ["document"], outputs: ["documentChange", "validationChange", "editorEvent"] }, { kind: "component", type: ColumnsConfigEditorComponent, selector: "columns-config-editor", inputs: ["config", "readonly", "fieldMetadata"], outputs: ["configChange", "columnChange"] }, { kind: "component", type: BehaviorConfigEditorComponent, selector: "behavior-config-editor", inputs: ["config", "resourcePath", "forceClientStrategies"], 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", "validationChange", "toolbarActionsChange"] }, { kind: "component", type: MessagesLocalizationEditorComponent, selector: "messages-localization-editor", inputs: ["config"], outputs: ["configChange", "messagesLocalizationChange"] }, { kind: "component", type: FilterSettingsComponent, selector: "filter-settings", inputs: ["metadata", "metadataSource", "metadataLoading", "metadataErrorMsg", "settings", "configKey"], outputs: ["settingsChange"] }, { kind: "component", type: CrudIntegrationEditorComponent, selector: "crud-integration-editor", inputs: ["tableId", "crudContext", "componentKeyId"] }, { 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"] }, { kind: "component", type: TableDetailEditorComponent, selector: "praxis-table-detail-editor", inputs: ["config"], outputs: ["configChange", "draftStateChange"] }] });
|
|
73683
73895
|
}
|
|
73684
73896
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: PraxisTableConfigEditor, decorators: [{
|
|
73685
73897
|
type: Component,
|
|
@@ -73707,7 +73919,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
|
|
|
73707
73919
|
], providers: [
|
|
73708
73920
|
TableConfigService,
|
|
73709
73921
|
providePraxisI18nConfig(PRAXIS_TABLE_EDITOR_I18N_CONFIG),
|
|
73710
|
-
], template: "<div class=\"editor-section-selector\">\n <mat-form-field appearance=\"outline\" subscriptSizing=\"dynamic\">\n <mat-label>{{ tx('sections.selector', 'Editor section') }}</mat-label>\n <mat-select [(ngModel)]=\"activeSectionIndex\" data-testid=\"table-config-editor-sections\">\n @for (section of sections; track section.id; let index = $index) {\n <mat-option [value]=\"index\">{{ section.label }}</mat-option>\n }\n </mat-select>\n </mat-form-field>\n</div>\n<mat-tab-group [preserveContent]=\"true\" class=\"config-tabs\" [(selectedIndex)]=\"activeSectionIndex\">\n @for (section of sections; track section.id) {\n <mat-tab>\n <ng-template mat-tab-label>\n @if (section.icon) { <mat-icon [praxisIcon]=\"section.icon\"></mat-icon> }\n <span [attr.data-testid]=\"'config-tab-' + section.id\">{{ section.label }}</span>\n </ng-template>\n <div class=\"tab-content\">\n @switch (section.id) {\n @case ('connect') {\n <div class=\"connect-grid\">\n <mat-form-field appearance=\"outline\">\n <mat-label>{{ tx('connect.resource', 'Resource') }}</mat-label>\n <input matInput [(ngModel)]=\"resourcePath\" (ngModelChange)=\"onResourcePathChange($event)\" [placeholder]=\"tx('connect.resource.placeholder', 'e.g. employees')\" />\n <mat-icon matSuffix>link</mat-icon>\n </mat-form-field>\n <mat-form-field appearance=\"outline\">\n <mat-label>{{ tx('connect.primaryKey', 'Primary key') }}</mat-label>\n <input\n matInput\n [(ngModel)]=\"idField\"\n (ngModelChange)=\"onIdFieldChange($event)\"\n [matAutocomplete]=\"idFieldPicker\"\n [placeholder]=\"tx('connect.primaryKey.placeholder', 'e.g. id, uuid, code')\"\n />\n <mat-icon matSuffix>fingerprint</mat-icon>\n <mat-autocomplete\n #idFieldPicker=\"matAutocomplete\"\n (optionSelected)=\"onIdFieldOptionSelected($event.option.value)\"\n >\n @for (option of filteredIdFieldOptions; track option.name) {\n <mat-option [value]=\"option.name\">\n <span>{{ option.name }}</span>\n @if (option.label && option.label !== option.name) {\n <small> - {{ option.label }}</small>\n }\n </mat-option>\n }\n @if (filteredIdFieldOptions.length === 0) {\n <mat-option disabled>\n {{ tx('connect.primaryKey.empty', 'No matching field found.') }}\n </mat-option>\n }\n </mat-autocomplete>\n </mat-form-field>\n <p class=\"connect-note\">{{ tx('connect.note', 'Define the API resource and, when needed, the primary key.') }}</p>\n <!-- Diverg\u00EAncia: idField -->\n @if (idFieldDiverges) { <div class=\"alert alert--warning connect-alert\">\n <mat-icon class=\"alert__icon\">warning</mat-icon>\n <div class=\"alert__text connect-alert__text\">\n {{ tx('connect.serverPrimaryKeyDiverges', 'The primary key on the server differs from the current configuration.') }}\n <span class=\"connect-alert__meta\">(config: {{ idField || 'id' }} | servidor: {{ serverIdField || 'id' }})</span>\n </div>\n <button mat-stroked-button color=\"primary\" type=\"button\" (click)=\"onReconcileIdField()\">{{ tx('connect.reconcile', 'Reconcile') }}</button>\n </div> }\n <!-- Diverg\u00EAncia: serverHash -->\n @if (schemaHashDiverges) { <div class=\"alert alert--info connect-alert\">\n <mat-icon class=\"alert__icon\">info</mat-icon>\n <div class=\"alert__text connect-alert__text\">\n {{ tx('connect.schemaSnapshotDiverges', 'The saved schema snapshot differs from the current server schema.') }}\n </div>\n <button mat-stroked-button color=\"primary\" type=\"button\" (click)=\"onAcceptServerHash()\">{{ tx('connect.updateMetadata', 'Update metadata') }}</button>\n </div> }\n @if (!schemaHashDiverges && schemaSnapshotMissing) { <div class=\"alert alert--info connect-alert\">\n <mat-icon class=\"alert__icon\">info</mat-icon>\n <div class=\"alert__text connect-alert__text\">\n {{ tx('connect.schemaSnapshotMissing', 'A current schema exists on the server, but there is still no persisted snapshot for reconciliation.') }}\n </div>\n <button mat-stroked-button color=\"primary\" type=\"button\" (click)=\"onAcceptServerHash()\">{{ tx('connect.saveSnapshot', 'Save snapshot') }}</button>\n </div> }\n </div>\n }\n @case ('overview') {\n <div class=\"overview-grid\">\n <section class=\"responsive-settings\" aria-labelledby=\"table-responsive-title\">\n <div class=\"responsive-settings__heading\">\n <mat-icon aria-hidden=\"true\">devices</mat-icon>\n <h3 id=\"table-responsive-title\">{{ tx('overview.responsive.title', 'Narrow screens') }}</h3>\n </div>\n <p>{{ tx('overview.responsive.description', 'Choose how records appear when the table has less space.') }}</p>\n <mat-form-field appearance=\"outline\" subscriptSizing=\"dynamic\">\n <mat-label>{{ tx('overview.responsive.mode', 'Record layout') }}</mat-label>\n <mat-select [ngModel]=\"mobileCardMode\" (ngModelChange)=\"onMobileCardModeChange($event)\">\n <mat-option [value]=\"false\">{{ tx('overview.responsive.table', 'Table') }}</mat-option>\n <mat-option [value]=\"true\">{{ tx('overview.responsive.cards', 'Cards') }}</mat-option>\n </mat-select>\n </mat-form-field>\n @if (mobileCardMode) {\n <p class=\"responsive-settings__hint\">{{ tx('overview.responsive.cardsHint', 'Each record becomes a card with its visible columns. Selection and row actions remain available. Wider areas keep the table layout.') }}</p>\n <mat-form-field appearance=\"outline\" subscriptSizing=\"dynamic\">\n <mat-label>{{ tx('overview.responsive.breakpoint', 'Show cards at widths up to') }}</mat-label>\n <input matInput type=\"number\" min=\"1\" step=\"1\" required\n [ngModel]=\"mobileBreakpoint\" (ngModelChange)=\"onMobileBreakpointChange($event)\"\n [attr.aria-invalid]=\"mobileBreakpointInvalid\"\n aria-describedby=\"table-responsive-width-help\" />\n <span matTextSuffix>px</span>\n </mat-form-field>\n @if (mobileBreakpointInvalid) {\n <p class=\"responsive-settings__error\" role=\"alert\">{{ tx('overview.responsive.invalidWidth', 'Enter a positive whole number.') }}</p>\n }\n <p id=\"table-responsive-width-help\" class=\"responsive-settings__hint\">{{ tx('overview.responsive.widthHint', 'Uses the smaller width of the screen and the table area. Default: 768 px.') }}</p>\n <p class=\"responsive-settings__hint\">{{ tx('overview.responsive.virtualizationHint', 'Cards require standard rows. With virtual scrolling enabled, records remain in a table.') }}</p>\n }\n </section>\n <div class=\"overview-row\">\n <mat-form-field appearance=\"outline\" class=\"hs-field\">\n <mat-label>{{ tx('overview.horizontalScroll', 'Horizontal scroll') }}</mat-label>\n <mat-select [(ngModel)]=\"horizontalScroll\" (ngModelChange)=\"onHorizontalScrollChange($event)\">\n <mat-option value=\"auto\">{{ tx('overview.horizontalScroll.auto', 'Auto (default)') }}</mat-option>\n <mat-option value=\"wrap\">{{ tx('overview.horizontalScroll.wrap', 'Wrap') }}</mat-option>\n <mat-option value=\"none\">{{ tx('overview.horizontalScroll.none', 'Host controls') }}</mat-option>\n </mat-select>\n </mat-form-field>\n <div class=\"help small\">{{ tx('overview.horizontalScroll.help', 'Controls how the table handles horizontal width and scrollbar behavior.') }}</div>\n </div>\n @if (isEffectiveLocalMode()) { <div class=\"alert alert--info overview-mode-alert\">\n <mat-icon class=\"alert__icon\">info</mat-icon>\n <div class=\"alert__text\">\n {{ tx('overview.localModeActive', 'Effective local mode is active: server pagination and sorting strategies are blocked and persisted as client mode.') }}\n </div>\n </div> }\n <behavior-config-editor\n [config]=\"editedConfig\"\n [resourcePath]=\"resourcePath\"\n [forceClientStrategies]=\"isEffectiveLocalMode()\"\n (configChange)=\"onBehaviorConfigChange($event)\"\n (behaviorChange)=\"onBehaviorChange($event)\"\n ></behavior-config-editor>\n </div>\n }\n @case ('columns') {\n <columns-config-editor\n [config]=\"editedConfig\"\n [fieldMetadata]=\"getColumnAuthoringMetas()\"\n (configChange)=\"onColumnsConfigChange($event)\"\n (columnChange)=\"onColumnChange($event)\"\n ></columns-config-editor>\n }\n @case ('detail') {\n <praxis-table-detail-editor [config]=\"editedConfig\"\n (configChange)=\"onDetailConfigChange($event)\"\n (draftStateChange)=\"onDetailDraftStateChange($event)\"\n ></praxis-table-detail-editor>\n }\n @case ('rules') {\n <table-rules-editor\n [config]=\"editedConfig\"\n [resourcePath]=\"resourcePath\"\n (configChange)=\"onRulesConfigChange($event)\"\n ></table-rules-editor>\n }\n @case ('header') {\n <header-appearance-editor\n [config]=\"editedConfig\"\n (configChange)=\"onColumnsConfigChange($event)\"\n ></header-appearance-editor>\n }\n @case ('toolbar') {\n <toolbar-actions-editor\n [config]=\"editedConfig\"\n (configChange)=\"onToolbarActionsConfigChange($event)\"\n (toolbarActionsChange)=\"onToolbarActionsChange($event)\"\n (validationChange)=\"onSurfaceDraftValidationChange($event)\"\n ></toolbar-actions-editor>\n }\n <!-- Aba extra para integra\u00E7\u00F5es CRUD (vis\u00EDvel quando em contexto CRUD) -->\n @case ('crud') {\n <crud-integration-editor\n #crudEditorRef\n [tableId]=\"crudContext?.tableId || 'default'\"\n [crudContext]=\"crudContext\"\n [componentKeyId]=\"crudContext?.componentKeyId\"\n ></crud-integration-editor>\n }\n @case ('filters') {\n <div class=\"filters-authoring-stack\">\n <section\n class=\"responsive-settings toolbar-filters-region\"\n data-testid=\"table-unified-filter-region-section\"\n aria-labelledby=\"table-unified-filter-region-title\"\n >\n <div class=\"responsive-settings__heading\">\n <mat-icon aria-hidden=\"true\">filter_list</mat-icon>\n <h3 id=\"table-unified-filter-region-title\">\n {{ tx('filters.region.title', 'Regi\u00E3o \u00FAnica de filtros e escopos da toolbar') }}\n </h3>\n </div>\n <p class=\"responsive-settings__hint\">\n {{\n tx(\n 'filters.region.description',\n 'Centralize escopos r\u00E1pidos (Todos / Ativos / Inativos), busca e gaveta avan\u00E7ada na toolbar da tabela sem controles duplicados.'\n )\n }}\n </p>\n\n <div class=\"toolbar-filters-toggles\">\n <mat-form-field appearance=\"outline\" subscriptSizing=\"dynamic\">\n <mat-label>{{ tx('filters.region.enabled', 'Regi\u00E3o de filtros na toolbar') }}</mat-label>\n <mat-select\n [ngModel]=\"toolbarFiltersEnabled\"\n (ngModelChange)=\"onToolbarFiltersEnabledChange($event)\"\n data-testid=\"table-toolbar-filters-enabled-select\"\n >\n <mat-option [value]=\"true\">{{ tx('common.enabled', 'Ativada') }}</mat-option>\n <mat-option [value]=\"false\">{{ tx('common.disabled', 'Desativada') }}</mat-option>\n </mat-select>\n </mat-form-field>\n\n <mat-form-field appearance=\"outline\" subscriptSizing=\"dynamic\">\n <mat-label>{{ tx('filters.region.showQuickFilters', 'Exibir escopos r\u00E1pidos') }}</mat-label>\n <mat-select\n [ngModel]=\"toolbarShowQuickFilters\"\n (ngModelChange)=\"onToolbarShowQuickFiltersChange($event)\"\n data-testid=\"table-toolbar-show-quick-filters-select\"\n >\n <mat-option [value]=\"true\">{{ tx('common.yes', 'Sim') }}</mat-option>\n <mat-option [value]=\"false\">{{ tx('common.no', 'N\u00E3o') }}</mat-option>\n </mat-select>\n </mat-form-field>\n\n <mat-form-field appearance=\"outline\" subscriptSizing=\"dynamic\">\n <mat-label>{{ tx('filters.region.showAdvancedButton', 'Bot\u00E3o de gaveta avan\u00E7ada') }}</mat-label>\n <mat-select\n [ngModel]=\"toolbarShowAdvancedButton\"\n (ngModelChange)=\"onToolbarShowAdvancedButtonChange($event)\"\n data-testid=\"table-toolbar-show-advanced-button-select\"\n >\n <mat-option [value]=\"true\">{{ tx('common.yes', 'Sim') }}</mat-option>\n <mat-option [value]=\"false\">{{ tx('common.no', 'N\u00E3o') }}</mat-option>\n </mat-select>\n </mat-form-field>\n\n <mat-form-field appearance=\"outline\" subscriptSizing=\"dynamic\">\n <mat-label>{{ tx('filters.region.showAddButton', 'Bot\u00E3o \"Gerenciar campos\"') }}</mat-label>\n <mat-select\n [ngModel]=\"advancedFilterShowAddButton\"\n (ngModelChange)=\"onAdvancedFilterShowAddButtonChange($event)\"\n data-testid=\"table-toolbar-show-add-button-select\"\n >\n <mat-option [value]=\"true\">{{ tx('common.yes', 'Sim') }}</mat-option>\n <mat-option [value]=\"false\">{{ tx('common.no', 'N\u00E3o') }}</mat-option>\n </mat-select>\n </mat-form-field>\n\n <mat-form-field appearance=\"outline\" subscriptSizing=\"dynamic\">\n <mat-label>{{ tx('filters.region.showFilterSettings', 'Bot\u00E3o \"Configura\u00E7\u00F5es do filtro\"') }}</mat-label>\n <mat-select\n [ngModel]=\"advancedFilterShowFilterSettings\"\n (ngModelChange)=\"onAdvancedFilterShowFilterSettingsChange($event)\"\n data-testid=\"table-toolbar-show-filter-settings-select\"\n >\n <mat-option [value]=\"true\">{{ tx('common.yes', 'Sim') }}</mat-option>\n <mat-option [value]=\"false\">{{ tx('common.no', 'N\u00E3o') }}</mat-option>\n </mat-select>\n </mat-form-field>\n </div>\n\n @if (duplicatedQuickFilterInlineFields.length > 0) {\n <div\n class=\"alert alert--warning connect-alert\"\n data-testid=\"table-filter-duplicate-scope-warning\"\n >\n <mat-icon class=\"alert__icon\">warning</mat-icon>\n <div class=\"alert__text connect-alert__text\">\n {{\n tx(\n 'filters.region.duplicateWarning',\n 'Os campos abaixo j\u00E1 possuem escopos r\u00E1pidos na toolbar e tamb\u00E9m est\u00E3o nos filtros inline:'\n )\n }}\n <strong>{{ duplicatedQuickFilterInlineFields.join(', ') }}</strong>\n </div>\n <button\n mat-stroked-button\n color=\"primary\"\n type=\"button\"\n data-testid=\"table-filter-consolidate-duplicates-btn\"\n (click)=\"consolidateDuplicateInlineFilterFields()\"\n >\n {{ tx('filters.region.consolidateBtn', 'Consolidar nos escopos r\u00E1pidos') }}\n </button>\n </div>\n }\n\n <div class=\"quick-filters-header\">\n <strong>{{ tx('filters.quickFilters.heading', 'Escopos r\u00E1pidos (quickFilters)') }}</strong>\n <div class=\"quick-filters-actions\">\n <button\n mat-stroked-button\n type=\"button\"\n data-testid=\"table-quick-filters-preset-boolean-btn\"\n (click)=\"applyBooleanQuickFilterPreset()\"\n >\n {{ tx('filters.quickFilters.presetBoolean', 'Preset Todos / Ativos / Inativos') }}\n </button>\n <button\n mat-stroked-button\n color=\"primary\"\n type=\"button\"\n data-testid=\"table-quick-filters-add-btn\"\n (click)=\"addQuickFilterScope()\"\n >\n {{ tx('filters.quickFilters.add', 'Adicionar escopo') }}\n </button>\n </div>\n </div>\n\n @if (toolbarQuickFilters.length > 0) {\n <div class=\"quick-filters-list\" data-testid=\"table-quick-filters-list\">\n @for (qf of toolbarQuickFilters; track $index; let idx = $index) {\n <div class=\"quick-filter-row\" [attr.data-testid]=\"'table-quick-filter-row-' + idx\">\n <mat-form-field appearance=\"outline\" subscriptSizing=\"dynamic\">\n <mat-label>{{ tx('filters.quickFilters.id', 'ID') }}</mat-label>\n <input\n matInput\n [ngModel]=\"qf.id\"\n (ngModelChange)=\"updateQuickFilterMeta(idx, { id: $event })\"\n [attr.data-testid]=\"'table-quick-filter-id-' + idx\"\n />\n </mat-form-field>\n\n <mat-form-field appearance=\"outline\" subscriptSizing=\"dynamic\">\n <mat-label>{{ tx('filters.quickFilters.label', 'R\u00F3tulo') }}</mat-label>\n <input\n matInput\n [ngModel]=\"qf.label\"\n (ngModelChange)=\"updateQuickFilterMeta(idx, { label: $event })\"\n [attr.data-testid]=\"'table-quick-filter-label-' + idx\"\n />\n </mat-form-field>\n\n <mat-form-field appearance=\"outline\" subscriptSizing=\"dynamic\">\n <mat-label>{{ tx('filters.quickFilters.mode', 'Tipo de escopo') }}</mat-label>\n <mat-select\n [ngModel]=\"getQuickFilterMode(qf)\"\n (ngModelChange)=\"onQuickFilterModeChange(idx, $event)\"\n [attr.data-testid]=\"'table-quick-filter-mode-' + idx\"\n >\n <mat-option value=\"all\">{{ tx('filters.quickFilters.mode.all', 'Todos (limpar filtro)') }}</mat-option>\n <mat-option value=\"boolean\">{{ tx('filters.quickFilters.mode.boolean', 'Status booleano (Sim/N\u00E3o)') }}</mat-option>\n <mat-option value=\"equals\">{{ tx('filters.quickFilters.mode.equals', 'Campo igual a valor') }}</mat-option>\n </mat-select>\n </mat-form-field>\n\n @if (getQuickFilterMode(qf) !== 'all') {\n <mat-form-field appearance=\"outline\" subscriptSizing=\"dynamic\">\n <mat-label>{{ tx('filters.quickFilters.field', 'Campo') }}</mat-label>\n <input\n matInput\n [ngModel]=\"getQuickFilterField(qf)\"\n (ngModelChange)=\"onQuickFilterFieldChange(idx, $event)\"\n [attr.data-testid]=\"'table-quick-filter-field-' + idx\"\n />\n </mat-form-field>\n\n @if (getQuickFilterMode(qf) === 'boolean') {\n <mat-form-field appearance=\"outline\" subscriptSizing=\"dynamic\">\n <mat-label>{{ tx('filters.quickFilters.value', 'Valor') }}</mat-label>\n <mat-select\n [ngModel]=\"getQuickFilterValue(qf)\"\n (ngModelChange)=\"onQuickFilterValueChange(idx, $event)\"\n [attr.data-testid]=\"'table-quick-filter-bool-value-' + idx\"\n >\n <mat-option [value]=\"true\">{{ tx('common.boolean.true', 'Verdadeiro (true)') }}</mat-option>\n <mat-option [value]=\"false\">{{ tx('common.boolean.false', 'Falso (false)') }}</mat-option>\n </mat-select>\n </mat-form-field>\n } @else {\n <mat-form-field appearance=\"outline\" subscriptSizing=\"dynamic\">\n <mat-label>{{ tx('filters.quickFilters.value', 'Valor') }}</mat-label>\n <input\n matInput\n [ngModel]=\"getQuickFilterValue(qf)\"\n (ngModelChange)=\"onQuickFilterValueChange(idx, $event)\"\n [attr.data-testid]=\"'table-quick-filter-value-' + idx\"\n />\n </mat-form-field>\n }\n }\n\n <button\n mat-stroked-button\n color=\"warn\"\n type=\"button\"\n [attr.data-testid]=\"'table-quick-filter-remove-' + idx\"\n (click)=\"removeQuickFilterScope(idx)\"\n >\n {{ tx('common.remove', 'Remover') }}\n </button>\n </div>\n }\n </div>\n }\n </section>\n\n <filter-settings\n #tableFilterSettingsRef\n [metadata]=\"getFilterSettingsMetas()\"\n [metadataSource]=\"isUsingFilterDtoMetas() ? 'filter-dto' : 'columns'\"\n [metadataLoading]=\"filterDtoMetasLoading\"\n [metadataErrorMsg]=\"filterDtoMetasErrorMsg\"\n [settings]=\"\n editedConfig.behavior?.filtering?.advancedFilters?.settings\n \"\n (settingsChange)=\"onFilterSettingsChange($event)\"\n ></filter-settings>\n </div>\n }\n @case ('messages') {\n <messages-localization-editor\n [config]=\"editedConfig\"\n (configChange)=\"onMessagesLocalizationConfigChange($event)\"\n (messagesLocalizationChange)=\"\n onMessagesLocalizationChange($event)\n \"\n ></messages-localization-editor>\n }\n @case ('dialogs') {\n <confirm-dialog-appearance-editor\n [config]=\"editedConfig\"\n (configChange)=\"onJsonConfigChange($event)\"\n ></confirm-dialog-appearance-editor>\n }\n @case ('json') {\n <json-config-editor\n [document]=\"buildJsonAuthoringDocument()\"\n (documentChange)=\"onJsonConfigChange($event)\"\n (validationChange)=\"onJsonValidationChange($event)\"\n (editorEvent)=\"onJsonEditorEvent($event)\"\n ></json-config-editor>\n }\n }\n </div>\n </mat-tab>\n }\n</mat-tab-group>\n@if (statusMessage) { <div class=\"config-editor-status\">\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\";:host{display:block;min-width:0;container:praxis-authoring-editor/inline-size}.editor-section-selector{display:none;padding:var(--pfx-spacing-2, 8px)}.editor-section-selector mat-form-field{width:100%}@container praxis-authoring-editor (max-width: 768px){.editor-section-selector{display:block}::ng-deep .config-tabs>.mat-mdc-tab-header{display:none}}.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;min-width:0;grid-template-columns:minmax(0,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}.overview-mode-alert{align-items:center}.connect-grid{display:grid;gap:12px;padding:8px;grid-template-columns:minmax(0,1fr);align-items:start}.connect-note{grid-column:1/-1;margin:0;font-size:12px;color:var(--md-sys-color-on-surface-variant)}.connect-alert{grid-column:1/-1;align-items:center}.connect-alert__text{flex:1}.connect-alert__meta{opacity:.85}.educational-card{margin-bottom:24px;background:var(--md-sys-color-surface-container-low);border-left:4px solid var(--md-sys-color-primary);flex-shrink:0}.config-editor-status{padding:12px 16px;margin-top:auto;border-top:1px solid var(--md-sys-color-outline-variant);background:var(--md-sys-color-surface-container);flex-shrink:0;position:relative}.status-text{font-size:.875rem;line-height:1.2}.status-text.error{color:var(--md-sys-color-error)}.status-text.success{color:var(--md-sys-color-primary)}@media(max-width:768px){.tab-content{padding:8px 8px 72px}.config-editor-status{padding:12px 16px}.connect-grid{grid-template-columns:1fr}.overview-grid .overview-row{grid-template-columns:1fr;align-items:start}:host{display:flex;flex-direction:column;flex:1 1 auto;min-height:0}}.responsive-settings{display:grid;grid-template-columns:minmax(0,1fr);gap:12px;min-width:0;padding:16px;border:1px solid var(--md-sys-color-outline-variant);border-radius:var(--md-sys-shape-corner-medium, 12px);background:var(--md-sys-color-surface-container-low)}.responsive-settings__heading{display:flex;align-items:center;gap:8px}.responsive-settings h3,.responsive-settings p{margin:0}.responsive-settings h3{font-size:1rem;font-weight:600}.responsive-settings p{font-size:.875rem;line-height:1.5}.responsive-settings__hint{color:var(--md-sys-color-on-surface-variant)}.responsive-settings__error{color:var(--md-sys-color-error)}.responsive-settings mat-form-field{width:100%;min-width:0}.filters-authoring-stack{display:grid;grid-template-columns:minmax(0,1fr);gap:16px}.toolbar-filters-toggles{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:12px}.quick-filters-header{display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;gap:8px}.quick-filters-actions{display:flex;flex-wrap:wrap;gap:8px}.quick-filters-list{display:grid;gap:10px}.quick-filter-row{display:grid;grid-template-columns:repeat(auto-fit,minmax(140px,1fr));align-items:center;gap:8px;padding:10px;border:1px solid var(--md-sys-color-outline-variant);border-radius:8px;background:var(--md-sys-color-surface)}\n"] }]
|
|
73922
|
+
], template: "<div class=\"editor-section-selector\">\n <mat-form-field appearance=\"outline\" subscriptSizing=\"dynamic\">\n <mat-label>{{ tx('sections.selector', 'Editor section') }}</mat-label>\n <mat-select [(ngModel)]=\"activeSectionIndex\" data-testid=\"table-config-editor-sections\">\n @for (section of sections; track section.id; let index = $index) {\n <mat-option [value]=\"index\">{{ section.label }}</mat-option>\n }\n </mat-select>\n </mat-form-field>\n</div>\n<mat-tab-group [preserveContent]=\"true\" class=\"config-tabs\" [(selectedIndex)]=\"activeSectionIndex\">\n @for (section of sections; track section.id) {\n <mat-tab>\n <ng-template mat-tab-label>\n @if (section.icon) { <mat-icon [praxisIcon]=\"section.icon\"></mat-icon> }\n <span [attr.data-testid]=\"'config-tab-' + section.id\">{{ section.label }}</span>\n </ng-template>\n <div class=\"tab-content\">\n @switch (section.id) {\n @case ('connect') {\n <div class=\"connect-grid\">\n <mat-form-field appearance=\"outline\">\n <mat-label>{{ tx('connect.resource', 'Resource') }}</mat-label>\n <input matInput [(ngModel)]=\"resourcePath\" (ngModelChange)=\"onResourcePathChange($event)\" [placeholder]=\"tx('connect.resource.placeholder', 'e.g. employees')\" />\n <mat-icon matSuffix>link</mat-icon>\n </mat-form-field>\n <mat-form-field appearance=\"outline\">\n <mat-label>{{ tx('connect.primaryKey', 'Primary key') }}</mat-label>\n <input\n matInput\n [(ngModel)]=\"idField\"\n (ngModelChange)=\"onIdFieldChange($event)\"\n [matAutocomplete]=\"idFieldPicker\"\n [placeholder]=\"tx('connect.primaryKey.placeholder', 'e.g. id, uuid, code')\"\n />\n <mat-icon matSuffix>fingerprint</mat-icon>\n <mat-autocomplete\n #idFieldPicker=\"matAutocomplete\"\n (optionSelected)=\"onIdFieldOptionSelected($event.option.value)\"\n >\n @for (option of filteredIdFieldOptions; track option.name) {\n <mat-option [value]=\"option.name\">\n <span>{{ option.name }}</span>\n @if (option.label && option.label !== option.name) {\n <small> - {{ option.label }}</small>\n }\n </mat-option>\n }\n @if (filteredIdFieldOptions.length === 0) {\n <mat-option disabled>\n {{ tx('connect.primaryKey.empty', 'No matching field found.') }}\n </mat-option>\n }\n </mat-autocomplete>\n </mat-form-field>\n <p class=\"connect-note\">{{ tx('connect.note', 'Define the API resource and, when needed, the primary key.') }}</p>\n <!-- Diverg\u00EAncia: idField -->\n @if (idFieldDiverges) { <div class=\"alert alert--warning connect-alert\">\n <mat-icon class=\"alert__icon\">warning</mat-icon>\n <div class=\"alert__text connect-alert__text\">\n {{ tx('connect.serverPrimaryKeyDiverges', 'The primary key on the server differs from the current configuration.') }}\n <span class=\"connect-alert__meta\">(config: {{ idField || 'id' }} | servidor: {{ serverIdField || 'id' }})</span>\n </div>\n <button mat-stroked-button color=\"primary\" type=\"button\" (click)=\"onReconcileIdField()\">{{ tx('connect.reconcile', 'Reconcile') }}</button>\n </div> }\n <!-- Diverg\u00EAncia: serverHash -->\n @if (schemaHashDiverges) { <div class=\"alert alert--info connect-alert\">\n <mat-icon class=\"alert__icon\">info</mat-icon>\n <div class=\"alert__text connect-alert__text\">\n {{ tx('connect.schemaSnapshotDiverges', 'The saved schema snapshot differs from the current server schema.') }}\n </div>\n <button mat-stroked-button color=\"primary\" type=\"button\" (click)=\"onAcceptServerHash()\">{{ tx('connect.updateMetadata', 'Update metadata') }}</button>\n </div> }\n @if (!schemaHashDiverges && schemaSnapshotMissing) { <div class=\"alert alert--info connect-alert\">\n <mat-icon class=\"alert__icon\">info</mat-icon>\n <div class=\"alert__text connect-alert__text\">\n {{ tx('connect.schemaSnapshotMissing', 'A current schema exists on the server, but there is still no persisted snapshot for reconciliation.') }}\n </div>\n <button mat-stroked-button color=\"primary\" type=\"button\" (click)=\"onAcceptServerHash()\">{{ tx('connect.saveSnapshot', 'Save snapshot') }}</button>\n </div> }\n </div>\n }\n @case ('overview') {\n <div class=\"overview-grid\">\n <section class=\"responsive-settings\" aria-labelledby=\"table-responsive-title\">\n <div class=\"responsive-settings__heading\">\n <mat-icon aria-hidden=\"true\">devices</mat-icon>\n <h3 id=\"table-responsive-title\">{{ tx('overview.responsive.title', 'Narrow screens') }}</h3>\n </div>\n <p>{{ tx('overview.responsive.description', 'Choose how records appear when the table has less space.') }}</p>\n <mat-form-field appearance=\"outline\" subscriptSizing=\"dynamic\">\n <mat-label>{{ tx('overview.responsive.mode', 'Record layout') }}</mat-label>\n <mat-select [ngModel]=\"mobileCardMode\" (ngModelChange)=\"onMobileCardModeChange($event)\">\n <mat-option [value]=\"false\">{{ tx('overview.responsive.table', 'Table') }}</mat-option>\n <mat-option [value]=\"true\">{{ tx('overview.responsive.cards', 'Cards') }}</mat-option>\n </mat-select>\n </mat-form-field>\n @if (mobileCardMode) {\n <p class=\"responsive-settings__hint\">{{ tx('overview.responsive.cardsHint', 'Each record becomes a card with its visible columns. Selection and row actions remain available. Wider areas keep the table layout.') }}</p>\n <mat-form-field appearance=\"outline\" subscriptSizing=\"dynamic\">\n <mat-label>{{ tx('overview.responsive.breakpoint', 'Show cards at widths up to') }}</mat-label>\n <input matInput type=\"number\" min=\"1\" step=\"1\" required\n [ngModel]=\"mobileBreakpoint\" (ngModelChange)=\"onMobileBreakpointChange($event)\"\n [attr.aria-invalid]=\"mobileBreakpointInvalid\"\n aria-describedby=\"table-responsive-width-help\" />\n <span matTextSuffix>px</span>\n </mat-form-field>\n @if (mobileBreakpointInvalid) {\n <p class=\"responsive-settings__error\" role=\"alert\">{{ tx('overview.responsive.invalidWidth', 'Enter a positive whole number.') }}</p>\n }\n <p id=\"table-responsive-width-help\" class=\"responsive-settings__hint\">{{ tx('overview.responsive.widthHint', 'Uses the smaller width of the screen and the table area. Default: 768 px.') }}</p>\n <p class=\"responsive-settings__hint\">{{ tx('overview.responsive.virtualizationHint', 'Cards require standard rows. With virtual scrolling enabled, records remain in a table.') }}</p>\n }\n </section>\n <div class=\"overview-row\">\n <mat-form-field appearance=\"outline\" class=\"hs-field\">\n <mat-label>{{ tx('overview.horizontalScroll', 'Horizontal scroll') }}</mat-label>\n <mat-select [(ngModel)]=\"horizontalScroll\" (ngModelChange)=\"onHorizontalScrollChange($event)\">\n <mat-option value=\"auto\">{{ tx('overview.horizontalScroll.auto', 'Auto (default)') }}</mat-option>\n <mat-option value=\"wrap\">{{ tx('overview.horizontalScroll.wrap', 'Wrap') }}</mat-option>\n <mat-option value=\"none\">{{ tx('overview.horizontalScroll.none', 'Host controls') }}</mat-option>\n </mat-select>\n </mat-form-field>\n <div class=\"help small\">{{ tx('overview.horizontalScroll.help', 'Controls how the table handles horizontal width and scrollbar behavior.') }}</div>\n </div>\n @if (isEffectiveLocalMode()) { <div class=\"alert alert--info overview-mode-alert\">\n <mat-icon class=\"alert__icon\">info</mat-icon>\n <div class=\"alert__text\">\n {{ tx('overview.localModeActive', 'Effective local mode is active: server pagination and sorting strategies are blocked and persisted as client mode.') }}\n </div>\n </div> }\n <behavior-config-editor\n [config]=\"editedConfig\"\n [resourcePath]=\"resourcePath\"\n [forceClientStrategies]=\"isEffectiveLocalMode()\"\n (configChange)=\"onBehaviorConfigChange($event)\"\n (behaviorChange)=\"onBehaviorChange($event)\"\n ></behavior-config-editor>\n </div>\n }\n @case ('columns') {\n <columns-config-editor\n [config]=\"editedConfig\"\n [fieldMetadata]=\"getColumnAuthoringMetas()\"\n (configChange)=\"onColumnsConfigChange($event)\"\n (columnChange)=\"onColumnChange($event)\"\n ></columns-config-editor>\n }\n @case ('detail') {\n <praxis-table-detail-editor [config]=\"editedConfig\"\n (configChange)=\"onDetailConfigChange($event)\"\n (draftStateChange)=\"onDetailDraftStateChange($event)\"\n ></praxis-table-detail-editor>\n }\n @case ('rules') {\n <table-rules-editor\n [config]=\"editedConfig\"\n [resourcePath]=\"resourcePath\"\n (configChange)=\"onRulesConfigChange($event)\"\n ></table-rules-editor>\n }\n @case ('header') {\n <header-appearance-editor\n [config]=\"editedConfig\"\n (configChange)=\"onColumnsConfigChange($event)\"\n ></header-appearance-editor>\n }\n @case ('toolbar') {\n <toolbar-actions-editor\n [config]=\"editedConfig\"\n (configChange)=\"onToolbarActionsConfigChange($event)\"\n (toolbarActionsChange)=\"onToolbarActionsChange($event)\"\n (validationChange)=\"onSurfaceDraftValidationChange($event)\"\n ></toolbar-actions-editor>\n }\n <!-- Aba extra para integra\u00E7\u00F5es CRUD (vis\u00EDvel quando em contexto CRUD) -->\n @case ('crud') {\n <crud-integration-editor\n #crudEditorRef\n [tableId]=\"crudContext?.tableId || 'default'\"\n [crudContext]=\"crudContext\"\n [componentKeyId]=\"crudContext?.componentKeyId\"\n ></crud-integration-editor>\n }\n @case ('filters') {\n <div class=\"filters-authoring-stack\">\n <section\n class=\"responsive-settings toolbar-filters-region\"\n data-testid=\"table-unified-filter-region-section\"\n aria-labelledby=\"table-unified-filter-region-title\"\n >\n <div class=\"responsive-settings__heading\">\n <mat-icon aria-hidden=\"true\">filter_list</mat-icon>\n <h3 id=\"table-unified-filter-region-title\">\n {{ tx('filters.region.title', 'Regi\u00E3o \u00FAnica de filtros e escopos da toolbar') }}\n </h3>\n </div>\n <p class=\"responsive-settings__hint\">\n {{\n tx(\n 'filters.region.description',\n 'Centralize escopos r\u00E1pidos (Todos / Ativos / Inativos), busca e gaveta avan\u00E7ada na toolbar da tabela sem controles duplicados.'\n )\n }}\n </p>\n\n <div class=\"toolbar-filters-toggles\">\n <mat-form-field appearance=\"outline\" subscriptSizing=\"dynamic\">\n <mat-label>{{ tx('filters.region.enabled', 'Regi\u00E3o de filtros na toolbar') }}</mat-label>\n <mat-select\n [ngModel]=\"toolbarFiltersEnabled\"\n (ngModelChange)=\"onToolbarFiltersEnabledChange($event)\"\n data-testid=\"table-toolbar-filters-enabled-select\"\n >\n <mat-option [value]=\"true\">{{ tx('common.enabled', 'Ativada') }}</mat-option>\n <mat-option [value]=\"false\">{{ tx('common.disabled', 'Desativada') }}</mat-option>\n </mat-select>\n </mat-form-field>\n\n <mat-form-field appearance=\"outline\" subscriptSizing=\"dynamic\">\n <mat-label>{{ tx('filters.region.showQuickFilters', 'Exibir escopos r\u00E1pidos') }}</mat-label>\n <mat-select\n [ngModel]=\"toolbarShowQuickFilters\"\n (ngModelChange)=\"onToolbarShowQuickFiltersChange($event)\"\n data-testid=\"table-toolbar-show-quick-filters-select\"\n >\n <mat-option [value]=\"true\">{{ tx('common.yes', 'Sim') }}</mat-option>\n <mat-option [value]=\"false\">{{ tx('common.no', 'N\u00E3o') }}</mat-option>\n </mat-select>\n </mat-form-field>\n\n <mat-form-field appearance=\"outline\" subscriptSizing=\"dynamic\">\n <mat-label>{{ tx('filters.region.showAdvancedButton', 'Bot\u00E3o de gaveta avan\u00E7ada') }}</mat-label>\n <mat-select\n [ngModel]=\"toolbarShowAdvancedButton\"\n (ngModelChange)=\"onToolbarShowAdvancedButtonChange($event)\"\n data-testid=\"table-toolbar-show-advanced-button-select\"\n >\n <mat-option [value]=\"true\">{{ tx('common.yes', 'Sim') }}</mat-option>\n <mat-option [value]=\"false\">{{ tx('common.no', 'N\u00E3o') }}</mat-option>\n </mat-select>\n </mat-form-field>\n\n <mat-form-field appearance=\"outline\" subscriptSizing=\"dynamic\">\n <mat-label>{{ tx('filters.region.showAddButton', 'Bot\u00E3o \"Gerenciar campos\"') }}</mat-label>\n <mat-select\n [ngModel]=\"advancedFilterShowAddButton\"\n (ngModelChange)=\"onAdvancedFilterShowAddButtonChange($event)\"\n data-testid=\"table-toolbar-show-add-button-select\"\n >\n <mat-option [value]=\"true\">{{ tx('common.yes', 'Sim') }}</mat-option>\n <mat-option [value]=\"false\">{{ tx('common.no', 'N\u00E3o') }}</mat-option>\n </mat-select>\n </mat-form-field>\n\n <mat-form-field appearance=\"outline\" subscriptSizing=\"dynamic\">\n <mat-label>{{ tx('filters.region.showFilterSettings', 'Bot\u00E3o \"Configura\u00E7\u00F5es do filtro\"') }}</mat-label>\n <mat-select\n [ngModel]=\"advancedFilterShowFilterSettings\"\n (ngModelChange)=\"onAdvancedFilterShowFilterSettingsChange($event)\"\n data-testid=\"table-toolbar-show-filter-settings-select\"\n >\n <mat-option [value]=\"true\">{{ tx('common.yes', 'Sim') }}</mat-option>\n <mat-option [value]=\"false\">{{ tx('common.no', 'N\u00E3o') }}</mat-option>\n </mat-select>\n </mat-form-field>\n </div>\n\n @if (duplicatedQuickFilterInlineFields.length > 0) {\n <div\n class=\"alert alert--warning connect-alert\"\n data-testid=\"table-filter-duplicate-scope-warning\"\n >\n <mat-icon class=\"alert__icon\">warning</mat-icon>\n <div class=\"alert__text connect-alert__text\">\n {{\n tx(\n 'filters.region.duplicateWarning',\n 'Os campos abaixo j\u00E1 possuem escopos r\u00E1pidos na toolbar e tamb\u00E9m est\u00E3o nos filtros inline:'\n )\n }}\n <strong>{{ duplicatedQuickFilterInlineFields.join(', ') }}</strong>\n </div>\n <button\n mat-stroked-button\n color=\"primary\"\n type=\"button\"\n data-testid=\"table-filter-consolidate-duplicates-btn\"\n (click)=\"consolidateDuplicateInlineFilterFields()\"\n >\n {{ tx('filters.region.consolidateBtn', 'Consolidar nos escopos r\u00E1pidos') }}\n </button>\n </div>\n }\n\n <div class=\"quick-filters-header\">\n <strong>{{ tx('filters.quickFilters.heading', 'Escopos r\u00E1pidos (quickFilters)') }}</strong>\n <div class=\"quick-filters-actions\">\n <button\n mat-stroked-button\n type=\"button\"\n data-testid=\"table-quick-filters-preset-boolean-btn\"\n (click)=\"applyBooleanQuickFilterPreset()\"\n >\n {{ tx('filters.quickFilters.presetBoolean', 'Preset Todos / Ativos / Inativos') }}\n </button>\n <button\n mat-stroked-button\n color=\"primary\"\n type=\"button\"\n data-testid=\"table-quick-filters-add-btn\"\n (click)=\"addQuickFilterScope()\"\n >\n {{ tx('filters.quickFilters.add', 'Adicionar escopo') }}\n </button>\n </div>\n </div>\n\n @if (toolbarQuickFilters.length > 0) {\n <div class=\"quick-filters-list\" data-testid=\"table-quick-filters-list\">\n @for (qf of toolbarQuickFilters; track $index; let idx = $index) {\n <div class=\"quick-filter-row\" [attr.data-testid]=\"'table-quick-filter-row-' + idx\">\n <mat-form-field appearance=\"outline\" subscriptSizing=\"dynamic\">\n <mat-label>{{ tx('filters.quickFilters.id', 'ID') }}</mat-label>\n <input\n matInput\n [ngModel]=\"qf.id\"\n (ngModelChange)=\"updateQuickFilterMeta(idx, { id: $event })\"\n [attr.data-testid]=\"'table-quick-filter-id-' + idx\"\n />\n </mat-form-field>\n\n <mat-form-field appearance=\"outline\" subscriptSizing=\"dynamic\">\n <mat-label>{{ tx('filters.quickFilters.label', 'R\u00F3tulo') }}</mat-label>\n <input\n matInput\n [ngModel]=\"qf.label\"\n (ngModelChange)=\"updateQuickFilterMeta(idx, { label: $event })\"\n [attr.data-testid]=\"'table-quick-filter-label-' + idx\"\n />\n </mat-form-field>\n\n <mat-form-field appearance=\"outline\" subscriptSizing=\"dynamic\">\n <mat-label>{{ tx('filters.quickFilters.mode', 'Tipo de escopo') }}</mat-label>\n <mat-select\n [ngModel]=\"getQuickFilterMode(qf)\"\n (ngModelChange)=\"onQuickFilterModeChange(idx, $event)\"\n [attr.data-testid]=\"'table-quick-filter-mode-' + idx\"\n >\n <mat-option value=\"all\">{{ tx('filters.quickFilters.mode.all', 'Todos (limpar filtro)') }}</mat-option>\n <mat-option value=\"boolean\">{{ tx('filters.quickFilters.mode.boolean', 'Status booleano (Sim/N\u00E3o)') }}</mat-option>\n <mat-option value=\"equals\">{{ tx('filters.quickFilters.mode.equals', 'Campo igual a valor') }}</mat-option>\n </mat-select>\n </mat-form-field>\n\n @if (getQuickFilterMode(qf) !== 'all') {\n <mat-form-field appearance=\"outline\" subscriptSizing=\"dynamic\">\n <mat-label>{{ tx('filters.quickFilters.field', 'Campo') }}</mat-label>\n <input\n matInput\n [ngModel]=\"getQuickFilterField(qf)\"\n (ngModelChange)=\"onQuickFilterFieldChange(idx, $event)\"\n [attr.data-testid]=\"'table-quick-filter-field-' + idx\"\n />\n </mat-form-field>\n\n @if (getQuickFilterMode(qf) === 'boolean') {\n <mat-form-field appearance=\"outline\" subscriptSizing=\"dynamic\">\n <mat-label>{{ tx('filters.quickFilters.value', 'Valor') }}</mat-label>\n <mat-select\n [ngModel]=\"getQuickFilterValue(qf)\"\n (ngModelChange)=\"onQuickFilterValueChange(idx, $event)\"\n [attr.data-testid]=\"'table-quick-filter-bool-value-' + idx\"\n >\n <mat-option [value]=\"true\">{{ tx('common.boolean.true', 'Verdadeiro (true)') }}</mat-option>\n <mat-option [value]=\"false\">{{ tx('common.boolean.false', 'Falso (false)') }}</mat-option>\n </mat-select>\n </mat-form-field>\n } @else {\n <mat-form-field appearance=\"outline\" subscriptSizing=\"dynamic\">\n <mat-label>{{ tx('filters.quickFilters.value', 'Valor') }}</mat-label>\n <input\n matInput\n [ngModel]=\"getQuickFilterValue(qf)\"\n (ngModelChange)=\"onQuickFilterValueChange(idx, $event)\"\n [attr.data-testid]=\"'table-quick-filter-value-' + idx\"\n />\n </mat-form-field>\n }\n }\n\n <button\n mat-stroked-button\n color=\"warn\"\n type=\"button\"\n [attr.data-testid]=\"'table-quick-filter-remove-' + idx\"\n (click)=\"removeQuickFilterScope(idx)\"\n >\n {{ tx('common.remove', 'Remover') }}\n </button>\n </div>\n }\n </div>\n }\n </section>\n\n <filter-settings\n #tableFilterSettingsRef\n [metadata]=\"getFilterSettingsMetas()\"\n [metadataSource]=\"isUsingFilterDtoMetas() ? 'filter-dto' : 'columns'\"\n [metadataLoading]=\"filterDtoMetasLoading\"\n [metadataErrorMsg]=\"filterDtoMetasErrorMsg\"\n [settings]=\"\n editedConfig.behavior?.filtering?.advancedFilters?.settings\n \"\n (settingsChange)=\"onFilterSettingsChange($event)\"\n ></filter-settings>\n </div>\n }\n @case ('messages') {\n <messages-localization-editor\n [config]=\"editedConfig\"\n (configChange)=\"onMessagesLocalizationConfigChange($event)\"\n (messagesLocalizationChange)=\"\n onMessagesLocalizationChange($event)\n \"\n ></messages-localization-editor>\n }\n @case ('dialogs') {\n <confirm-dialog-appearance-editor\n [config]=\"editedConfig\"\n (configChange)=\"onJsonConfigChange($event)\"\n ></confirm-dialog-appearance-editor>\n }\n @case ('json') {\n <json-config-editor\n [document]=\"buildJsonAuthoringDocument()\"\n (documentChange)=\"onJsonConfigChange($event)\"\n (validationChange)=\"onJsonValidationChange($event)\"\n (editorEvent)=\"onJsonEditorEvent($event)\"\n ></json-config-editor>\n }\n }\n </div>\n </mat-tab>\n }\n</mat-tab-group>\n@if (statusMessage) { <div class=\"config-editor-status\">\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\";:host{display:block;min-width:0;container:praxis-authoring-editor/inline-size}.editor-section-selector{display:block;padding:var(--pfx-spacing-2, 8px)}.editor-section-selector mat-form-field{width:100%}@container praxis-authoring-editor (max-width: 768px){.editor-section-selector{display:block}::ng-deep .config-tabs>.mat-mdc-tab-header{display:none}}.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;min-width:0;grid-template-columns:minmax(0,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}.overview-mode-alert{align-items:center}.connect-grid{display:grid;gap:12px;padding:8px;grid-template-columns:minmax(0,1fr);align-items:start}.connect-note{grid-column:1/-1;margin:0;font-size:12px;color:var(--md-sys-color-on-surface-variant)}.connect-alert{grid-column:1/-1;align-items:center}.connect-alert__text{flex:1}.connect-alert__meta{opacity:.85}.educational-card{margin-bottom:24px;background:var(--md-sys-color-surface-container-low);border-left:4px solid var(--md-sys-color-primary);flex-shrink:0}.config-editor-status{padding:12px 16px;margin-top:auto;border-top:1px solid var(--md-sys-color-outline-variant);background:var(--md-sys-color-surface-container);flex-shrink:0;position:relative}.status-text{font-size:.875rem;line-height:1.2}.status-text.error{color:var(--md-sys-color-error)}.status-text.success{color:var(--md-sys-color-primary)}@media(max-width:768px){.tab-content{padding:8px 8px 72px}.config-editor-status{padding:12px 16px}.connect-grid{grid-template-columns:1fr}.overview-grid .overview-row{grid-template-columns:1fr;align-items:start}:host{display:flex;flex-direction:column;flex:1 1 auto;min-height:0}}.responsive-settings{display:grid;grid-template-columns:minmax(0,1fr);gap:12px;min-width:0;padding:16px;border:1px solid var(--md-sys-color-outline-variant);border-radius:var(--md-sys-shape-corner-medium, 12px);background:var(--md-sys-color-surface-container-low)}.responsive-settings__heading{display:flex;align-items:center;gap:8px}.responsive-settings h3,.responsive-settings p{margin:0}.responsive-settings h3{font-size:1rem;font-weight:600}.responsive-settings p{font-size:.875rem;line-height:1.5}.responsive-settings__hint{color:var(--md-sys-color-on-surface-variant)}.responsive-settings__error{color:var(--md-sys-color-error)}.responsive-settings mat-form-field{width:100%;min-width:0}.filters-authoring-stack{display:grid;grid-template-columns:minmax(0,1fr);gap:16px}.toolbar-filters-toggles{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:12px}.quick-filters-header{display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;gap:8px}.quick-filters-actions{display:flex;flex-wrap:wrap;gap:8px}.quick-filters-list{display:grid;gap:10px}.quick-filter-row{display:grid;grid-template-columns:repeat(auto-fit,minmax(140px,1fr));align-items:center;gap:8px;padding:10px;border:1px solid var(--md-sys-color-outline-variant);border-radius:8px;background:var(--md-sys-color-surface)}\n"] }]
|
|
73711
73923
|
}], ctorParameters: () => [{ type: i0.ChangeDetectorRef }, { type: i1.TableConfigService }], propDecorators: { filterSettingsEditor: [{
|
|
73712
73924
|
type: ViewChild,
|
|
73713
73925
|
args: ['tableFilterSettingsRef']
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Observable, firstValueFrom } from 'rxjs';
|
|
2
2
|
import { withAuthoringScopePolicy } from '@praxisui/ai';
|
|
3
|
-
import { ar as setTableActionGlobalActionRef } from './praxisui-table-praxisui-table-
|
|
3
|
+
import { ar as setTableActionGlobalActionRef } from './praxisui-table-praxisui-table-CWOg6JDN.mjs';
|
|
4
4
|
|
|
5
5
|
class TableAgenticAuthoringTurnFlow {
|
|
6
6
|
adapter;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { firstValueFrom } from 'rxjs';
|
|
2
2
|
import { BaseAiAdapter, sanitizePraxisAssistantText, createComponentAuthoringContext } from '@praxisui/ai';
|
|
3
3
|
import { PRAXIS_GLOBAL_ACTION_CATALOG, deepMerge } from '@praxisui/core';
|
|
4
|
-
import { W as TABLE_COMPONENT_EDIT_PLAN_OPERATION_IDS, p as PRAXIS_TABLE_AUTHORING_MANIFEST, T as TABLE_AI_CAPABILITIES, a6 as coerceTableComponentEditPlans, a8 as compileTableComponentEditPlans, Y as TASK_PRESETS, ae as getTableComponentEditPlanCapabilities, R as TABLE_COMPONENT_EDIT_PLAN_EXPECTED_PATHS, O as TABLE_COMPONENT_EDIT_PLAN_ALLOWED_CHANGE_KINDS, U as TABLE_COMPONENT_EDIT_PLAN_JSON_SCHEMA, X as TABLE_COMPONENT_EDIT_PLAN_VERSION, Q as TABLE_COMPONENT_EDIT_PLAN_BATCH_KIND, V as TABLE_COMPONENT_EDIT_PLAN_KIND } from './praxisui-table-praxisui-table-
|
|
4
|
+
import { W as TABLE_COMPONENT_EDIT_PLAN_OPERATION_IDS, p as PRAXIS_TABLE_AUTHORING_MANIFEST, T as TABLE_AI_CAPABILITIES, a6 as coerceTableComponentEditPlans, a8 as compileTableComponentEditPlans, Y as TASK_PRESETS, ae as getTableComponentEditPlanCapabilities, R as TABLE_COMPONENT_EDIT_PLAN_EXPECTED_PATHS, O as TABLE_COMPONENT_EDIT_PLAN_ALLOWED_CHANGE_KINDS, U as TABLE_COMPONENT_EDIT_PLAN_JSON_SCHEMA, X as TABLE_COMPONENT_EDIT_PLAN_VERSION, Q as TABLE_COMPONENT_EDIT_PLAN_BATCH_KIND, V as TABLE_COMPONENT_EDIT_PLAN_KIND } from './praxisui-table-praxisui-table-CWOg6JDN.mjs';
|
|
5
5
|
|
|
6
6
|
const TABLE_ROW_EXPRESSION_CONTEXT_OPTION = {
|
|
7
7
|
mode: 'expression',
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { A as ANALYTICS_TABLE_ROW_KEY_FIELD, a as AnalyticalDrawerRegistryService, b as AnalyticsTableConfigAdapterService, c as AnalyticsTableContractService, d as AnalyticsTableStatsApiService, B as BOOLEAN_PRESETS, e as BehaviorConfigEditorComponent, C as CURRENCY_PRESETS, f as ColumnsConfigEditorComponent, D as DATE_PRESETS, g as DataFormatterComponent, h as DataFormattingService, F as FORMULA_TEMPLATES, i as FilterConfigService, j as FilterSettingsComponent, k as FormulaGeneratorService, J as JsonConfigEditorComponent, M as MessagesLocalizationEditorComponent, N as NUMBER_PRESETS, P as PERCENTAGE_PRESETS, l as PRAXIS_ANALYTICAL_DRAWER_SCHEMAS, m as PRAXIS_FILTER_AUTHORING_MANIFEST, n as PRAXIS_FILTER_COMPONENT_METADATA, o as PRAXIS_FILTER_VIEW_CONTEXT_SCHEMA_VERSION, p as PRAXIS_TABLE_AUTHORING_MANIFEST, q as PRAXIS_TABLE_COMPONENT_METADATA, r as PRAXIS_TABLE_TOOLBAR_APPEARANCE_PRESETS, s as PRAXIS_TABLE_TOOLBAR_DEFAULT_APPEARANCE, t as PRAXIS_TABLE_TOOLBAR_TOKEN_PRESETS, u as PraxisAnalyticalDrawerComponent, v as PraxisFilter, w as PraxisFilterOutletComponent, x as PraxisFilterOutletDirective, y as PraxisFilterWidgetConfigEditor, z as PraxisScopeBarComponent, E as PraxisTable, G as PraxisTableConfigEditor, H as PraxisTableInlineAuthoringEditorComponent, I as PraxisTableToolbar, K as PraxisTableWidgetConfigEditor, S as STRING_PRESETS, T as TABLE_AI_CAPABILITIES, L as TABLE_COMPONENT_AI_CAPABILITIES, O as TABLE_COMPONENT_EDIT_PLAN_ALLOWED_CHANGE_KINDS, Q as TABLE_COMPONENT_EDIT_PLAN_BATCH_KIND, R as TABLE_COMPONENT_EDIT_PLAN_EXPECTED_PATHS, U as TABLE_COMPONENT_EDIT_PLAN_JSON_SCHEMA, V as TABLE_COMPONENT_EDIT_PLAN_KIND, X as TABLE_COMPONENT_EDIT_PLAN_VERSION, Y as TASK_PRESETS, Z as TableDefaultsProvider, _ as TableRulesEditorComponent, $ as ToolbarActionsEditorComponent, a0 as ValueMappingEditorComponent, a1 as VisualFormulaBuilderComponent, a2 as analyticsComparisonMetricField, a3 as applyComputedFieldsToRows, a4 as buildTableApplyPlan, a5 as coerceTableComponentEditPlan, a6 as coerceTableComponentEditPlans, a7 as compileTableComponentEditPlan, a8 as compileTableComponentEditPlans, a9 as createTableAuthoringDocument, aa as formatComputedFieldValue, ab as getActionId, ac as getEnum, ad as getTableCapabilities, ae as getTableComponentEditPlanCapabilities, af as interpolateRelationEndpoint, ag as isAnalyticalDrawerSchema, ah as isTableRendererSupportedByRichContentP0, ai as mapTableRendererToRichContentP0, aj as normalizeComputedFieldDefinition, ak as normalizeTableAuthoringDocument, al as parseLegacyOrTableDocument, am as providePraxisAnalyticalDrawerSchemas, an as providePraxisFilterMetadata, ao as providePraxisTableMetadata, ap as providePraxisTableToolbarAppearance, aq as serializeTableAuthoringDocument, as as toCanonicalTableConfig, at as validateTableAuthoringDocument } from './praxisui-table-praxisui-table-
|
|
1
|
+
export { A as ANALYTICS_TABLE_ROW_KEY_FIELD, a as AnalyticalDrawerRegistryService, b as AnalyticsTableConfigAdapterService, c as AnalyticsTableContractService, d as AnalyticsTableStatsApiService, B as BOOLEAN_PRESETS, e as BehaviorConfigEditorComponent, C as CURRENCY_PRESETS, f as ColumnsConfigEditorComponent, D as DATE_PRESETS, g as DataFormatterComponent, h as DataFormattingService, F as FORMULA_TEMPLATES, i as FilterConfigService, j as FilterSettingsComponent, k as FormulaGeneratorService, J as JsonConfigEditorComponent, M as MessagesLocalizationEditorComponent, N as NUMBER_PRESETS, P as PERCENTAGE_PRESETS, l as PRAXIS_ANALYTICAL_DRAWER_SCHEMAS, m as PRAXIS_FILTER_AUTHORING_MANIFEST, n as PRAXIS_FILTER_COMPONENT_METADATA, o as PRAXIS_FILTER_VIEW_CONTEXT_SCHEMA_VERSION, p as PRAXIS_TABLE_AUTHORING_MANIFEST, q as PRAXIS_TABLE_COMPONENT_METADATA, r as PRAXIS_TABLE_TOOLBAR_APPEARANCE_PRESETS, s as PRAXIS_TABLE_TOOLBAR_DEFAULT_APPEARANCE, t as PRAXIS_TABLE_TOOLBAR_TOKEN_PRESETS, u as PraxisAnalyticalDrawerComponent, v as PraxisFilter, w as PraxisFilterOutletComponent, x as PraxisFilterOutletDirective, y as PraxisFilterWidgetConfigEditor, z as PraxisScopeBarComponent, E as PraxisTable, G as PraxisTableConfigEditor, H as PraxisTableInlineAuthoringEditorComponent, I as PraxisTableToolbar, K as PraxisTableWidgetConfigEditor, S as STRING_PRESETS, T as TABLE_AI_CAPABILITIES, L as TABLE_COMPONENT_AI_CAPABILITIES, O as TABLE_COMPONENT_EDIT_PLAN_ALLOWED_CHANGE_KINDS, Q as TABLE_COMPONENT_EDIT_PLAN_BATCH_KIND, R as TABLE_COMPONENT_EDIT_PLAN_EXPECTED_PATHS, U as TABLE_COMPONENT_EDIT_PLAN_JSON_SCHEMA, V as TABLE_COMPONENT_EDIT_PLAN_KIND, X as TABLE_COMPONENT_EDIT_PLAN_VERSION, Y as TASK_PRESETS, Z as TableDefaultsProvider, _ as TableRulesEditorComponent, $ as ToolbarActionsEditorComponent, a0 as ValueMappingEditorComponent, a1 as VisualFormulaBuilderComponent, a2 as analyticsComparisonMetricField, a3 as applyComputedFieldsToRows, a4 as buildTableApplyPlan, a5 as coerceTableComponentEditPlan, a6 as coerceTableComponentEditPlans, a7 as compileTableComponentEditPlan, a8 as compileTableComponentEditPlans, a9 as createTableAuthoringDocument, aa as formatComputedFieldValue, ab as getActionId, ac as getEnum, ad as getTableCapabilities, ae as getTableComponentEditPlanCapabilities, af as interpolateRelationEndpoint, ag as isAnalyticalDrawerSchema, ah as isTableRendererSupportedByRichContentP0, ai as mapTableRendererToRichContentP0, aj as normalizeComputedFieldDefinition, ak as normalizeTableAuthoringDocument, al as parseLegacyOrTableDocument, am as providePraxisAnalyticalDrawerSchemas, an as providePraxisFilterMetadata, ao as providePraxisTableMetadata, ap as providePraxisTableToolbarAppearance, aq as serializeTableAuthoringDocument, as as toCanonicalTableConfig, at as validateTableAuthoringDocument } from './praxisui-table-praxisui-table-CWOg6JDN.mjs';
|
|
2
2
|
export { createDynamicRecord, extractRecordId, isDynamicDataRecord, resolveDataField } from '@praxisui/core';
|
package/package.json
CHANGED
|
@@ -1,24 +1,24 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@praxisui/table",
|
|
3
|
-
"version": "10.0.0-rc.
|
|
3
|
+
"version": "10.0.0-rc.32",
|
|
4
4
|
"description": "Advanced data table for Angular (Praxis UI) with editing, filtering, sorting, virtualization, and settings panel integration.",
|
|
5
5
|
"peerDependencies": {
|
|
6
6
|
"@angular/common": "^21.0.0",
|
|
7
7
|
"@angular/core": "^21.0.0",
|
|
8
8
|
"@angular/platform-browser": "^21.0.0",
|
|
9
|
-
"@praxisui/ai": "^10.0.0-rc.
|
|
10
|
-
"@praxisui/core": "^10.0.0-rc.
|
|
11
|
-
"@praxisui/dynamic-fields": "^10.0.0-rc.
|
|
12
|
-
"@praxisui/dynamic-form": "^10.0.0-rc.
|
|
13
|
-
"@praxisui/metadata-editor": "^10.0.0-rc.
|
|
14
|
-
"@praxisui/rich-content": "^10.0.0-rc.
|
|
15
|
-
"@praxisui/settings-panel": "^10.0.0-rc.
|
|
16
|
-
"@praxisui/table-rule-builder": "^10.0.0-rc.
|
|
9
|
+
"@praxisui/ai": "^10.0.0-rc.32",
|
|
10
|
+
"@praxisui/core": "^10.0.0-rc.32",
|
|
11
|
+
"@praxisui/dynamic-fields": "^10.0.0-rc.32",
|
|
12
|
+
"@praxisui/dynamic-form": "^10.0.0-rc.32",
|
|
13
|
+
"@praxisui/metadata-editor": "^10.0.0-rc.32",
|
|
14
|
+
"@praxisui/rich-content": "^10.0.0-rc.32",
|
|
15
|
+
"@praxisui/settings-panel": "^10.0.0-rc.32",
|
|
16
|
+
"@praxisui/table-rule-builder": "^10.0.0-rc.32",
|
|
17
17
|
"@angular/cdk": "^21.0.0",
|
|
18
18
|
"@angular/forms": "^21.0.0",
|
|
19
19
|
"@angular/material": "^21.0.0",
|
|
20
20
|
"@angular/router": "^21.0.0",
|
|
21
|
-
"@praxisui/dialog": "^10.0.0-rc.
|
|
21
|
+
"@praxisui/dialog": "^10.0.0-rc.32",
|
|
22
22
|
"rxjs": "~7.8.0"
|
|
23
23
|
},
|
|
24
24
|
"dependencies": {
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import * as i0 from '@angular/core';
|
|
2
|
-
import { InjectionToken, AfterViewInit, OnDestroy, EventEmitter, ElementRef, Provider, OnInit, OnChanges, DoCheck, DestroyRef, ChangeDetectorRef, NgZone, SimpleChanges, ComponentRef, AfterViewChecked, AfterContentInit, TemplateRef, Injector, Type } from '@angular/core';
|
|
3
1
|
import * as _praxisui_core from '@praxisui/core';
|
|
4
|
-
import { BulkExecutionContract, ResourceDiscoveryRequestOptions, BulkWireId, RestApiLinks, BulkSyncSession, BulkFieldChange, TableToolbarAppearanceConfig, TableConfig, TableToolbarAppearanceDensity, ToolbarActionEvent, PraxisExportScope, LoggerService, PraxisI18nService, TableToolbarAppearanceVariant, TableToolbarAppearanceShape, TableToolbarAppearanceDivider, TableToolbarTokenName, ToolbarAction as ToolbarAction$1, GlobalConfigService, FilterPresentationConfig, AsyncConfigStorage, LocalStorageConfigService, ApiUrlEntry, FieldMetadata, SchemaIdParams, FormConfig, GenericCrudService, DynamicFormService, SchemaNormalizerService, ComponentKeyService, ComponentDocMeta, PraxisTextValue, PraxisAnalyticsProjection, PraxisDataQueryContext, ApiUrlConfig, DynamicDataRecord, MaterializedResourceIdentity, PraxisQueryFilterExpression, RecordRelatedSurfaceContextPack, PraxisResourceEvent, LoadingState, ColumnDefinition, RichBlockNode, ResourceCapabilityDigest, ConnectionStorage, LoadingOrchestrator, GlobalActionService, EnterpriseRuntimeContextService, PraxisLoadingRenderer, PraxisRuntimeComponentObservationEnvelope, TableDetailRichListNode, TableDetailListNode, TableDetailCardGridNode, TableDetailCardGridCardNode, TableDetailTimelineNode, JsonLogicDataRecord, TableDetailListItemAction, TableDetailActionBarNode, TableDetailActionBarAction, TableDetailRefNode, TableDetailTemplateRefNode, TableDetailDiagramEmbedNode, TableDetailEmbedAction, RichContentDocument, RichBlockHostCapabilities, GlobalActionRef, PraxisRuntimeGlobalActionEffect, ResourceActionCatalogItem, ResourceSurfaceCatalogItem, ResourceCapabilityOperation, JsonLogicExpression, PraxisPresentationVisualizationKind, PraxisTableCellVisualizationConstraint, PraxisPresentationVisualizationThreshold, PraxisPresentationVisualizationTone, GlobalActionCatalogEntry, IconPickerService, SurfaceOpenPayload, GlobalActionField, FieldDefinition, PraxisRuntimeConditionalEffectRule, PraxisJsonLogicService, TableConfigService, SettingsValueProvider as SettingsValueProvider$1, ResourceQuickConnectComponent, AnalyticsSchemaContractService, AnalyticsPresentationResolver, RichPresenterNode, RichComposeNode, ComponentAuthoringManifest, AiCapability, AiCapabilityCategory, AiValueKind, AiCapabilityCatalog, TableDrawerConfig, PraxisAnalyticalDrawerTab, PraxisPresentationVisualizationConfig, PraxisAnalyticalDrawerSchema, SafeExpressionEvaluator, PraxisComputedFieldsConfig, PraxisComputedFieldDefinition } from '@praxisui/core';
|
|
2
|
+
import { BulkExecutionContract, ResourceDiscoveryRequestOptions, BulkWireId, RestApiLinks, BulkSyncSession, BulkFieldChange, TableToolbarAppearanceConfig, TableConfig, TableToolbarAppearanceDensity, ToolbarActionEvent, PraxisExportScope, LoggerService, PraxisI18nService, TableToolbarAppearanceVariant, TableToolbarAppearanceShape, TableToolbarAppearanceDivider, TableToolbarTokenName, ToolbarAction as ToolbarAction$1, GlobalConfigService, FilterPresentationConfig, AsyncConfigStorage, LocalStorageConfigService, ApiUrlEntry, FieldMetadata, SchemaIdParams, FormConfig, GenericCrudService, DynamicFormService, SchemaNormalizerService, ComponentKeyService, ComponentDocMeta, PraxisTextValue, PraxisAnalyticsProjection, PraxisDataQueryContext, ApiUrlConfig, DynamicDataRecord, MaterializedResourceIdentity, TableConfigInput, PraxisQueryFilterExpression, RecordRelatedSurfaceContextPack, PraxisResourceEvent, LoadingState, ColumnDefinition, RichBlockNode, ResourceCapabilityDigest, ConnectionStorage, LoadingOrchestrator, GlobalActionService, EnterpriseRuntimeContextService, PraxisLoadingRenderer, PraxisRuntimeComponentObservationEnvelope, TableDetailRichListNode, TableDetailListNode, TableDetailCardGridNode, TableDetailCardGridCardNode, TableDetailTimelineNode, JsonLogicDataRecord, TableDetailListItemAction, TableDetailActionBarNode, TableDetailActionBarAction, TableDetailRefNode, TableDetailTemplateRefNode, TableDetailDiagramEmbedNode, TableDetailEmbedAction, RichContentDocument, RichBlockHostCapabilities, GlobalActionRef, PraxisRuntimeGlobalActionEffect, ResourceActionCatalogItem, ResourceSurfaceCatalogItem, ResourceCapabilityOperation, JsonLogicExpression, PraxisPresentationVisualizationKind, PraxisTableCellVisualizationConstraint, PraxisPresentationVisualizationThreshold, PraxisPresentationVisualizationTone, GlobalActionCatalogEntry, IconPickerService, SurfaceOpenPayload, GlobalActionField, FieldDefinition, PraxisRuntimeConditionalEffectRule, PraxisJsonLogicService, TableConfigService, SettingsValueProvider as SettingsValueProvider$1, ResourceQuickConnectComponent, AnalyticsSchemaContractService, AnalyticsPresentationResolver, RichPresenterNode, RichComposeNode, ComponentAuthoringManifest, AiCapability, AiCapabilityCategory, AiValueKind, AiCapabilityCatalog, TableDrawerConfig, PraxisAnalyticalDrawerTab, PraxisPresentationVisualizationConfig, PraxisAnalyticalDrawerSchema, SafeExpressionEvaluator, PraxisComputedFieldsConfig, PraxisComputedFieldDefinition } from '@praxisui/core';
|
|
5
3
|
export { DynamicDataCollection, DynamicDataRecord, DynamicRecordMeta, ResourceLinkItem, ResourceLinks, createDynamicRecord, extractRecordId, isDynamicDataRecord, resolveDataField } from '@praxisui/core';
|
|
4
|
+
import * as i0 from '@angular/core';
|
|
5
|
+
import { InjectionToken, AfterViewInit, OnDestroy, EventEmitter, ElementRef, Provider, OnInit, OnChanges, DoCheck, DestroyRef, ChangeDetectorRef, NgZone, SimpleChanges, ComponentRef, AfterViewChecked, AfterContentInit, TemplateRef, Injector, Type } from '@angular/core';
|
|
6
6
|
import { ActivatedRoute } from '@angular/router';
|
|
7
7
|
import { SafeHtml } from '@angular/platform-browser';
|
|
8
8
|
import { MatTable, MatTableDataSource } from '@angular/material/table';
|
|
@@ -454,6 +454,7 @@ declare class TableDefaultsProvider {
|
|
|
454
454
|
constructor(global: GlobalConfigService);
|
|
455
455
|
/**
|
|
456
456
|
* Returns default configuration for a given table identifier.
|
|
457
|
+
* Precedence inside defaults: GlobalConfig.table > createDefaultTableConfig().
|
|
457
458
|
* @param tableId Table identifier
|
|
458
459
|
*/
|
|
459
460
|
getDefaults(_tableId: string): TableConfig;
|
|
@@ -1428,7 +1429,10 @@ declare class PraxisTable implements OnInit, OnChanges, AfterViewInit, AfterView
|
|
|
1428
1429
|
readonly paginatorSelectConfig: MatPaginatorSelectConfig;
|
|
1429
1430
|
private static readonly ROW_ANIMATION_PRESETS;
|
|
1430
1431
|
private static readonly ROW_ANIMATION_PRESET_ALIASES;
|
|
1432
|
+
static ngAcceptInputType_config: TableConfigInput;
|
|
1431
1433
|
config: TableConfig;
|
|
1434
|
+
private hostInputConfig?;
|
|
1435
|
+
private persistedUserConfig?;
|
|
1432
1436
|
resourcePath: string;
|
|
1433
1437
|
data: any[] | null;
|
|
1434
1438
|
tableId: string;
|
|
@@ -1443,9 +1447,15 @@ declare class PraxisTable implements OnInit, OnChanges, AfterViewInit, AfterView
|
|
|
1443
1447
|
autoOpenSettingsOnOutdated: boolean;
|
|
1444
1448
|
crudContext: any;
|
|
1445
1449
|
filterCriteria: Record<string, any>;
|
|
1446
|
-
|
|
1450
|
+
readonly filterCriteriaChange: EventEmitter<Record<string, any>>;
|
|
1451
|
+
private _filterTeleport;
|
|
1452
|
+
set filterTeleport(value: boolean);
|
|
1453
|
+
get filterTeleport(): boolean;
|
|
1447
1454
|
widgetId?: string;
|
|
1448
|
-
|
|
1455
|
+
readonly filterTemplateSignal: i0.WritableSignal<TemplateRef<unknown> | undefined>;
|
|
1456
|
+
private _filterBarTemplate?;
|
|
1457
|
+
set filterBarTemplate(tpl: TemplateRef<unknown> | undefined);
|
|
1458
|
+
get filterBarTemplate(): TemplateRef<unknown> | undefined;
|
|
1449
1459
|
get filterTemplate(): TemplateRef<unknown> | undefined;
|
|
1450
1460
|
private readonly widgetEventBus;
|
|
1451
1461
|
queryContext: PraxisDataQueryContextBridge | null;
|
|
@@ -1854,6 +1864,7 @@ declare class PraxisTable implements OnInit, OnChanges, AfterViewInit, AfterView
|
|
|
1854
1864
|
private tableConfigKey;
|
|
1855
1865
|
private filterConfigKey;
|
|
1856
1866
|
private ensureConfigDefaults;
|
|
1867
|
+
private recomposeEffectiveTableConfig;
|
|
1857
1868
|
private hasDeclaredAppearanceDensity;
|
|
1858
1869
|
private hasDeclaredAppearanceSection;
|
|
1859
1870
|
private shouldApplyAppearanceDefaultValue;
|
|
@@ -2372,6 +2383,7 @@ declare class PraxisTable implements OnInit, OnChanges, AfterViewInit, AfterView
|
|
|
2372
2383
|
private syncQuickFilterStateFromEffectiveCriteria;
|
|
2373
2384
|
private clearQuickFilterRuntimeState;
|
|
2374
2385
|
private hasEquivalentFilterCriteria;
|
|
2386
|
+
private lastAppliedFilterCriteria;
|
|
2375
2387
|
applyAdvancedFilterCriteria(criteria: Record<string, any> | null | undefined, reason?: string): void;
|
|
2376
2388
|
private setAdvancedFilterCriteria;
|
|
2377
2389
|
private syncAdvancedFilterValueFromCriteria;
|
|
@@ -2755,6 +2767,7 @@ declare class PraxisTable implements OnInit, OnChanges, AfterViewInit, AfterView
|
|
|
2755
2767
|
private isColumnFiltersSupported;
|
|
2756
2768
|
private isRowDraggingSupported;
|
|
2757
2769
|
private isRowExpansionSupported;
|
|
2770
|
+
private hasComplementarySchemaExpansionFields;
|
|
2758
2771
|
private enforceAppearanceSchemaGuards;
|
|
2759
2772
|
private enforceUnsupportedFeatureGuards;
|
|
2760
2773
|
getToolbarEvaluationContext(): Record<string, any>;
|
|
@@ -3065,7 +3078,7 @@ declare class PraxisTable implements OnInit, OnChanges, AfterViewInit, AfterView
|
|
|
3065
3078
|
private scheduleRowDiscoveryMarkForCheck;
|
|
3066
3079
|
ngOnDestroy(): void;
|
|
3067
3080
|
static ɵfac: i0.ɵɵFactoryDeclaration<PraxisTable, [null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, { optional: true; }, { optional: true; }, { optional: true; }, { optional: true; }, { optional: true; }]>;
|
|
3068
|
-
static ɵcmp: i0.ɵɵComponentDeclaration<PraxisTable, "praxis-table", never, { "config": { "alias": "config"; "required": false; }; "resourcePath": { "alias": "resourcePath"; "required": false; }; "data": { "alias": "data"; "required": false; }; "tableId": { "alias": "tableId"; "required": true; }; "componentInstanceId": { "alias": "componentInstanceId"; "required": false; }; "configPersistenceStrategy": { "alias": "configPersistenceStrategy"; "required": false; }; "title": { "alias": "title"; "required": false; }; "subtitle": { "alias": "subtitle"; "required": false; }; "icon": { "alias": "icon"; "required": false; }; "autoDelete": { "alias": "autoDelete"; "required": false; }; "notifyIfOutdated": { "alias": "notifyIfOutdated"; "required": false; }; "snoozeMs": { "alias": "snoozeMs"; "required": false; }; "autoOpenSettingsOnOutdated": { "alias": "autoOpenSettingsOnOutdated"; "required": false; }; "crudContext": { "alias": "crudContext"; "required": false; }; "filterCriteria": { "alias": "filterCriteria"; "required": false; }; "filterTeleport": { "alias": "filterTeleport"; "required": false; }; "widgetId": { "alias": "widgetId"; "required": false; }; "queryContext": { "alias": "queryContext"; "required": false; }; "aiContext": { "alias": "aiContext"; "required": false; }; "aiAssistantVoiceInputMode": { "alias": "aiAssistantVoiceInputMode"; "required": false; }; "aiAssistantVoiceLanguage": { "alias": "aiAssistantVoiceLanguage"; "required": false; }; "horizontalScroll": { "alias": "horizontalScroll"; "required": false; }; "enableCustomization": { "alias": "enableCustomization"; "required": false; }; "authoringCapability": { "alias": "authoringCapability"; "required": false; }; "dense": { "alias": "dense"; "required": false; }; }, { "queryContextClear": "queryContextClear"; "queryContextChange": "queryContextChange"; "rowClick": "rowClick"; "widgetEvent": "widgetEvent"; "resourceEvent": "resourceEvent"; "rowDoubleClick": "rowDoubleClick"; "rowExpansionChange": "rowExpansionChange"; "rowAction": "rowAction"; "toolbarAction": "toolbarAction"; "bulkAction": "bulkAction"; "exportAction": "exportAction"; "columnReorder": "columnReorder"; "columnReorderAttempt": "columnReorderAttempt"; "columnResize": "columnResize"; "beforeDelete": "beforeDelete"; "afterDelete": "afterDelete"; "deleteError": "deleteError"; "beforeBulkDelete": "beforeBulkDelete"; "afterBulkDelete": "afterBulkDelete"; "bulkDeleteError": "bulkDeleteError"; "schemaStatusChange": "schemaStatusChange"; "configChange": "configChange"; "metadataChange": "metadataChange"; "loadingStateChange": "loadingStateChange"; "collectionLinksChange": "collectionLinksChange"; "selectionChange": "selectionChange"; "drawerOpen": "drawerOpen"; "drawerClose": "drawerClose"; "drawerTabChange": "drawerTabChange"; }, ["toolbar", "projectedFilter"], ["[advancedFilter]", "[toolbar]", "[advancedFilter]", "[toolbar]", "[advancedFilter]", "[toolbar]"], true, never>;
|
|
3081
|
+
static ɵcmp: i0.ɵɵComponentDeclaration<PraxisTable, "praxis-table", never, { "config": { "alias": "config"; "required": false; }; "resourcePath": { "alias": "resourcePath"; "required": false; }; "data": { "alias": "data"; "required": false; }; "tableId": { "alias": "tableId"; "required": true; }; "componentInstanceId": { "alias": "componentInstanceId"; "required": false; }; "configPersistenceStrategy": { "alias": "configPersistenceStrategy"; "required": false; }; "title": { "alias": "title"; "required": false; }; "subtitle": { "alias": "subtitle"; "required": false; }; "icon": { "alias": "icon"; "required": false; }; "autoDelete": { "alias": "autoDelete"; "required": false; }; "notifyIfOutdated": { "alias": "notifyIfOutdated"; "required": false; }; "snoozeMs": { "alias": "snoozeMs"; "required": false; }; "autoOpenSettingsOnOutdated": { "alias": "autoOpenSettingsOnOutdated"; "required": false; }; "crudContext": { "alias": "crudContext"; "required": false; }; "filterCriteria": { "alias": "filterCriteria"; "required": false; }; "filterTeleport": { "alias": "filterTeleport"; "required": false; }; "widgetId": { "alias": "widgetId"; "required": false; }; "queryContext": { "alias": "queryContext"; "required": false; }; "aiContext": { "alias": "aiContext"; "required": false; }; "aiAssistantVoiceInputMode": { "alias": "aiAssistantVoiceInputMode"; "required": false; }; "aiAssistantVoiceLanguage": { "alias": "aiAssistantVoiceLanguage"; "required": false; }; "horizontalScroll": { "alias": "horizontalScroll"; "required": false; }; "enableCustomization": { "alias": "enableCustomization"; "required": false; }; "authoringCapability": { "alias": "authoringCapability"; "required": false; }; "dense": { "alias": "dense"; "required": false; }; }, { "filterCriteriaChange": "filterCriteriaChange"; "queryContextClear": "queryContextClear"; "queryContextChange": "queryContextChange"; "rowClick": "rowClick"; "widgetEvent": "widgetEvent"; "resourceEvent": "resourceEvent"; "rowDoubleClick": "rowDoubleClick"; "rowExpansionChange": "rowExpansionChange"; "rowAction": "rowAction"; "toolbarAction": "toolbarAction"; "bulkAction": "bulkAction"; "exportAction": "exportAction"; "columnReorder": "columnReorder"; "columnReorderAttempt": "columnReorderAttempt"; "columnResize": "columnResize"; "beforeDelete": "beforeDelete"; "afterDelete": "afterDelete"; "deleteError": "deleteError"; "beforeBulkDelete": "beforeBulkDelete"; "afterBulkDelete": "afterBulkDelete"; "bulkDeleteError": "bulkDeleteError"; "schemaStatusChange": "schemaStatusChange"; "configChange": "configChange"; "metadataChange": "metadataChange"; "loadingStateChange": "loadingStateChange"; "collectionLinksChange": "collectionLinksChange"; "selectionChange": "selectionChange"; "drawerOpen": "drawerOpen"; "drawerClose": "drawerClose"; "drawerTabChange": "drawerTabChange"; }, ["toolbar", "projectedFilter"], ["[advancedFilter]", "[toolbar]", "[advancedFilter]", "[toolbar]", "[advancedFilter]", "[toolbar]"], true, never>;
|
|
3069
3082
|
static ngAcceptInputType_filterTeleport: unknown;
|
|
3070
3083
|
static ngAcceptInputType_enableCustomization: unknown;
|
|
3071
3084
|
}
|