@praxisui/table 3.0.0-beta.1 → 3.0.0-beta.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -379,7 +379,7 @@ Quando `resourcePath` é fornecido, a tabela se torna "inteligente":
379
379
  Neste exemplo:
380
380
 
381
381
  - `resourcePath="human-resources/departamentos"` instrui a tabela a se comunicar com o endpoint `/api/human-resources/departamentos`.
382
- - A tabela fará requisições como `POST /api/human-resources/departamentos/filter` para obter os dados e `GET /api/human-resources/departamentos/schemas` para obter a configuração das colunas.
382
+ - A tabela fará requisições como `POST /api/human-resources/departamentos/filter` para obter os dados e `GET /schemas/filtered?path=/api/human-resources/departamentos/all&operation=get&schemaType=response` para obter o schema estrutural usado no bootstrap das colunas.
383
383
  - `enableCustomization` controla explicitamente o gate de edição visual. O default canônico agora é `false`; declare `[enableCustomization]="true"` quando o host quiser expor customização e surfaces editoriais.
384
384
 
385
385
  ### Empty State + Quick Connect (sem `resourcePath`)
@@ -394,20 +394,22 @@ Ao aplicar/salvar, a `<praxis-table>` é automaticamente configurada para buscar
394
394
 
395
395
  ### Fluxo de Comunicação do `resourcePath`
396
396
 
397
- O diagrama abaixo ilustra como a propriedade `resourcePath` conecta o componente frontend ao controller do backend. O fluxo de inicialização ocorre em três etapas principais: **Configurar**, **Carregar Schema** e **Buscar Dados**.
397
+ O diagrama abaixo ilustra como a propriedade `resourcePath` conecta o componente frontend ao backend no runtime atual da tabela. Antes de iniciar o fluxo remoto, a lib resolve o modo de dados com precedência **`resourcePath` explícito > `data` local > conexão persistida**. Quando o modo efetivo é `remote`, o bootstrap ocorre em três etapas principais: **Configurar**, **Carregar Schema estrutural** e **Buscar Dados**.
398
398
 
399
399
  ```mermaid
400
400
  sequenceDiagram
401
401
  participant FE_Component as Componente Angular<br>(departamentos.html)
402
402
  participant Praxis_Table as @praxisui/table<br>(praxis-table.ts)
403
403
  participant Crud_Service as @praxisui/core<br>(generic-crud.service.ts)
404
+ participant Docs_Controller as ApiDocsController<br>(/schemas/filtered)
404
405
  participant BE_Controller as Backend Controller<br>(DepartamentoController.java)
405
- participant Abstract_Controller as AbstractCrudController
406
+ participant Abstract_Controller as AbstractCrudController<br>(/filter)
406
407
 
407
408
  FE_Component->>Praxis_Table: Usa o componente com <br> <praxis-table resourcePath="human-resources/departamentos">
408
409
 
409
410
  activate Praxis_Table
410
- Praxis_Table->>Praxis_Table: ngOnChanges() detecta o @Input() resourcePath
411
+ Praxis_Table->>Praxis_Table: ngOnInit()/ngOnChanges() resolve dataMode
412
+ Note over Praxis_Table: remote quando há resourcePath efetivo
411
413
  Praxis_Table->>Crud_Service: 1. Chama crudService.configure("human-resources/departamentos")
412
414
 
413
415
  activate Crud_Service
@@ -418,24 +420,19 @@ sequenceDiagram
418
420
  Praxis_Table->>Crud_Service: Chama crudService.getSchema()
419
421
 
420
422
  activate Crud_Service
421
- Crud_Service->>Crud_Service: getEndpointUrl('schema') constrói a URL: <br> "/api/human-resources/departamentos/schemas"
422
- Crud_Service->>BE_Controller: Requisição HTTP GET para .../schemas
423
+ Crud_Service->>Crud_Service: schemaUrl() preserva o base path canônico
424
+ Crud_Service->>Crud_Service: Deriva path="/api/human-resources/departamentos/all"<br>operation="get", schemaType="response"
425
+ Crud_Service->>Docs_Controller: GET /schemas/filtered?path=.../all&operation=get&schemaType=response
423
426
  deactivate Crud_Service
424
427
 
425
- activate BE_Controller
426
- Note over BE_Controller: @RequestMapping("/human-resources/departamentos")
427
- BE_Controller->>Abstract_Controller: Herda o método que lida com @GetMapping("/schemas")
428
-
429
- activate Abstract_Controller
430
- Abstract_Controller->>Abstract_Controller: Gera e retorna o Schema da UI
431
- Abstract_Controller-->>BE_Controller: Retorna o Schema
432
- deactivate Abstract_Controller
433
-
434
- BE_Controller-->>Crud_Service: Resposta HTTP com o JSON do Schema
435
- deactivate BE_Controller
428
+ activate Docs_Controller
429
+ Docs_Controller->>Docs_Controller: Resolve grupo OpenAPI a partir do path
430
+ Docs_Controller->>Docs_Controller: Filtra payload estrutural + x-ui
431
+ Docs_Controller-->>Crud_Service: 200/304 com schema + ETag/X-Schema-Hash
432
+ deactivate Docs_Controller
436
433
 
437
434
  activate Crud_Service
438
- Crud_Service-->>Praxis_Table: Retorna um Observable com as<br>definições de colunas (FieldDefinition[])
435
+ Crud_Service-->>Praxis_Table: Normaliza schema e retorna FieldDefinition[]
439
436
  deactivate Crud_Service
440
437
 
441
438
  Praxis_Table->>Praxis_Table: Constrói as colunas da tabela<br>a partir do schema recebido
@@ -460,13 +457,20 @@ sequenceDiagram
460
457
  deactivate BE_Controller
461
458
 
462
459
  activate Crud_Service
463
- Crud_Service-->>Praxis_Table: Retorna um Observable com os dados
460
+ Crud_Service-->>Praxis_Table: Retorna Page<T> com os dados paginados
464
461
  deactivate Crud_Service
465
462
 
466
463
  Praxis_Table->>Praxis_Table: Atualiza o dataSource da tabela com os dados recebidos
467
464
  deactivate Praxis_Table
468
465
  ```
469
466
 
467
+ Notas importantes:
468
+
469
+ - O host informa `resourcePath` sem o prefixo `/api`; o `GenericCrudService` resolve as URLs reais do backend a partir da configuração de API do host.
470
+ - O bootstrap de schema não depende mais de uma chamada frontend para `GET /{resource}/schemas`; o runtime consome diretamente `/schemas/filtered` com `ETag`/`X-Schema-Hash`.
471
+ - O `praxis-filter` acoplado acompanha o mesmo `resourcePath` em modo remoto e deriva seu schema via `/schemas/filtered?path=.../filter&operation=post&schemaType=request`.
472
+ - Sem `resourcePath` efetivo, a tabela não entra nesse fluxo remoto; ela cai em `local` ou `empty` conforme a precedência canônica.
473
+
470
474
  ## ℹ️ Dicas de UX (Tabela)
471
475
 
472
476
  - Multi‑sort: habilite em Comportamento → Ordenação. No uso, mantenha Ctrl/Cmd pressionado ao clicar em múltiplas colunas.
@@ -805,12 +809,13 @@ sequenceDiagram
805
809
  autonumber
806
810
  participant PT as PraxisTable
807
811
  participant GS as GenericCrudService
808
- participant API as Backend
812
+ participant Docs as ApiDocsController (/schemas/filtered)
809
813
 
810
814
  PT->>GS: configure(resourcePath)
811
815
  PT->>GS: getSchema()
812
- GS->>API: GET {resource}/schemas 302 → /schemas/filtered
813
- API-->>GS: 200/304 schema + x-ui.resource.idField
816
+ GS->>GS: deriva path=/api/.../all + schemaType=response
817
+ GS->>Docs: GET /schemas/filtered?path=.../all&operation=get&schemaType=response
818
+ Docs-->>GS: 200/304 schema + x-ui.resource.idField
814
819
  GS->>GS: cache + lastResourceMeta.idField
815
820
  GS-->>PT: FieldDefinition[] (normalizado)
816
821
  Note over PT: idField = input || context || GS.getResourceIdField() || 'id'
@@ -827,11 +832,12 @@ sequenceDiagram
827
832
  participant API as Backend
828
833
 
829
834
  PT->>PT: key = getIdField() (precedência)
830
- PT->>PT: id = row[key] || row['id'] || heurísticas
835
+ PT->>PT: id = getNestedPropertyValue(row, key)
831
836
  PT->>GS: delete(id)
832
837
  GS->>API: DELETE {resource}/{id}
833
838
  API-->>GS: 204 No Content
834
- GS-->>PT: sucesso → refresh
839
+ GS-->>PT: sucesso
840
+ PT->>PT: fetchData() em modo remoto
835
841
  ```
836
842
 
837
843
  ### Troubleshooting rápido (idField)
@@ -882,78 +888,113 @@ export class ExampleComponent {
882
888
 
883
889
  ## ⚙️ Fluxo de Paginação e Filtros (Server-Side)
884
890
 
885
- Quando a `<praxis-table>` é conectada a um `resourcePath`, as operações de paginação, ordenação e filtro são delegadas ao backend. Isso garante alta performance, pois apenas os dados visíveis na tela são trafegados pela rede.
891
+ Quando a `<praxis-table>` opera com `resourcePath`, o runtime resolve o modo remoto e passa a delegar paginação, ordenação e filtros ao backend. Isso reduz tráfego, preserva a semântica do DTO de filtro e mantém o banco como fonte de verdade para `WHERE`, `ORDER BY`, `LIMIT` e `OFFSET`.
886
892
 
887
893
  Importante: se você não configurar explicitamente as estratégias de paginação/ordenação no `TableConfig`, a tabela resolve automaticamente como `server` quando há `resourcePath`. Se preferir operar no cliente, defina `behavior.pagination.strategy = 'client'` e/ou `behavior.sorting.strategy = 'client'` conscientemente.
888
894
 
889
- O diagrama abaixo detalha a sequência de eventos, desde a interação do usuário na UI até a construção da consulta JPA no servidor.
895
+ ### Versão Pedagógica de Alto Nível
896
+
897
+ Esta é a leitura adequada para documentação pública e landing pages.
890
898
 
891
899
  ```mermaid
892
900
  sequenceDiagram
893
- participant UI as @praxisui/table (UI)
894
- participant CrudService as @praxisui/core (GenericCrudService)
895
- participant Controller as Backend (AbstractCrudController)
896
- participant Service as Backend (BaseCrudService)
897
- participant SpecBuilder as Backend (GenericSpecificationsBuilder)
898
- participant Repository as Spring Data JPA (JpaSpecificationExecutor)
899
-
900
- UI->>UI: Usuário clica na página 2 e<br>digita "Tech" no filtro de nome.
901
-
902
- UI->>UI: onPageChange({pageIndex: 1, pageSize: 10})<br>onFilterChange({nome: 'Tech'})
903
-
904
- UI->>UI: Chama fetchData() com:<br>filterCriteria = {nome: 'Tech'}<br>pageable = {pageNumber: 1, pageSize: 10, sort: 'nome,asc'}
905
-
906
- UI->>CrudService: Chama .filter({nome: 'Tech'}, pageable)
907
-
908
- activate CrudService
909
- CrudService->>CrudService: Cria HttpParams:<br>page=1, size=10, sort=nome,asc
910
- CrudService->>Controller: Requisição POST para /api/.../filter<br>Body: {nome: 'Tech'}<br>Params: ?page=1&size=10&sort=nome,asc
911
- deactivate CrudService
912
-
913
- activate Controller
914
- Controller->>Controller: Spring injeta o corpo no FilterDTO<br>e os params no objeto Pageable.
915
- Controller->>Service: Chama .filter(filterDTO, pageable)
916
- deactivate Controller
917
-
918
- activate Service
919
- Service->>SpecBuilder: Chama .buildSpecification(filterDTO)
901
+ participant Usuario as Usuário
902
+ participant Tabela as praxis-table
903
+ participant Frontend as GenericCrudService
904
+ participant Backend as API Praxis
905
+ participant Banco as Banco de Dados
906
+
907
+ Usuario->>Tabela: muda página, ordena ou aplica filtro
908
+ Tabela->>Tabela: consolida filterCriteria + paginação + sort
909
+ Tabela->>Frontend: filter(criteria, pageable)
910
+ Frontend->>Backend: POST /api/.../filter?page&size&sort
911
+ Backend->>Banco: executa consulta filtrada e paginada
912
+ Banco-->>Backend: retorna página de resultados
913
+ Backend-->>Frontend: responde com página de DTOs
914
+ Frontend-->>Tabela: entrega Page<T>
915
+ Tabela->>Tabela: atualiza linhas, paginação e estado visual
916
+ ```
920
917
 
921
- activate SpecBuilder
922
- SpecBuilder->>SpecBuilder: Itera nos campos do FilterDTO.<br>Encontra @Filterable no campo 'nome'.
923
- SpecBuilder->>SpecBuilder: Cria um Predicate JPA:<br> `criteriaBuilder.like(root.get("nome"), "%tech%")`
924
- SpecBuilder->>Service: Retorna a Specification JPA construída.
925
- deactivate SpecBuilder
918
+ Leitura pedagógica:
926
919
 
927
- Service->>Repository: Chama .findAll(specification, pageable)
920
+ 1. **A tabela captura a intenção do usuário**: página, ordenação e filtros viram estado de consulta.
921
+ 2. **O frontend envia o DTO de filtro para o endpoint canônico**: corpo JSON para filtro, query params para paginação e sort.
922
+ 3. **O backend aplica o filtro no conjunto remoto**: não é a UI que filtra localmente em modo remoto.
923
+ 4. **O resultado volta já paginado**: a tabela apenas renderiza a página retornada pela API.
928
924
 
929
- activate Repository
930
- Repository->>Repository: Spring Data JPA executa a<br>query SQL com WHERE, LIMIT, OFFSET, ORDER BY.
931
- Repository-->>Service: Retorna um objeto Page<Entity> do BD.
932
- deactivate Repository
925
+ ### Versão Detalhada e Fiel ao Runtime Atual
933
926
 
934
- Service-->>Controller: Retorna o Page<Entity>
935
- deactivate Service
927
+ Esta versão documenta o fluxo real do `praxis-table`, do `praxis-filter`, do `GenericCrudService` e do `praxis-metadata-starter`.
936
928
 
937
- activate Controller
938
- Controller->>Controller: Mapeia Page<Entity> para Page<DTO><br>e encapsula em RestApiResponse.
939
- Controller-->>CrudService: Resposta HTTP 200 com<br>JSON do RestApiResponse.
940
- deactivate Controller
929
+ ```mermaid
930
+ sequenceDiagram
931
+ participant Host as Host / bindings
932
+ participant Tabela as PraxisTable
933
+ participant Filtro as PraxisFilter
934
+ participant Crud as GenericCrudService
935
+ participant Controller as AbstractCrudController
936
+ participant Service as BaseCrudService
937
+ participant Builder as GenericSpecificationsBuilder
938
+ participant Repo as JpaSpecificationExecutor
939
+
940
+ Host->>Tabela: fornece resourcePath
941
+ Tabela->>Crud: configure(resourcePath)
942
+ alt sem colunas prontas
943
+ Tabela->>Crud: getSchema()
944
+ Crud-->>Tabela: schema normalizado
945
+ else com colunas prontas
946
+ Tabela->>Tabela: verifyServerSchemaVersion()
947
+ end
941
948
 
942
- activate CrudService
943
- CrudService-->>UI: Retorna Observable<Page<DTO>>
944
- deactivate CrudService
949
+ alt advancedFilters habilitado
950
+ Tabela->>Filtro: monta praxis-filter
951
+ Filtro->>Crud: getFilteredSchema(...) ou getSchema()
952
+ Crud-->>Filtro: metadata de filtro
953
+ end
945
954
 
946
- UI->>UI: Atualiza a tabela com os novos dados e o paginador.
955
+ alt paginação
956
+ Tabela->>Tabela: onPageChange(pageIndex, pageSize)
957
+ else ordenação
958
+ Tabela->>Tabela: onSortChange(active, direction)
959
+ Tabela->>Tabela: reseta pageIndex = 0
960
+ else filtro avançado
961
+ Filtro-->>Tabela: submit/change/clear
962
+ Tabela->>Tabela: onAdvancedFilterSubmit(criteria)
963
+ end
947
964
 
965
+ Tabela->>Tabela: fetchData()
966
+ Tabela->>Tabela: monta PageableRequest com pageIndex, pageSize e sortField efetivo
967
+ Tabela->>Crud: filter(filterCriteria, pageable)
968
+
969
+ Crud->>Crud: normalizeRangeCriteria(...)
970
+ Crud->>Controller: POST /filter?page&size&sort
971
+ Note over Crud,Controller: body = filterCriteria JSON
972
+
973
+ Controller->>Controller: lê page,size,sort de query params
974
+ Controller->>Controller: PageableBuilder.from(page,size,sort,...)
975
+ Controller->>Service: filterMappedWithIncludeIds(filterDTO, pageable, includeIds, toDto)
976
+
977
+ Service->>Builder: buildSpecification(filterDTO, pageable)
978
+ Builder->>Builder: inspeciona campos @Filterable do DTO
979
+ Builder-->>Service: Specification pronta
980
+ Service->>Repo: findAll(specification, pageable)
981
+ Repo-->>Service: Page<Entity>
982
+ Service-->>Controller: Page<DTO>
983
+
984
+ Controller->>Controller: mapeia para EntityModel<DTO> e monta RestApiResponse.success(...)
985
+ Controller-->>Crud: HTTP 200
986
+ Crud->>Crud: unwrapPageResponse(...)
987
+ Crud-->>Tabela: Page<T>
988
+ Tabela->>Tabela: atualiza dataSubject, totalElements e paginator
948
989
  ```
949
990
 
950
- ### Pontos-Chave do Fluxo:
991
+ ### Pontos-Chave do Fluxo Real
951
992
 
952
- 1. **UI (`@praxisui/table`)**: Captura eventos do usuário e os traduz em objetos `filterCriteria` e `pageable`.
953
- 2. **Serviço Frontend (`@praxisui/core`)**: O `GenericCrudService` serializa o `pageable` como parâmetros de URL e o `filterCriteria` como corpo de uma requisição POST.
954
- 3. **Controller Backend**: O `AbstractCrudController` recebe a requisição. O Spring Boot automaticamente popula o DTO de filtro com o corpo da requisição e o objeto `Pageable` com os parâmetros da URL.
955
- 4. **Serviço Backend (`praxis-metadata-core`)**: O `GenericSpecificationsBuilder` inspeciona as anotações `@Filterable` no DTO de filtro para construir uma `Specification` JPA dinâmica.
956
- 5. **Repositório (Spring Data JPA)**: O `JpaSpecificationExecutor` (geralmente estendido pelo seu repositório) usa a `Specification` e o `Pageable` para gerar e executar a consulta SQL final, otimizada para o banco de dados.
993
+ 1. **`resourcePath` não dispara só fetch**: em modo remoto, a tabela primeiro configura o `GenericCrudService` e pode carregar schema antes da primeira busca.
994
+ 2. **O filtro avançado vive em `praxis-filter`**: os eventos reais são `submit`, `change` e `clear`, que a tabela recebe como `onAdvancedFilterSubmit`, `onAdvancedFilterChange` e `onAdvancedFilterClear`.
995
+ 3. **O controller não recebe `Pageable` pronto do Spring nesse endpoint**: ele reconstrói o `Pageable` a partir de `page`, `size` e `sort`.
996
+ 4. **O backend do starter responde com `RestApiResponse<Page<...>>`**: o `GenericCrudService` faz `unwrapPageResponse(...)` para entregar `Page<T>` ao runtime da tabela.
997
+ 5. **A coluna ordenada pode mapear para `sortField`**: o `active` da UI não é necessariamente o campo final enviado ao backend.
957
998
 
958
999
  ## 🎨 Edição Visual da Tabela: O Poder do Low-Code
959
1000
 
@@ -1,6 +1,6 @@
1
1
  import * as i0 from '@angular/core';
2
2
  import { Inject, Component } from '@angular/core';
3
- import * as i1$1 from '@angular/common';
3
+ import * as i2 from '@angular/common';
4
4
  import { CommonModule } from '@angular/common';
5
5
  import * as i1 from '@angular/material/dialog';
6
6
  import { MAT_DIALOG_DATA, MatDialogModule } from '@angular/material/dialog';
@@ -115,7 +115,7 @@ class FilterFormDialogHostComponent {
115
115
  {{ data.i18n?.apply || 'Aplicar' }}
116
116
  </button>
117
117
  </mat-dialog-actions>
118
- `, isInline: true, styles: [".pfx-dialog-title{display:flex;align-items:center;justify-content:space-between;gap:12px;padding-right:8px}.pfx-dialog-title-text{display:inline-flex;align-items:center;gap:8px;font-weight:600;color:var(--md-sys-color-on-surface)}.pfx-dialog-close{margin-left:auto}.pfx-filter-dialog-content{display:flex;flex-direction:column;gap:12px;padding-top:8px}.pfx-empty-state{margin:8px 0 0;color:var(--md-sys-color-on-surface-variant)}.pfx-dialog-actions{padding:var(--pdx-dialog-actions-padding, 12px 24px 16px);border-top:1px solid var(--md-sys-color-outline-variant);background:transparent;display:flex;align-items:center;gap:8px}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: MatDialogModule }, { kind: "directive", type: i1.MatDialogTitle, selector: "[mat-dialog-title], [matDialogTitle]", inputs: ["id"], exportAs: ["matDialogTitle"] }, { kind: "directive", type: i1.MatDialogActions, selector: "[mat-dialog-actions], mat-dialog-actions, [matDialogActions]", inputs: ["align"] }, { kind: "directive", type: i1.MatDialogContent, selector: "[mat-dialog-content], mat-dialog-content, [matDialogContent]" }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i3.MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }, { kind: "component", type: i3.MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatProgressBarModule }, { kind: "component", type: i15.MatProgressBar, selector: "mat-progress-bar", inputs: ["color", "value", "bufferValue", "mode"], outputs: ["animationEnd"], exportAs: ["matProgressBar"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i5.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "component", type: PraxisFilterForm, selector: "praxis-filter-form", inputs: ["config", "formId", "resourcePath", "mode"], outputs: ["formReady", "valueChange", "submit", "validityChange"] }] });
118
+ `, isInline: true, styles: [".pfx-dialog-title{display:flex;align-items:center;justify-content:space-between;gap:12px;padding-right:8px}.pfx-dialog-title-text{display:inline-flex;align-items:center;gap:8px;font-weight:600;color:var(--md-sys-color-on-surface)}.pfx-dialog-close{margin-left:auto}.pfx-filter-dialog-content{display:flex;flex-direction:column;gap:12px;padding-top:8px}.pfx-empty-state{margin:8px 0 0;color:var(--md-sys-color-on-surface-variant)}.pfx-dialog-actions{padding:var(--pdx-dialog-actions-padding, 12px 24px 16px);border-top:1px solid var(--md-sys-color-outline-variant);background:transparent;display:flex;align-items:center;gap:8px}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: MatDialogModule }, { kind: "directive", type: i1.MatDialogTitle, selector: "[mat-dialog-title], [matDialogTitle]", inputs: ["id"], exportAs: ["matDialogTitle"] }, { kind: "directive", type: i1.MatDialogActions, selector: "[mat-dialog-actions], mat-dialog-actions, [matDialogActions]", inputs: ["align"] }, { kind: "directive", type: i1.MatDialogContent, selector: "[mat-dialog-content], mat-dialog-content, [matDialogContent]" }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i3.MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }, { kind: "component", type: i3.MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatProgressBarModule }, { kind: "component", type: i15.MatProgressBar, selector: "mat-progress-bar", inputs: ["color", "value", "bufferValue", "mode"], outputs: ["animationEnd"], exportAs: ["matProgressBar"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i5.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "component", type: PraxisFilterForm, selector: "praxis-filter-form", inputs: ["config", "formId", "resourcePath", "mode"], outputs: ["formReady", "valueChange", "submit", "validityChange"] }] });
119
119
  }
120
120
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: FilterFormDialogHostComponent, decorators: [{
121
121
  type: Component,
@@ -163,4 +163,4 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
163
163
  }] }, { type: i1.MatDialogRef }] });
164
164
 
165
165
  export { FilterFormDialogHostComponent };
166
- //# sourceMappingURL=praxisui-table-filter-form-dialog-host.component-C2rQnHE1.mjs.map
166
+ //# sourceMappingURL=praxisui-table-filter-form-dialog-host.component-CZsEBHoS.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"praxisui-table-filter-form-dialog-host.component-C2rQnHE1.mjs","sources":["../../../projects/praxis-table/src/lib/components/praxis-filter/filter-form-dialog-host.component.ts"],"sourcesContent":["import { Component, Inject } from '@angular/core';\nimport { CommonModule } from '@angular/common';\nimport { MatDialogModule, MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog';\nimport { MatButtonModule } from '@angular/material/button';\nimport { MatProgressBarModule } from '@angular/material/progress-bar';\nimport { MatIconModule } from '@angular/material/icon';\nimport { FormGroup } from '@angular/forms';\nimport { PraxisFilterForm } from '@praxisui/dynamic-form';\n\n@Component({\n selector: 'praxis-filter-form-dialog-host',\n standalone: true,\n imports: [CommonModule, MatDialogModule, MatButtonModule, MatProgressBarModule, MatIconModule, PraxisFilterForm],\n template: `\n <div mat-dialog-title class=\"pfx-dialog-title\" id=\"filterDialogTitle\">\n <div class=\"pfx-dialog-title-text\">\n <mat-icon>tune</mat-icon>\n <span>{{ data.title || 'Filtro avançado' }}</span>\n </div>\n <button mat-icon-button type=\"button\" class=\"pfx-dialog-close\" (click)=\"close()\"\n [attr.aria-label]=\"data.i18n?.cancel || 'Fechar'\">\n <mat-icon>close</mat-icon>\n </button>\n </div>\n <mat-dialog-content class=\"pfx-filter-dialog-content\" aria-labelledby=\"filterDialogTitle\">\n <mat-progress-bar *ngIf=\"data?.schemaLoading\" mode=\"indeterminate\"></mat-progress-bar>\n <praxis-filter-form\n *ngIf=\"data?.config\"\n [formId]=\"data.formId\"\n [resourcePath]=\"data.resourcePath\"\n [mode]=\"'edit'\"\n [config]=\"data.config\"\n (formReady)=\"onReady($event)\"\n (valueChange)=\"onChange($event)\"\n (validityChange)=\"onValidity($event)\"\n ></praxis-filter-form>\n <p *ngIf=\"!data?.config && !data?.schemaLoading\" class=\"pfx-empty-state\">{{ data.i18n?.noData || 'Nenhum dado' }}</p>\n </mat-dialog-content>\n <mat-dialog-actions align=\"end\" class=\"pfx-dialog-actions\">\n <button mat-button type=\"button\"\n *ngIf=\"data?.allowSaveTags\"\n [disabled]=\"!canSave\"\n (click)=\"saveShortcut()\">\n {{ data.i18n?.saveAsShortcut || 'Salvar como atalho' }}\n </button>\n <button mat-stroked-button type=\"button\" (click)=\"close()\">{{ data.i18n?.cancel || 'Cancelar' }}</button>\n <button mat-flat-button color=\"primary\" (click)=\"apply()\" [disabled]=\"!valid\">\n {{ data.i18n?.apply || 'Aplicar' }}\n </button>\n </mat-dialog-actions>\n `,\n styles: [`\n .pfx-dialog-title {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 12px;\n padding-right: 8px;\n }\n .pfx-dialog-title-text {\n display: inline-flex;\n align-items: center;\n gap: 8px;\n font-weight: 600;\n color: var(--md-sys-color-on-surface);\n }\n .pfx-dialog-close {\n margin-left: auto;\n }\n .pfx-filter-dialog-content {\n display: flex;\n flex-direction: column;\n gap: 12px;\n padding-top: 8px;\n }\n .pfx-empty-state {\n margin: 8px 0 0;\n color: var(--md-sys-color-on-surface-variant);\n }\n .pfx-dialog-actions {\n padding: var(--pdx-dialog-actions-padding, 12px 24px 16px);\n border-top: 1px solid var(--md-sys-color-outline-variant);\n background: transparent;\n display: flex;\n align-items: center;\n gap: 8px;\n }\n `],\n})\nexport class FilterFormDialogHostComponent {\n valid = true;\n private lastValue: any = {};\n private formGroup: FormGroup<Record<string, any>> | null = null;\n canSave = false;\n constructor(\n @Inject(MAT_DIALOG_DATA)\n public data: {\n formId: string;\n resourcePath: string;\n config: any;\n title?: string;\n schemaLoading?: boolean;\n initialDto?: Record<string, any>;\n allowSaveTags?: boolean;\n i18n?: { saveAsShortcut?: string; cancel?: string; apply?: string; noData?: string };\n onSaveShortcut?: (dto: Record<string, any>) => void;\n },\n private ref: MatDialogRef<FilterFormDialogHostComponent>,\n ) {}\n\n onReady(ev: { formGroup: any }): void {\n try {\n this.formGroup = (ev?.formGroup as FormGroup<Record<string, any>>) || null;\n const dto = this.data?.initialDto || {};\n if (ev?.formGroup && dto && Object.keys(dto).length) {\n ev.formGroup.patchValue(dto, { emitEvent: false });\n }\n this.lastValue = this.formGroup?.getRawValue?.() ?? this.lastValue;\n this.updateCanSave();\n } catch {}\n }\n onChange(ev: { formData: Record<string, any> }): void {\n this.lastValue = ev?.formData ?? {};\n this.updateCanSave();\n }\n onValidity(v: boolean): void {\n this.valid = v;\n this.updateCanSave();\n }\n apply(): void {\n const formData =\n this.formGroup?.getRawValue?.() ??\n this.lastValue ??\n this.data?.initialDto ??\n {};\n this.ref.close({ formData });\n }\n close(): void { this.ref.close(); }\n\n private clean(obj: Record<string, any> | undefined | null): Record<string, any> {\n const out: Record<string, any> = {};\n Object.keys(obj || {}).forEach((k) => {\n const v = (obj as any)[k];\n if (v !== '' && v !== null && v !== undefined) out[k] = v;\n });\n return out;\n }\n private buildDtoForSave(): Record<string, any> {\n const base = this.data?.initialDto || {};\n const merged = { ...base, ...(this.lastValue || {}) };\n return this.clean(merged);\n }\n private updateCanSave(): void {\n this.canSave = Object.keys(this.buildDtoForSave() || {}).length > 0;\n }\n saveShortcut(): void {\n try {\n const dto = this.buildDtoForSave();\n if (!Object.keys(dto).length) return;\n this.data?.onSaveShortcut?.(dto);\n } catch {}\n }\n}\n"],"names":["i2","i4"],"mappings":";;;;;;;;;;;;;;MAyFa,6BAA6B,CAAA;AAO/B,IAAA,IAAA;AAWC,IAAA,GAAA;IAjBV,KAAK,GAAG,IAAI;IACJ,SAAS,GAAQ,EAAE;IACnB,SAAS,GAA0C,IAAI;IAC/D,OAAO,GAAG,KAAK;IACf,WAAA,CAES,IAUN,EACO,GAAgD,EAAA;QAXjD,IAAA,CAAA,IAAI,GAAJ,IAAI;QAWH,IAAA,CAAA,GAAG,GAAH,GAAG;IACV;AAEH,IAAA,OAAO,CAAC,EAAsB,EAAA;AAC5B,QAAA,IAAI;YACF,IAAI,CAAC,SAAS,GAAI,EAAE,EAAE,SAA4C,IAAI,IAAI;YAC1E,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,EAAE,UAAU,IAAI,EAAE;AACvC,YAAA,IAAI,EAAE,EAAE,SAAS,IAAI,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE;AACnD,gBAAA,EAAE,CAAC,SAAS,CAAC,UAAU,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;YACpD;AACA,YAAA,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,SAAS,EAAE,WAAW,IAAI,IAAI,IAAI,CAAC,SAAS;YAClE,IAAI,CAAC,aAAa,EAAE;QACtB;QAAE,MAAM,EAAC;IACX;AACA,IAAA,QAAQ,CAAC,EAAqC,EAAA;QAC5C,IAAI,CAAC,SAAS,GAAG,EAAE,EAAE,QAAQ,IAAI,EAAE;QACnC,IAAI,CAAC,aAAa,EAAE;IACtB;AACA,IAAA,UAAU,CAAC,CAAU,EAAA;AACnB,QAAA,IAAI,CAAC,KAAK,GAAG,CAAC;QACd,IAAI,CAAC,aAAa,EAAE;IACtB;IACA,KAAK,GAAA;QACH,MAAM,QAAQ,GACZ,IAAI,CAAC,SAAS,EAAE,WAAW,IAAI;AAC/B,YAAA,IAAI,CAAC,SAAS;YACd,IAAI,CAAC,IAAI,EAAE,UAAU;AACrB,YAAA,EAAE;QACJ,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,QAAQ,EAAE,CAAC;IAC9B;IACA,KAAK,GAAA,EAAW,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC,CAAC;AAE1B,IAAA,KAAK,CAAC,GAA2C,EAAA;QACvD,MAAM,GAAG,GAAwB,EAAE;AACnC,QAAA,MAAM,CAAC,IAAI,CAAC,GAAG,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,KAAI;AACnC,YAAA,MAAM,CAAC,GAAI,GAAW,CAAC,CAAC,CAAC;YACzB,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,SAAS;AAAE,gBAAA,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC;AAC3D,QAAA,CAAC,CAAC;AACF,QAAA,OAAO,GAAG;IACZ;IACQ,eAAe,GAAA;QACrB,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,EAAE,UAAU,IAAI,EAAE;AACxC,QAAA,MAAM,MAAM,GAAG,EAAE,GAAG,IAAI,EAAE,IAAI,IAAI,CAAC,SAAS,IAAI,EAAE,CAAC,EAAE;AACrD,QAAA,OAAO,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC;IAC3B;IACQ,aAAa,GAAA;AACnB,QAAA,IAAI,CAAC,OAAO,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,eAAe,EAAE,IAAI,EAAE,CAAC,CAAC,MAAM,GAAG,CAAC;IACrE;IACA,YAAY,GAAA;AACV,QAAA,IAAI;AACF,YAAA,MAAM,GAAG,GAAG,IAAI,CAAC,eAAe,EAAE;YAClC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,MAAM;gBAAE;YAC9B,IAAI,CAAC,IAAI,EAAE,cAAc,GAAG,GAAG,CAAC;QAClC;QAAE,MAAM,EAAC;IACX;AAxEW,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,kBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,SAAA,EAAA,QAAA,EAAA,EAAA,EAAA,IAAA,EAAA,6BAA6B,kBAM9B,eAAe,EAAA,EAAA,EAAA,KAAA,EAAA,EAAA,CAAA,YAAA,EAAA,CAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;AANd,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,SAAA,EAAA,IAAA,EAAA,6BAA6B,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,gCAAA,EAAA,QAAA,EAAA,EAAA,EAAA,QAAA,EA5E9B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCT,EAAA,QAAA,EAAA,IAAA,EAAA,MAAA,EAAA,CAAA,unBAAA,CAAA,EAAA,YAAA,EAAA,CAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EAtCS,YAAY,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAAA,IAAA,CAAA,IAAA,EAAA,QAAA,EAAA,QAAA,EAAA,MAAA,EAAA,CAAA,MAAA,EAAA,UAAA,EAAA,UAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EAAE,eAAe,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,cAAA,EAAA,QAAA,EAAA,sCAAA,EAAA,MAAA,EAAA,CAAA,IAAA,CAAA,EAAA,QAAA,EAAA,CAAA,gBAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,gBAAA,EAAA,QAAA,EAAA,8DAAA,EAAA,MAAA,EAAA,CAAA,OAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,gBAAA,EAAA,QAAA,EAAA,8DAAA,EAAA,EAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EAAE,eAAe,0iBAAE,oBAAoB,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAAC,GAAA,CAAA,cAAA,EAAA,QAAA,EAAA,kBAAA,EAAA,MAAA,EAAA,CAAA,OAAA,EAAA,OAAA,EAAA,aAAA,EAAA,MAAA,CAAA,EAAA,OAAA,EAAA,CAAA,cAAA,CAAA,EAAA,QAAA,EAAA,CAAA,gBAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EAAE,aAAa,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,OAAA,EAAA,QAAA,EAAA,UAAA,EAAA,MAAA,EAAA,CAAA,OAAA,EAAA,QAAA,EAAA,SAAA,EAAA,SAAA,EAAA,UAAA,CAAA,EAAA,QAAA,EAAA,CAAA,SAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAE,gBAAgB,EAAA,QAAA,EAAA,oBAAA,EAAA,MAAA,EAAA,CAAA,QAAA,EAAA,QAAA,EAAA,cAAA,EAAA,MAAA,CAAA,EAAA,OAAA,EAAA,CAAA,WAAA,EAAA,aAAA,EAAA,QAAA,EAAA,gBAAA,CAAA,EAAA,CAAA,EAAA,CAAA;;4FA6EpG,6BAA6B,EAAA,UAAA,EAAA,CAAA;kBAhFzC,SAAS;AACE,YAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,gCAAgC,cAC9B,IAAI,EAAA,OAAA,EACP,CAAC,YAAY,EAAE,eAAe,EAAE,eAAe,EAAE,oBAAoB,EAAE,aAAa,EAAE,gBAAgB,CAAC,EAAA,QAAA,EACtG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAqCT,EAAA,CAAA,EAAA,MAAA,EAAA,CAAA,unBAAA,CAAA,EAAA;;0BA6CE,MAAM;2BAAC,eAAe;;;;;"}
1
+ {"version":3,"file":"praxisui-table-filter-form-dialog-host.component-CZsEBHoS.mjs","sources":["../../../projects/praxis-table/src/lib/components/praxis-filter/filter-form-dialog-host.component.ts"],"sourcesContent":["import { Component, Inject } from '@angular/core';\nimport { CommonModule } from '@angular/common';\nimport { MatDialogModule, MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog';\nimport { MatButtonModule } from '@angular/material/button';\nimport { MatProgressBarModule } from '@angular/material/progress-bar';\nimport { MatIconModule } from '@angular/material/icon';\nimport { FormGroup } from '@angular/forms';\nimport { PraxisFilterForm } from '@praxisui/dynamic-form';\n\n@Component({\n selector: 'praxis-filter-form-dialog-host',\n standalone: true,\n imports: [CommonModule, MatDialogModule, MatButtonModule, MatProgressBarModule, MatIconModule, PraxisFilterForm],\n template: `\n <div mat-dialog-title class=\"pfx-dialog-title\" id=\"filterDialogTitle\">\n <div class=\"pfx-dialog-title-text\">\n <mat-icon>tune</mat-icon>\n <span>{{ data.title || 'Filtro avançado' }}</span>\n </div>\n <button mat-icon-button type=\"button\" class=\"pfx-dialog-close\" (click)=\"close()\"\n [attr.aria-label]=\"data.i18n?.cancel || 'Fechar'\">\n <mat-icon>close</mat-icon>\n </button>\n </div>\n <mat-dialog-content class=\"pfx-filter-dialog-content\" aria-labelledby=\"filterDialogTitle\">\n <mat-progress-bar *ngIf=\"data?.schemaLoading\" mode=\"indeterminate\"></mat-progress-bar>\n <praxis-filter-form\n *ngIf=\"data?.config\"\n [formId]=\"data.formId\"\n [resourcePath]=\"data.resourcePath\"\n [mode]=\"'edit'\"\n [config]=\"data.config\"\n (formReady)=\"onReady($event)\"\n (valueChange)=\"onChange($event)\"\n (validityChange)=\"onValidity($event)\"\n ></praxis-filter-form>\n <p *ngIf=\"!data?.config && !data?.schemaLoading\" class=\"pfx-empty-state\">{{ data.i18n?.noData || 'Nenhum dado' }}</p>\n </mat-dialog-content>\n <mat-dialog-actions align=\"end\" class=\"pfx-dialog-actions\">\n <button mat-button type=\"button\"\n *ngIf=\"data?.allowSaveTags\"\n [disabled]=\"!canSave\"\n (click)=\"saveShortcut()\">\n {{ data.i18n?.saveAsShortcut || 'Salvar como atalho' }}\n </button>\n <button mat-stroked-button type=\"button\" (click)=\"close()\">{{ data.i18n?.cancel || 'Cancelar' }}</button>\n <button mat-flat-button color=\"primary\" (click)=\"apply()\" [disabled]=\"!valid\">\n {{ data.i18n?.apply || 'Aplicar' }}\n </button>\n </mat-dialog-actions>\n `,\n styles: [`\n .pfx-dialog-title {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 12px;\n padding-right: 8px;\n }\n .pfx-dialog-title-text {\n display: inline-flex;\n align-items: center;\n gap: 8px;\n font-weight: 600;\n color: var(--md-sys-color-on-surface);\n }\n .pfx-dialog-close {\n margin-left: auto;\n }\n .pfx-filter-dialog-content {\n display: flex;\n flex-direction: column;\n gap: 12px;\n padding-top: 8px;\n }\n .pfx-empty-state {\n margin: 8px 0 0;\n color: var(--md-sys-color-on-surface-variant);\n }\n .pfx-dialog-actions {\n padding: var(--pdx-dialog-actions-padding, 12px 24px 16px);\n border-top: 1px solid var(--md-sys-color-outline-variant);\n background: transparent;\n display: flex;\n align-items: center;\n gap: 8px;\n }\n `],\n})\nexport class FilterFormDialogHostComponent {\n valid = true;\n private lastValue: any = {};\n private formGroup: FormGroup<Record<string, any>> | null = null;\n canSave = false;\n constructor(\n @Inject(MAT_DIALOG_DATA)\n public data: {\n formId: string;\n resourcePath: string;\n config: any;\n title?: string;\n schemaLoading?: boolean;\n initialDto?: Record<string, any>;\n allowSaveTags?: boolean;\n i18n?: { saveAsShortcut?: string; cancel?: string; apply?: string; noData?: string };\n onSaveShortcut?: (dto: Record<string, any>) => void;\n },\n private ref: MatDialogRef<FilterFormDialogHostComponent>,\n ) {}\n\n onReady(ev: { formGroup: any }): void {\n try {\n this.formGroup = (ev?.formGroup as FormGroup<Record<string, any>>) || null;\n const dto = this.data?.initialDto || {};\n if (ev?.formGroup && dto && Object.keys(dto).length) {\n ev.formGroup.patchValue(dto, { emitEvent: false });\n }\n this.lastValue = this.formGroup?.getRawValue?.() ?? this.lastValue;\n this.updateCanSave();\n } catch {}\n }\n onChange(ev: { formData: Record<string, any> }): void {\n this.lastValue = ev?.formData ?? {};\n this.updateCanSave();\n }\n onValidity(v: boolean): void {\n this.valid = v;\n this.updateCanSave();\n }\n apply(): void {\n const formData =\n this.formGroup?.getRawValue?.() ??\n this.lastValue ??\n this.data?.initialDto ??\n {};\n this.ref.close({ formData });\n }\n close(): void { this.ref.close(); }\n\n private clean(obj: Record<string, any> | undefined | null): Record<string, any> {\n const out: Record<string, any> = {};\n Object.keys(obj || {}).forEach((k) => {\n const v = (obj as any)[k];\n if (v !== '' && v !== null && v !== undefined) out[k] = v;\n });\n return out;\n }\n private buildDtoForSave(): Record<string, any> {\n const base = this.data?.initialDto || {};\n const merged = { ...base, ...(this.lastValue || {}) };\n return this.clean(merged);\n }\n private updateCanSave(): void {\n this.canSave = Object.keys(this.buildDtoForSave() || {}).length > 0;\n }\n saveShortcut(): void {\n try {\n const dto = this.buildDtoForSave();\n if (!Object.keys(dto).length) return;\n this.data?.onSaveShortcut?.(dto);\n } catch {}\n }\n}\n"],"names":["i4"],"mappings":"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"}