@praxisui/metadata-editor 8.0.0-beta.0 → 8.0.0-beta.11
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 +9 -0
- package/fesm2022/praxisui-metadata-editor.mjs +1550 -29
- package/index.d.ts +24 -3
- package/package.json +1 -1
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { Injectable, inject, Component, Input, ViewEncapsulation, EventEmitter, DestroyRef, Output, signal } from '@angular/core';
|
|
3
|
-
import * as
|
|
4
|
-
import { FormControl, FormGroup, ReactiveFormsModule, FormsModule } from '@angular/forms';
|
|
5
|
-
import * as i3
|
|
2
|
+
import { Injectable, inject, Component, Input, ViewEncapsulation, EventEmitter, DestroyRef, Output, signal, ENVIRONMENT_INITIALIZER } from '@angular/core';
|
|
3
|
+
import * as i2 from '@angular/forms';
|
|
4
|
+
import { FormControl, FormGroup, ReactiveFormsModule, FormArray, FormBuilder, FormsModule } from '@angular/forms';
|
|
5
|
+
import * as i3 from '@angular/common';
|
|
6
6
|
import { CommonModule } from '@angular/common';
|
|
7
7
|
import { DynamicFieldLoaderDirective } from '@praxisui/dynamic-fields';
|
|
8
|
-
import * as i2$
|
|
9
|
-
import { FieldControlType, PraxisIconDirective, INLINE_FILTER_CONTROL_TYPES, resolveInlineFilterControlType, normalizeControlTypeToken } from '@praxisui/core';
|
|
8
|
+
import * as i2$2 from '@praxisui/core';
|
|
9
|
+
import { FieldControlType, PraxisIconDirective, providePraxisI18n, PraxisI18nService, INLINE_FILTER_CONTROL_TYPES, resolveInlineFilterControlType, normalizeControlTypeToken, ComponentMetadataRegistry } from '@praxisui/core';
|
|
10
10
|
import * as i5 from '@angular/material/expansion';
|
|
11
11
|
import { MatExpansionModule } from '@angular/material/expansion';
|
|
12
12
|
import * as i6 from '@angular/material/icon';
|
|
@@ -17,7 +17,7 @@ import * as i1 from '@angular/material/dialog';
|
|
|
17
17
|
import { MatDialogRef, MatDialogModule } from '@angular/material/dialog';
|
|
18
18
|
import * as i8 from '@angular/material/tooltip';
|
|
19
19
|
import { MatTooltipModule } from '@angular/material/tooltip';
|
|
20
|
-
import * as i2 from '@angular/material/list';
|
|
20
|
+
import * as i2$1 from '@angular/material/list';
|
|
21
21
|
import { MatListModule } from '@angular/material/list';
|
|
22
22
|
import { SETTINGS_PANEL_DATA } from '@praxisui/settings-panel';
|
|
23
23
|
import { BehaviorSubject } from 'rxjs';
|
|
@@ -276,13 +276,13 @@ class DynamicFormFactoryService {
|
|
|
276
276
|
}
|
|
277
277
|
return result;
|
|
278
278
|
}
|
|
279
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: DynamicFormFactoryService, deps: [{ token:
|
|
279
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: DynamicFormFactoryService, deps: [{ token: i2.FormBuilder }, { token: ContextValidatorRegistryService }], target: i0.ɵɵFactoryTarget.Injectable });
|
|
280
280
|
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: DynamicFormFactoryService, providedIn: 'root' });
|
|
281
281
|
}
|
|
282
282
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: DynamicFormFactoryService, decorators: [{
|
|
283
283
|
type: Injectable,
|
|
284
284
|
args: [{ providedIn: 'root' }]
|
|
285
|
-
}], ctorParameters: () => [{ type:
|
|
285
|
+
}], ctorParameters: () => [{ type: i2.FormBuilder }, { type: ContextValidatorRegistryService }] });
|
|
286
286
|
|
|
287
287
|
class EditorComponentRegistryService {
|
|
288
288
|
registry = new Map();
|
|
@@ -371,7 +371,7 @@ class RegexHelpDialogComponent {
|
|
|
371
371
|
<div mat-dialog-actions>
|
|
372
372
|
<button class="mat-mdc-button mdc-button" mat-dialog-close>Fechar</button>
|
|
373
373
|
</div>
|
|
374
|
-
`, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: MatDialogModule }, { kind: "directive", type: i1.MatDialogClose, selector: "[mat-dialog-close], [matDialogClose]", inputs: ["aria-label", "type", "mat-dialog-close", "matDialogClose"], exportAs: ["matDialogClose"] }, { 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: MatListModule }, { kind: "component", type: i2.MatNavList, selector: "mat-nav-list", exportAs: ["matNavList"] }, { kind: "component", type: i2.MatListItem, selector: "mat-list-item, a[mat-list-item], button[mat-list-item]", inputs: ["activated"], exportAs: ["matListItem"] }, { kind: "directive", type: i2.MatListItemLine, selector: "[matListItemLine]" }, { kind: "directive", type: i2.MatListItemTitle, selector: "[matListItemTitle]" }, { kind: "ngmodule", type: MatButtonModule }] });
|
|
374
|
+
`, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: MatDialogModule }, { kind: "directive", type: i1.MatDialogClose, selector: "[mat-dialog-close], [matDialogClose]", inputs: ["aria-label", "type", "mat-dialog-close", "matDialogClose"], exportAs: ["matDialogClose"] }, { 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: MatListModule }, { kind: "component", type: i2$1.MatNavList, selector: "mat-nav-list", exportAs: ["matNavList"] }, { kind: "component", type: i2$1.MatListItem, selector: "mat-list-item, a[mat-list-item], button[mat-list-item]", inputs: ["activated"], exportAs: ["matListItem"] }, { kind: "directive", type: i2$1.MatListItemLine, selector: "[matListItemLine]" }, { kind: "directive", type: i2$1.MatListItemTitle, selector: "[matListItemTitle]" }, { kind: "ngmodule", type: MatButtonModule }] });
|
|
375
375
|
}
|
|
376
376
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: RegexHelpDialogComponent, decorators: [{
|
|
377
377
|
type: Component,
|
|
@@ -683,7 +683,7 @@ class DynamicEditorRendererComponent {
|
|
|
683
683
|
this.form?.markAsDirty();
|
|
684
684
|
}
|
|
685
685
|
}
|
|
686
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: DynamicEditorRendererComponent, deps: [{ token: i1.MatDialog }, { token: i2$
|
|
686
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: DynamicEditorRendererComponent, deps: [{ token: i1.MatDialog }, { token: i2$2.IconPickerService }], target: i0.ɵɵFactoryTarget.Component });
|
|
687
687
|
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.17", type: DynamicEditorRendererComponent, isStandalone: true, selector: "praxis-dynamic-editor-renderer", inputs: { properties: "properties", form: "form" }, usesOnChanges: true, ngImport: i0, template: `
|
|
688
688
|
<ng-template #item let-field="field" let-index="index" let-content="content">
|
|
689
689
|
<div class="editor-item" [attr.data-control-type]="field.controlType">
|
|
@@ -753,7 +753,7 @@ class DynamicEditorRendererComponent {
|
|
|
753
753
|
</mat-expansion-panel>
|
|
754
754
|
</mat-accordion>
|
|
755
755
|
</div>
|
|
756
|
-
`, isInline: true, styles: [":host{display:block}.editor-surface{padding:8px 0 2px;border-radius:12px;background:transparent}.section-accordion{display:block}.section-card{margin:6px 0 8px;border-radius:12px;border:1px solid var(--md-sys-color-outline-variant);overflow:hidden}.section-card.mat-expanded{border-color:var(--md-sys-color-primary);box-shadow:0 2px 10px #0000000d}.section-card .mat-expansion-panel-body{background:var(--md-sys-color-surface-container-low)}.section-header{background:var(--md-sys-color-surface-container-low);border-bottom:1px solid var(--md-sys-color-outline-variant, var(--sicoob-stroke-medium));padding:2px 8px;min-height:32px;display:flex;align-items:center;color:var(--md-sys-color-on-surface)}.section-header .mat-expansion-panel-header-title,.section-header .mat-expansion-panel-header-description{display:flex;align-items:center;color:var(--md-sys-color-on-surface)}.section-title{display:inline-flex;align-items:center;gap:6px;font-weight:600;letter-spacing:.2px;color:var(--md-sys-color-on-surface);font-size:.9rem;line-height:1.2}.section-icon{color:var(--md-sys-color-primary, var(--md-sys-color-primary, #3f51b5));opacity:.9}.editor-row{display:flex;gap:12px;align-items:flex-start;flex-wrap:wrap;margin-bottom:8px}.editor-row>praxis-field-shell{flex:1 1 100%;min-width:280px}.editor-row praxis-field-shell .mat-mdc-form-field{width:100%;margin-bottom:8px}.editor-row.row-inline>praxis-field-shell{flex:0 0 auto}.editor-row.row-2>praxis-field-shell{flex:1 1 calc(50% - 12px);min-width:260px}.editor-row.row-3>praxis-field-shell{flex:1 1 calc(33.333% - 12px);min-width:220px}.editor-row>praxis-field-shell[data-field-name=controlType],.editor-row>praxis-field-shell[data-field-name=label],.editor-row>praxis-field-shell[data-field-name=placeholder]{flex:1 1 calc(50% - 12px);min-width:300px}praxis-field-shell[data-field-name=label] .mdc-floating-label,praxis-field-shell[data-field-name=placeholder] .mdc-floating-label{font-weight:600}.editor-row>praxis-field-shell[data-field-name=prefix],.editor-row>praxis-field-shell[data-field-name=suffix]{flex:0 0 200px;min-width:160px}.editor-row>praxis-field-shell[data-field-name=prefixIcon],.editor-row>praxis-field-shell[data-field-name=suffixIcon],.editor-row>praxis-field-shell[data-field-name=prefixIconColor],.editor-row>praxis-field-shell[data-field-name=suffixIconColor]{flex:1 1 auto;min-width:160px}.editor-item{display:flex;align-items:flex-start;gap:4px}.editor-item>ng-container,.editor-item>praxis-field-shell{flex:1;min-width:0}.actions-container{display:flex;align-items:center;gap:0;margin-top:12px;flex-shrink:0}.decorator-btn{position:static;color:var(--md-sys-color-primary, #3f51b5);opacity:.6;transform:scale(.8);width:32px;height:32px;line-height:32px;padding:0}.decorator-btn:hover{opacity:1}.icon-picker-btn,.hint-btn,.hint-btn.has-icon-picker{right:auto}.editor-row .mat-mdc-form-field-subscript-wrapper mat-hint{display:none!important}.editor-row .mat-mdc-form-field-subscript-wrapper mat-error{display:block!important}praxis-field-shell[data-field-name=showCharCount] .mdc-switch{transform:scale(1.05)}praxis-field-shell[data-field-name=showCharCount] .mat-mdc-slide-toggle{font-weight:600}praxis-field-shell[data-field-name=controlType] .mat-mdc-form-field-hint{display:flex;align-items:center;gap:8px;background:var(--md-sys-color-tertiary-container);border:1px solid var(--md-sys-color-tertiary);color:var(--md-sys-color-on-tertiary-container);padding:8px 10px;border-radius:6px;line-height:1.3;white-space:normal}praxis-field-shell[data-field-name=controlType] .mat-mdc-form-field-hint:before{content:\"\\26a0\\fe0f\";display:inline-block}praxis-field-shell[data-field-name=controlType] .mat-mdc-form-field-subscript-wrapper{margin-top:6px;margin-bottom:10px;min-height:auto}praxis-field-shell[data-field-name=controlType] .mat-mdc-form-field{margin-bottom:16px}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i3
|
|
756
|
+
`, isInline: true, styles: [":host{display:block}.editor-surface{padding:8px 0 2px;border-radius:12px;background:transparent}.section-accordion{display:block}.section-card{margin:6px 0 8px;border-radius:12px;border:1px solid var(--md-sys-color-outline-variant);overflow:hidden}.section-card.mat-expanded{border-color:var(--md-sys-color-primary);box-shadow:0 2px 10px #0000000d}.section-card .mat-expansion-panel-body{background:var(--md-sys-color-surface-container-low)}.section-header{background:var(--md-sys-color-surface-container-low);border-bottom:1px solid var(--md-sys-color-outline-variant, var(--sicoob-stroke-medium));padding:2px 8px;min-height:32px;display:flex;align-items:center;color:var(--md-sys-color-on-surface)}.section-header .mat-expansion-panel-header-title,.section-header .mat-expansion-panel-header-description{display:flex;align-items:center;color:var(--md-sys-color-on-surface)}.section-title{display:inline-flex;align-items:center;gap:6px;font-weight:600;letter-spacing:.2px;color:var(--md-sys-color-on-surface);font-size:.9rem;line-height:1.2}.section-icon{color:var(--md-sys-color-primary, var(--md-sys-color-primary, #3f51b5));opacity:.9}.editor-row{display:flex;gap:12px;align-items:flex-start;flex-wrap:wrap;margin-bottom:8px}.editor-row>praxis-field-shell{flex:1 1 100%;min-width:280px}.editor-row praxis-field-shell .mat-mdc-form-field{width:100%;margin-bottom:8px}.editor-row.row-inline>praxis-field-shell{flex:0 0 auto}.editor-row.row-2>praxis-field-shell{flex:1 1 calc(50% - 12px);min-width:260px}.editor-row.row-3>praxis-field-shell{flex:1 1 calc(33.333% - 12px);min-width:220px}.editor-row>praxis-field-shell[data-field-name=controlType],.editor-row>praxis-field-shell[data-field-name=label],.editor-row>praxis-field-shell[data-field-name=placeholder]{flex:1 1 calc(50% - 12px);min-width:300px}praxis-field-shell[data-field-name=label] .mdc-floating-label,praxis-field-shell[data-field-name=placeholder] .mdc-floating-label{font-weight:600}.editor-row>praxis-field-shell[data-field-name=prefix],.editor-row>praxis-field-shell[data-field-name=suffix]{flex:0 0 200px;min-width:160px}.editor-row>praxis-field-shell[data-field-name=prefixIcon],.editor-row>praxis-field-shell[data-field-name=suffixIcon],.editor-row>praxis-field-shell[data-field-name=prefixIconColor],.editor-row>praxis-field-shell[data-field-name=suffixIconColor]{flex:1 1 auto;min-width:160px}.editor-item{display:flex;align-items:flex-start;gap:4px}.editor-item>ng-container,.editor-item>praxis-field-shell{flex:1;min-width:0}.actions-container{display:flex;align-items:center;gap:0;margin-top:12px;flex-shrink:0}.decorator-btn{position:static;color:var(--md-sys-color-primary, #3f51b5);opacity:.6;transform:scale(.8);width:32px;height:32px;line-height:32px;padding:0}.decorator-btn:hover{opacity:1}.icon-picker-btn,.hint-btn,.hint-btn.has-icon-picker{right:auto}.editor-row .mat-mdc-form-field-subscript-wrapper mat-hint{display:none!important}.editor-row .mat-mdc-form-field-subscript-wrapper mat-error{display:block!important}praxis-field-shell[data-field-name=showCharCount] .mdc-switch{transform:scale(1.05)}praxis-field-shell[data-field-name=showCharCount] .mat-mdc-slide-toggle{font-weight:600}praxis-field-shell[data-field-name=controlType] .mat-mdc-form-field-hint{display:flex;align-items:center;gap:8px;background:var(--md-sys-color-tertiary-container);border:1px solid var(--md-sys-color-tertiary);color:var(--md-sys-color-on-tertiary-container);padding:8px 10px;border-radius:6px;line-height:1.3;white-space:normal}praxis-field-shell[data-field-name=controlType] .mat-mdc-form-field-hint:before{content:\"\\26a0\\fe0f\";display:inline-block}praxis-field-shell[data-field-name=controlType] .mat-mdc-form-field-subscript-wrapper{margin-top:6px;margin-bottom:10px;min-height:auto}praxis-field-shell[data-field-name=controlType] .mat-mdc-form-field{margin-bottom:16px}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i3.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i3.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i3.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: DynamicFieldLoaderDirective, selector: "[dynamicFieldLoader]", inputs: ["fields", "formGroup", "enableExternalControlBinding", "itemTemplate", "debugTrace", "debugTraceLabel", "readonlyMode", "disabledMode", "presentationMode", "visible", "canvasMode"], outputs: ["componentsCreated", "fieldCreated", "fieldDestroyed", "renderError", "canvasMouseEnter", "canvasMouseLeave", "canvasClick"] }, { kind: "ngmodule", type: MatExpansionModule }, { kind: "directive", type: i5.MatAccordion, selector: "mat-accordion", inputs: ["hideToggle", "displayMode", "togglePosition"], exportAs: ["matAccordion"] }, { kind: "component", type: i5.MatExpansionPanel, selector: "mat-expansion-panel", inputs: ["hideToggle", "togglePosition"], outputs: ["afterExpand", "afterCollapse"], exportAs: ["matExpansionPanel"] }, { kind: "component", type: i5.MatExpansionPanelHeader, selector: "mat-expansion-panel-header", inputs: ["expandedHeight", "collapsedHeight", "tabIndex"] }, { kind: "directive", type: i5.MatExpansionPanelTitle, selector: "mat-panel-title" }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i6.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i5$1.MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatDialogModule }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i8.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "directive", type: PraxisIconDirective, selector: "mat-icon[praxisIcon]", inputs: ["praxisIcon"] }], encapsulation: i0.ViewEncapsulation.None });
|
|
757
757
|
}
|
|
758
758
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: DynamicEditorRendererComponent, decorators: [{
|
|
759
759
|
type: Component,
|
|
@@ -837,12 +837,837 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
|
|
|
837
837
|
</mat-accordion>
|
|
838
838
|
</div>
|
|
839
839
|
`, styles: [":host{display:block}.editor-surface{padding:8px 0 2px;border-radius:12px;background:transparent}.section-accordion{display:block}.section-card{margin:6px 0 8px;border-radius:12px;border:1px solid var(--md-sys-color-outline-variant);overflow:hidden}.section-card.mat-expanded{border-color:var(--md-sys-color-primary);box-shadow:0 2px 10px #0000000d}.section-card .mat-expansion-panel-body{background:var(--md-sys-color-surface-container-low)}.section-header{background:var(--md-sys-color-surface-container-low);border-bottom:1px solid var(--md-sys-color-outline-variant, var(--sicoob-stroke-medium));padding:2px 8px;min-height:32px;display:flex;align-items:center;color:var(--md-sys-color-on-surface)}.section-header .mat-expansion-panel-header-title,.section-header .mat-expansion-panel-header-description{display:flex;align-items:center;color:var(--md-sys-color-on-surface)}.section-title{display:inline-flex;align-items:center;gap:6px;font-weight:600;letter-spacing:.2px;color:var(--md-sys-color-on-surface);font-size:.9rem;line-height:1.2}.section-icon{color:var(--md-sys-color-primary, var(--md-sys-color-primary, #3f51b5));opacity:.9}.editor-row{display:flex;gap:12px;align-items:flex-start;flex-wrap:wrap;margin-bottom:8px}.editor-row>praxis-field-shell{flex:1 1 100%;min-width:280px}.editor-row praxis-field-shell .mat-mdc-form-field{width:100%;margin-bottom:8px}.editor-row.row-inline>praxis-field-shell{flex:0 0 auto}.editor-row.row-2>praxis-field-shell{flex:1 1 calc(50% - 12px);min-width:260px}.editor-row.row-3>praxis-field-shell{flex:1 1 calc(33.333% - 12px);min-width:220px}.editor-row>praxis-field-shell[data-field-name=controlType],.editor-row>praxis-field-shell[data-field-name=label],.editor-row>praxis-field-shell[data-field-name=placeholder]{flex:1 1 calc(50% - 12px);min-width:300px}praxis-field-shell[data-field-name=label] .mdc-floating-label,praxis-field-shell[data-field-name=placeholder] .mdc-floating-label{font-weight:600}.editor-row>praxis-field-shell[data-field-name=prefix],.editor-row>praxis-field-shell[data-field-name=suffix]{flex:0 0 200px;min-width:160px}.editor-row>praxis-field-shell[data-field-name=prefixIcon],.editor-row>praxis-field-shell[data-field-name=suffixIcon],.editor-row>praxis-field-shell[data-field-name=prefixIconColor],.editor-row>praxis-field-shell[data-field-name=suffixIconColor]{flex:1 1 auto;min-width:160px}.editor-item{display:flex;align-items:flex-start;gap:4px}.editor-item>ng-container,.editor-item>praxis-field-shell{flex:1;min-width:0}.actions-container{display:flex;align-items:center;gap:0;margin-top:12px;flex-shrink:0}.decorator-btn{position:static;color:var(--md-sys-color-primary, #3f51b5);opacity:.6;transform:scale(.8);width:32px;height:32px;line-height:32px;padding:0}.decorator-btn:hover{opacity:1}.icon-picker-btn,.hint-btn,.hint-btn.has-icon-picker{right:auto}.editor-row .mat-mdc-form-field-subscript-wrapper mat-hint{display:none!important}.editor-row .mat-mdc-form-field-subscript-wrapper mat-error{display:block!important}praxis-field-shell[data-field-name=showCharCount] .mdc-switch{transform:scale(1.05)}praxis-field-shell[data-field-name=showCharCount] .mat-mdc-slide-toggle{font-weight:600}praxis-field-shell[data-field-name=controlType] .mat-mdc-form-field-hint{display:flex;align-items:center;gap:8px;background:var(--md-sys-color-tertiary-container);border:1px solid var(--md-sys-color-tertiary);color:var(--md-sys-color-on-tertiary-container);padding:8px 10px;border-radius:6px;line-height:1.3;white-space:normal}praxis-field-shell[data-field-name=controlType] .mat-mdc-form-field-hint:before{content:\"\\26a0\\fe0f\";display:inline-block}praxis-field-shell[data-field-name=controlType] .mat-mdc-form-field-subscript-wrapper{margin-top:6px;margin-bottom:10px;min-height:auto}praxis-field-shell[data-field-name=controlType] .mat-mdc-form-field{margin-bottom:16px}\n"] }]
|
|
840
|
-
}], ctorParameters: () => [{ type: i1.MatDialog }, { type: i2$
|
|
840
|
+
}], ctorParameters: () => [{ type: i1.MatDialog }, { type: i2$2.IconPickerService }], propDecorators: { properties: [{
|
|
841
841
|
type: Input
|
|
842
842
|
}], form: [{
|
|
843
843
|
type: Input
|
|
844
844
|
}] } });
|
|
845
845
|
|
|
846
|
+
const METADATA_EDITOR_EN_US = {
|
|
847
|
+
'praxis.metadataEditor.arrayFields.section': 'Collection subfields',
|
|
848
|
+
'praxis.metadataEditor.arrayFields.title': 'Subfields',
|
|
849
|
+
'praxis.metadataEditor.arrayFields.add': 'Add subfield',
|
|
850
|
+
'praxis.metadataEditor.arrayFields.duplicateNames': 'There are duplicate names: {{names}}',
|
|
851
|
+
'praxis.metadataEditor.arrayFields.empty': 'No local subfields configured.',
|
|
852
|
+
'praxis.metadataEditor.arrayFields.name': 'Name',
|
|
853
|
+
'praxis.metadataEditor.arrayFields.nameRequired': 'Enter the subfield name.',
|
|
854
|
+
'praxis.metadataEditor.arrayFields.nameDuplicated': 'This name is already used in the collection.',
|
|
855
|
+
'praxis.metadataEditor.arrayFields.label': 'Label',
|
|
856
|
+
'praxis.metadataEditor.arrayFields.controlType': 'Control',
|
|
857
|
+
'praxis.metadataEditor.arrayFields.required': 'Required',
|
|
858
|
+
'praxis.metadataEditor.arrayFields.moveUp': 'Move up',
|
|
859
|
+
'praxis.metadataEditor.arrayFields.moveDown': 'Move down',
|
|
860
|
+
'praxis.metadataEditor.arrayFields.duplicate': 'Duplicate',
|
|
861
|
+
'praxis.metadataEditor.arrayFields.remove': 'Remove',
|
|
862
|
+
'praxis.metadataEditor.arrayFields.removeBlocked': 'Remove references before deleting: {{references}}',
|
|
863
|
+
'praxis.metadataEditor.arrayFields.refOnly': 'The item schema comes from itemSchemaRef; create local subfields only when you need an override.',
|
|
864
|
+
'praxis.metadataEditor.arrayFields.overrideLocal': 'There is an itemSchemaRef and local subfields; local subfields work as an explicit override.',
|
|
865
|
+
'praxis.metadataEditor.arrayFields.imported': 'Subfields imported. Review them before applying or saving.',
|
|
866
|
+
'praxis.metadataEditor.arrayFields.localOnly': 'Local subfields will be saved in array.itemSchema.fields.',
|
|
867
|
+
'praxis.metadataEditor.arrayFields.control.input': 'Text',
|
|
868
|
+
'praxis.metadataEditor.arrayFields.control.textarea': 'Long text',
|
|
869
|
+
'praxis.metadataEditor.arrayFields.control.numeric': 'Number',
|
|
870
|
+
'praxis.metadataEditor.arrayFields.control.currency': 'Currency',
|
|
871
|
+
'praxis.metadataEditor.arrayFields.control.email': 'Email',
|
|
872
|
+
'praxis.metadataEditor.arrayFields.control.phone': 'Phone',
|
|
873
|
+
'praxis.metadataEditor.arrayFields.control.select': 'Select',
|
|
874
|
+
'praxis.metadataEditor.arrayFields.control.entityLookup': 'Entity lookup',
|
|
875
|
+
'praxis.metadataEditor.arrayFields.control.toggle': 'Toggle',
|
|
876
|
+
'praxis.metadataEditor.arrayFields.control.date': 'Date',
|
|
877
|
+
};
|
|
878
|
+
|
|
879
|
+
const METADATA_EDITOR_PT_BR = {
|
|
880
|
+
'praxis.metadataEditor.arrayFields.section': 'Subcampos da cole\u00e7\u00e3o',
|
|
881
|
+
'praxis.metadataEditor.arrayFields.title': 'Subcampos',
|
|
882
|
+
'praxis.metadataEditor.arrayFields.add': 'Adicionar subcampo',
|
|
883
|
+
'praxis.metadataEditor.arrayFields.duplicateNames': 'Existem nomes duplicados: {{names}}',
|
|
884
|
+
'praxis.metadataEditor.arrayFields.empty': 'Nenhum subcampo local configurado.',
|
|
885
|
+
'praxis.metadataEditor.arrayFields.name': 'Nome',
|
|
886
|
+
'praxis.metadataEditor.arrayFields.nameRequired': 'Informe o nome do subcampo.',
|
|
887
|
+
'praxis.metadataEditor.arrayFields.nameDuplicated': 'Este nome j\u00e1 est\u00e1 em uso na cole\u00e7\u00e3o.',
|
|
888
|
+
'praxis.metadataEditor.arrayFields.label': 'Label',
|
|
889
|
+
'praxis.metadataEditor.arrayFields.controlType': 'Controle',
|
|
890
|
+
'praxis.metadataEditor.arrayFields.required': 'Obrigat\u00f3rio',
|
|
891
|
+
'praxis.metadataEditor.arrayFields.moveUp': 'Subir',
|
|
892
|
+
'praxis.metadataEditor.arrayFields.moveDown': 'Descer',
|
|
893
|
+
'praxis.metadataEditor.arrayFields.duplicate': 'Duplicar',
|
|
894
|
+
'praxis.metadataEditor.arrayFields.remove': 'Remover',
|
|
895
|
+
'praxis.metadataEditor.arrayFields.removeBlocked': 'Remova as refer\u00eancias antes de excluir: {{references}}',
|
|
896
|
+
'praxis.metadataEditor.arrayFields.refOnly': 'O schema do item vem do itemSchemaRef; crie subcampos locais apenas quando precisar de override.',
|
|
897
|
+
'praxis.metadataEditor.arrayFields.overrideLocal': 'H\u00e1 um itemSchemaRef e subcampos locais; os subcampos locais funcionam como override expl\u00edcito.',
|
|
898
|
+
'praxis.metadataEditor.arrayFields.imported': 'Subcampos importados. Revise antes de aplicar ou salvar.',
|
|
899
|
+
'praxis.metadataEditor.arrayFields.localOnly': 'Subcampos locais ser\u00e3o salvos em array.itemSchema.fields.',
|
|
900
|
+
'praxis.metadataEditor.arrayFields.control.input': 'Texto',
|
|
901
|
+
'praxis.metadataEditor.arrayFields.control.textarea': 'Texto longo',
|
|
902
|
+
'praxis.metadataEditor.arrayFields.control.numeric': 'N\u00famero',
|
|
903
|
+
'praxis.metadataEditor.arrayFields.control.currency': 'Moeda',
|
|
904
|
+
'praxis.metadataEditor.arrayFields.control.email': 'E-mail',
|
|
905
|
+
'praxis.metadataEditor.arrayFields.control.phone': 'Telefone',
|
|
906
|
+
'praxis.metadataEditor.arrayFields.control.select': 'Sele\u00e7\u00e3o',
|
|
907
|
+
'praxis.metadataEditor.arrayFields.control.entityLookup': 'Busca de entidade',
|
|
908
|
+
'praxis.metadataEditor.arrayFields.control.toggle': 'Liga/desliga',
|
|
909
|
+
'praxis.metadataEditor.arrayFields.control.date': 'Data',
|
|
910
|
+
};
|
|
911
|
+
|
|
912
|
+
function createPraxisMetadataEditorI18nConfig(options = {}) {
|
|
913
|
+
const dictionaries = {
|
|
914
|
+
'pt-BR': {
|
|
915
|
+
...METADATA_EDITOR_PT_BR,
|
|
916
|
+
...(options.dictionaries?.['pt-BR'] ?? {}),
|
|
917
|
+
},
|
|
918
|
+
'en-US': {
|
|
919
|
+
...METADATA_EDITOR_EN_US,
|
|
920
|
+
...(options.dictionaries?.['en-US'] ?? {}),
|
|
921
|
+
},
|
|
922
|
+
};
|
|
923
|
+
for (const [locale, dictionary] of Object.entries(options.dictionaries ?? {})) {
|
|
924
|
+
if (locale === 'pt-BR' || locale === 'en-US') {
|
|
925
|
+
continue;
|
|
926
|
+
}
|
|
927
|
+
dictionaries[locale] = {
|
|
928
|
+
...(dictionaries[locale] ?? {}),
|
|
929
|
+
...dictionary,
|
|
930
|
+
};
|
|
931
|
+
}
|
|
932
|
+
return {
|
|
933
|
+
locale: options.locale,
|
|
934
|
+
fallbackLocale: options.fallbackLocale ?? 'pt-BR',
|
|
935
|
+
dictionaries,
|
|
936
|
+
};
|
|
937
|
+
}
|
|
938
|
+
const METADATA_EDITOR_I18N_CONFIG = createPraxisMetadataEditorI18nConfig();
|
|
939
|
+
function providePraxisMetadataEditorI18n(options = {}) {
|
|
940
|
+
return providePraxisI18n(createPraxisMetadataEditorI18nConfig(options));
|
|
941
|
+
}
|
|
942
|
+
function resolvePraxisMetadataEditorText(i18n, key, fallback) {
|
|
943
|
+
const namespacedKey = key.startsWith('praxis.metadataEditor.')
|
|
944
|
+
? key
|
|
945
|
+
: `praxis.metadataEditor.${key}`;
|
|
946
|
+
return i18n.t(namespacedKey, undefined, fallback) || fallback;
|
|
947
|
+
}
|
|
948
|
+
|
|
949
|
+
class ArrayItemSchemaFieldsEditorComponent {
|
|
950
|
+
static nextInstanceId = 0;
|
|
951
|
+
control = null;
|
|
952
|
+
arrayControl = null;
|
|
953
|
+
formArray = new FormArray([]);
|
|
954
|
+
form = new FormGroup({ fields: this.formArray });
|
|
955
|
+
controlTypeOptions = [
|
|
956
|
+
FieldControlType.INPUT,
|
|
957
|
+
FieldControlType.TEXTAREA,
|
|
958
|
+
FieldControlType.NUMERIC_TEXT_BOX,
|
|
959
|
+
FieldControlType.CURRENCY_INPUT,
|
|
960
|
+
FieldControlType.EMAIL_INPUT,
|
|
961
|
+
FieldControlType.PHONE,
|
|
962
|
+
FieldControlType.SELECT,
|
|
963
|
+
FieldControlType.ENTITY_LOOKUP,
|
|
964
|
+
FieldControlType.TOGGLE,
|
|
965
|
+
FieldControlType.DATE_INPUT,
|
|
966
|
+
];
|
|
967
|
+
schemaSourceState = 'local-only';
|
|
968
|
+
duplicateNames = [];
|
|
969
|
+
fb = inject(FormBuilder);
|
|
970
|
+
i18n = inject(PraxisI18nService);
|
|
971
|
+
instanceId = ++ArrayItemSchemaFieldsEditorComponent.nextInstanceId;
|
|
972
|
+
externalSubscription;
|
|
973
|
+
internalSubscription;
|
|
974
|
+
originalNames = [];
|
|
975
|
+
importedFieldsFingerprint = null;
|
|
976
|
+
hydrating = false;
|
|
977
|
+
get rows() {
|
|
978
|
+
return this.formArray.controls;
|
|
979
|
+
}
|
|
980
|
+
ngOnChanges(changes) {
|
|
981
|
+
if (changes['control']) {
|
|
982
|
+
this.externalSubscription?.unsubscribe();
|
|
983
|
+
this.hydrateFromControl();
|
|
984
|
+
this.externalSubscription = this.control?.valueChanges.subscribe(() => {
|
|
985
|
+
if (!this.hydrating) {
|
|
986
|
+
this.hydrateFromControl();
|
|
987
|
+
}
|
|
988
|
+
});
|
|
989
|
+
}
|
|
990
|
+
if (changes['arrayControl'] || changes['control']) {
|
|
991
|
+
this.updateSchemaSourceState();
|
|
992
|
+
}
|
|
993
|
+
}
|
|
994
|
+
ngOnDestroy() {
|
|
995
|
+
this.externalSubscription?.unsubscribe();
|
|
996
|
+
this.internalSubscription?.unsubscribe();
|
|
997
|
+
}
|
|
998
|
+
text(key, fallback, fallbackWithParams, params) {
|
|
999
|
+
return this.i18n.t(key, params, fallbackWithParams ?? fallback);
|
|
1000
|
+
}
|
|
1001
|
+
controlTypeLabel(controlType) {
|
|
1002
|
+
const labels = {
|
|
1003
|
+
[FieldControlType.INPUT]: this.text('praxis.metadataEditor.arrayFields.control.input', 'Texto'),
|
|
1004
|
+
[FieldControlType.TEXTAREA]: this.text('praxis.metadataEditor.arrayFields.control.textarea', 'Texto longo'),
|
|
1005
|
+
[FieldControlType.NUMERIC_TEXT_BOX]: this.text('praxis.metadataEditor.arrayFields.control.numeric', 'N\u00famero'),
|
|
1006
|
+
[FieldControlType.CURRENCY_INPUT]: this.text('praxis.metadataEditor.arrayFields.control.currency', 'Moeda'),
|
|
1007
|
+
[FieldControlType.EMAIL_INPUT]: this.text('praxis.metadataEditor.arrayFields.control.email', 'E-mail'),
|
|
1008
|
+
[FieldControlType.PHONE]: this.text('praxis.metadataEditor.arrayFields.control.phone', 'Telefone'),
|
|
1009
|
+
[FieldControlType.SELECT]: this.text('praxis.metadataEditor.arrayFields.control.select', 'Sele\u00e7\u00e3o'),
|
|
1010
|
+
[FieldControlType.ENTITY_LOOKUP]: this.text('praxis.metadataEditor.arrayFields.control.entityLookup', 'Busca de entidade'),
|
|
1011
|
+
[FieldControlType.TOGGLE]: this.text('praxis.metadataEditor.arrayFields.control.toggle', 'Liga/desliga'),
|
|
1012
|
+
[FieldControlType.DATE_INPUT]: this.text('praxis.metadataEditor.arrayFields.control.date', 'Data'),
|
|
1013
|
+
};
|
|
1014
|
+
return labels[controlType] ?? controlType;
|
|
1015
|
+
}
|
|
1016
|
+
addField(seed = {}) {
|
|
1017
|
+
const fieldName = seed.name || this.nextAvailableName();
|
|
1018
|
+
this.formArray.push(this.createRow({
|
|
1019
|
+
...seed,
|
|
1020
|
+
name: fieldName,
|
|
1021
|
+
label: seed.label || fieldName,
|
|
1022
|
+
controlType: seed.controlType || FieldControlType.INPUT,
|
|
1023
|
+
required: seed.required ?? false,
|
|
1024
|
+
}));
|
|
1025
|
+
this.originalNames.push(fieldName);
|
|
1026
|
+
this.syncToControl();
|
|
1027
|
+
}
|
|
1028
|
+
duplicateField(index) {
|
|
1029
|
+
const current = this.rowValue(index);
|
|
1030
|
+
if (!current)
|
|
1031
|
+
return;
|
|
1032
|
+
const nextName = this.nextAvailableName(`${current.name || 'field'}Copy`);
|
|
1033
|
+
this.addField({
|
|
1034
|
+
...current,
|
|
1035
|
+
name: nextName,
|
|
1036
|
+
label: nextName,
|
|
1037
|
+
});
|
|
1038
|
+
}
|
|
1039
|
+
removeField(index) {
|
|
1040
|
+
const name = String(this.formArray.at(index)?.get('name')?.value || '').trim();
|
|
1041
|
+
if (this.isReferenced(name)) {
|
|
1042
|
+
return;
|
|
1043
|
+
}
|
|
1044
|
+
this.formArray.removeAt(index);
|
|
1045
|
+
this.originalNames.splice(index, 1);
|
|
1046
|
+
this.syncToControl();
|
|
1047
|
+
}
|
|
1048
|
+
moveField(index, delta) {
|
|
1049
|
+
const target = index + delta;
|
|
1050
|
+
if (target < 0 || target >= this.formArray.length)
|
|
1051
|
+
return;
|
|
1052
|
+
const row = this.formArray.at(index);
|
|
1053
|
+
this.formArray.removeAt(index);
|
|
1054
|
+
this.formArray.insert(target, row);
|
|
1055
|
+
const [originalName] = this.originalNames.splice(index, 1);
|
|
1056
|
+
this.originalNames.splice(target, 0, originalName);
|
|
1057
|
+
this.syncToControl();
|
|
1058
|
+
}
|
|
1059
|
+
onNameBlur(index) {
|
|
1060
|
+
const previous = this.originalNames[index];
|
|
1061
|
+
const next = String(this.formArray.at(index)?.get('name')?.value || '').trim();
|
|
1062
|
+
if (previous && !next && this.isReferenced(previous)) {
|
|
1063
|
+
this.formArray.at(index)?.get('name')?.setValue(previous, { emitEvent: false });
|
|
1064
|
+
this.syncToControl();
|
|
1065
|
+
return;
|
|
1066
|
+
}
|
|
1067
|
+
if (previous && next && previous !== next) {
|
|
1068
|
+
this.renameReferences(previous, next);
|
|
1069
|
+
this.originalNames[index] = next;
|
|
1070
|
+
}
|
|
1071
|
+
this.syncToControl();
|
|
1072
|
+
}
|
|
1073
|
+
importFieldsFromJson(raw) {
|
|
1074
|
+
try {
|
|
1075
|
+
const parsed = JSON.parse(String(raw || '').trim());
|
|
1076
|
+
if (!Array.isArray(parsed) ||
|
|
1077
|
+
parsed.some((entry) => !this.isImportableField(entry))) {
|
|
1078
|
+
return false;
|
|
1079
|
+
}
|
|
1080
|
+
this.replaceRows(parsed);
|
|
1081
|
+
this.schemaSourceState = 'imported';
|
|
1082
|
+
this.importedFieldsFingerprint = this.fieldsFingerprint();
|
|
1083
|
+
this.syncToControl();
|
|
1084
|
+
return true;
|
|
1085
|
+
}
|
|
1086
|
+
catch {
|
|
1087
|
+
return false;
|
|
1088
|
+
}
|
|
1089
|
+
}
|
|
1090
|
+
isImportableField(value) {
|
|
1091
|
+
if (!value || typeof value !== 'object' || Array.isArray(value)) {
|
|
1092
|
+
return false;
|
|
1093
|
+
}
|
|
1094
|
+
const raw = value;
|
|
1095
|
+
return typeof raw.name === 'string' && raw.name.trim().length > 0;
|
|
1096
|
+
}
|
|
1097
|
+
isNameDuplicated(index) {
|
|
1098
|
+
const name = String(this.formArray.at(index)?.get('name')?.value || '').trim();
|
|
1099
|
+
return !!name && this.duplicateNames.includes(name);
|
|
1100
|
+
}
|
|
1101
|
+
isNameInvalid(index) {
|
|
1102
|
+
const control = this.formArray.at(index)?.get('name');
|
|
1103
|
+
return !!control?.invalid;
|
|
1104
|
+
}
|
|
1105
|
+
nameErrorId(index) {
|
|
1106
|
+
return `praxis-array-field-name-error-${this.instanceId}-${index}`;
|
|
1107
|
+
}
|
|
1108
|
+
nameErrorDescribedBy(index) {
|
|
1109
|
+
return this.nameErrorMessage(index) ? this.nameErrorId(index) : null;
|
|
1110
|
+
}
|
|
1111
|
+
nameErrorMessage(index) {
|
|
1112
|
+
const control = this.formArray.at(index)?.get('name');
|
|
1113
|
+
if (!control?.errors) {
|
|
1114
|
+
return '';
|
|
1115
|
+
}
|
|
1116
|
+
if (control.errors['arrayFieldNameRequired']) {
|
|
1117
|
+
return this.text('praxis.metadataEditor.arrayFields.nameRequired', 'Informe o nome do subcampo.');
|
|
1118
|
+
}
|
|
1119
|
+
if (control.errors['arrayFieldNameDuplicated']) {
|
|
1120
|
+
return this.text('praxis.metadataEditor.arrayFields.nameDuplicated', 'Este nome j\u00e1 est\u00e1 em uso na cole\u00e7\u00e3o.');
|
|
1121
|
+
}
|
|
1122
|
+
return '';
|
|
1123
|
+
}
|
|
1124
|
+
isReferenced(fieldName) {
|
|
1125
|
+
return this.referencedBy(fieldName).length > 0;
|
|
1126
|
+
}
|
|
1127
|
+
removeTitle(fieldName) {
|
|
1128
|
+
const references = this.referencedBy(fieldName);
|
|
1129
|
+
if (!references.length) {
|
|
1130
|
+
return '';
|
|
1131
|
+
}
|
|
1132
|
+
return this.text('praxis.metadataEditor.arrayFields.removeBlocked', undefined, 'Remova as refer\u00eancias antes de excluir: {{references}}', { references: references.join(', ') });
|
|
1133
|
+
}
|
|
1134
|
+
schemaStateDescription() {
|
|
1135
|
+
switch (this.schemaSourceState) {
|
|
1136
|
+
case 'ref-only':
|
|
1137
|
+
return this.text('praxis.metadataEditor.arrayFields.refOnly', 'O schema do item vem do itemSchemaRef; crie subcampos locais apenas quando precisar de override.');
|
|
1138
|
+
case 'override-local':
|
|
1139
|
+
return this.text('praxis.metadataEditor.arrayFields.overrideLocal', 'H\u00e1 um itemSchemaRef e subcampos locais; os subcampos locais funcionam como override expl\u00edcito.');
|
|
1140
|
+
case 'imported':
|
|
1141
|
+
return this.text('praxis.metadataEditor.arrayFields.imported', 'Subcampos importados. Revise antes de aplicar ou salvar.');
|
|
1142
|
+
default:
|
|
1143
|
+
return this.text('praxis.metadataEditor.arrayFields.localOnly', 'Subcampos locais ser\u00e3o salvos em array.itemSchema.fields.');
|
|
1144
|
+
}
|
|
1145
|
+
}
|
|
1146
|
+
hydrateFromControl() {
|
|
1147
|
+
const fields = this.normalizeFields(this.control?.value);
|
|
1148
|
+
this.replaceRows(fields, false);
|
|
1149
|
+
this.updateSchemaSourceState();
|
|
1150
|
+
}
|
|
1151
|
+
replaceRows(fields, emit = true) {
|
|
1152
|
+
this.hydrating = true;
|
|
1153
|
+
this.internalSubscription?.unsubscribe();
|
|
1154
|
+
while (this.formArray.length) {
|
|
1155
|
+
this.formArray.removeAt(0, { emitEvent: false });
|
|
1156
|
+
}
|
|
1157
|
+
this.originalNames = [];
|
|
1158
|
+
for (const field of fields) {
|
|
1159
|
+
const normalized = this.normalizeField(field);
|
|
1160
|
+
this.formArray.push(this.createRow(normalized), { emitEvent: false });
|
|
1161
|
+
this.originalNames.push(normalized.name);
|
|
1162
|
+
}
|
|
1163
|
+
this.internalSubscription = this.formArray.valueChanges.subscribe(() => this.syncToControl());
|
|
1164
|
+
this.hydrating = false;
|
|
1165
|
+
this.updateFieldListValidity();
|
|
1166
|
+
if (emit) {
|
|
1167
|
+
this.syncToControl();
|
|
1168
|
+
}
|
|
1169
|
+
}
|
|
1170
|
+
createRow(field) {
|
|
1171
|
+
return this.fb.group({
|
|
1172
|
+
name: [field.name || ''],
|
|
1173
|
+
label: [field.label || field.name || ''],
|
|
1174
|
+
controlType: [field.controlType || FieldControlType.INPUT],
|
|
1175
|
+
required: [!!field.required],
|
|
1176
|
+
metadata: [this.clonePlainObject(field)],
|
|
1177
|
+
});
|
|
1178
|
+
}
|
|
1179
|
+
rowValue(index) {
|
|
1180
|
+
const row = this.formArray.at(index);
|
|
1181
|
+
return row ? this.normalizeField(row.getRawValue()) : null;
|
|
1182
|
+
}
|
|
1183
|
+
syncToControl() {
|
|
1184
|
+
if (this.hydrating || !this.control)
|
|
1185
|
+
return;
|
|
1186
|
+
const normalizedRows = this.formArray.controls.map((row) => this.normalizeField(row.getRawValue()));
|
|
1187
|
+
this.updateDuplicateNames(normalizedRows);
|
|
1188
|
+
const fields = normalizedRows.filter((field) => field.name);
|
|
1189
|
+
this.hydrating = true;
|
|
1190
|
+
this.control.setValue(fields, { emitEvent: true });
|
|
1191
|
+
this.control.markAsDirty();
|
|
1192
|
+
this.control.markAsTouched();
|
|
1193
|
+
this.hydrating = false;
|
|
1194
|
+
this.updateFieldListValidity(normalizedRows);
|
|
1195
|
+
this.updateSchemaSourceState();
|
|
1196
|
+
}
|
|
1197
|
+
normalizeFields(value) {
|
|
1198
|
+
if (Array.isArray(value)) {
|
|
1199
|
+
return value;
|
|
1200
|
+
}
|
|
1201
|
+
if (typeof value === 'string' && value.trim()) {
|
|
1202
|
+
try {
|
|
1203
|
+
const parsed = JSON.parse(value);
|
|
1204
|
+
return Array.isArray(parsed) ? parsed : [];
|
|
1205
|
+
}
|
|
1206
|
+
catch {
|
|
1207
|
+
return [];
|
|
1208
|
+
}
|
|
1209
|
+
}
|
|
1210
|
+
return [];
|
|
1211
|
+
}
|
|
1212
|
+
normalizeField(value) {
|
|
1213
|
+
const raw = (value && typeof value === 'object' ? value : {});
|
|
1214
|
+
const base = raw.metadata && typeof raw.metadata === 'object' && !Array.isArray(raw.metadata)
|
|
1215
|
+
? this.clonePlainObject(raw.metadata)
|
|
1216
|
+
: this.clonePlainObject(raw);
|
|
1217
|
+
const name = String(raw.name ?? base.name ?? '').trim();
|
|
1218
|
+
return {
|
|
1219
|
+
...base,
|
|
1220
|
+
name,
|
|
1221
|
+
label: String(raw.label ?? base.label ?? name ?? '').trim(),
|
|
1222
|
+
controlType: raw.controlType || base.controlType || FieldControlType.INPUT,
|
|
1223
|
+
required: raw.required === true,
|
|
1224
|
+
};
|
|
1225
|
+
}
|
|
1226
|
+
nextAvailableName(prefix = 'campo') {
|
|
1227
|
+
const existing = new Set(this.formArray.controls
|
|
1228
|
+
.map((row) => String(row.get('name')?.value || '').trim())
|
|
1229
|
+
.filter(Boolean));
|
|
1230
|
+
let index = 1;
|
|
1231
|
+
let candidate = prefix;
|
|
1232
|
+
while (existing.has(candidate)) {
|
|
1233
|
+
index += 1;
|
|
1234
|
+
candidate = `${prefix}${index}`;
|
|
1235
|
+
}
|
|
1236
|
+
return candidate;
|
|
1237
|
+
}
|
|
1238
|
+
updateDuplicateNames(fields) {
|
|
1239
|
+
const source = fields ?? this.formArray.controls.map((row) => this.normalizeField(row.getRawValue()));
|
|
1240
|
+
const seen = new Set();
|
|
1241
|
+
const duplicated = new Set();
|
|
1242
|
+
for (const field of source) {
|
|
1243
|
+
const name = String(field.name || '').trim();
|
|
1244
|
+
if (!name)
|
|
1245
|
+
continue;
|
|
1246
|
+
if (seen.has(name)) {
|
|
1247
|
+
duplicated.add(name);
|
|
1248
|
+
}
|
|
1249
|
+
seen.add(name);
|
|
1250
|
+
}
|
|
1251
|
+
this.duplicateNames = Array.from(duplicated);
|
|
1252
|
+
}
|
|
1253
|
+
updateFieldListValidity(fields = this.formArray.controls.map((row) => this.normalizeField(row.getRawValue()))) {
|
|
1254
|
+
this.updateDuplicateNames(fields);
|
|
1255
|
+
const duplicateSet = new Set(this.duplicateNames);
|
|
1256
|
+
const hasRequiredNameError = fields.some((field) => !String(field.name || '').trim());
|
|
1257
|
+
const hasDuplicateNameError = duplicateSet.size > 0;
|
|
1258
|
+
this.formArray.controls.forEach((row) => {
|
|
1259
|
+
const nameControl = row.get('name');
|
|
1260
|
+
const name = String(nameControl?.value || '').trim();
|
|
1261
|
+
this.setControlError(nameControl, 'arrayFieldNameRequired', !name);
|
|
1262
|
+
this.setControlError(nameControl, 'arrayFieldNameDuplicated', !!name && duplicateSet.has(name));
|
|
1263
|
+
});
|
|
1264
|
+
const errorPayload = hasDuplicateNameError ? { names: this.duplicateNames } : null;
|
|
1265
|
+
this.setControlError(this.control, 'arrayFieldNameRequired', hasRequiredNameError);
|
|
1266
|
+
this.setControlError(this.control, 'arrayFieldNameDuplicated', errorPayload);
|
|
1267
|
+
this.setControlError(this.formArray, 'arrayFieldNameRequired', hasRequiredNameError);
|
|
1268
|
+
this.setControlError(this.formArray, 'arrayFieldNameDuplicated', errorPayload);
|
|
1269
|
+
}
|
|
1270
|
+
setControlError(control, key, value) {
|
|
1271
|
+
if (!control)
|
|
1272
|
+
return;
|
|
1273
|
+
const errors = { ...(control.errors || {}) };
|
|
1274
|
+
const hasError = value !== null && value !== undefined && value !== false;
|
|
1275
|
+
if (hasError) {
|
|
1276
|
+
errors[key] = value === true ? true : value;
|
|
1277
|
+
}
|
|
1278
|
+
else {
|
|
1279
|
+
delete errors[key];
|
|
1280
|
+
}
|
|
1281
|
+
control.setErrors(Object.keys(errors).length ? errors : null);
|
|
1282
|
+
}
|
|
1283
|
+
updateSchemaSourceState() {
|
|
1284
|
+
const rawArray = this.arrayValue();
|
|
1285
|
+
const hasRef = typeof rawArray.itemSchemaRef === 'string' && rawArray.itemSchemaRef.trim().length > 0;
|
|
1286
|
+
const hasFields = this.formArray.length > 0;
|
|
1287
|
+
if (this.schemaSourceState === 'imported' &&
|
|
1288
|
+
hasFields &&
|
|
1289
|
+
this.importedFieldsFingerprint === this.fieldsFingerprint()) {
|
|
1290
|
+
return;
|
|
1291
|
+
}
|
|
1292
|
+
if (this.schemaSourceState === 'imported') {
|
|
1293
|
+
this.importedFieldsFingerprint = null;
|
|
1294
|
+
}
|
|
1295
|
+
this.schemaSourceState = hasRef && hasFields ? 'override-local' : hasRef ? 'ref-only' : 'local-only';
|
|
1296
|
+
}
|
|
1297
|
+
arrayValue() {
|
|
1298
|
+
const value = this.arrayControl?.value;
|
|
1299
|
+
return value && typeof value === 'object' ? value : {};
|
|
1300
|
+
}
|
|
1301
|
+
referencedBy(fieldName) {
|
|
1302
|
+
const name = String(fieldName || '').trim();
|
|
1303
|
+
if (!name)
|
|
1304
|
+
return [];
|
|
1305
|
+
const array = this.arrayValue();
|
|
1306
|
+
const references = [];
|
|
1307
|
+
if (array.itemIdentityField === name)
|
|
1308
|
+
references.push('itemIdentityField');
|
|
1309
|
+
if (this.uniqueByFields(array.collectionValidation?.uniqueBy).includes(name)) {
|
|
1310
|
+
references.push('collectionValidation.uniqueBy');
|
|
1311
|
+
}
|
|
1312
|
+
if (array.collectionValidation?.exactlyOne?.field === name) {
|
|
1313
|
+
references.push('collectionValidation.exactlyOne.field');
|
|
1314
|
+
}
|
|
1315
|
+
if (array.collectionValidation?.atLeastOne?.field === name) {
|
|
1316
|
+
references.push('collectionValidation.atLeastOne.field');
|
|
1317
|
+
}
|
|
1318
|
+
if (typeof array.itemTitleTemplate === 'string' && this.templateReferencesField(array.itemTitleTemplate, name)) {
|
|
1319
|
+
references.push('itemTitleTemplate');
|
|
1320
|
+
}
|
|
1321
|
+
return references;
|
|
1322
|
+
}
|
|
1323
|
+
renameReferences(previous, next) {
|
|
1324
|
+
if (!this.arrayControl || !previous || !next)
|
|
1325
|
+
return;
|
|
1326
|
+
const array = { ...this.arrayValue() };
|
|
1327
|
+
if (array.itemIdentityField === previous)
|
|
1328
|
+
array.itemIdentityField = next;
|
|
1329
|
+
const collectionValidation = array.collectionValidation && typeof array.collectionValidation === 'object'
|
|
1330
|
+
? { ...array.collectionValidation }
|
|
1331
|
+
: undefined;
|
|
1332
|
+
if (collectionValidation) {
|
|
1333
|
+
if (Array.isArray(collectionValidation.uniqueBy)) {
|
|
1334
|
+
collectionValidation.uniqueBy = collectionValidation.uniqueBy.map((entry) => entry === previous ? next : entry);
|
|
1335
|
+
}
|
|
1336
|
+
else if (typeof collectionValidation.uniqueBy === 'string') {
|
|
1337
|
+
collectionValidation.uniqueBy = this.replaceUniqueByField(collectionValidation.uniqueBy, previous, next);
|
|
1338
|
+
}
|
|
1339
|
+
if (collectionValidation.exactlyOne?.field === previous) {
|
|
1340
|
+
collectionValidation.exactlyOne = { ...collectionValidation.exactlyOne, field: next };
|
|
1341
|
+
}
|
|
1342
|
+
if (collectionValidation.atLeastOne?.field === previous) {
|
|
1343
|
+
collectionValidation.atLeastOne = { ...collectionValidation.atLeastOne, field: next };
|
|
1344
|
+
}
|
|
1345
|
+
array.collectionValidation = collectionValidation;
|
|
1346
|
+
}
|
|
1347
|
+
if (typeof array.itemTitleTemplate === 'string') {
|
|
1348
|
+
array.itemTitleTemplate = array.itemTitleTemplate.replace(new RegExp(`{{\\s*${this.escapeRegExp(previous)}\\s*}}`, 'g'), `{{${next}}}`);
|
|
1349
|
+
}
|
|
1350
|
+
this.arrayControl.patchValue(array);
|
|
1351
|
+
this.arrayControl.markAsDirty();
|
|
1352
|
+
}
|
|
1353
|
+
uniqueByFields(value) {
|
|
1354
|
+
if (Array.isArray(value)) {
|
|
1355
|
+
return value.map((entry) => String(entry || '').trim()).filter(Boolean);
|
|
1356
|
+
}
|
|
1357
|
+
if (typeof value !== 'string') {
|
|
1358
|
+
return [];
|
|
1359
|
+
}
|
|
1360
|
+
const trimmed = value.trim();
|
|
1361
|
+
if (!trimmed) {
|
|
1362
|
+
return [];
|
|
1363
|
+
}
|
|
1364
|
+
try {
|
|
1365
|
+
const parsed = JSON.parse(trimmed);
|
|
1366
|
+
if (Array.isArray(parsed)) {
|
|
1367
|
+
return parsed.map((entry) => String(entry || '').trim()).filter(Boolean);
|
|
1368
|
+
}
|
|
1369
|
+
}
|
|
1370
|
+
catch { }
|
|
1371
|
+
return trimmed
|
|
1372
|
+
.split(/\r?\n|,/)
|
|
1373
|
+
.map((entry) => entry.trim())
|
|
1374
|
+
.filter(Boolean);
|
|
1375
|
+
}
|
|
1376
|
+
replaceUniqueByField(value, previous, next) {
|
|
1377
|
+
const trimmed = value.trim();
|
|
1378
|
+
if (!trimmed) {
|
|
1379
|
+
return value;
|
|
1380
|
+
}
|
|
1381
|
+
try {
|
|
1382
|
+
const parsed = JSON.parse(trimmed);
|
|
1383
|
+
if (Array.isArray(parsed)) {
|
|
1384
|
+
return JSON.stringify(parsed.map((entry) => String(entry || '').trim() === previous ? next : entry));
|
|
1385
|
+
}
|
|
1386
|
+
}
|
|
1387
|
+
catch { }
|
|
1388
|
+
return value
|
|
1389
|
+
.split(/(\r?\n|,)/)
|
|
1390
|
+
.map((entry) => entry.trim() === previous ? next : entry)
|
|
1391
|
+
.join('');
|
|
1392
|
+
}
|
|
1393
|
+
templateReferencesField(template, fieldName) {
|
|
1394
|
+
return new RegExp(`{{\\s*${this.escapeRegExp(fieldName)}\\s*}}`).test(template);
|
|
1395
|
+
}
|
|
1396
|
+
clonePlainObject(value) {
|
|
1397
|
+
return this.cloneMetadataValue(value, new WeakMap());
|
|
1398
|
+
}
|
|
1399
|
+
cloneMetadataValue(value, seen) {
|
|
1400
|
+
if (!value || typeof value !== 'object') {
|
|
1401
|
+
return value;
|
|
1402
|
+
}
|
|
1403
|
+
if (seen.has(value)) {
|
|
1404
|
+
return seen.get(value);
|
|
1405
|
+
}
|
|
1406
|
+
if (value instanceof Date) {
|
|
1407
|
+
return new Date(value.getTime());
|
|
1408
|
+
}
|
|
1409
|
+
if (value instanceof RegExp) {
|
|
1410
|
+
return new RegExp(value.source, value.flags);
|
|
1411
|
+
}
|
|
1412
|
+
if (Array.isArray(value)) {
|
|
1413
|
+
const clone = [];
|
|
1414
|
+
seen.set(value, clone);
|
|
1415
|
+
clone.push(...value.map((entry) => this.cloneMetadataValue(entry, seen)));
|
|
1416
|
+
return clone;
|
|
1417
|
+
}
|
|
1418
|
+
if (value instanceof Map) {
|
|
1419
|
+
const clone = new Map();
|
|
1420
|
+
seen.set(value, clone);
|
|
1421
|
+
value.forEach((entry, key) => {
|
|
1422
|
+
clone.set(this.cloneMetadataValue(key, seen), this.cloneMetadataValue(entry, seen));
|
|
1423
|
+
});
|
|
1424
|
+
return clone;
|
|
1425
|
+
}
|
|
1426
|
+
if (value instanceof Set) {
|
|
1427
|
+
const clone = new Set();
|
|
1428
|
+
seen.set(value, clone);
|
|
1429
|
+
value.forEach((entry) => clone.add(this.cloneMetadataValue(entry, seen)));
|
|
1430
|
+
return clone;
|
|
1431
|
+
}
|
|
1432
|
+
const prototype = Object.getPrototypeOf(value);
|
|
1433
|
+
if (prototype !== Object.prototype && prototype !== null) {
|
|
1434
|
+
return value;
|
|
1435
|
+
}
|
|
1436
|
+
const clone = {};
|
|
1437
|
+
seen.set(value, clone);
|
|
1438
|
+
for (const [key, entry] of Object.entries(value)) {
|
|
1439
|
+
clone[key] = this.cloneMetadataValue(entry, seen);
|
|
1440
|
+
}
|
|
1441
|
+
return clone;
|
|
1442
|
+
}
|
|
1443
|
+
fieldsFingerprint() {
|
|
1444
|
+
return JSON.stringify(this.formArray.controls.map((row) => this.normalizeField(row.getRawValue())));
|
|
1445
|
+
}
|
|
1446
|
+
escapeRegExp(value) {
|
|
1447
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
1448
|
+
}
|
|
1449
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: ArrayItemSchemaFieldsEditorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1450
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.17", type: ArrayItemSchemaFieldsEditorComponent, isStandalone: true, selector: "praxis-array-item-schema-fields-editor", inputs: { control: "control", arrayControl: "arrayControl" }, providers: [providePraxisMetadataEditorI18n()], usesOnChanges: true, ngImport: i0, template: `
|
|
1451
|
+
<section
|
|
1452
|
+
class="array-fields-editor"
|
|
1453
|
+
[attr.data-schema-source]="schemaSourceState"
|
|
1454
|
+
[attr.aria-label]="text('praxis.metadataEditor.arrayFields.section', 'Subcampos da cole\u00e7\u00e3o')"
|
|
1455
|
+
>
|
|
1456
|
+
<header class="array-fields-editor__header">
|
|
1457
|
+
<div>
|
|
1458
|
+
<h3>{{ text('praxis.metadataEditor.arrayFields.title', 'Subcampos') }}</h3>
|
|
1459
|
+
<p>
|
|
1460
|
+
{{ schemaStateDescription() }}
|
|
1461
|
+
</p>
|
|
1462
|
+
</div>
|
|
1463
|
+
<button type="button" class="array-fields-editor__primary" (click)="addField()">
|
|
1464
|
+
{{ text('praxis.metadataEditor.arrayFields.add', 'Adicionar subcampo') }}
|
|
1465
|
+
</button>
|
|
1466
|
+
</header>
|
|
1467
|
+
|
|
1468
|
+
<div
|
|
1469
|
+
class="array-fields-editor__warning"
|
|
1470
|
+
*ngIf="duplicateNames.length"
|
|
1471
|
+
role="alert"
|
|
1472
|
+
>
|
|
1473
|
+
{{
|
|
1474
|
+
text(
|
|
1475
|
+
'praxis.metadataEditor.arrayFields.duplicateNames',
|
|
1476
|
+
undefined,
|
|
1477
|
+
'Existem nomes duplicados: {{names}}',
|
|
1478
|
+
{ names: duplicateNames.join(', ') }
|
|
1479
|
+
)
|
|
1480
|
+
}}
|
|
1481
|
+
</div>
|
|
1482
|
+
|
|
1483
|
+
<div
|
|
1484
|
+
class="array-fields-editor__empty"
|
|
1485
|
+
*ngIf="formArray.length === 0"
|
|
1486
|
+
>
|
|
1487
|
+
{{ text('praxis.metadataEditor.arrayFields.empty', 'Nenhum subcampo local configurado.') }}
|
|
1488
|
+
</div>
|
|
1489
|
+
|
|
1490
|
+
<div class="array-fields-editor__list" [formGroup]="form">
|
|
1491
|
+
<div
|
|
1492
|
+
class="array-fields-editor__row"
|
|
1493
|
+
*ngFor="let row of rows; let i = index"
|
|
1494
|
+
[formGroup]="row"
|
|
1495
|
+
>
|
|
1496
|
+
<label>
|
|
1497
|
+
<span>{{ text('praxis.metadataEditor.arrayFields.name', 'Nome') }}</span>
|
|
1498
|
+
<input
|
|
1499
|
+
type="text"
|
|
1500
|
+
formControlName="name"
|
|
1501
|
+
(blur)="onNameBlur(i)"
|
|
1502
|
+
[attr.aria-invalid]="isNameInvalid(i) ? 'true' : null"
|
|
1503
|
+
[attr.aria-describedby]="nameErrorDescribedBy(i)"
|
|
1504
|
+
/>
|
|
1505
|
+
<span
|
|
1506
|
+
class="array-fields-editor__field-error"
|
|
1507
|
+
*ngIf="nameErrorMessage(i) as nameError"
|
|
1508
|
+
[id]="nameErrorId(i)"
|
|
1509
|
+
>
|
|
1510
|
+
{{ nameError }}
|
|
1511
|
+
</span>
|
|
1512
|
+
</label>
|
|
1513
|
+
|
|
1514
|
+
<label>
|
|
1515
|
+
<span>{{ text('praxis.metadataEditor.arrayFields.label', 'Label') }}</span>
|
|
1516
|
+
<input type="text" formControlName="label" />
|
|
1517
|
+
</label>
|
|
1518
|
+
|
|
1519
|
+
<label>
|
|
1520
|
+
<span>{{ text('praxis.metadataEditor.arrayFields.controlType', 'Controle') }}</span>
|
|
1521
|
+
<select formControlName="controlType">
|
|
1522
|
+
<option *ngFor="let option of controlTypeOptions" [value]="option">
|
|
1523
|
+
{{ controlTypeLabel(option) }}
|
|
1524
|
+
</option>
|
|
1525
|
+
</select>
|
|
1526
|
+
</label>
|
|
1527
|
+
|
|
1528
|
+
<label class="array-fields-editor__check">
|
|
1529
|
+
<input type="checkbox" formControlName="required" />
|
|
1530
|
+
<span>{{ text('praxis.metadataEditor.arrayFields.required', 'Obrigat\u00f3rio') }}</span>
|
|
1531
|
+
</label>
|
|
1532
|
+
|
|
1533
|
+
<div class="array-fields-editor__actions">
|
|
1534
|
+
<button type="button" (click)="moveField(i, -1)" [disabled]="i === 0">
|
|
1535
|
+
{{ text('praxis.metadataEditor.arrayFields.moveUp', 'Subir') }}
|
|
1536
|
+
</button>
|
|
1537
|
+
<button type="button" (click)="moveField(i, 1)" [disabled]="i === formArray.length - 1">
|
|
1538
|
+
{{ text('praxis.metadataEditor.arrayFields.moveDown', 'Descer') }}
|
|
1539
|
+
</button>
|
|
1540
|
+
<button type="button" (click)="duplicateField(i)">
|
|
1541
|
+
{{ text('praxis.metadataEditor.arrayFields.duplicate', 'Duplicar') }}
|
|
1542
|
+
</button>
|
|
1543
|
+
<button
|
|
1544
|
+
type="button"
|
|
1545
|
+
(click)="removeField(i)"
|
|
1546
|
+
[disabled]="isReferenced(row.get('name')?.value)"
|
|
1547
|
+
[title]="removeTitle(row.get('name')?.value)"
|
|
1548
|
+
>
|
|
1549
|
+
{{ text('praxis.metadataEditor.arrayFields.remove', 'Remover') }}
|
|
1550
|
+
</button>
|
|
1551
|
+
</div>
|
|
1552
|
+
</div>
|
|
1553
|
+
</div>
|
|
1554
|
+
</section>
|
|
1555
|
+
`, isInline: true, styles: [":host{display:block}.array-fields-editor{display:block;margin:10px 0 2px;padding:12px;border:1px solid var(--md-sys-color-outline-variant);border-radius:8px;background:var(--md-sys-color-surface-container-low);color:var(--md-sys-color-on-surface)}.array-fields-editor__header{display:flex;align-items:flex-start;justify-content:space-between;gap:12px;margin-bottom:12px}.array-fields-editor__header h3{margin:0 0 4px;font-size:1rem;line-height:1.25}.array-fields-editor__header p,.array-fields-editor__empty{margin:0;color:var(--md-sys-color-on-surface-variant);font-size:.875rem;line-height:1.35}.array-fields-editor__primary,.array-fields-editor button{border:1px solid var(--md-sys-color-outline-variant);border-radius:6px;background:var(--md-sys-color-surface);color:var(--md-sys-color-on-surface);cursor:pointer;min-height:32px;padding:5px 10px}.array-fields-editor__primary{border-color:var(--md-sys-color-primary);color:var(--md-sys-color-primary);font-weight:600;white-space:nowrap}.array-fields-editor button:disabled{cursor:not-allowed;opacity:.55}.array-fields-editor__warning{margin:8px 0 12px;padding:8px 10px;border:1px solid var(--md-sys-color-error);border-radius:6px;color:var(--md-sys-color-error);background:var(--md-sys-color-error-container)}.array-fields-editor__list{display:grid;gap:10px}.array-fields-editor__row{display:grid;grid-template-columns:minmax(140px,1fr) minmax(160px,1.2fr) minmax(140px,.9fr) auto;gap:10px;align-items:end;padding:10px;border:1px solid var(--md-sys-color-outline-variant);border-radius:8px;background:var(--md-sys-color-surface)}.array-fields-editor label{display:grid;gap:4px;font-size:.8rem;font-weight:600}.array-fields-editor input[type=text],.array-fields-editor select{box-sizing:border-box;width:100%;min-height:34px;border:1px solid var(--md-sys-color-outline-variant);border-radius:6px;background:var(--md-sys-color-surface);color:var(--md-sys-color-on-surface);padding:5px 8px}.array-fields-editor input[aria-invalid=true]{border-color:var(--md-sys-color-error)}.array-fields-editor__field-error{color:var(--md-sys-color-error);font-size:.75rem;font-weight:500;line-height:1.3}.array-fields-editor__check{display:flex!important;align-items:center;gap:6px;min-height:34px}.array-fields-editor__actions{grid-column:1 / -1;display:flex;flex-wrap:wrap;gap:6px}@media(max-width:720px){.array-fields-editor__header,.array-fields-editor__row{display:grid;grid-template-columns:1fr}.array-fields-editor__primary{width:100%}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i3.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i2.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i2.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i2.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: i2.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i2.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i2.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }] });
|
|
1556
|
+
}
|
|
1557
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: ArrayItemSchemaFieldsEditorComponent, decorators: [{
|
|
1558
|
+
type: Component,
|
|
1559
|
+
args: [{ selector: 'praxis-array-item-schema-fields-editor', standalone: true, imports: [CommonModule, ReactiveFormsModule], providers: [providePraxisMetadataEditorI18n()], template: `
|
|
1560
|
+
<section
|
|
1561
|
+
class="array-fields-editor"
|
|
1562
|
+
[attr.data-schema-source]="schemaSourceState"
|
|
1563
|
+
[attr.aria-label]="text('praxis.metadataEditor.arrayFields.section', 'Subcampos da cole\u00e7\u00e3o')"
|
|
1564
|
+
>
|
|
1565
|
+
<header class="array-fields-editor__header">
|
|
1566
|
+
<div>
|
|
1567
|
+
<h3>{{ text('praxis.metadataEditor.arrayFields.title', 'Subcampos') }}</h3>
|
|
1568
|
+
<p>
|
|
1569
|
+
{{ schemaStateDescription() }}
|
|
1570
|
+
</p>
|
|
1571
|
+
</div>
|
|
1572
|
+
<button type="button" class="array-fields-editor__primary" (click)="addField()">
|
|
1573
|
+
{{ text('praxis.metadataEditor.arrayFields.add', 'Adicionar subcampo') }}
|
|
1574
|
+
</button>
|
|
1575
|
+
</header>
|
|
1576
|
+
|
|
1577
|
+
<div
|
|
1578
|
+
class="array-fields-editor__warning"
|
|
1579
|
+
*ngIf="duplicateNames.length"
|
|
1580
|
+
role="alert"
|
|
1581
|
+
>
|
|
1582
|
+
{{
|
|
1583
|
+
text(
|
|
1584
|
+
'praxis.metadataEditor.arrayFields.duplicateNames',
|
|
1585
|
+
undefined,
|
|
1586
|
+
'Existem nomes duplicados: {{names}}',
|
|
1587
|
+
{ names: duplicateNames.join(', ') }
|
|
1588
|
+
)
|
|
1589
|
+
}}
|
|
1590
|
+
</div>
|
|
1591
|
+
|
|
1592
|
+
<div
|
|
1593
|
+
class="array-fields-editor__empty"
|
|
1594
|
+
*ngIf="formArray.length === 0"
|
|
1595
|
+
>
|
|
1596
|
+
{{ text('praxis.metadataEditor.arrayFields.empty', 'Nenhum subcampo local configurado.') }}
|
|
1597
|
+
</div>
|
|
1598
|
+
|
|
1599
|
+
<div class="array-fields-editor__list" [formGroup]="form">
|
|
1600
|
+
<div
|
|
1601
|
+
class="array-fields-editor__row"
|
|
1602
|
+
*ngFor="let row of rows; let i = index"
|
|
1603
|
+
[formGroup]="row"
|
|
1604
|
+
>
|
|
1605
|
+
<label>
|
|
1606
|
+
<span>{{ text('praxis.metadataEditor.arrayFields.name', 'Nome') }}</span>
|
|
1607
|
+
<input
|
|
1608
|
+
type="text"
|
|
1609
|
+
formControlName="name"
|
|
1610
|
+
(blur)="onNameBlur(i)"
|
|
1611
|
+
[attr.aria-invalid]="isNameInvalid(i) ? 'true' : null"
|
|
1612
|
+
[attr.aria-describedby]="nameErrorDescribedBy(i)"
|
|
1613
|
+
/>
|
|
1614
|
+
<span
|
|
1615
|
+
class="array-fields-editor__field-error"
|
|
1616
|
+
*ngIf="nameErrorMessage(i) as nameError"
|
|
1617
|
+
[id]="nameErrorId(i)"
|
|
1618
|
+
>
|
|
1619
|
+
{{ nameError }}
|
|
1620
|
+
</span>
|
|
1621
|
+
</label>
|
|
1622
|
+
|
|
1623
|
+
<label>
|
|
1624
|
+
<span>{{ text('praxis.metadataEditor.arrayFields.label', 'Label') }}</span>
|
|
1625
|
+
<input type="text" formControlName="label" />
|
|
1626
|
+
</label>
|
|
1627
|
+
|
|
1628
|
+
<label>
|
|
1629
|
+
<span>{{ text('praxis.metadataEditor.arrayFields.controlType', 'Controle') }}</span>
|
|
1630
|
+
<select formControlName="controlType">
|
|
1631
|
+
<option *ngFor="let option of controlTypeOptions" [value]="option">
|
|
1632
|
+
{{ controlTypeLabel(option) }}
|
|
1633
|
+
</option>
|
|
1634
|
+
</select>
|
|
1635
|
+
</label>
|
|
1636
|
+
|
|
1637
|
+
<label class="array-fields-editor__check">
|
|
1638
|
+
<input type="checkbox" formControlName="required" />
|
|
1639
|
+
<span>{{ text('praxis.metadataEditor.arrayFields.required', 'Obrigat\u00f3rio') }}</span>
|
|
1640
|
+
</label>
|
|
1641
|
+
|
|
1642
|
+
<div class="array-fields-editor__actions">
|
|
1643
|
+
<button type="button" (click)="moveField(i, -1)" [disabled]="i === 0">
|
|
1644
|
+
{{ text('praxis.metadataEditor.arrayFields.moveUp', 'Subir') }}
|
|
1645
|
+
</button>
|
|
1646
|
+
<button type="button" (click)="moveField(i, 1)" [disabled]="i === formArray.length - 1">
|
|
1647
|
+
{{ text('praxis.metadataEditor.arrayFields.moveDown', 'Descer') }}
|
|
1648
|
+
</button>
|
|
1649
|
+
<button type="button" (click)="duplicateField(i)">
|
|
1650
|
+
{{ text('praxis.metadataEditor.arrayFields.duplicate', 'Duplicar') }}
|
|
1651
|
+
</button>
|
|
1652
|
+
<button
|
|
1653
|
+
type="button"
|
|
1654
|
+
(click)="removeField(i)"
|
|
1655
|
+
[disabled]="isReferenced(row.get('name')?.value)"
|
|
1656
|
+
[title]="removeTitle(row.get('name')?.value)"
|
|
1657
|
+
>
|
|
1658
|
+
{{ text('praxis.metadataEditor.arrayFields.remove', 'Remover') }}
|
|
1659
|
+
</button>
|
|
1660
|
+
</div>
|
|
1661
|
+
</div>
|
|
1662
|
+
</div>
|
|
1663
|
+
</section>
|
|
1664
|
+
`, styles: [":host{display:block}.array-fields-editor{display:block;margin:10px 0 2px;padding:12px;border:1px solid var(--md-sys-color-outline-variant);border-radius:8px;background:var(--md-sys-color-surface-container-low);color:var(--md-sys-color-on-surface)}.array-fields-editor__header{display:flex;align-items:flex-start;justify-content:space-between;gap:12px;margin-bottom:12px}.array-fields-editor__header h3{margin:0 0 4px;font-size:1rem;line-height:1.25}.array-fields-editor__header p,.array-fields-editor__empty{margin:0;color:var(--md-sys-color-on-surface-variant);font-size:.875rem;line-height:1.35}.array-fields-editor__primary,.array-fields-editor button{border:1px solid var(--md-sys-color-outline-variant);border-radius:6px;background:var(--md-sys-color-surface);color:var(--md-sys-color-on-surface);cursor:pointer;min-height:32px;padding:5px 10px}.array-fields-editor__primary{border-color:var(--md-sys-color-primary);color:var(--md-sys-color-primary);font-weight:600;white-space:nowrap}.array-fields-editor button:disabled{cursor:not-allowed;opacity:.55}.array-fields-editor__warning{margin:8px 0 12px;padding:8px 10px;border:1px solid var(--md-sys-color-error);border-radius:6px;color:var(--md-sys-color-error);background:var(--md-sys-color-error-container)}.array-fields-editor__list{display:grid;gap:10px}.array-fields-editor__row{display:grid;grid-template-columns:minmax(140px,1fr) minmax(160px,1.2fr) minmax(140px,.9fr) auto;gap:10px;align-items:end;padding:10px;border:1px solid var(--md-sys-color-outline-variant);border-radius:8px;background:var(--md-sys-color-surface)}.array-fields-editor label{display:grid;gap:4px;font-size:.8rem;font-weight:600}.array-fields-editor input[type=text],.array-fields-editor select{box-sizing:border-box;width:100%;min-height:34px;border:1px solid var(--md-sys-color-outline-variant);border-radius:6px;background:var(--md-sys-color-surface);color:var(--md-sys-color-on-surface);padding:5px 8px}.array-fields-editor input[aria-invalid=true]{border-color:var(--md-sys-color-error)}.array-fields-editor__field-error{color:var(--md-sys-color-error);font-size:.75rem;font-weight:500;line-height:1.3}.array-fields-editor__check{display:flex!important;align-items:center;gap:6px;min-height:34px}.array-fields-editor__actions{grid-column:1 / -1;display:flex;flex-wrap:wrap;gap:6px}@media(max-width:720px){.array-fields-editor__header,.array-fields-editor__row{display:grid;grid-template-columns:1fr}.array-fields-editor__primary{width:100%}}\n"] }]
|
|
1665
|
+
}], propDecorators: { control: [{
|
|
1666
|
+
type: Input
|
|
1667
|
+
}], arrayControl: [{
|
|
1668
|
+
type: Input
|
|
1669
|
+
}] } });
|
|
1670
|
+
|
|
846
1671
|
const inputProperties = [
|
|
847
1672
|
// Geral
|
|
848
1673
|
{ name: 'label', label: 'Label', editorType: 'text', placeholder: 'Rótulo do campo', group: 'Geral' },
|
|
@@ -1054,6 +1879,61 @@ const inputProperties = [
|
|
|
1054
1879
|
{ name: 'defaultValue', label: 'Valor padrão', editorType: 'text', group: 'Geral' },
|
|
1055
1880
|
];
|
|
1056
1881
|
|
|
1882
|
+
const arrayProperties = [
|
|
1883
|
+
{ name: 'label', label: 'Label', editorType: 'text', group: 'Geral' },
|
|
1884
|
+
{ name: 'hint', label: 'Hint', editorType: 'text', group: 'Geral' },
|
|
1885
|
+
{ name: 'defaultValue', label: 'Valor inicial (JSON array)', editorType: 'textarea', group: 'Geral' },
|
|
1886
|
+
{
|
|
1887
|
+
name: 'array.itemType',
|
|
1888
|
+
label: 'Tipo do item',
|
|
1889
|
+
editorType: 'select',
|
|
1890
|
+
group: 'Colecao',
|
|
1891
|
+
defaultValue: 'object',
|
|
1892
|
+
options: [
|
|
1893
|
+
{ value: 'object', text: 'Objeto' },
|
|
1894
|
+
],
|
|
1895
|
+
},
|
|
1896
|
+
{
|
|
1897
|
+
name: 'array.mode',
|
|
1898
|
+
label: 'Modo',
|
|
1899
|
+
editorType: 'select',
|
|
1900
|
+
group: 'Colecao',
|
|
1901
|
+
defaultValue: 'cards',
|
|
1902
|
+
options: [
|
|
1903
|
+
{ value: 'cards', text: 'Cards' },
|
|
1904
|
+
],
|
|
1905
|
+
},
|
|
1906
|
+
{ name: 'array.itemSchemaRef', label: 'Schema do item ($ref)', editorType: 'text', group: 'Colecao' },
|
|
1907
|
+
{ name: 'array.itemIdentityField', label: 'Campo de identidade', editorType: 'text', group: 'Colecao' },
|
|
1908
|
+
{ name: 'array.addLabel', label: 'Texto do botao adicionar', editorType: 'text', group: 'Colecao' },
|
|
1909
|
+
{ name: 'array.emptyState', label: 'Texto vazio', editorType: 'text', group: 'Colecao' },
|
|
1910
|
+
{ name: 'array.itemTitleTemplate', label: 'Template do titulo do item', editorType: 'text', group: 'Colecao', hint: 'Ex.: {{nome}} - {{cargo}}' },
|
|
1911
|
+
{ name: 'array.minItems', label: 'Minimo de itens', editorType: 'number', group: 'Validacao' },
|
|
1912
|
+
{ name: 'array.maxItems', label: 'Maximo de itens', editorType: 'number', group: 'Validacao' },
|
|
1913
|
+
{
|
|
1914
|
+
name: 'array.deleteMode',
|
|
1915
|
+
label: 'Modo de exclusao',
|
|
1916
|
+
editorType: 'select',
|
|
1917
|
+
group: 'Operacoes',
|
|
1918
|
+
defaultValue: 'removeFromPayload',
|
|
1919
|
+
options: [
|
|
1920
|
+
{ value: 'removeFromPayload', text: 'Remover do payload' },
|
|
1921
|
+
],
|
|
1922
|
+
},
|
|
1923
|
+
{ name: 'array.operations.add', label: 'Permitir adicionar', editorType: 'checkbox', group: 'Operacoes', defaultValue: true },
|
|
1924
|
+
{ name: 'array.operations.edit', label: 'Permitir editar', editorType: 'checkbox', group: 'Operacoes', defaultValue: true },
|
|
1925
|
+
{ name: 'array.operations.remove', label: 'Permitir remover', editorType: 'checkbox', group: 'Operacoes', defaultValue: true },
|
|
1926
|
+
{ name: 'array.collectionValidation.uniqueBy', label: 'Unico por campos', editorType: 'textarea', group: 'Validacao', hint: 'JSON array ou uma linha por campo. Ex.: ["email"]' },
|
|
1927
|
+
{ name: 'array.collectionValidation.exactlyOne.field', label: 'Exatamente um: campo', editorType: 'text', group: 'Validacao' },
|
|
1928
|
+
{ name: 'array.collectionValidation.exactlyOne.value', label: 'Exatamente um: valor tipado', editorType: 'text', group: 'Validacao', hint: 'Use true/false, numero ou texto. Ex.: true, 1, PRINCIPAL.' },
|
|
1929
|
+
{ name: 'array.collectionValidation.exactlyOne.message', label: 'Mensagem: exatamente um', editorType: 'text', group: 'Validacao' },
|
|
1930
|
+
{ name: 'array.collectionValidation.atLeastOne.field', label: 'Pelo menos um: campo', editorType: 'text', group: 'Validacao' },
|
|
1931
|
+
{ name: 'array.collectionValidation.atLeastOne.value', label: 'Pelo menos um: valor tipado', editorType: 'text', group: 'Validacao', hint: 'Use true/false, numero ou texto. Ex.: true, 1, ACTIVE.' },
|
|
1932
|
+
{ name: 'array.collectionValidation.atLeastOne.message', label: 'Mensagem: pelo menos um', editorType: 'text', group: 'Validacao' },
|
|
1933
|
+
{ name: 'array.itemSchema.fields', label: 'Subcampos', editorType: 'field-list', group: 'Subcampos', hint: 'Lista FieldMetadata[] usada quando nao houver itemSchemaRef resolvido.' },
|
|
1934
|
+
{ name: 'required', label: 'Obrigatorio', editorType: 'checkbox', group: 'Validacao' },
|
|
1935
|
+
];
|
|
1936
|
+
|
|
1057
1937
|
// Editor de metadados para componentes SELECT-like
|
|
1058
1938
|
// Paridade com INPUT: grupos, linhas e propriedades canônicas
|
|
1059
1939
|
const selectProperties = [
|
|
@@ -1215,6 +2095,302 @@ const selectProperties = [
|
|
|
1215
2095
|
{ name: 'dataAttributes', label: 'Data attributes (JSON)', editorType: 'textarea', group: 'Acessibilidade', hint: '{ "testId": "select-a" }' },
|
|
1216
2096
|
];
|
|
1217
2097
|
|
|
2098
|
+
function cloneProperty$7(prop) {
|
|
2099
|
+
return {
|
|
2100
|
+
...prop,
|
|
2101
|
+
options: Array.isArray(prop.options)
|
|
2102
|
+
? prop.options.map((opt) => typeof opt === 'object' && opt !== null ? { ...opt } : opt)
|
|
2103
|
+
: prop.options,
|
|
2104
|
+
};
|
|
2105
|
+
}
|
|
2106
|
+
const entityLookupProperties = [
|
|
2107
|
+
...selectProperties.map((prop) => cloneProperty$7(prop)),
|
|
2108
|
+
{
|
|
2109
|
+
name: 'optionSource.key',
|
|
2110
|
+
label: 'Option source key',
|
|
2111
|
+
editorType: 'text',
|
|
2112
|
+
group: 'Fonte de entidade',
|
|
2113
|
+
required: true,
|
|
2114
|
+
hint: 'Chave publicada pelo backend para filtrar e reidratar a entidade.',
|
|
2115
|
+
},
|
|
2116
|
+
{
|
|
2117
|
+
name: 'optionSource.type',
|
|
2118
|
+
label: 'Tipo da fonte',
|
|
2119
|
+
editorType: 'select',
|
|
2120
|
+
group: 'Fonte de entidade',
|
|
2121
|
+
defaultValue: 'RESOURCE_ENTITY',
|
|
2122
|
+
options: [
|
|
2123
|
+
{ value: 'RESOURCE_ENTITY', text: 'RESOURCE_ENTITY' },
|
|
2124
|
+
{ value: 'LIGHT_LOOKUP', text: 'LIGHT_LOOKUP' },
|
|
2125
|
+
],
|
|
2126
|
+
hint: 'Use RESOURCE_ENTITY para entidades reais de dominio.',
|
|
2127
|
+
},
|
|
2128
|
+
{
|
|
2129
|
+
name: 'optionSource.entityKey',
|
|
2130
|
+
label: 'Entity key',
|
|
2131
|
+
editorType: 'text',
|
|
2132
|
+
group: 'Fonte de entidade',
|
|
2133
|
+
hint: 'Identificador semantico da entidade, por exemplo supplier, customer ou contract.',
|
|
2134
|
+
},
|
|
2135
|
+
{
|
|
2136
|
+
name: 'optionSource.resourcePath',
|
|
2137
|
+
label: 'Resource path',
|
|
2138
|
+
editorType: 'text',
|
|
2139
|
+
group: 'Fonte de entidade',
|
|
2140
|
+
hint: 'Caminho base do recurso que publica option-sources e by-ids.',
|
|
2141
|
+
},
|
|
2142
|
+
{
|
|
2143
|
+
name: 'optionSource.filterField',
|
|
2144
|
+
label: 'Campo de filtro principal',
|
|
2145
|
+
editorType: 'text',
|
|
2146
|
+
group: 'Fonte de entidade',
|
|
2147
|
+
hint: 'Campo usado por fontes derivadas quando houver filtro simples no backend.',
|
|
2148
|
+
},
|
|
2149
|
+
{
|
|
2150
|
+
name: 'optionSource.propertyPath',
|
|
2151
|
+
label: 'Property path',
|
|
2152
|
+
editorType: 'text',
|
|
2153
|
+
group: 'Fonte de entidade',
|
|
2154
|
+
hint: 'Caminho de propriedade usado por fontes derivadas ou projeções leves.',
|
|
2155
|
+
},
|
|
2156
|
+
{
|
|
2157
|
+
name: 'optionSource.valuePropertyPath',
|
|
2158
|
+
label: 'Campo de valor',
|
|
2159
|
+
editorType: 'text',
|
|
2160
|
+
group: 'Fonte de entidade',
|
|
2161
|
+
defaultValue: 'id',
|
|
2162
|
+
hint: 'Campo canonico salvo no payload do formulario.',
|
|
2163
|
+
},
|
|
2164
|
+
{
|
|
2165
|
+
name: 'optionSource.labelPropertyPath',
|
|
2166
|
+
label: 'Campo de label',
|
|
2167
|
+
editorType: 'text',
|
|
2168
|
+
group: 'Fonte de entidade',
|
|
2169
|
+
defaultValue: 'label',
|
|
2170
|
+
hint: 'Campo principal exibido para o usuario.',
|
|
2171
|
+
},
|
|
2172
|
+
{
|
|
2173
|
+
name: 'optionSource.codePropertyPath',
|
|
2174
|
+
label: 'Campo de codigo',
|
|
2175
|
+
editorType: 'text',
|
|
2176
|
+
group: 'Exibicao de entidade',
|
|
2177
|
+
hint: 'Codigo curto exibido antes do label, por exemplo FOR-8742.',
|
|
2178
|
+
},
|
|
2179
|
+
{
|
|
2180
|
+
name: 'optionSource.descriptionPropertyPaths',
|
|
2181
|
+
label: 'Campos de descricao',
|
|
2182
|
+
editorType: 'textarea',
|
|
2183
|
+
group: 'Exibicao de entidade',
|
|
2184
|
+
hint: 'JSON array ou uma linha por campo. Ex.: ["documentNumber", "city", "state"].',
|
|
2185
|
+
},
|
|
2186
|
+
{
|
|
2187
|
+
name: 'optionSource.statusPropertyPath',
|
|
2188
|
+
label: 'Campo de status',
|
|
2189
|
+
editorType: 'text',
|
|
2190
|
+
group: 'Exibicao de entidade',
|
|
2191
|
+
hint: 'Campo que informa status operacional da entidade.',
|
|
2192
|
+
},
|
|
2193
|
+
{
|
|
2194
|
+
name: 'optionSource.disabledPropertyPath',
|
|
2195
|
+
label: 'Campo disabled',
|
|
2196
|
+
editorType: 'text',
|
|
2197
|
+
group: 'Exibicao de entidade',
|
|
2198
|
+
hint: 'Campo booleano que indica bloqueio visual ou operacional da entidade.',
|
|
2199
|
+
},
|
|
2200
|
+
{
|
|
2201
|
+
name: 'optionSource.disabledReasonPropertyPath',
|
|
2202
|
+
label: 'Campo de motivo bloqueado',
|
|
2203
|
+
editorType: 'text',
|
|
2204
|
+
group: 'Exibicao de entidade',
|
|
2205
|
+
hint: 'Campo opcional com mensagem de bloqueio quando selectable=false.',
|
|
2206
|
+
},
|
|
2207
|
+
{
|
|
2208
|
+
name: 'optionSource.searchPropertyPaths',
|
|
2209
|
+
label: 'Campos de busca',
|
|
2210
|
+
editorType: 'textarea',
|
|
2211
|
+
group: 'Busca',
|
|
2212
|
+
hint: 'JSON array ou uma linha por campo pesquisavel.',
|
|
2213
|
+
},
|
|
2214
|
+
{
|
|
2215
|
+
name: 'optionSource.searchMode',
|
|
2216
|
+
label: 'Modo de busca',
|
|
2217
|
+
editorType: 'select',
|
|
2218
|
+
group: 'Busca',
|
|
2219
|
+
options: [
|
|
2220
|
+
{ value: 'contains', text: 'contains' },
|
|
2221
|
+
{ value: 'startsWith', text: 'startsWith' },
|
|
2222
|
+
{ value: 'exact', text: 'exact' },
|
|
2223
|
+
],
|
|
2224
|
+
hint: 'Semantica de busca publicada pelo backend para esta fonte.',
|
|
2225
|
+
},
|
|
2226
|
+
{
|
|
2227
|
+
name: 'optionSource.pageSize',
|
|
2228
|
+
label: 'Tamanho da pagina',
|
|
2229
|
+
editorType: 'number',
|
|
2230
|
+
group: 'Busca',
|
|
2231
|
+
hint: 'Quantidade sugerida de resultados por pagina.',
|
|
2232
|
+
},
|
|
2233
|
+
{
|
|
2234
|
+
name: 'optionSource.includeIds',
|
|
2235
|
+
label: 'Incluir IDs selecionados',
|
|
2236
|
+
editorType: 'checkbox',
|
|
2237
|
+
group: 'Busca',
|
|
2238
|
+
defaultValue: true,
|
|
2239
|
+
hint: 'Mantem entidades ja selecionadas visiveis durante busca paginada.',
|
|
2240
|
+
},
|
|
2241
|
+
{
|
|
2242
|
+
name: 'optionSource.dependsOn',
|
|
2243
|
+
label: 'Dependencias',
|
|
2244
|
+
editorType: 'textarea',
|
|
2245
|
+
group: 'Dependencias',
|
|
2246
|
+
hint: 'JSON array ou uma linha por campo do formulario que filtra o lookup.',
|
|
2247
|
+
},
|
|
2248
|
+
{
|
|
2249
|
+
name: 'optionSource.dependencyFilterMap',
|
|
2250
|
+
label: 'Mapa de filtros',
|
|
2251
|
+
editorType: 'textarea',
|
|
2252
|
+
group: 'Dependencias',
|
|
2253
|
+
hint: 'JSON object. Ex.: { "empresaId": "companyId", "fornecedorId": "supplierId" }.',
|
|
2254
|
+
},
|
|
2255
|
+
{
|
|
2256
|
+
name: 'optionSource.selectionPolicy.statusPropertyPath',
|
|
2257
|
+
label: 'Politica: campo de status',
|
|
2258
|
+
editorType: 'text',
|
|
2259
|
+
group: 'Politica de selecao',
|
|
2260
|
+
hint: 'Campo usado para aplicar allowedStatuses ou blockedStatuses.',
|
|
2261
|
+
},
|
|
2262
|
+
{
|
|
2263
|
+
name: 'optionSource.selectionPolicy.selectablePropertyPath',
|
|
2264
|
+
label: 'Politica: campo selectable',
|
|
2265
|
+
editorType: 'text',
|
|
2266
|
+
group: 'Politica de selecao',
|
|
2267
|
+
hint: 'Campo booleano publicado pelo backend para indicar se a entidade pode ser selecionada.',
|
|
2268
|
+
},
|
|
2269
|
+
{
|
|
2270
|
+
name: 'optionSource.selectionPolicy.allowedStatuses',
|
|
2271
|
+
label: 'Status permitidos',
|
|
2272
|
+
editorType: 'textarea',
|
|
2273
|
+
group: 'Politica de selecao',
|
|
2274
|
+
hint: 'JSON array ou uma linha por status. Ex.: ACTIVE, SIGNED.',
|
|
2275
|
+
},
|
|
2276
|
+
{
|
|
2277
|
+
name: 'optionSource.selectionPolicy.blockedStatuses',
|
|
2278
|
+
label: 'Status bloqueados',
|
|
2279
|
+
editorType: 'textarea',
|
|
2280
|
+
group: 'Politica de selecao',
|
|
2281
|
+
hint: 'JSON array ou uma linha por status.',
|
|
2282
|
+
},
|
|
2283
|
+
{
|
|
2284
|
+
name: 'optionSource.selectionPolicy.disabledReasonTemplate',
|
|
2285
|
+
label: 'Template de motivo bloqueado',
|
|
2286
|
+
editorType: 'text',
|
|
2287
|
+
group: 'Politica de selecao',
|
|
2288
|
+
hint: 'Mensagem template exibida quando a entidade nao pode ser selecionada.',
|
|
2289
|
+
},
|
|
2290
|
+
{
|
|
2291
|
+
name: 'optionSource.selectionPolicy.validationMessageTemplate',
|
|
2292
|
+
label: 'Template de validacao',
|
|
2293
|
+
editorType: 'text',
|
|
2294
|
+
group: 'Politica de selecao',
|
|
2295
|
+
hint: 'Mensagem template usada em validacoes de selecao.',
|
|
2296
|
+
},
|
|
2297
|
+
{
|
|
2298
|
+
name: 'optionSource.selectionPolicy.allowRetainInvalidExistingValue',
|
|
2299
|
+
label: 'Manter valor invalido existente',
|
|
2300
|
+
editorType: 'checkbox',
|
|
2301
|
+
group: 'Politica de selecao',
|
|
2302
|
+
hint: 'Exibe entidade historica ja salva mesmo quando nao pode ser selecionada em novos registros.',
|
|
2303
|
+
},
|
|
2304
|
+
{
|
|
2305
|
+
name: 'optionSource.capabilities.filter',
|
|
2306
|
+
label: 'Capability: filter',
|
|
2307
|
+
editorType: 'checkbox',
|
|
2308
|
+
group: 'Capabilities',
|
|
2309
|
+
defaultValue: true,
|
|
2310
|
+
},
|
|
2311
|
+
{
|
|
2312
|
+
name: 'optionSource.capabilities.byIds',
|
|
2313
|
+
label: 'Capability: by-ids',
|
|
2314
|
+
editorType: 'checkbox',
|
|
2315
|
+
group: 'Capabilities',
|
|
2316
|
+
defaultValue: true,
|
|
2317
|
+
},
|
|
2318
|
+
{
|
|
2319
|
+
name: 'optionSource.capabilities.navigateToDetail',
|
|
2320
|
+
label: 'Capability: detalhe',
|
|
2321
|
+
editorType: 'checkbox',
|
|
2322
|
+
group: 'Capabilities',
|
|
2323
|
+
},
|
|
2324
|
+
{
|
|
2325
|
+
name: 'optionSource.capabilities.detail',
|
|
2326
|
+
label: 'Capability: endpoint de detalhe',
|
|
2327
|
+
editorType: 'checkbox',
|
|
2328
|
+
group: 'Capabilities',
|
|
2329
|
+
},
|
|
2330
|
+
{
|
|
2331
|
+
name: 'optionSource.capabilities.edit',
|
|
2332
|
+
label: 'Capability: editar',
|
|
2333
|
+
editorType: 'checkbox',
|
|
2334
|
+
group: 'Capabilities',
|
|
2335
|
+
},
|
|
2336
|
+
{
|
|
2337
|
+
name: 'optionSource.capabilities.create',
|
|
2338
|
+
label: 'Capability: criar',
|
|
2339
|
+
editorType: 'checkbox',
|
|
2340
|
+
group: 'Capabilities',
|
|
2341
|
+
},
|
|
2342
|
+
{
|
|
2343
|
+
name: 'optionSource.capabilities.multiSelect',
|
|
2344
|
+
label: 'Capability: multi-select',
|
|
2345
|
+
editorType: 'checkbox',
|
|
2346
|
+
group: 'Capabilities',
|
|
2347
|
+
},
|
|
2348
|
+
{
|
|
2349
|
+
name: 'optionSource.capabilities.recent',
|
|
2350
|
+
label: 'Capability: recentes',
|
|
2351
|
+
editorType: 'checkbox',
|
|
2352
|
+
group: 'Capabilities',
|
|
2353
|
+
},
|
|
2354
|
+
{
|
|
2355
|
+
name: 'optionSource.capabilities.favorites',
|
|
2356
|
+
label: 'Capability: favoritos',
|
|
2357
|
+
editorType: 'checkbox',
|
|
2358
|
+
group: 'Capabilities',
|
|
2359
|
+
},
|
|
2360
|
+
{
|
|
2361
|
+
name: 'optionSource.capabilities.auditSnapshot',
|
|
2362
|
+
label: 'Capability: snapshot de auditoria',
|
|
2363
|
+
editorType: 'checkbox',
|
|
2364
|
+
group: 'Capabilities',
|
|
2365
|
+
},
|
|
2366
|
+
{
|
|
2367
|
+
name: 'optionSource.detail.hrefTemplate',
|
|
2368
|
+
label: 'Template de detalhe',
|
|
2369
|
+
editorType: 'text',
|
|
2370
|
+
group: 'Navegacao',
|
|
2371
|
+
hint: 'Template de detalhe, por exemplo /contracts/{id}.',
|
|
2372
|
+
},
|
|
2373
|
+
{
|
|
2374
|
+
name: 'optionSource.detail.routeTemplate',
|
|
2375
|
+
label: 'Template de rota',
|
|
2376
|
+
editorType: 'text',
|
|
2377
|
+
group: 'Navegacao',
|
|
2378
|
+
hint: 'Template de rota de detalhe, por exemplo /contracts/:id.',
|
|
2379
|
+
},
|
|
2380
|
+
{
|
|
2381
|
+
name: 'optionSource.detail.openDetailMode',
|
|
2382
|
+
label: 'Modo de detalhe',
|
|
2383
|
+
editorType: 'select',
|
|
2384
|
+
group: 'Navegacao',
|
|
2385
|
+
options: [
|
|
2386
|
+
{ value: 'route', text: 'Rota' },
|
|
2387
|
+
{ value: 'drawer', text: 'Drawer' },
|
|
2388
|
+
{ value: 'dialog', text: 'Dialog' },
|
|
2389
|
+
{ value: 'external', text: 'Externo' },
|
|
2390
|
+
],
|
|
2391
|
+
},
|
|
2392
|
+
];
|
|
2393
|
+
|
|
1218
2394
|
const transferListProperties = [
|
|
1219
2395
|
// Geral
|
|
1220
2396
|
{ name: 'label', label: 'Label', editorType: 'text', group: 'Geral' },
|
|
@@ -3710,6 +4886,41 @@ const avatarProperties = [
|
|
|
3710
4886
|
{ name: 'extra.ariaLabel', label: 'ARIA label', editorType: 'text', group: 'Acessibilidade', hint: 'Use quando não houver label visível.' },
|
|
3711
4887
|
];
|
|
3712
4888
|
|
|
4889
|
+
const fieldSubmitProperties = [
|
|
4890
|
+
{
|
|
4891
|
+
name: 'source',
|
|
4892
|
+
label: 'Field source',
|
|
4893
|
+
editorType: 'select',
|
|
4894
|
+
group: 'Submit',
|
|
4895
|
+
defaultValue: 'schema',
|
|
4896
|
+
options: [
|
|
4897
|
+
{ value: 'schema', text: 'Schema field' },
|
|
4898
|
+
{ value: 'local', text: 'Local field' },
|
|
4899
|
+
],
|
|
4900
|
+
hint: 'Local fields are authored by the host and do not belong to the backend schema.',
|
|
4901
|
+
},
|
|
4902
|
+
{
|
|
4903
|
+
name: 'transient',
|
|
4904
|
+
label: 'Transient field',
|
|
4905
|
+
editorType: 'checkbox',
|
|
4906
|
+
group: 'Submit',
|
|
4907
|
+
hint: 'Transient fields stay available to the form but are omitted from submit payloads by default.',
|
|
4908
|
+
},
|
|
4909
|
+
{
|
|
4910
|
+
name: 'submitPolicy',
|
|
4911
|
+
label: 'Submit policy',
|
|
4912
|
+
editorType: 'select',
|
|
4913
|
+
group: 'Submit',
|
|
4914
|
+
options: [
|
|
4915
|
+
{ value: undefined, text: 'Default' },
|
|
4916
|
+
{ value: 'include', text: 'Include' },
|
|
4917
|
+
{ value: 'omit', text: 'Omit' },
|
|
4918
|
+
{ value: 'includeWhenDirty', text: 'Include when dirty' },
|
|
4919
|
+
],
|
|
4920
|
+
hint: 'When set, this policy has priority over source and transient.',
|
|
4921
|
+
},
|
|
4922
|
+
];
|
|
4923
|
+
|
|
3713
4924
|
/** Garante que minLength <= maxLength quando ambos definidos. */
|
|
3714
4925
|
function minLenLeMaxLen(group) {
|
|
3715
4926
|
const v = group.value || {};
|
|
@@ -5288,7 +6499,7 @@ const INLINE_FILTER_EDITOR_PROPERTIES_BY_CONTROL_TYPE = Object.freeze({
|
|
|
5288
6499
|
[INLINE_FILTER_CONTROL_TYPES.SELECT]: selectProperties,
|
|
5289
6500
|
[INLINE_FILTER_CONTROL_TYPES.SEARCHABLE_SELECT]: selectProperties,
|
|
5290
6501
|
[INLINE_FILTER_CONTROL_TYPES.ASYNC_SELECT]: selectProperties,
|
|
5291
|
-
[INLINE_FILTER_CONTROL_TYPES.ENTITY_LOOKUP]:
|
|
6502
|
+
[INLINE_FILTER_CONTROL_TYPES.ENTITY_LOOKUP]: entityLookupProperties,
|
|
5292
6503
|
[INLINE_FILTER_CONTROL_TYPES.AUTOCOMPLETE]: selectProperties,
|
|
5293
6504
|
[INLINE_FILTER_CONTROL_TYPES.MULTI_SELECT]: selectProperties,
|
|
5294
6505
|
[INLINE_FILTER_CONTROL_TYPES.INPUT]: inputProperties,
|
|
@@ -5331,6 +6542,7 @@ class FieldMetadataEditorComponent {
|
|
|
5331
6542
|
cancel = new EventEmitter();
|
|
5332
6543
|
form;
|
|
5333
6544
|
normalizedProps = [];
|
|
6545
|
+
renderedProps = [];
|
|
5334
6546
|
initialSnapshot = null;
|
|
5335
6547
|
baselineReady = false;
|
|
5336
6548
|
// Lista de tipos suportados no editor (curada para os tipos com config disponível)
|
|
@@ -5345,10 +6557,12 @@ class FieldMetadataEditorComponent {
|
|
|
5345
6557
|
{ value: FieldControlType.URL_INPUT, label: 'URL' },
|
|
5346
6558
|
{ value: FieldControlType.SEARCH_INPUT, label: 'Busca' },
|
|
5347
6559
|
{ value: FieldControlType.PHONE, label: 'Telefone' },
|
|
6560
|
+
{ value: FieldControlType.ARRAY_INPUT, label: 'Colecao editavel' },
|
|
5348
6561
|
{ value: FieldControlType.SELECT, label: 'Seleção (Select)' },
|
|
5349
6562
|
{ value: FieldControlType.MULTI_SELECT, label: 'Seleção múltipla' },
|
|
5350
6563
|
{ value: FieldControlType.SEARCHABLE_SELECT, label: 'Seleção buscável' },
|
|
5351
6564
|
{ value: FieldControlType.ASYNC_SELECT, label: 'Seleção assíncrona' },
|
|
6565
|
+
{ value: FieldControlType.ENTITY_LOOKUP, label: 'Entity Lookup' },
|
|
5352
6566
|
{ value: FieldControlType.AUTO_COMPLETE, label: 'Auto-completar' },
|
|
5353
6567
|
{ value: FieldControlType.SELECTION_LIST, label: 'Lista de seleção' },
|
|
5354
6568
|
{ value: FieldControlType.TREE_SELECT, label: 'Árvore (Tree Select)' },
|
|
@@ -5436,9 +6650,12 @@ class FieldMetadataEditorComponent {
|
|
|
5436
6650
|
return inlineProps;
|
|
5437
6651
|
if (controlType === FieldControlType.INPUT)
|
|
5438
6652
|
return inputProperties;
|
|
6653
|
+
if (controlType === FieldControlType.ARRAY_INPUT)
|
|
6654
|
+
return arrayProperties;
|
|
6655
|
+
if (controlTypeToken === 'entitylookup')
|
|
6656
|
+
return entityLookupProperties;
|
|
5439
6657
|
if (controlTypeToken === 'searchableselect' ||
|
|
5440
|
-
controlTypeToken === 'asyncselect'
|
|
5441
|
-
controlTypeToken === 'entitylookup')
|
|
6658
|
+
controlTypeToken === 'asyncselect')
|
|
5442
6659
|
return selectProperties;
|
|
5443
6660
|
if (controlType === FieldControlType.NUMERIC_TEXT_BOX)
|
|
5444
6661
|
return numberProperties;
|
|
@@ -5483,6 +6700,8 @@ class FieldMetadataEditorComponent {
|
|
|
5483
6700
|
controlType === FieldControlType.AUTO_COMPLETE ||
|
|
5484
6701
|
controlType === FieldControlType.SELECTION_LIST)
|
|
5485
6702
|
return selectProperties;
|
|
6703
|
+
if (controlType === FieldControlType.ENTITY_LOOKUP)
|
|
6704
|
+
return entityLookupProperties;
|
|
5486
6705
|
if (controlType === FieldControlType.TEXTAREA)
|
|
5487
6706
|
return textareaProperties;
|
|
5488
6707
|
if (controlType === FieldControlType.TRANSFER_LIST)
|
|
@@ -5559,11 +6778,14 @@ class FieldMetadataEditorComponent {
|
|
|
5559
6778
|
this.registry.register(this.controlType, inputProperties);
|
|
5560
6779
|
props = inputProperties;
|
|
5561
6780
|
}
|
|
6781
|
+
else if (controlTypeToken === 'entitylookup') {
|
|
6782
|
+
this.registry.register(this.controlType, entityLookupProperties);
|
|
6783
|
+
props = entityLookupProperties;
|
|
6784
|
+
}
|
|
5562
6785
|
else if (
|
|
5563
6786
|
// Aliases for select-like
|
|
5564
6787
|
controlTypeToken === 'searchableselect' ||
|
|
5565
|
-
controlTypeToken === 'asyncselect'
|
|
5566
|
-
controlTypeToken === 'entitylookup') {
|
|
6788
|
+
controlTypeToken === 'asyncselect') {
|
|
5567
6789
|
this.registry.register(this.controlType, selectProperties);
|
|
5568
6790
|
props = selectProperties;
|
|
5569
6791
|
}
|
|
@@ -5648,6 +6870,10 @@ class FieldMetadataEditorComponent {
|
|
|
5648
6870
|
this.registry.register(this.controlType, selectProperties);
|
|
5649
6871
|
props = selectProperties;
|
|
5650
6872
|
}
|
|
6873
|
+
else if (this.controlType === FieldControlType.ENTITY_LOOKUP) {
|
|
6874
|
+
this.registry.register(this.controlType, entityLookupProperties);
|
|
6875
|
+
props = entityLookupProperties;
|
|
6876
|
+
}
|
|
5651
6877
|
else if (this.controlType === FieldControlType.TEXTAREA) {
|
|
5652
6878
|
this.registry.register(this.controlType, textareaProperties);
|
|
5653
6879
|
props = textareaProperties;
|
|
@@ -5734,7 +6960,7 @@ class FieldMetadataEditorComponent {
|
|
|
5734
6960
|
options: this.typeOptions.map((o) => ({ value: o.value, text: o.label })),
|
|
5735
6961
|
defaultValue: this.controlType,
|
|
5736
6962
|
};
|
|
5737
|
-
props = [typeProp, ...props];
|
|
6963
|
+
props = this.withSharedFieldMetadataProperties([typeProp, ...props]);
|
|
5738
6964
|
}
|
|
5739
6965
|
catch { }
|
|
5740
6966
|
this.normalizedProps = this.normalizer.normalize(props, this.seed);
|
|
@@ -5779,6 +7005,7 @@ class FieldMetadataEditorComponent {
|
|
|
5779
7005
|
}
|
|
5780
7006
|
}
|
|
5781
7007
|
catch { }
|
|
7008
|
+
this.renderedProps = this.buildRenderedProps(this.normalizedProps);
|
|
5782
7009
|
// Register contextual validators for INPUT/TEXTAREA (minLength <= maxLength)
|
|
5783
7010
|
if (this.controlType === FieldControlType.INPUT ||
|
|
5784
7011
|
this.controlType === FieldControlType.TEXTAREA) {
|
|
@@ -5809,7 +7036,7 @@ class FieldMetadataEditorComponent {
|
|
|
5809
7036
|
const name = p?.name;
|
|
5810
7037
|
if (!name)
|
|
5811
7038
|
continue;
|
|
5812
|
-
const val = getByPath(this.seed, name);
|
|
7039
|
+
const val = this.toEditorControlValue(p, getByPath(this.seed, name));
|
|
5813
7040
|
// Preserve false/0; skip only null/undefined
|
|
5814
7041
|
if (val !== undefined && val !== null) {
|
|
5815
7042
|
this.factory.setValueByPath(this.form, name, val);
|
|
@@ -5993,6 +7220,9 @@ class FieldMetadataEditorComponent {
|
|
|
5993
7220
|
});
|
|
5994
7221
|
}
|
|
5995
7222
|
apply() {
|
|
7223
|
+
if (!this.canEmitSettingsValue()) {
|
|
7224
|
+
return;
|
|
7225
|
+
}
|
|
5996
7226
|
const raw = this.factory.extractPatch(this.form);
|
|
5997
7227
|
const patch = this.buildDeltaPatch(raw, this.initialSnapshot);
|
|
5998
7228
|
this.normalizeKnownTextareaPatchValues(patch);
|
|
@@ -6020,6 +7250,9 @@ class FieldMetadataEditorComponent {
|
|
|
6020
7250
|
}
|
|
6021
7251
|
// Settings Panel value provider API
|
|
6022
7252
|
getSettingsValue() {
|
|
7253
|
+
if (!this.canEmitSettingsValue()) {
|
|
7254
|
+
return {};
|
|
7255
|
+
}
|
|
6023
7256
|
const raw = this.factory.extractPatch(this.form);
|
|
6024
7257
|
const patch = this.buildDeltaPatch(raw, this.initialSnapshot);
|
|
6025
7258
|
this.normalizeKnownTextareaPatchValues(patch);
|
|
@@ -6119,6 +7352,97 @@ class FieldMetadataEditorComponent {
|
|
|
6119
7352
|
patch.links = parsedLinks;
|
|
6120
7353
|
}
|
|
6121
7354
|
}
|
|
7355
|
+
this.normalizeEntityLookupPatchValues(patch);
|
|
7356
|
+
this.normalizeArrayPatchValues(patch);
|
|
7357
|
+
}
|
|
7358
|
+
normalizeEntityLookupPatchValues(patch) {
|
|
7359
|
+
const optionSource = patch?.optionSource;
|
|
7360
|
+
if (!optionSource || typeof optionSource !== 'object') {
|
|
7361
|
+
return;
|
|
7362
|
+
}
|
|
7363
|
+
this.normalizeStringListProperty(optionSource, 'descriptionPropertyPaths');
|
|
7364
|
+
this.normalizeStringListProperty(optionSource, 'searchPropertyPaths');
|
|
7365
|
+
this.normalizeStringListProperty(optionSource, 'dependsOn');
|
|
7366
|
+
this.normalizeJsonObjectProperty(optionSource, 'dependencyFilterMap');
|
|
7367
|
+
const selectionPolicy = optionSource.selectionPolicy;
|
|
7368
|
+
if (selectionPolicy && typeof selectionPolicy === 'object') {
|
|
7369
|
+
this.normalizeStringListProperty(selectionPolicy, 'allowedStatuses');
|
|
7370
|
+
this.normalizeStringListProperty(selectionPolicy, 'blockedStatuses');
|
|
7371
|
+
}
|
|
7372
|
+
}
|
|
7373
|
+
normalizeStringListProperty(target, key) {
|
|
7374
|
+
if (!target || typeof target !== 'object' || typeof target[key] !== 'string') {
|
|
7375
|
+
return;
|
|
7376
|
+
}
|
|
7377
|
+
const parsed = this.parseStringListTextarea(target[key]);
|
|
7378
|
+
if (parsed) {
|
|
7379
|
+
target[key] = parsed;
|
|
7380
|
+
}
|
|
7381
|
+
}
|
|
7382
|
+
normalizeJsonObjectProperty(target, key) {
|
|
7383
|
+
if (!target || typeof target !== 'object' || typeof target[key] !== 'string') {
|
|
7384
|
+
return;
|
|
7385
|
+
}
|
|
7386
|
+
const parsed = this.tryParseJson(String(target[key]).trim());
|
|
7387
|
+
if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) {
|
|
7388
|
+
target[key] = parsed;
|
|
7389
|
+
}
|
|
7390
|
+
}
|
|
7391
|
+
normalizeArrayPatchValues(patch) {
|
|
7392
|
+
const arrayPatch = patch?.array;
|
|
7393
|
+
if (!arrayPatch || typeof arrayPatch !== 'object') {
|
|
7394
|
+
return;
|
|
7395
|
+
}
|
|
7396
|
+
const collectionValidation = arrayPatch.collectionValidation;
|
|
7397
|
+
if (collectionValidation &&
|
|
7398
|
+
typeof collectionValidation === 'object' &&
|
|
7399
|
+
typeof collectionValidation.uniqueBy === 'string') {
|
|
7400
|
+
const parsedUniqueBy = this.parseStringListTextarea(collectionValidation.uniqueBy);
|
|
7401
|
+
if (parsedUniqueBy) {
|
|
7402
|
+
collectionValidation.uniqueBy = parsedUniqueBy;
|
|
7403
|
+
}
|
|
7404
|
+
}
|
|
7405
|
+
this.normalizeArrayCountRuleValue(collectionValidation?.exactlyOne);
|
|
7406
|
+
this.normalizeArrayCountRuleValue(collectionValidation?.atLeastOne);
|
|
7407
|
+
const itemSchema = arrayPatch.itemSchema;
|
|
7408
|
+
if (itemSchema &&
|
|
7409
|
+
typeof itemSchema === 'object' &&
|
|
7410
|
+
typeof itemSchema.fields === 'string') {
|
|
7411
|
+
const parsedFields = this.parseArrayTextarea(itemSchema.fields);
|
|
7412
|
+
if (parsedFields) {
|
|
7413
|
+
itemSchema.fields = parsedFields;
|
|
7414
|
+
}
|
|
7415
|
+
}
|
|
7416
|
+
if (typeof patch.defaultValue === 'string') {
|
|
7417
|
+
const parsedDefaultValue = this.parseArrayTextarea(patch.defaultValue);
|
|
7418
|
+
if (parsedDefaultValue) {
|
|
7419
|
+
patch.defaultValue = parsedDefaultValue;
|
|
7420
|
+
}
|
|
7421
|
+
}
|
|
7422
|
+
}
|
|
7423
|
+
normalizeArrayCountRuleValue(rule) {
|
|
7424
|
+
if (!rule || typeof rule !== 'object' || typeof rule.value !== 'string') {
|
|
7425
|
+
return;
|
|
7426
|
+
}
|
|
7427
|
+
const raw = rule.value.trim();
|
|
7428
|
+
if (!raw) {
|
|
7429
|
+
return;
|
|
7430
|
+
}
|
|
7431
|
+
try {
|
|
7432
|
+
rule.value = JSON.parse(raw);
|
|
7433
|
+
}
|
|
7434
|
+
catch {
|
|
7435
|
+
rule.value = raw;
|
|
7436
|
+
}
|
|
7437
|
+
}
|
|
7438
|
+
toEditorControlValue(prop, value) {
|
|
7439
|
+
if (prop?.editorType === 'textarea' &&
|
|
7440
|
+
value !== undefined &&
|
|
7441
|
+
value !== null &&
|
|
7442
|
+
typeof value !== 'string') {
|
|
7443
|
+
return JSON.stringify(value, null, 2);
|
|
7444
|
+
}
|
|
7445
|
+
return value;
|
|
6122
7446
|
}
|
|
6123
7447
|
/**
|
|
6124
7448
|
* Interpreta textarea como lista simples de strings:
|
|
@@ -6172,7 +7496,11 @@ class FieldMetadataEditorComponent {
|
|
|
6172
7496
|
}
|
|
6173
7497
|
}
|
|
6174
7498
|
reset() {
|
|
6175
|
-
this.
|
|
7499
|
+
const snapshot = this.cloneSnapshot(this.initialSnapshot ?? this.form.getRawValue());
|
|
7500
|
+
this.form.reset(snapshot);
|
|
7501
|
+
this.form.markAsPristine();
|
|
7502
|
+
this.form.markAsUntouched();
|
|
7503
|
+
this.form.updateValueAndValidity({ emitEvent: true });
|
|
6176
7504
|
this.isDirty$.next(false);
|
|
6177
7505
|
}
|
|
6178
7506
|
onControlTypeChange(next) {
|
|
@@ -6185,28 +7513,167 @@ class FieldMetadataEditorComponent {
|
|
|
6185
7513
|
if (value != null)
|
|
6186
7514
|
this.onControlTypeChange(value);
|
|
6187
7515
|
}
|
|
7516
|
+
withSharedFieldMetadataProperties(props) {
|
|
7517
|
+
const propNames = new Set(props.map((prop) => prop.name));
|
|
7518
|
+
const missingSharedProps = fieldSubmitProperties.filter((prop) => !propNames.has(prop.name));
|
|
7519
|
+
return missingSharedProps.length ? [...props, ...missingSharedProps] : props;
|
|
7520
|
+
}
|
|
7521
|
+
get isArrayEditor() {
|
|
7522
|
+
return this.controlType === FieldControlType.ARRAY_INPUT;
|
|
7523
|
+
}
|
|
7524
|
+
buildRenderedProps(props) {
|
|
7525
|
+
if (!this.isArrayEditor) {
|
|
7526
|
+
return props;
|
|
7527
|
+
}
|
|
7528
|
+
return (props || []).filter((prop) => prop?.name !== 'array.itemSchema.fields');
|
|
7529
|
+
}
|
|
7530
|
+
cloneSnapshot(value) {
|
|
7531
|
+
return this.cloneMetadataValue(value, new WeakMap());
|
|
7532
|
+
}
|
|
7533
|
+
cloneMetadataValue(value, seen) {
|
|
7534
|
+
if (!value || typeof value !== 'object') {
|
|
7535
|
+
return value;
|
|
7536
|
+
}
|
|
7537
|
+
if (seen.has(value)) {
|
|
7538
|
+
return seen.get(value);
|
|
7539
|
+
}
|
|
7540
|
+
if (value instanceof Date) {
|
|
7541
|
+
return new Date(value.getTime());
|
|
7542
|
+
}
|
|
7543
|
+
if (value instanceof RegExp) {
|
|
7544
|
+
return new RegExp(value.source, value.flags);
|
|
7545
|
+
}
|
|
7546
|
+
if (Array.isArray(value)) {
|
|
7547
|
+
const clone = [];
|
|
7548
|
+
seen.set(value, clone);
|
|
7549
|
+
clone.push(...value.map((entry) => this.cloneMetadataValue(entry, seen)));
|
|
7550
|
+
return clone;
|
|
7551
|
+
}
|
|
7552
|
+
if (value instanceof Map) {
|
|
7553
|
+
const clone = new Map();
|
|
7554
|
+
seen.set(value, clone);
|
|
7555
|
+
value.forEach((entry, key) => {
|
|
7556
|
+
clone.set(this.cloneMetadataValue(key, seen), this.cloneMetadataValue(entry, seen));
|
|
7557
|
+
});
|
|
7558
|
+
return clone;
|
|
7559
|
+
}
|
|
7560
|
+
if (value instanceof Set) {
|
|
7561
|
+
const clone = new Set();
|
|
7562
|
+
seen.set(value, clone);
|
|
7563
|
+
value.forEach((entry) => clone.add(this.cloneMetadataValue(entry, seen)));
|
|
7564
|
+
return clone;
|
|
7565
|
+
}
|
|
7566
|
+
const prototype = Object.getPrototypeOf(value);
|
|
7567
|
+
if (prototype !== Object.prototype && prototype !== null) {
|
|
7568
|
+
return value;
|
|
7569
|
+
}
|
|
7570
|
+
const clone = {};
|
|
7571
|
+
seen.set(value, clone);
|
|
7572
|
+
for (const [key, entry] of Object.entries(value)) {
|
|
7573
|
+
clone[key] = this.cloneMetadataValue(entry, seen);
|
|
7574
|
+
}
|
|
7575
|
+
return clone;
|
|
7576
|
+
}
|
|
7577
|
+
canEmitSettingsValue() {
|
|
7578
|
+
this.validateArrayItemSchemaFields();
|
|
7579
|
+
this.form.updateValueAndValidity({ emitEvent: true });
|
|
7580
|
+
const valid = this.form.valid;
|
|
7581
|
+
this.isValid$.next(valid);
|
|
7582
|
+
if (!valid) {
|
|
7583
|
+
this.form.markAllAsTouched();
|
|
7584
|
+
}
|
|
7585
|
+
return valid;
|
|
7586
|
+
}
|
|
7587
|
+
validateArrayItemSchemaFields() {
|
|
7588
|
+
if (!this.isArrayEditor) {
|
|
7589
|
+
return;
|
|
7590
|
+
}
|
|
7591
|
+
const control = this.form.get('array.itemSchema.fields');
|
|
7592
|
+
if (!control) {
|
|
7593
|
+
return;
|
|
7594
|
+
}
|
|
7595
|
+
const value = control.value;
|
|
7596
|
+
const fields = Array.isArray(value)
|
|
7597
|
+
? value
|
|
7598
|
+
: typeof value === 'string' && value.trim()
|
|
7599
|
+
? this.parseArrayItemFields(value)
|
|
7600
|
+
: [];
|
|
7601
|
+
const seen = new Set();
|
|
7602
|
+
const duplicated = new Set();
|
|
7603
|
+
let hasEmptyName = false;
|
|
7604
|
+
for (const field of fields) {
|
|
7605
|
+
const name = String(field?.name || '').trim();
|
|
7606
|
+
if (!name) {
|
|
7607
|
+
hasEmptyName = true;
|
|
7608
|
+
continue;
|
|
7609
|
+
}
|
|
7610
|
+
if (seen.has(name)) {
|
|
7611
|
+
duplicated.add(name);
|
|
7612
|
+
}
|
|
7613
|
+
seen.add(name);
|
|
7614
|
+
}
|
|
7615
|
+
this.setControlError(control, 'arrayFieldNameRequired', hasEmptyName);
|
|
7616
|
+
this.setControlError(control, 'arrayFieldNameDuplicated', duplicated.size ? { names: Array.from(duplicated) } : null);
|
|
7617
|
+
}
|
|
7618
|
+
parseArrayItemFields(value) {
|
|
7619
|
+
try {
|
|
7620
|
+
const parsed = JSON.parse(value);
|
|
7621
|
+
return Array.isArray(parsed) ? parsed : [];
|
|
7622
|
+
}
|
|
7623
|
+
catch {
|
|
7624
|
+
return [];
|
|
7625
|
+
}
|
|
7626
|
+
}
|
|
7627
|
+
setControlError(control, key, value) {
|
|
7628
|
+
const errors = { ...(control.errors || {}) };
|
|
7629
|
+
const hasError = value !== null && value !== undefined && value !== false;
|
|
7630
|
+
if (hasError) {
|
|
7631
|
+
errors[key] = value === true ? true : value;
|
|
7632
|
+
}
|
|
7633
|
+
else {
|
|
7634
|
+
delete errors[key];
|
|
7635
|
+
}
|
|
7636
|
+
control.setErrors(Object.keys(errors).length ? errors : null);
|
|
7637
|
+
}
|
|
6188
7638
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: FieldMetadataEditorComponent, deps: [{ token: ConfigRegistryService }, { token: SchemaNormalizerService }, { token: DynamicFormFactoryService }, { token: ContextValidatorRegistryService }], target: i0.ɵɵFactoryTarget.Component });
|
|
6189
7639
|
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.17", type: FieldMetadataEditorComponent, isStandalone: true, selector: "praxis-field-metadata-editor", inputs: { controlType: "controlType", seed: "seed" }, outputs: { applied: "applied", cancel: "cancel" }, ngImport: i0, template: `
|
|
6190
7640
|
<div class="p-3" *ngIf="form">
|
|
6191
7641
|
<praxis-dynamic-editor-renderer
|
|
6192
|
-
[properties]="
|
|
7642
|
+
[properties]="renderedProps"
|
|
6193
7643
|
[form]="form"
|
|
6194
7644
|
></praxis-dynamic-editor-renderer>
|
|
7645
|
+
|
|
7646
|
+
<praxis-array-item-schema-fields-editor
|
|
7647
|
+
*ngIf="isArrayEditor"
|
|
7648
|
+
[control]="form.get('array.itemSchema.fields')"
|
|
7649
|
+
[arrayControl]="form.get('array')"
|
|
7650
|
+
></praxis-array-item-schema-fields-editor>
|
|
6195
7651
|
</div>
|
|
6196
|
-
`, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i3
|
|
7652
|
+
`, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "component", type: DynamicEditorRendererComponent, selector: "praxis-dynamic-editor-renderer", inputs: ["properties", "form"] }, { kind: "component", type: ArrayItemSchemaFieldsEditorComponent, selector: "praxis-array-item-schema-fields-editor", inputs: ["control", "arrayControl"] }] });
|
|
6197
7653
|
}
|
|
6198
7654
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: FieldMetadataEditorComponent, decorators: [{
|
|
6199
7655
|
type: Component,
|
|
6200
7656
|
args: [{
|
|
6201
7657
|
selector: 'praxis-field-metadata-editor',
|
|
6202
7658
|
standalone: true,
|
|
6203
|
-
imports: [
|
|
7659
|
+
imports: [
|
|
7660
|
+
CommonModule,
|
|
7661
|
+
ReactiveFormsModule,
|
|
7662
|
+
DynamicEditorRendererComponent,
|
|
7663
|
+
ArrayItemSchemaFieldsEditorComponent,
|
|
7664
|
+
],
|
|
6204
7665
|
template: `
|
|
6205
7666
|
<div class="p-3" *ngIf="form">
|
|
6206
7667
|
<praxis-dynamic-editor-renderer
|
|
6207
|
-
[properties]="
|
|
7668
|
+
[properties]="renderedProps"
|
|
6208
7669
|
[form]="form"
|
|
6209
7670
|
></praxis-dynamic-editor-renderer>
|
|
7671
|
+
|
|
7672
|
+
<praxis-array-item-schema-fields-editor
|
|
7673
|
+
*ngIf="isArrayEditor"
|
|
7674
|
+
[control]="form.get('array.itemSchema.fields')"
|
|
7675
|
+
[arrayControl]="form.get('array')"
|
|
7676
|
+
></praxis-array-item-schema-fields-editor>
|
|
6210
7677
|
</div>
|
|
6211
7678
|
`,
|
|
6212
7679
|
}]
|
|
@@ -6227,15 +7694,19 @@ class CascadeRulesService {
|
|
|
6227
7694
|
return map;
|
|
6228
7695
|
}
|
|
6229
7696
|
hydrateRule(field) {
|
|
6230
|
-
const deps = field.dependencyFields
|
|
7697
|
+
const deps = (field.dependencyFields ??
|
|
7698
|
+
field.optionSource?.dependsOn);
|
|
6231
7699
|
if (!deps || deps.length === 0)
|
|
6232
7700
|
return null;
|
|
7701
|
+
const dependencyFilterMap = field.dependencyFilterMap ??
|
|
7702
|
+
field.optionSource?.dependencyFilterMap ??
|
|
7703
|
+
null;
|
|
6233
7704
|
const vm = {
|
|
6234
7705
|
targetField: field.name,
|
|
6235
7706
|
dependencyFields: [...deps],
|
|
6236
7707
|
enableDependencyCascade: field.enableDependencyCascade === false ? false : true,
|
|
6237
7708
|
resetOnDependentChange: !!field.resetOnDependentChange,
|
|
6238
|
-
dependencyFilterMap
|
|
7709
|
+
dependencyFilterMap,
|
|
6239
7710
|
dependencyValuePath: field.dependencyValuePath || null,
|
|
6240
7711
|
dependencyMergeStrategy: field.dependencyMergeStrategy || 'merge',
|
|
6241
7712
|
dependencyDebounceMs: field.dependencyDebounceMs != null
|
|
@@ -6916,7 +8387,7 @@ class CascadeManagerTabComponent {
|
|
|
6916
8387
|
</div>
|
|
6917
8388
|
</div>
|
|
6918
8389
|
</div>
|
|
6919
|
-
`, isInline: true, styles: [":host{display:block}.cm-root{display:grid;grid-template-columns:320px 1fr;gap:16px;min-height:420px}.cm-left{border-right:1px solid var(--md-sys-color-outline-variant);padding-right:8px}.cm-search{width:100%;margin-bottom:8px}.cm-right{padding-left:8px}.field-item{display:flex;align-items:center;justify-content:space-between;padding:8px 6px;cursor:pointer;border-radius:10px;transition:background .12s ease,border .12s ease;border:1px solid transparent}.field-item:hover{background:var(--md-sys-color-surface-container-high)}.field-item.selected{background:var(--md-sys-color-surface-container-highest);border-color:var(--md-sys-color-outline-variant)}.rule-badges{display:inline-flex;gap:6px}.rule-badge{font-size:11px;padding:2px 8px;border-radius:999px;font-weight:600}.b-active{background:var(--md-sys-color-primary-container);color:var(--md-sys-color-on-primary-container)}.b-manual{background:var(--md-sys-color-surface-container-high);color:var(--md-sys-color-on-surface-variant)}.b-immediate{background:var(--md-sys-color-secondary-container);color:var(--md-sys-color-on-secondary-container)}.b-conflict{background:var(--md-sys-color-error-container);color:var(--md-sys-color-on-error-container)}.cm-header{display:flex;align-items:center;justify-content:space-between;margin-bottom:8px}.rules-empty{opacity:.8;font-style:italic;padding:8px 0;color:var(--md-sys-color-on-surface-variant)}.rule-row{display:grid;grid-template-columns:1fr auto;align-items:center;padding:10px 0;border-bottom:1px dashed var(--md-sys-color-outline-variant)}.rule-actions button{margin-left:4px}.banner{background:var(--md-sys-color-tertiary-container);color:var(--md-sys-color-on-tertiary-container);padding:10px 12px;border:1px solid var(--md-sys-color-outline-variant);border-radius:8px;margin-bottom:10px;display:flex;gap:8px;align-items:center}.import-panel{background:var(--md-sys-color-surface-container-high);border:1px solid var(--md-sys-color-outline-variant);border-radius:8px;padding:10px;margin-bottom:10px}.full{width:100%}.form-row{display:flex;gap:12px;align-items:center;flex-wrap:wrap}.form-grid{display:grid;gap:12px;padding:8px 0}.map-table{width:100%;border-collapse:collapse}.map-table th,.map-table td{padding:8px;border-bottom:1px dashed var(--md-sys-color-outline-variant)}.kbd{font-family:monospace;background:var(--md-sys-color-surface-container-highest);padding:0 6px;border-radius:4px;color:var(--md-sys-color-on-surface-variant)}.panel-surface{background:var(--md-sys-color-surface-container-high);border:1px solid var(--md-sys-color-outline-variant);border-radius:10px;box-shadow:var(--md-sys-elevation-level1, none);margin-bottom:12px}.panel-stack{display:grid;gap:12px;margin:12px 0}.stack-panel{background:var(--md-sys-color-surface-container-high);border:1px solid var(--md-sys-color-outline-variant);border-radius:10px;box-shadow:var(--md-sys-elevation-level1, none)}.stack-panel .mat-expansion-panel-content{padding:0 16px 12px}.panel-header{display:flex;align-items:center;gap:8px}.preview-box{background:var(--md-sys-color-surface-container-low);border:1px solid var(--md-sys-color-outline-variant);border-radius:8px;padding:8px;color:var(--md-sys-color-on-surface)}.help-icon-button{--mdc-icon-button-state-layer-size: 28px;--mdc-icon-button-icon-size: 18px;width:28px;height:28px;padding:0;display:inline-flex;align-items:center;justify-content:center;margin-right:-4px}.help-icon-button mat-icon{font-size:18px;width:18px;height:18px}.mat-mdc-form-field-icon-suffix{align-self:center}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i3$1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i3$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i3.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: i3.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { kind: "directive", type: i3.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i3.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i6.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i5$1.MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }, { kind: "component", type: i5$1.MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i8.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i7.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly", "disabledInteractive"], exportAs: ["matInput"] }, { kind: "component", type: i7.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i7.MatLabel, selector: "mat-label" }, { kind: "directive", type: i7.MatSuffix, selector: "[matSuffix], [matIconSuffix], [matTextSuffix]", inputs: ["matTextSuffix"] }, { kind: "ngmodule", type: MatChipsModule }, { kind: "ngmodule", type: MatListModule }, { kind: "ngmodule", type: MatDividerModule }, { kind: "ngmodule", type: MatSelectModule }, { kind: "component", type: i8$1.MatSelect, selector: "mat-select", inputs: ["aria-describedby", "panelClass", "disabled", "disableRipple", "tabIndex", "hideSingleSelectionIndicator", "placeholder", "required", "multiple", "disableOptionCentering", "compareWith", "value", "aria-label", "aria-labelledby", "errorStateMatcher", "typeaheadDebounceInterval", "sortComparator", "id", "panelWidth", "canSelectNullableOptions"], outputs: ["openedChange", "opened", "closed", "selectionChange", "valueChange"], exportAs: ["matSelect"] }, { kind: "component", type: i8$1.MatOption, selector: "mat-option", inputs: ["value", "id", "disabled"], outputs: ["onSelectionChange"], exportAs: ["matOption"] }, { kind: "ngmodule", type: MatCheckboxModule }, { kind: "component", type: i9.MatCheckbox, selector: "mat-checkbox", inputs: ["aria-label", "aria-labelledby", "aria-describedby", "aria-expanded", "aria-controls", "aria-owns", "id", "required", "labelPosition", "name", "value", "disableRipple", "tabIndex", "color", "disabledInteractive", "checked", "disabled", "indeterminate"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }, { kind: "ngmodule", type: MatExpansionModule }, { kind: "component", type: i5.MatExpansionPanel, selector: "mat-expansion-panel", inputs: ["hideToggle", "togglePosition"], outputs: ["afterExpand", "afterCollapse"], exportAs: ["matExpansionPanel"] }, { kind: "component", type: i5.MatExpansionPanelHeader, selector: "mat-expansion-panel-header", inputs: ["expandedHeight", "collapsedHeight", "tabIndex"] }, { kind: "directive", type: i5.MatExpansionPanelTitle, selector: "mat-panel-title" }, { kind: "ngmodule", type: MatMenuModule }, { kind: "component", type: i11.MatMenu, selector: "mat-menu", inputs: ["backdropClass", "aria-label", "aria-labelledby", "aria-describedby", "xPosition", "yPosition", "overlapTrigger", "hasBackdrop", "class", "classList"], outputs: ["closed", "close"], exportAs: ["matMenu"] }, { kind: "component", type: i11.MatMenuItem, selector: "[mat-menu-item]", inputs: ["role", "disabled", "disableRipple"], exportAs: ["matMenuItem"] }, { kind: "directive", type: i11.MatMenuTrigger, selector: "[mat-menu-trigger-for], [matMenuTriggerFor]", inputs: ["mat-menu-trigger-for", "matMenuTriggerFor", "matMenuTriggerData", "matMenuTriggerRestoreFocus"], outputs: ["menuOpened", "onMenuOpen", "menuClosed", "onMenuClose"], exportAs: ["matMenuTrigger"] }, { kind: "ngmodule", type: MatAutocompleteModule }, { kind: "component", type: i12.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: "directive", type: i12.MatAutocompleteTrigger, selector: "input[matAutocomplete], textarea[matAutocomplete]", inputs: ["matAutocomplete", "matAutocompletePosition", "matAutocompleteConnectedTo", "autocomplete", "matAutocompleteDisabled"], exportAs: ["matAutocompleteTrigger"] }, { kind: "ngmodule", type: ScrollingModule }, { kind: "directive", type: i13.CdkFixedSizeVirtualScroll, selector: "cdk-virtual-scroll-viewport[itemSize]", inputs: ["itemSize", "minBufferPx", "maxBufferPx"] }, { kind: "directive", type: i13.CdkVirtualForOf, selector: "[cdkVirtualFor][cdkVirtualForOf]", inputs: ["cdkVirtualForOf", "cdkVirtualForTrackBy", "cdkVirtualForTemplate", "cdkVirtualForTemplateCacheSize"] }, { kind: "component", type: i13.CdkVirtualScrollViewport, selector: "cdk-virtual-scroll-viewport", inputs: ["orientation", "appendOnly"], outputs: ["scrolledIndexChange"] }, { kind: "directive", type: PraxisIconDirective, selector: "mat-icon[praxisIcon]", inputs: ["praxisIcon"] }] });
|
|
8390
|
+
`, isInline: true, styles: [":host{display:block}.cm-root{display:grid;grid-template-columns:320px 1fr;gap:16px;min-height:420px}.cm-left{border-right:1px solid var(--md-sys-color-outline-variant);padding-right:8px}.cm-search{width:100%;margin-bottom:8px}.cm-right{padding-left:8px}.field-item{display:flex;align-items:center;justify-content:space-between;padding:8px 6px;cursor:pointer;border-radius:10px;transition:background .12s ease,border .12s ease;border:1px solid transparent}.field-item:hover{background:var(--md-sys-color-surface-container-high)}.field-item.selected{background:var(--md-sys-color-surface-container-highest);border-color:var(--md-sys-color-outline-variant)}.rule-badges{display:inline-flex;gap:6px}.rule-badge{font-size:11px;padding:2px 8px;border-radius:999px;font-weight:600}.b-active{background:var(--md-sys-color-primary-container);color:var(--md-sys-color-on-primary-container)}.b-manual{background:var(--md-sys-color-surface-container-high);color:var(--md-sys-color-on-surface-variant)}.b-immediate{background:var(--md-sys-color-secondary-container);color:var(--md-sys-color-on-secondary-container)}.b-conflict{background:var(--md-sys-color-error-container);color:var(--md-sys-color-on-error-container)}.cm-header{display:flex;align-items:center;justify-content:space-between;margin-bottom:8px}.rules-empty{opacity:.8;font-style:italic;padding:8px 0;color:var(--md-sys-color-on-surface-variant)}.rule-row{display:grid;grid-template-columns:1fr auto;align-items:center;padding:10px 0;border-bottom:1px dashed var(--md-sys-color-outline-variant)}.rule-actions button{margin-left:4px}.banner{background:var(--md-sys-color-tertiary-container);color:var(--md-sys-color-on-tertiary-container);padding:10px 12px;border:1px solid var(--md-sys-color-outline-variant);border-radius:8px;margin-bottom:10px;display:flex;gap:8px;align-items:center}.import-panel{background:var(--md-sys-color-surface-container-high);border:1px solid var(--md-sys-color-outline-variant);border-radius:8px;padding:10px;margin-bottom:10px}.full{width:100%}.form-row{display:flex;gap:12px;align-items:center;flex-wrap:wrap}.form-grid{display:grid;gap:12px;padding:8px 0}.map-table{width:100%;border-collapse:collapse}.map-table th,.map-table td{padding:8px;border-bottom:1px dashed var(--md-sys-color-outline-variant)}.kbd{font-family:monospace;background:var(--md-sys-color-surface-container-highest);padding:0 6px;border-radius:4px;color:var(--md-sys-color-on-surface-variant)}.panel-surface{background:var(--md-sys-color-surface-container-high);border:1px solid var(--md-sys-color-outline-variant);border-radius:10px;box-shadow:var(--md-sys-elevation-level1, none);margin-bottom:12px}.panel-stack{display:grid;gap:12px;margin:12px 0}.stack-panel{background:var(--md-sys-color-surface-container-high);border:1px solid var(--md-sys-color-outline-variant);border-radius:10px;box-shadow:var(--md-sys-elevation-level1, none)}.stack-panel .mat-expansion-panel-content{padding:0 16px 12px}.panel-header{display:flex;align-items:center;gap:8px}.preview-box{background:var(--md-sys-color-surface-container-low);border:1px solid var(--md-sys-color-outline-variant);border-radius:8px;padding:8px;color:var(--md-sys-color-on-surface)}.help-icon-button{--mdc-icon-button-state-layer-size: 28px;--mdc-icon-button-icon-size: 18px;width:28px;height:28px;padding:0;display:inline-flex;align-items:center;justify-content:center;margin-right:-4px}.help-icon-button mat-icon{font-size:18px;width:18px;height:18px}.mat-mdc-form-field-icon-suffix{align-self:center}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i3.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i2.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: i2.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i6.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i5$1.MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }, { kind: "component", type: i5$1.MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i8.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i7.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly", "disabledInteractive"], exportAs: ["matInput"] }, { kind: "component", type: i7.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i7.MatLabel, selector: "mat-label" }, { kind: "directive", type: i7.MatSuffix, selector: "[matSuffix], [matIconSuffix], [matTextSuffix]", inputs: ["matTextSuffix"] }, { kind: "ngmodule", type: MatChipsModule }, { kind: "ngmodule", type: MatListModule }, { kind: "ngmodule", type: MatDividerModule }, { kind: "ngmodule", type: MatSelectModule }, { kind: "component", type: i8$1.MatSelect, selector: "mat-select", inputs: ["aria-describedby", "panelClass", "disabled", "disableRipple", "tabIndex", "hideSingleSelectionIndicator", "placeholder", "required", "multiple", "disableOptionCentering", "compareWith", "value", "aria-label", "aria-labelledby", "errorStateMatcher", "typeaheadDebounceInterval", "sortComparator", "id", "panelWidth", "canSelectNullableOptions"], outputs: ["openedChange", "opened", "closed", "selectionChange", "valueChange"], exportAs: ["matSelect"] }, { kind: "component", type: i8$1.MatOption, selector: "mat-option", inputs: ["value", "id", "disabled"], outputs: ["onSelectionChange"], exportAs: ["matOption"] }, { kind: "ngmodule", type: MatCheckboxModule }, { kind: "component", type: i9.MatCheckbox, selector: "mat-checkbox", inputs: ["aria-label", "aria-labelledby", "aria-describedby", "aria-expanded", "aria-controls", "aria-owns", "id", "required", "labelPosition", "name", "value", "disableRipple", "tabIndex", "color", "disabledInteractive", "checked", "disabled", "indeterminate"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }, { kind: "ngmodule", type: MatExpansionModule }, { kind: "component", type: i5.MatExpansionPanel, selector: "mat-expansion-panel", inputs: ["hideToggle", "togglePosition"], outputs: ["afterExpand", "afterCollapse"], exportAs: ["matExpansionPanel"] }, { kind: "component", type: i5.MatExpansionPanelHeader, selector: "mat-expansion-panel-header", inputs: ["expandedHeight", "collapsedHeight", "tabIndex"] }, { kind: "directive", type: i5.MatExpansionPanelTitle, selector: "mat-panel-title" }, { kind: "ngmodule", type: MatMenuModule }, { kind: "component", type: i11.MatMenu, selector: "mat-menu", inputs: ["backdropClass", "aria-label", "aria-labelledby", "aria-describedby", "xPosition", "yPosition", "overlapTrigger", "hasBackdrop", "class", "classList"], outputs: ["closed", "close"], exportAs: ["matMenu"] }, { kind: "component", type: i11.MatMenuItem, selector: "[mat-menu-item]", inputs: ["role", "disabled", "disableRipple"], exportAs: ["matMenuItem"] }, { kind: "directive", type: i11.MatMenuTrigger, selector: "[mat-menu-trigger-for], [matMenuTriggerFor]", inputs: ["mat-menu-trigger-for", "matMenuTriggerFor", "matMenuTriggerData", "matMenuTriggerRestoreFocus"], outputs: ["menuOpened", "onMenuOpen", "menuClosed", "onMenuClose"], exportAs: ["matMenuTrigger"] }, { kind: "ngmodule", type: MatAutocompleteModule }, { kind: "component", type: i12.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: "directive", type: i12.MatAutocompleteTrigger, selector: "input[matAutocomplete], textarea[matAutocomplete]", inputs: ["matAutocomplete", "matAutocompletePosition", "matAutocompleteConnectedTo", "autocomplete", "matAutocompleteDisabled"], exportAs: ["matAutocompleteTrigger"] }, { kind: "ngmodule", type: ScrollingModule }, { kind: "directive", type: i13.CdkFixedSizeVirtualScroll, selector: "cdk-virtual-scroll-viewport[itemSize]", inputs: ["itemSize", "minBufferPx", "maxBufferPx"] }, { kind: "directive", type: i13.CdkVirtualForOf, selector: "[cdkVirtualFor][cdkVirtualForOf]", inputs: ["cdkVirtualForOf", "cdkVirtualForTrackBy", "cdkVirtualForTemplate", "cdkVirtualForTemplateCacheSize"] }, { kind: "component", type: i13.CdkVirtualScrollViewport, selector: "cdk-virtual-scroll-viewport", inputs: ["orientation", "appendOnly"], outputs: ["scrolledIndexChange"] }, { kind: "directive", type: PraxisIconDirective, selector: "mat-icon[praxisIcon]", inputs: ["praxisIcon"] }] });
|
|
6920
8391
|
}
|
|
6921
8392
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: CascadeManagerTabComponent, decorators: [{
|
|
6922
8393
|
type: Component,
|
|
@@ -7253,8 +8724,58 @@ const METADATA_EDITOR_AI_CAPABILITY_CATALOG = {
|
|
|
7253
8724
|
enums: {},
|
|
7254
8725
|
};
|
|
7255
8726
|
|
|
8727
|
+
/** Metadata for Praxis Metadata Editor component */
|
|
8728
|
+
const PRAXIS_METADATA_EDITOR_COMPONENT_METADATA = {
|
|
8729
|
+
id: 'praxis-metadata-editor',
|
|
8730
|
+
selector: 'praxis-field-metadata-editor',
|
|
8731
|
+
component: FieldMetadataEditorComponent,
|
|
8732
|
+
friendlyName: 'Praxis Metadata Editor',
|
|
8733
|
+
description: 'Editor for field metadata and schema helpers.',
|
|
8734
|
+
inputs: [
|
|
8735
|
+
{
|
|
8736
|
+
name: 'controlType',
|
|
8737
|
+
type: 'FieldControlType',
|
|
8738
|
+
label: 'Tipo de controle',
|
|
8739
|
+
description: 'Tipo de controle do campo alvo.',
|
|
8740
|
+
},
|
|
8741
|
+
{
|
|
8742
|
+
name: 'seed',
|
|
8743
|
+
type: 'Partial<FieldDefinition>',
|
|
8744
|
+
label: 'Seed',
|
|
8745
|
+
description: 'Valores iniciais do FieldDefinition para hidratar o editor.',
|
|
8746
|
+
},
|
|
8747
|
+
],
|
|
8748
|
+
outputs: [
|
|
8749
|
+
{
|
|
8750
|
+
name: 'applied',
|
|
8751
|
+
type: 'Partial<FieldDefinition>',
|
|
8752
|
+
label: 'Aplicado',
|
|
8753
|
+
description: 'Disparado quando o patch de metadata e aplicado.',
|
|
8754
|
+
},
|
|
8755
|
+
{
|
|
8756
|
+
name: 'cancel',
|
|
8757
|
+
type: 'void',
|
|
8758
|
+
label: 'Cancelar',
|
|
8759
|
+
description: 'Disparado quando o usuario cancela a edicao.',
|
|
8760
|
+
},
|
|
8761
|
+
],
|
|
8762
|
+
tags: ['widget', 'metadata', 'configurable'],
|
|
8763
|
+
lib: '@praxisui/metadata-editor',
|
|
8764
|
+
};
|
|
8765
|
+
/** Provider para auto-registrar metadados do componente Metadata Editor. */
|
|
8766
|
+
function providePraxisMetadataEditorMetadata() {
|
|
8767
|
+
return {
|
|
8768
|
+
provide: ENVIRONMENT_INITIALIZER,
|
|
8769
|
+
multi: true,
|
|
8770
|
+
useFactory: (registry) => () => {
|
|
8771
|
+
registry.register(PRAXIS_METADATA_EDITOR_COMPONENT_METADATA);
|
|
8772
|
+
},
|
|
8773
|
+
deps: [ComponentMetadataRegistry],
|
|
8774
|
+
};
|
|
8775
|
+
}
|
|
8776
|
+
|
|
7256
8777
|
/**
|
|
7257
8778
|
* Generated bundle index. Do not edit.
|
|
7258
8779
|
*/
|
|
7259
8780
|
|
|
7260
|
-
export { CascadeManagerTabComponent, CascadeRulesService, ConfigRegistryService, ContextValidatorRegistryService, DynamicEditorRendererComponent, DynamicFormFactoryService, EditorComponentRegistryService, FieldMetadataEditorComponent, METADATA_EDITOR_AI_CAPABILITIES, METADATA_EDITOR_AI_CAPABILITY_CATALOG, SchemaNormalizerService };
|
|
8781
|
+
export { CascadeManagerTabComponent, CascadeRulesService, ConfigRegistryService, ContextValidatorRegistryService, DynamicEditorRendererComponent, DynamicFormFactoryService, EditorComponentRegistryService, FieldMetadataEditorComponent, METADATA_EDITOR_AI_CAPABILITIES, METADATA_EDITOR_AI_CAPABILITY_CATALOG, PRAXIS_METADATA_EDITOR_COMPONENT_METADATA, SchemaNormalizerService, providePraxisMetadataEditorMetadata };
|