ngx-dsxlibrary 2.21.67 → 2.21.68
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.
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
2
|
import { input, forwardRef, Component, EventEmitter, effect, Output, viewChild, signal, Input, model, inject, computed, Injectable, isDevMode, InjectionToken, output, HostBinding, ChangeDetectorRef, untracked, Pipe, ViewEncapsulation, HostListener, Directive, NgZone, ElementRef, NgModule, Injector } from '@angular/core';
|
|
3
3
|
import * as i1 from '@angular/forms';
|
|
4
|
-
import { FormsModule, NG_VALUE_ACCESSOR, FormControl, NG_VALIDATORS, FormBuilder, Validators, ReactiveFormsModule, NgControl, FormGroup } from '@angular/forms';
|
|
4
|
+
import { FormsModule, NG_VALUE_ACCESSOR, AbstractControl, FormControl, NG_VALIDATORS, FormBuilder, Validators, ReactiveFormsModule, NgControl, FormGroup } from '@angular/forms';
|
|
5
5
|
import * as i2 from 'primeng/togglebutton';
|
|
6
6
|
import { ToggleButtonModule } from 'primeng/togglebutton';
|
|
7
7
|
import * as i1$1 from '@angular/common';
|
|
@@ -1079,7 +1079,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
|
|
|
1079
1079
|
args: [{ selector: 'icon-dsx', imports: [AsyncPipe], template: "<span class=\"dsx-icon\" [innerHTML]=\"svg$ | async\"></span>\r\n", styles: [":host{display:inline-flex;align-items:center;justify-content:center;vertical-align:middle;width:1em;height:1em;font-size:24px;line-height:1;flex-shrink:0}.dsx-icon{display:inline-flex;align-items:center;justify-content:center;width:100%;height:100%}:host ::ng-deep .dsx-icon svg{width:100%;height:100%;fill:currentColor;shape-rendering:geometricPrecision;stroke:currentColor;stroke-width:4px;stroke-linejoin:round;stroke-linecap:round;overflow:visible;transition:fill .2s ease,stroke .2s ease}\n"] }]
|
|
1080
1080
|
}], ctorParameters: () => [{ type: IconDsxService }], propDecorators: { name: [{ type: i0.Input, args: [{ isSignal: true, alias: "name", required: false }] }], style: [{ type: i0.Input, args: [{ isSignal: true, alias: "style", required: false }] }], debug: [{ type: i0.Input, args: [{ isSignal: true, alias: "debug", required: false }] }] } });
|
|
1081
1081
|
|
|
1082
|
-
// app-message-error.component.ts - Versión corregida
|
|
1083
1082
|
class AppMessageErrorComponent {
|
|
1084
1083
|
elementRef;
|
|
1085
1084
|
renderer;
|
|
@@ -1128,7 +1127,6 @@ class AppMessageErrorComponent {
|
|
|
1128
1127
|
this.renderer = renderer;
|
|
1129
1128
|
}
|
|
1130
1129
|
ngAfterViewInit() {
|
|
1131
|
-
// Intentar encontrar el floatLabel padre
|
|
1132
1130
|
this.floatLabelElement = this.elementRef.nativeElement.closest('.p-floatlabel');
|
|
1133
1131
|
if (this.floatLabelElement) {
|
|
1134
1132
|
this.previousInlineMarginBottom =
|
|
@@ -1142,7 +1140,6 @@ class AppMessageErrorComponent {
|
|
|
1142
1140
|
console.log('[ERROR-COMPONENT] No hay FloatLabel, modo estático');
|
|
1143
1141
|
}
|
|
1144
1142
|
}
|
|
1145
|
-
// Observador de visibilidad
|
|
1146
1143
|
if (typeof window !== 'undefined' && 'IntersectionObserver' in window) {
|
|
1147
1144
|
this.observer = new IntersectionObserver((entries) => {
|
|
1148
1145
|
entries.forEach((entry) => {
|
|
@@ -1191,7 +1188,6 @@ class AppMessageErrorComponent {
|
|
|
1191
1188
|
if (this.observer) {
|
|
1192
1189
|
this.observer.disconnect();
|
|
1193
1190
|
}
|
|
1194
|
-
// Restaurar margen solo si existe floatLabelElement
|
|
1195
1191
|
if (this.floatLabelElement) {
|
|
1196
1192
|
if (this.previousInlineMarginBottom) {
|
|
1197
1193
|
this.renderer.setStyle(this.floatLabelElement, 'margin-bottom', this.previousInlineMarginBottom);
|
|
@@ -1202,11 +1198,7 @@ class AppMessageErrorComponent {
|
|
|
1202
1198
|
}
|
|
1203
1199
|
}
|
|
1204
1200
|
syncFloatLabelSpacing() {
|
|
1205
|
-
|
|
1206
|
-
if (!this.floatLabelElement) {
|
|
1207
|
-
return;
|
|
1208
|
-
}
|
|
1209
|
-
if (!this.isElementAttachedAndVisible)
|
|
1201
|
+
if (!this.floatLabelElement || !this.isElementAttachedAndVisible)
|
|
1210
1202
|
return;
|
|
1211
1203
|
const isVisible = this.isControlErrorVisible();
|
|
1212
1204
|
const desiredSpace = this.getFloatLabelErrorSpace();
|
|
@@ -1228,11 +1220,9 @@ class AppMessageErrorComponent {
|
|
|
1228
1220
|
this.renderer.removeStyle(this.floatLabelElement, 'margin-bottom');
|
|
1229
1221
|
}
|
|
1230
1222
|
isControlErrorVisible() {
|
|
1231
|
-
// ✅ La condición base es la misma para ambos contextos
|
|
1232
1223
|
if (!this.control || !this.control.invalid) {
|
|
1233
1224
|
return false;
|
|
1234
1225
|
}
|
|
1235
|
-
// Solo mostrar si el usuario ha interactuado
|
|
1236
1226
|
return !!(this.control.touched || this.control.dirty);
|
|
1237
1227
|
}
|
|
1238
1228
|
getFloatLabelErrorSpace() {
|
|
@@ -1258,11 +1248,11 @@ class AppMessageErrorComponent {
|
|
|
1258
1248
|
return num % 1 === 0 ? String(num) : parseFloat(num.toFixed(2)).toString();
|
|
1259
1249
|
}
|
|
1260
1250
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: AppMessageErrorComponent, deps: [{ token: i0.ElementRef }, { token: i0.Renderer2 }], target: i0.ɵɵFactoryTarget.Component });
|
|
1261
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.17", type: AppMessageErrorComponent, isStandalone: true, selector: "app-message-error", inputs: { control: "control", form: "form", debugMode: "debugMode" }, ngImport: i0, template: "
|
|
1251
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.17", type: AppMessageErrorComponent, isStandalone: true, selector: "app-message-error", inputs: { control: "control", form: "form", debugMode: "debugMode" }, ngImport: i0, template: "<div class=\"dsx-error-slot\" [class.is-visible]=\"isControlErrorVisible()\">\r\n <div class=\"dsx-error-message\">\r\n <div class=\"dsx-error-message-content\">\r\n <icon-dsx name=\"warning\"></icon-dsx>\r\n\r\n @if (control?.errors?.[\"required\"]) {\r\n El campo <strong>es requerido.</strong>\r\n } @else if (control?.errors?.[\"invalidNIT\"]) {\r\n <strong>{{ control?.errors?.[\"invalidNIT\"]?.message }}</strong>\r\n } @else if (control?.errors?.[\"invalidCUI\"]) {\r\n <strong>{{ control?.errors?.[\"invalidCUI\"]?.message }}</strong>\r\n } @else if (control?.errors?.[\"invalidDateRange\"]) {\r\n <strong>{{ control?.errors?.[\"invalidDateRange\"]?.message }}</strong>\r\n } @else if (control?.errors?.[\"dateNotRange\"]) {\r\n <strong>{{ control?.errors?.[\"dateNotRange\"]?.message }}</strong>\r\n } @else if (control?.errors?.[\"invalidDate\"]) {\r\n <strong>{{ control?.errors?.[\"invalidDate\"]?.message }}</strong>\r\n } @else if (control?.errors?.[\"minimumAge\"]) {\r\n <strong>{{ control?.errors?.[\"minimumAge\"]?.message }}</strong>\r\n } @else if (control?.errors?.[\"minlength\"]) {\r\n Debe tener al menos\r\n <strong>{{ control?.errors?.[\"minlength\"]?.requiredLength }}</strong>\r\n caracteres.\r\n } @else if (control?.errors?.[\"maxlength\"]) {\r\n Debe tener como m\u00E1ximo\r\n <strong>{{ control?.errors?.[\"maxlength\"]?.requiredLength }}</strong>\r\n caracteres.\r\n } @else if (control?.errors?.[\"min\"]) {\r\n El valor m\u00EDnimo permitido es\r\n <strong>{{ formatNumber(control?.errors?.[\"min\"]?.min) }}</strong>\r\n } @else if (control?.errors?.[\"max\"]) {\r\n El valor m\u00E1ximo permitido es\r\n <strong>{{ formatNumber(control?.errors?.[\"max\"]?.max) }}</strong>\r\n } @else if (control?.errors?.[\"email\"]) {\r\n Debe ser una direcci\u00F3n de correo v\u00E1lida.\r\n } @else if (control?.errors?.[\"pattern\"]) {\r\n El campo no tiene el formato requerido.\r\n } @else if (control?.errors?.[\"alreadyValueExists\"]) {\r\n <strong>{{ control?.errors?.[\"alreadyValueExists\"]?.message }}</strong>\r\n } @else if (control?.errors?.[\"invalidTemplateVariables\"]) {\r\n <div class=\"dsx-template-error\">\r\n <strong>\r\n {{ control?.errors?.[\"invalidTemplateVariables\"]?.message }}\r\n </strong>\r\n @if (control?.errors?.[\"invalidTemplateVariables\"]?.details?.length) {\r\n <span class=\"dsx-template-error-detail\">\r\n {{ control?.errors?.[\"invalidTemplateVariables\"]?.details?.[0] }}\r\n </span>\r\n }\r\n </div>\r\n } @else if (control?.errors?.[\"invalidTemplateStructure\"]) {\r\n <div class=\"dsx-template-error\">\r\n <strong>\r\n {{ control?.errors?.[\"invalidTemplateStructure\"]?.message }}\r\n </strong>\r\n @if (control?.errors?.[\"invalidTemplateStructure\"]?.details?.length) {\r\n <span class=\"dsx-template-error-detail\">\r\n {{ control?.errors?.[\"invalidTemplateStructure\"]?.details?.[0] }}\r\n </span>\r\n }\r\n </div>\r\n } @else if (control?.errors?.[\"similitudDetectada\"]) {\r\n Ya existe un registro muy similar en el sistema:\r\n <strong\r\n >\"{{ control?.errors?.[\"similitudDetectada\"]?.sugerencia }}\"</strong\r\n >.\r\n } @else {\r\n Existe un error a\u00FAn no identificado.\r\n }\r\n </div>\r\n </div>\r\n</div>\r\n\r\n<!-- Mensaje para formulario en general -->\r\n@if (form?.invalid && form?.dirty) {\r\n <div class=\"mt-2 mb-2\">\r\n @if (this.form?.errors?.[\"atLeastOneRequired\"]) {\r\n <p-tag severity=\"danger\" [rounded]=\"true\">\r\n {{ form?.getError(\"atLeastOneRequired\")?.message }}\r\n </p-tag>\r\n }\r\n </div>\r\n}\r\n", styles: [".dsx-error-slot{display:block;max-height:0;overflow:hidden;opacity:0;transform:translateY(-4px) scale(.98);transition:max-height .3s cubic-bezier(.4,0,.2,1),opacity .25s cubic-bezier(.4,0,.2,1),transform .25s cubic-bezier(.4,0,.2,1),margin .25s cubic-bezier(.4,0,.2,1)}.dsx-error-slot.is-visible{max-height:60px;opacity:1;transform:translateY(0) scale(1)}.dsx-error-message{display:block;width:100%}.dsx-error-message-content{display:flex;align-items:center;gap:.4rem;width:100%;box-sizing:border-box;padding:.25rem .6rem;font-size:.82rem;background:var(--dsx-error-bg, #fff2f0)!important;color:var(--dsx-error-color, #b42318)!important;border-left:3px solid var(--dsx-error-color, #b42318)!important;border-radius:.3rem;box-shadow:0 1px 2px #0000000f;line-height:1.3;animation:errorSlideIn .25s cubic-bezier(.4,0,.2,1)}.dsx-error-icon{flex:0 0 auto;line-height:1;display:inline-flex;align-items:center;justify-content:center}.dsx-error-icon icon-dsx{transform:scale(.85);transition:transform .2s ease}.dsx-error-slot.is-visible .dsx-error-icon icon-dsx{transform:scale(1)}.dsx-error-message-content icon-dsx,.dsx-error-message-content icon-dsx svg,.dsx-error-message-content icon-dsx svg path{color:var(--dsx-error-color, #ff5a4e)!important;fill:var(--dsx-error-color, #e45036)!important}@keyframes errorSlideIn{0%{opacity:0;transform:translateY(-6px) scale(.97)}to{opacity:1;transform:translateY(0) scale(1)}}@keyframes errorPulse{0%{box-shadow:0 1px 2px #0000000f}50%{box-shadow:0 2px 8px #b4231826}to{box-shadow:0 1px 2px #0000000f}}.dsx-error-slot.is-visible .dsx-error-message-content{animation:errorSlideIn .25s cubic-bezier(.4,0,.2,1),errorPulse .4s ease .15s}:host-context(.p-floatlabel){position:absolute;top:100%;left:0;width:100%;z-index:10;pointer-events:none}:host-context(.p-floatlabel) .dsx-error-slot.is-visible{margin-top:.08rem}:host-context(.p-floatlabel) .dsx-error-message-content{padding:.2rem .6rem .2rem .4rem}:host-context(:not(.p-floatlabel)){display:block;width:100%}:host-context(:not(.p-floatlabel)) .dsx-error-slot.is-visible{margin-top:.15rem;margin-bottom:0}:host-context(:not(.p-floatlabel)) .dsx-error-message-content{padding:.2rem .6rem}@media(max-width:640px){.dsx-error-message-content{padding:.15rem .5rem;font-size:.75rem;gap:.3rem}.dsx-error-icon icon-dsx{transform:scale(.8)}.dsx-error-slot{transition:max-height .25s cubic-bezier(.4,0,.2,1),opacity .2s cubic-bezier(.4,0,.2,1),transform .2s cubic-bezier(.4,0,.2,1)}@keyframes errorSlideIn{0%{opacity:0;transform:translateY(-4px) scale(.97)}to{opacity:1;transform:translateY(0) scale(1)}}:host-context(.p-floatlabel) .dsx-error-slot.is-visible{margin-top:.05rem}:host-context(:not(.p-floatlabel)) .dsx-error-slot.is-visible{margin-top:.1rem}}@media(prefers-color-scheme:dark){.dsx-error-message-content{background:#2d1a1a;border-left-color:#ef4444;color:#fca5a5}.dsx-error-message-content icon-dsx,.dsx-error-message-content icon-dsx svg,.dsx-error-message-content icon-dsx svg path{color:#ef4444!important;fill:#ef4444!important}@keyframes errorPulse{0%{box-shadow:0 1px 2px #0000004d}50%{box-shadow:0 2px 8px #ef444433}to{box-shadow:0 1px 2px #0000004d}}}\n"], dependencies: [{ kind: "ngmodule", type: TagModule }, { kind: "component", type: i1$2.Tag, selector: "p-tag", inputs: ["styleClass", "severity", "value", "icon", "rounded"] }, { kind: "component", type: IconDsxComponent, selector: "icon-dsx", inputs: ["name", "style", "debug"] }] });
|
|
1262
1252
|
}
|
|
1263
1253
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: AppMessageErrorComponent, decorators: [{
|
|
1264
1254
|
type: Component,
|
|
1265
|
-
args: [{ selector: 'app-message-error', standalone: true, imports: [TagModule, IconDsxComponent], template: "
|
|
1255
|
+
args: [{ selector: 'app-message-error', standalone: true, imports: [TagModule, IconDsxComponent], template: "<div class=\"dsx-error-slot\" [class.is-visible]=\"isControlErrorVisible()\">\r\n <div class=\"dsx-error-message\">\r\n <div class=\"dsx-error-message-content\">\r\n <icon-dsx name=\"warning\"></icon-dsx>\r\n\r\n @if (control?.errors?.[\"required\"]) {\r\n El campo <strong>es requerido.</strong>\r\n } @else if (control?.errors?.[\"invalidNIT\"]) {\r\n <strong>{{ control?.errors?.[\"invalidNIT\"]?.message }}</strong>\r\n } @else if (control?.errors?.[\"invalidCUI\"]) {\r\n <strong>{{ control?.errors?.[\"invalidCUI\"]?.message }}</strong>\r\n } @else if (control?.errors?.[\"invalidDateRange\"]) {\r\n <strong>{{ control?.errors?.[\"invalidDateRange\"]?.message }}</strong>\r\n } @else if (control?.errors?.[\"dateNotRange\"]) {\r\n <strong>{{ control?.errors?.[\"dateNotRange\"]?.message }}</strong>\r\n } @else if (control?.errors?.[\"invalidDate\"]) {\r\n <strong>{{ control?.errors?.[\"invalidDate\"]?.message }}</strong>\r\n } @else if (control?.errors?.[\"minimumAge\"]) {\r\n <strong>{{ control?.errors?.[\"minimumAge\"]?.message }}</strong>\r\n } @else if (control?.errors?.[\"minlength\"]) {\r\n Debe tener al menos\r\n <strong>{{ control?.errors?.[\"minlength\"]?.requiredLength }}</strong>\r\n caracteres.\r\n } @else if (control?.errors?.[\"maxlength\"]) {\r\n Debe tener como m\u00E1ximo\r\n <strong>{{ control?.errors?.[\"maxlength\"]?.requiredLength }}</strong>\r\n caracteres.\r\n } @else if (control?.errors?.[\"min\"]) {\r\n El valor m\u00EDnimo permitido es\r\n <strong>{{ formatNumber(control?.errors?.[\"min\"]?.min) }}</strong>\r\n } @else if (control?.errors?.[\"max\"]) {\r\n El valor m\u00E1ximo permitido es\r\n <strong>{{ formatNumber(control?.errors?.[\"max\"]?.max) }}</strong>\r\n } @else if (control?.errors?.[\"email\"]) {\r\n Debe ser una direcci\u00F3n de correo v\u00E1lida.\r\n } @else if (control?.errors?.[\"pattern\"]) {\r\n El campo no tiene el formato requerido.\r\n } @else if (control?.errors?.[\"alreadyValueExists\"]) {\r\n <strong>{{ control?.errors?.[\"alreadyValueExists\"]?.message }}</strong>\r\n } @else if (control?.errors?.[\"invalidTemplateVariables\"]) {\r\n <div class=\"dsx-template-error\">\r\n <strong>\r\n {{ control?.errors?.[\"invalidTemplateVariables\"]?.message }}\r\n </strong>\r\n @if (control?.errors?.[\"invalidTemplateVariables\"]?.details?.length) {\r\n <span class=\"dsx-template-error-detail\">\r\n {{ control?.errors?.[\"invalidTemplateVariables\"]?.details?.[0] }}\r\n </span>\r\n }\r\n </div>\r\n } @else if (control?.errors?.[\"invalidTemplateStructure\"]) {\r\n <div class=\"dsx-template-error\">\r\n <strong>\r\n {{ control?.errors?.[\"invalidTemplateStructure\"]?.message }}\r\n </strong>\r\n @if (control?.errors?.[\"invalidTemplateStructure\"]?.details?.length) {\r\n <span class=\"dsx-template-error-detail\">\r\n {{ control?.errors?.[\"invalidTemplateStructure\"]?.details?.[0] }}\r\n </span>\r\n }\r\n </div>\r\n } @else if (control?.errors?.[\"similitudDetectada\"]) {\r\n Ya existe un registro muy similar en el sistema:\r\n <strong\r\n >\"{{ control?.errors?.[\"similitudDetectada\"]?.sugerencia }}\"</strong\r\n >.\r\n } @else {\r\n Existe un error a\u00FAn no identificado.\r\n }\r\n </div>\r\n </div>\r\n</div>\r\n\r\n<!-- Mensaje para formulario en general -->\r\n@if (form?.invalid && form?.dirty) {\r\n <div class=\"mt-2 mb-2\">\r\n @if (this.form?.errors?.[\"atLeastOneRequired\"]) {\r\n <p-tag severity=\"danger\" [rounded]=\"true\">\r\n {{ form?.getError(\"atLeastOneRequired\")?.message }}\r\n </p-tag>\r\n }\r\n </div>\r\n}\r\n", styles: [".dsx-error-slot{display:block;max-height:0;overflow:hidden;opacity:0;transform:translateY(-4px) scale(.98);transition:max-height .3s cubic-bezier(.4,0,.2,1),opacity .25s cubic-bezier(.4,0,.2,1),transform .25s cubic-bezier(.4,0,.2,1),margin .25s cubic-bezier(.4,0,.2,1)}.dsx-error-slot.is-visible{max-height:60px;opacity:1;transform:translateY(0) scale(1)}.dsx-error-message{display:block;width:100%}.dsx-error-message-content{display:flex;align-items:center;gap:.4rem;width:100%;box-sizing:border-box;padding:.25rem .6rem;font-size:.82rem;background:var(--dsx-error-bg, #fff2f0)!important;color:var(--dsx-error-color, #b42318)!important;border-left:3px solid var(--dsx-error-color, #b42318)!important;border-radius:.3rem;box-shadow:0 1px 2px #0000000f;line-height:1.3;animation:errorSlideIn .25s cubic-bezier(.4,0,.2,1)}.dsx-error-icon{flex:0 0 auto;line-height:1;display:inline-flex;align-items:center;justify-content:center}.dsx-error-icon icon-dsx{transform:scale(.85);transition:transform .2s ease}.dsx-error-slot.is-visible .dsx-error-icon icon-dsx{transform:scale(1)}.dsx-error-message-content icon-dsx,.dsx-error-message-content icon-dsx svg,.dsx-error-message-content icon-dsx svg path{color:var(--dsx-error-color, #ff5a4e)!important;fill:var(--dsx-error-color, #e45036)!important}@keyframes errorSlideIn{0%{opacity:0;transform:translateY(-6px) scale(.97)}to{opacity:1;transform:translateY(0) scale(1)}}@keyframes errorPulse{0%{box-shadow:0 1px 2px #0000000f}50%{box-shadow:0 2px 8px #b4231826}to{box-shadow:0 1px 2px #0000000f}}.dsx-error-slot.is-visible .dsx-error-message-content{animation:errorSlideIn .25s cubic-bezier(.4,0,.2,1),errorPulse .4s ease .15s}:host-context(.p-floatlabel){position:absolute;top:100%;left:0;width:100%;z-index:10;pointer-events:none}:host-context(.p-floatlabel) .dsx-error-slot.is-visible{margin-top:.08rem}:host-context(.p-floatlabel) .dsx-error-message-content{padding:.2rem .6rem .2rem .4rem}:host-context(:not(.p-floatlabel)){display:block;width:100%}:host-context(:not(.p-floatlabel)) .dsx-error-slot.is-visible{margin-top:.15rem;margin-bottom:0}:host-context(:not(.p-floatlabel)) .dsx-error-message-content{padding:.2rem .6rem}@media(max-width:640px){.dsx-error-message-content{padding:.15rem .5rem;font-size:.75rem;gap:.3rem}.dsx-error-icon icon-dsx{transform:scale(.8)}.dsx-error-slot{transition:max-height .25s cubic-bezier(.4,0,.2,1),opacity .2s cubic-bezier(.4,0,.2,1),transform .2s cubic-bezier(.4,0,.2,1)}@keyframes errorSlideIn{0%{opacity:0;transform:translateY(-4px) scale(.97)}to{opacity:1;transform:translateY(0) scale(1)}}:host-context(.p-floatlabel) .dsx-error-slot.is-visible{margin-top:.05rem}:host-context(:not(.p-floatlabel)) .dsx-error-slot.is-visible{margin-top:.1rem}}@media(prefers-color-scheme:dark){.dsx-error-message-content{background:#2d1a1a;border-left-color:#ef4444;color:#fca5a5}.dsx-error-message-content icon-dsx,.dsx-error-message-content icon-dsx svg,.dsx-error-message-content icon-dsx svg path{color:#ef4444!important;fill:#ef4444!important}@keyframes errorPulse{0%{box-shadow:0 1px 2px #0000004d}50%{box-shadow:0 2px 8px #ef444433}to{box-shadow:0 1px 2px #0000004d}}}\n"] }]
|
|
1266
1256
|
}], ctorParameters: () => [{ type: i0.ElementRef }, { type: i0.Renderer2 }], propDecorators: { control: [{
|
|
1267
1257
|
type: Input
|
|
1268
1258
|
}], form: [{
|
|
@@ -2671,11 +2661,18 @@ class UtilityAddService {
|
|
|
2671
2661
|
const resolvedOptions = Array.isArray(groupValidatorsOrOptions)
|
|
2672
2662
|
? options
|
|
2673
2663
|
: (groupValidatorsOrOptions ?? options);
|
|
2664
|
+
// IMPORTANTE: Cambiamos el tipado a AbstractControl para permitir meter FormArrays o FormGroups
|
|
2674
2665
|
const formGroup = {};
|
|
2675
|
-
// Crear controles de formulario individuales
|
|
2666
|
+
// Crear controles de formulario individuales o inyectar estructuras abstractas
|
|
2676
2667
|
for (const key in config) {
|
|
2677
2668
|
if (Object.prototype.hasOwnProperty.call(config, key)) {
|
|
2678
2669
|
const fieldConfig = config[key];
|
|
2670
|
+
// ¡EL CAMBIO MÁGICO!: Si ya pasaste un FormArray o FormGroup pre-construido, lo asignamos directo
|
|
2671
|
+
if (fieldConfig instanceof AbstractControl) {
|
|
2672
|
+
formGroup[key] = fieldConfig;
|
|
2673
|
+
continue; // Saltamos a la siguiente iteración
|
|
2674
|
+
}
|
|
2675
|
+
// Tu lógica intacta original para los FormControl estándar
|
|
2679
2676
|
const { value, validators = [], asyncValidators = [], } = fieldConfig;
|
|
2680
2677
|
const hasAssignedDisabled = Object.prototype.hasOwnProperty.call(fieldConfig, 'disabled');
|
|
2681
2678
|
const disabled = hasAssignedDisabled
|
|
@@ -4771,13 +4768,9 @@ class DsxAutocomplete {
|
|
|
4771
4768
|
// Inputs usando Señales
|
|
4772
4769
|
datasource = input.required(...(ngDevMode ? [{ debugName: "datasource" }] : /* istanbul ignore next */ []));
|
|
4773
4770
|
optionLabel = input.required(...(ngDevMode ? [{ debugName: "optionLabel" }] : /* istanbul ignore next */ []));
|
|
4774
|
-
// Label del input (ej: 'Requisitos')
|
|
4775
4771
|
label = input('Seleccionar', ...(ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []));
|
|
4776
|
-
//Delay por defecto
|
|
4777
4772
|
delay = input(100, ...(ngDevMode ? [{ debugName: "delay" }] : /* istanbul ignore next */ []));
|
|
4778
|
-
// OBLIGATORIO para la creación automática: nombre de la propiedad ID (ej: 'requisitoId')
|
|
4779
4773
|
idKey = input.required(...(ngDevMode ? [{ debugName: "idKey" }] : /* istanbul ignore next */ []));
|
|
4780
|
-
// Opcional para PrimeNG (por defecto toma el valor de idKey para identificar duplicados)
|
|
4781
4774
|
dataKey = input('', ...(ngDevMode ? [{ debugName: "dataKey" }] : /* istanbul ignore next */ []));
|
|
4782
4775
|
permitirCrear = input(false, ...(ngDevMode ? [{ debugName: "permitirCrear" }] : /* istanbul ignore next */ []));
|
|
4783
4776
|
debug = input(false, ...(ngDevMode ? [{ debugName: "debug" }] : /* istanbul ignore next */ []));
|
|
@@ -4788,20 +4781,30 @@ class DsxAutocomplete {
|
|
|
4788
4781
|
onChange = () => { };
|
|
4789
4782
|
onTouched = () => { };
|
|
4790
4783
|
disabled = false;
|
|
4784
|
+
lastLogTime = 0;
|
|
4785
|
+
timeoutLimpieza = null;
|
|
4786
|
+
logDebug(message, data) {
|
|
4787
|
+
if (!this.debug())
|
|
4788
|
+
return;
|
|
4789
|
+
const now = Date.now();
|
|
4790
|
+
if (now - this.lastLogTime < 50)
|
|
4791
|
+
return;
|
|
4792
|
+
this.lastLogTime = now;
|
|
4793
|
+
console.log(`[DsxAutocomplete] ${message}`, data || '');
|
|
4794
|
+
}
|
|
4791
4795
|
searchRequisitos(event) {
|
|
4792
4796
|
const inicio = performance.now();
|
|
4793
4797
|
const label = this.optionLabel();
|
|
4794
|
-
// FLUJO A:
|
|
4798
|
+
// FLUJO A: Dropdown (sin texto)
|
|
4795
4799
|
if (!event.query || event.query.trim() === '') {
|
|
4796
|
-
// Cargamos TODO el universo de datos para que el usuario pueda navegar libremente
|
|
4797
4800
|
const todoElUniverso = this.datasource();
|
|
4798
4801
|
this.dataFiltrada.set(todoElUniverso);
|
|
4799
|
-
|
|
4800
|
-
|
|
4801
|
-
}
|
|
4802
|
+
this.logDebug('Modo dropdown activo', {
|
|
4803
|
+
registros: todoElUniverso.length,
|
|
4804
|
+
});
|
|
4802
4805
|
return;
|
|
4803
4806
|
}
|
|
4804
|
-
// FLUJO B:
|
|
4807
|
+
// FLUJO B: Búsqueda
|
|
4805
4808
|
const palabrasBuscadas = event.query
|
|
4806
4809
|
.toLowerCase()
|
|
4807
4810
|
.trim()
|
|
@@ -4812,25 +4815,26 @@ class DsxAutocomplete {
|
|
|
4812
4815
|
const textoRegistro = String(item[label] || '').toLowerCase();
|
|
4813
4816
|
return palabrasBuscadas.every((palabra) => textoRegistro.includes(palabra));
|
|
4814
4817
|
})
|
|
4815
|
-
.slice(0, 10);
|
|
4818
|
+
.slice(0, 10);
|
|
4816
4819
|
this.dataFiltrada.set(filtrados);
|
|
4817
|
-
|
|
4818
|
-
console.log(`[DsxAutocomplete] Búsqueda inteligente para "${event.query}" tardó ${(performance.now() - inicio).toFixed(2)}ms. Encontrados:`, filtrados.length);
|
|
4819
|
-
}
|
|
4820
|
+
this.logDebug(`Búsqueda "${event.query}" (${(performance.now() - inicio).toFixed(2)}ms)`, { encontrados: filtrados.length });
|
|
4820
4821
|
}
|
|
4821
4822
|
evaluarYAgregar(event) {
|
|
4822
4823
|
const valorInput = event.target.value?.trim();
|
|
4823
|
-
if (!valorInput)
|
|
4824
|
+
if (!valorInput) {
|
|
4825
|
+
this.dataFiltrada.set([]);
|
|
4824
4826
|
return;
|
|
4827
|
+
}
|
|
4825
4828
|
const sugerencias = this.dataFiltrada();
|
|
4826
4829
|
const actuales = this.value || [];
|
|
4827
|
-
const campoId = this.idKey();
|
|
4830
|
+
const campoId = this.idKey();
|
|
4828
4831
|
if (sugerencias.length > 0) {
|
|
4829
4832
|
const primeraMatch = sugerencias[0];
|
|
4830
|
-
// Comparamos identidades usando el campoId dinámico
|
|
4831
4833
|
const yaExiste = actuales.some((item) => item[campoId] === primeraMatch[campoId]);
|
|
4832
|
-
if (!yaExiste)
|
|
4834
|
+
if (!yaExiste) {
|
|
4833
4835
|
this.actualizarFormulario([...actuales, primeraMatch]);
|
|
4836
|
+
this.logDebug('✅ Elemento agregado');
|
|
4837
|
+
}
|
|
4834
4838
|
}
|
|
4835
4839
|
else if (this.permitirCrear()) {
|
|
4836
4840
|
let nuevo;
|
|
@@ -4838,7 +4842,6 @@ class DsxAutocomplete {
|
|
|
4838
4842
|
nuevo = this.factoryNuevoRegistro()(valorInput);
|
|
4839
4843
|
}
|
|
4840
4844
|
else {
|
|
4841
|
-
// Al estructurar el objeto usando [campoId], garantizamos que viaje con el nombre correcto de tu entidad
|
|
4842
4845
|
nuevo = {
|
|
4843
4846
|
[campoId]: 0,
|
|
4844
4847
|
[this.optionLabel()]: valorInput.toUpperCase(),
|
|
@@ -4846,19 +4849,47 @@ class DsxAutocomplete {
|
|
|
4846
4849
|
};
|
|
4847
4850
|
}
|
|
4848
4851
|
this.actualizarFormulario([...actuales, nuevo]);
|
|
4852
|
+
this.logDebug('🆕 Nuevo elemento creado', valorInput);
|
|
4849
4853
|
}
|
|
4850
4854
|
event.target.value = '';
|
|
4851
4855
|
this.dataFiltrada.set([]);
|
|
4852
4856
|
}
|
|
4857
|
+
onHide() {
|
|
4858
|
+
this.logDebug('Dropdown ocultado - Limpiando estado');
|
|
4859
|
+
// Limpiar timeout anterior si existe
|
|
4860
|
+
if (this.timeoutLimpieza) {
|
|
4861
|
+
clearTimeout(this.timeoutLimpieza);
|
|
4862
|
+
this.timeoutLimpieza = null;
|
|
4863
|
+
}
|
|
4864
|
+
// Limpiar después de un pequeño delay
|
|
4865
|
+
this.timeoutLimpieza = setTimeout(() => {
|
|
4866
|
+
this.dataFiltrada.set([]);
|
|
4867
|
+
this.timeoutLimpieza = null;
|
|
4868
|
+
}, 100);
|
|
4869
|
+
}
|
|
4870
|
+
onShow() {
|
|
4871
|
+
this.logDebug('Dropdown mostrado');
|
|
4872
|
+
// Limpiar timeout pendiente
|
|
4873
|
+
if (this.timeoutLimpieza) {
|
|
4874
|
+
clearTimeout(this.timeoutLimpieza);
|
|
4875
|
+
this.timeoutLimpieza = null;
|
|
4876
|
+
}
|
|
4877
|
+
}
|
|
4853
4878
|
actualizarFormulario(nuevaLista) {
|
|
4854
4879
|
this.value = nuevaLista;
|
|
4855
4880
|
this.onChange(this.value);
|
|
4856
|
-
|
|
4857
|
-
|
|
4881
|
+
this.logDebug('Formulario actualizado', {
|
|
4882
|
+
total: nuevaLista.length,
|
|
4883
|
+
});
|
|
4858
4884
|
}
|
|
4859
4885
|
// --- ControlValueAccessor ---
|
|
4860
4886
|
writeValue(value) {
|
|
4861
4887
|
this.value = value || [];
|
|
4888
|
+
this.dataFiltrada.set([]);
|
|
4889
|
+
if (this.timeoutLimpieza) {
|
|
4890
|
+
clearTimeout(this.timeoutLimpieza);
|
|
4891
|
+
this.timeoutLimpieza = null;
|
|
4892
|
+
}
|
|
4862
4893
|
}
|
|
4863
4894
|
registerOnChange(fn) {
|
|
4864
4895
|
this.onChange = fn;
|
|
@@ -4876,7 +4907,7 @@ class DsxAutocomplete {
|
|
|
4876
4907
|
useExisting: forwardRef(() => DsxAutocomplete),
|
|
4877
4908
|
multi: true,
|
|
4878
4909
|
},
|
|
4879
|
-
], ngImport: i0, template: "<p-floatlabel variant=\"on\">\r\n <p-autoComplete\r\n fluid\r\n multiple\r\n [dropdown]=\"true\"\r\n [suggestions]=\"dataFiltrada()\"\r\n (completeMethod)=\"searchRequisitos($event)\"\r\n [(ngModel)]=\"value\"\r\n (ngModelChange)=\"onChange(value)\"\r\n (onBlur)=\"onTouched()\"\r\n [disabled]=\"disabled\"\r\n [optionLabel]=\"optionLabel()\"\r\n [dataKey]=\"dataKey() || idKey()\"\r\n (keyup.enter)=\"evaluarYAgregar($event)\"\r\n [delay]=\"delay()\"\r\n >\r\n </p-autoComplete>\r\n <label>{{ label() }}</label>\r\n</p-floatlabel>\r\n", styles: [""], dependencies: [{ kind: "component", type: AutoComplete, selector: "p-autoComplete, p-autocomplete, p-auto-complete", inputs: ["minLength", "minQueryLength", "delay", "panelStyle", "styleClass", "panelStyleClass", "inputStyle", "inputId", "inputStyleClass", "placeholder", "readonly", "scrollHeight", "lazy", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "autoHighlight", "forceSelection", "type", "autoZIndex", "baseZIndex", "ariaLabel", "dropdownAriaLabel", "ariaLabelledBy", "dropdownIcon", "unique", "group", "completeOnFocus", "showClear", "dropdown", "showEmptyMessage", "dropdownMode", "multiple", "addOnTab", "tabindex", "dataKey", "emptyMessage", "showTransitionOptions", "hideTransitionOptions", "autofocus", "autocomplete", "optionGroupChildren", "optionGroupLabel", "overlayOptions", "suggestions", "optionLabel", "optionValue", "id", "searchMessage", "emptySelectionMessage", "selectionMessage", "autoOptionFocus", "selectOnFocus", "searchLocale", "optionDisabled", "focusOnHover", "typeahead", "addOnBlur", "separator", "appendTo", "motionOptions"], outputs: ["completeMethod", "onSelect", "onUnselect", "onAdd", "onFocus", "onBlur", "onDropdownClick", "onClear", "onInputKeydown", "onKeyUp", "onShow", "onHide", "onLazyLoad"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: FloatLabel, selector: "p-floatlabel, p-floatLabel, p-float-label", inputs: ["variant"] }] });
|
|
4910
|
+
], ngImport: i0, template: "<p-floatlabel variant=\"on\">\r\n <p-autoComplete\r\n fluid\r\n multiple\r\n [dropdown]=\"true\"\r\n [suggestions]=\"dataFiltrada()\"\r\n (completeMethod)=\"searchRequisitos($event)\"\r\n [(ngModel)]=\"value\"\r\n (ngModelChange)=\"onChange(value)\"\r\n (onBlur)=\"onTouched()\"\r\n (onShow)=\"onShow()\"\r\n (onHide)=\"onHide()\"\r\n [disabled]=\"disabled\"\r\n [optionLabel]=\"optionLabel()\"\r\n [dataKey]=\"dataKey() || idKey()\"\r\n (keyup.enter)=\"evaluarYAgregar($event)\"\r\n [delay]=\"delay()\"\r\n placeholder=\"Ingresa un texto....\"\r\n >\r\n </p-autoComplete>\r\n <label>{{ label() }}</label>\r\n</p-floatlabel>\r\n", styles: [""], dependencies: [{ kind: "component", type: AutoComplete, selector: "p-autoComplete, p-autocomplete, p-auto-complete", inputs: ["minLength", "minQueryLength", "delay", "panelStyle", "styleClass", "panelStyleClass", "inputStyle", "inputId", "inputStyleClass", "placeholder", "readonly", "scrollHeight", "lazy", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "autoHighlight", "forceSelection", "type", "autoZIndex", "baseZIndex", "ariaLabel", "dropdownAriaLabel", "ariaLabelledBy", "dropdownIcon", "unique", "group", "completeOnFocus", "showClear", "dropdown", "showEmptyMessage", "dropdownMode", "multiple", "addOnTab", "tabindex", "dataKey", "emptyMessage", "showTransitionOptions", "hideTransitionOptions", "autofocus", "autocomplete", "optionGroupChildren", "optionGroupLabel", "overlayOptions", "suggestions", "optionLabel", "optionValue", "id", "searchMessage", "emptySelectionMessage", "selectionMessage", "autoOptionFocus", "selectOnFocus", "searchLocale", "optionDisabled", "focusOnHover", "typeahead", "addOnBlur", "separator", "appendTo", "motionOptions"], outputs: ["completeMethod", "onSelect", "onUnselect", "onAdd", "onFocus", "onBlur", "onDropdownClick", "onClear", "onInputKeydown", "onKeyUp", "onShow", "onHide", "onLazyLoad"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: FloatLabel, selector: "p-floatlabel, p-floatLabel, p-float-label", inputs: ["variant"] }] });
|
|
4880
4911
|
}
|
|
4881
4912
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: DsxAutocomplete, decorators: [{
|
|
4882
4913
|
type: Component,
|
|
@@ -4886,13 +4917,14 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
|
|
|
4886
4917
|
useExisting: forwardRef(() => DsxAutocomplete),
|
|
4887
4918
|
multi: true,
|
|
4888
4919
|
},
|
|
4889
|
-
], template: "<p-floatlabel variant=\"on\">\r\n <p-autoComplete\r\n fluid\r\n multiple\r\n [dropdown]=\"true\"\r\n [suggestions]=\"dataFiltrada()\"\r\n (completeMethod)=\"searchRequisitos($event)\"\r\n [(ngModel)]=\"value\"\r\n (ngModelChange)=\"onChange(value)\"\r\n (onBlur)=\"onTouched()\"\r\n [disabled]=\"disabled\"\r\n [optionLabel]=\"optionLabel()\"\r\n [dataKey]=\"dataKey() || idKey()\"\r\n (keyup.enter)=\"evaluarYAgregar($event)\"\r\n [delay]=\"delay()\"\r\n >\r\n </p-autoComplete>\r\n <label>{{ label() }}</label>\r\n</p-floatlabel>\r\n" }]
|
|
4920
|
+
], template: "<p-floatlabel variant=\"on\">\r\n <p-autoComplete\r\n fluid\r\n multiple\r\n [dropdown]=\"true\"\r\n [suggestions]=\"dataFiltrada()\"\r\n (completeMethod)=\"searchRequisitos($event)\"\r\n [(ngModel)]=\"value\"\r\n (ngModelChange)=\"onChange(value)\"\r\n (onBlur)=\"onTouched()\"\r\n (onShow)=\"onShow()\"\r\n (onHide)=\"onHide()\"\r\n [disabled]=\"disabled\"\r\n [optionLabel]=\"optionLabel()\"\r\n [dataKey]=\"dataKey() || idKey()\"\r\n (keyup.enter)=\"evaluarYAgregar($event)\"\r\n [delay]=\"delay()\"\r\n placeholder=\"Ingresa un texto....\"\r\n >\r\n </p-autoComplete>\r\n <label>{{ label() }}</label>\r\n</p-floatlabel>\r\n" }]
|
|
4890
4921
|
}], propDecorators: { datasource: [{ type: i0.Input, args: [{ isSignal: true, alias: "datasource", required: true }] }], optionLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "optionLabel", required: true }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], delay: [{ type: i0.Input, args: [{ isSignal: true, alias: "delay", required: false }] }], idKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "idKey", required: true }] }], dataKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "dataKey", required: false }] }], permitirCrear: [{ type: i0.Input, args: [{ isSignal: true, alias: "permitirCrear", required: false }] }], debug: [{ type: i0.Input, args: [{ isSignal: true, alias: "debug", required: false }] }], factoryNuevoRegistro: [{ type: i0.Input, args: [{ isSignal: true, alias: "factoryNuevoRegistro", required: false }] }] } });
|
|
4891
4922
|
|
|
4892
4923
|
class FileComponent {
|
|
4893
4924
|
// Inputs
|
|
4894
4925
|
existingFile = input(null, ...(ngDevMode ? [{ debugName: "existingFile" }] : /* istanbul ignore next */ []));
|
|
4895
4926
|
existingFileName = input(null, ...(ngDevMode ? [{ debugName: "existingFileName" }] : /* istanbul ignore next */ []));
|
|
4927
|
+
overrideFileName = input(null, ...(ngDevMode ? [{ debugName: "overrideFileName" }] : /* istanbul ignore next */ []));
|
|
4896
4928
|
debug = input(false, ...(ngDevMode ? [{ debugName: "debug" }] : /* istanbul ignore next */ []));
|
|
4897
4929
|
required = input(true, ...(ngDevMode ? [{ debugName: "required" }] : /* istanbul ignore next */ []));
|
|
4898
4930
|
accept = input('.xls,.xlsx', ...(ngDevMode ? [{ debugName: "accept" }] : /* istanbul ignore next */ []));
|
|
@@ -5101,7 +5133,7 @@ class FileComponent {
|
|
|
5101
5133
|
console.log(`[FileComponent] ${method}`, data || '');
|
|
5102
5134
|
}
|
|
5103
5135
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: FileComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
5104
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.17", type: FileComponent, isStandalone: true, selector: "dsx-file-upload", inputs: { existingFile: { classPropertyName: "existingFile", publicName: "existingFile", isSignal: true, isRequired: false, transformFunction: null }, existingFileName: { classPropertyName: "existingFileName", publicName: "existingFileName", isSignal: true, isRequired: false, transformFunction: null }, debug: { classPropertyName: "debug", publicName: "debug", isSignal: true, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, accept: { classPropertyName: "accept", publicName: "accept", isSignal: true, isRequired: false, transformFunction: null }, pTooltipOverride: { classPropertyName: "pTooltipOverride", publicName: "pTooltipOverride", isSignal: true, isRequired: false, transformFunction: null }, tooltipPositionOverride: { classPropertyName: "tooltipPositionOverride", publicName: "tooltipPositionOverride", isSignal: true, isRequired: false, transformFunction: null }, maxFileSize: { classPropertyName: "maxFileSize", publicName: "maxFileSize", isSignal: true, isRequired: false, transformFunction: null }, invalidSummary: { classPropertyName: "invalidSummary", publicName: "invalidSummary", isSignal: true, isRequired: false, transformFunction: null }, invalidDetail: { classPropertyName: "invalidDetail", publicName: "invalidDetail", isSignal: true, isRequired: false, transformFunction: null }, invalidSizeSummary: { classPropertyName: "invalidSizeSummary", publicName: "invalidSizeSummary", isSignal: true, isRequired: false, transformFunction: null }, invalidSizeDetail: { classPropertyName: "invalidSizeDetail", publicName: "invalidSizeDetail", isSignal: true, isRequired: false, transformFunction: null } }, providers: [
|
|
5136
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.17", type: FileComponent, isStandalone: true, selector: "dsx-file-upload", inputs: { existingFile: { classPropertyName: "existingFile", publicName: "existingFile", isSignal: true, isRequired: false, transformFunction: null }, existingFileName: { classPropertyName: "existingFileName", publicName: "existingFileName", isSignal: true, isRequired: false, transformFunction: null }, overrideFileName: { classPropertyName: "overrideFileName", publicName: "overrideFileName", isSignal: true, isRequired: false, transformFunction: null }, debug: { classPropertyName: "debug", publicName: "debug", isSignal: true, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, accept: { classPropertyName: "accept", publicName: "accept", isSignal: true, isRequired: false, transformFunction: null }, pTooltipOverride: { classPropertyName: "pTooltipOverride", publicName: "pTooltipOverride", isSignal: true, isRequired: false, transformFunction: null }, tooltipPositionOverride: { classPropertyName: "tooltipPositionOverride", publicName: "tooltipPositionOverride", isSignal: true, isRequired: false, transformFunction: null }, maxFileSize: { classPropertyName: "maxFileSize", publicName: "maxFileSize", isSignal: true, isRequired: false, transformFunction: null }, invalidSummary: { classPropertyName: "invalidSummary", publicName: "invalidSummary", isSignal: true, isRequired: false, transformFunction: null }, invalidDetail: { classPropertyName: "invalidDetail", publicName: "invalidDetail", isSignal: true, isRequired: false, transformFunction: null }, invalidSizeSummary: { classPropertyName: "invalidSizeSummary", publicName: "invalidSizeSummary", isSignal: true, isRequired: false, transformFunction: null }, invalidSizeDetail: { classPropertyName: "invalidSizeDetail", publicName: "invalidSizeDetail", isSignal: true, isRequired: false, transformFunction: null } }, providers: [
|
|
5105
5137
|
{
|
|
5106
5138
|
provide: NG_VALUE_ACCESSOR,
|
|
5107
5139
|
useExisting: forwardRef(() => FileComponent),
|
|
@@ -5112,7 +5144,7 @@ class FileComponent {
|
|
|
5112
5144
|
useExisting: forwardRef(() => FileComponent),
|
|
5113
5145
|
multi: true,
|
|
5114
5146
|
},
|
|
5115
|
-
], viewQueries: [{ propertyName: "fileUpload", first: true, predicate: ["fileUpload"], descendants: true, isSignal: true }], ngImport: i0, template: "@if (showExistingFile() && !existingFile()) {\r\n <div class=\"flex items-center gap-2\">\r\n <span class=\"file-name\"
|
|
5147
|
+
], viewQueries: [{ propertyName: "fileUpload", first: true, predicate: ["fileUpload"], descendants: true, isSignal: true }], ngImport: i0, template: "@if (showExistingFile() && !existingFile()) {\r\n <div class=\"flex items-center gap-2\">\r\n <span class=\"file-name\">\r\n \uD83D\uDCC4 {{ overrideFileName() ?? existingFileName() }}\r\n </span>\r\n\r\n <p-button\r\n icon=\"pi pi-cloud-upload\"\r\n [rounded]=\"true\"\r\n severity=\"info\"\r\n (click)=\"startReplace()\"\r\n [disabled]=\"isReplaceButtonDisabled()\"\r\n pTooltip=\"Reemplazar archivo\"\r\n tooltipPosition=\"top\"\r\n />\r\n </div>\r\n} @else {\r\n <div class=\"flex items-center gap-2\">\r\n <p-fileUpload\r\n #fileUpload\r\n mode=\"basic\"\r\n [accept]=\"accept()\"\r\n [maxFileSize]=\"maxFileSize() * 1024 * 1024\"\r\n [invalidFileTypeMessageSummary]=\"invalidSummary()\"\r\n [invalidFileTypeMessageDetail]=\"invalidDetail()\"\r\n [invalidFileSizeMessageSummary]=\"invalidSizeSummary()\"\r\n [invalidFileSizeMessageDetail]=\"invalidSizeDetail()\"\r\n (onSelect)=\"onSelect($event)\"\r\n [disabled]=\"!isFileUploadEnabled()\"\r\n [pTooltip]=\"pTooltipOverride()\"\r\n [tooltipPosition]=\"tooltipPositionOverride()\"\r\n />\r\n\r\n @if (isReplacing() || existingFile()) {\r\n <p-button\r\n icon=\"pi pi-times\"\r\n [rounded]=\"true\"\r\n severity=\"secondary\"\r\n (click)=\"cancelReplace()\"\r\n [disabled]=\"disabled()\"\r\n pTooltip=\"Cancelar reemplazo\"\r\n tooltipPosition=\"top\"\r\n />\r\n }\r\n </div>\r\n}\r\n", styles: [".file-name{display:inline-block;font-size:clamp(.85rem,1vw + .5rem,1.4rem);font-weight:500;color:#2c3e50;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:100%}\n"], dependencies: [{ kind: "component", type: FileUpload, selector: "p-fileupload, p-fileUpload", inputs: ["name", "url", "method", "multiple", "accept", "disabled", "auto", "withCredentials", "maxFileSize", "invalidFileSizeMessageSummary", "invalidFileSizeMessageDetail", "invalidFileTypeMessageSummary", "invalidFileTypeMessageDetail", "invalidFileLimitMessageDetail", "invalidFileLimitMessageSummary", "style", "styleClass", "previewWidth", "chooseLabel", "uploadLabel", "cancelLabel", "chooseIcon", "uploadIcon", "cancelIcon", "showUploadButton", "showCancelButton", "mode", "headers", "customUpload", "fileLimit", "uploadStyleClass", "cancelStyleClass", "removeStyleClass", "chooseStyleClass", "chooseButtonProps", "uploadButtonProps", "cancelButtonProps", "files"], outputs: ["onBeforeUpload", "onSend", "onUpload", "onError", "onClear", "onRemove", "onSelect", "onProgress", "uploadHandler", "onImageError", "onRemoveUploadedFile"] }, { kind: "directive", type: Tooltip, selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "autoHide", "fitContent", "hideOnEscape", "showOnEllipsis", "pTooltip", "tooltipDisabled", "tooltipOptions", "appendTo", "ptTooltip", "pTooltipPT", "pTooltipUnstyled"] }, { kind: "component", type: Button, selector: "p-button", inputs: ["hostName", "type", "badge", "disabled", "raised", "rounded", "text", "plain", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "iconPos", "icon", "label", "loading", "loadingIcon", "severity", "buttonProps", "fluid"], outputs: ["onClick", "onFocus", "onBlur"] }] });
|
|
5116
5148
|
}
|
|
5117
5149
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: FileComponent, decorators: [{
|
|
5118
5150
|
type: Component,
|
|
@@ -5127,8 +5159,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
|
|
|
5127
5159
|
useExisting: forwardRef(() => FileComponent),
|
|
5128
5160
|
multi: true,
|
|
5129
5161
|
},
|
|
5130
|
-
], template: "@if (showExistingFile() && !existingFile()) {\r\n <div class=\"flex items-center gap-2\">\r\n <span class=\"file-name\"
|
|
5131
|
-
}], ctorParameters: () => [], propDecorators: { existingFile: [{ type: i0.Input, args: [{ isSignal: true, alias: "existingFile", required: false }] }], existingFileName: [{ type: i0.Input, args: [{ isSignal: true, alias: "existingFileName", required: false }] }], debug: [{ type: i0.Input, args: [{ isSignal: true, alias: "debug", required: false }] }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }], accept: [{ type: i0.Input, args: [{ isSignal: true, alias: "accept", required: false }] }], pTooltipOverride: [{ type: i0.Input, args: [{ isSignal: true, alias: "pTooltipOverride", required: false }] }], tooltipPositionOverride: [{ type: i0.Input, args: [{ isSignal: true, alias: "tooltipPositionOverride", required: false }] }], maxFileSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxFileSize", required: false }] }], invalidSummary: [{ type: i0.Input, args: [{ isSignal: true, alias: "invalidSummary", required: false }] }], invalidDetail: [{ type: i0.Input, args: [{ isSignal: true, alias: "invalidDetail", required: false }] }], invalidSizeSummary: [{ type: i0.Input, args: [{ isSignal: true, alias: "invalidSizeSummary", required: false }] }], invalidSizeDetail: [{ type: i0.Input, args: [{ isSignal: true, alias: "invalidSizeDetail", required: false }] }], fileUpload: [{ type: i0.ViewChild, args: ['fileUpload', { isSignal: true }] }] } });
|
|
5162
|
+
], template: "@if (showExistingFile() && !existingFile()) {\r\n <div class=\"flex items-center gap-2\">\r\n <span class=\"file-name\">\r\n \uD83D\uDCC4 {{ overrideFileName() ?? existingFileName() }}\r\n </span>\r\n\r\n <p-button\r\n icon=\"pi pi-cloud-upload\"\r\n [rounded]=\"true\"\r\n severity=\"info\"\r\n (click)=\"startReplace()\"\r\n [disabled]=\"isReplaceButtonDisabled()\"\r\n pTooltip=\"Reemplazar archivo\"\r\n tooltipPosition=\"top\"\r\n />\r\n </div>\r\n} @else {\r\n <div class=\"flex items-center gap-2\">\r\n <p-fileUpload\r\n #fileUpload\r\n mode=\"basic\"\r\n [accept]=\"accept()\"\r\n [maxFileSize]=\"maxFileSize() * 1024 * 1024\"\r\n [invalidFileTypeMessageSummary]=\"invalidSummary()\"\r\n [invalidFileTypeMessageDetail]=\"invalidDetail()\"\r\n [invalidFileSizeMessageSummary]=\"invalidSizeSummary()\"\r\n [invalidFileSizeMessageDetail]=\"invalidSizeDetail()\"\r\n (onSelect)=\"onSelect($event)\"\r\n [disabled]=\"!isFileUploadEnabled()\"\r\n [pTooltip]=\"pTooltipOverride()\"\r\n [tooltipPosition]=\"tooltipPositionOverride()\"\r\n />\r\n\r\n @if (isReplacing() || existingFile()) {\r\n <p-button\r\n icon=\"pi pi-times\"\r\n [rounded]=\"true\"\r\n severity=\"secondary\"\r\n (click)=\"cancelReplace()\"\r\n [disabled]=\"disabled()\"\r\n pTooltip=\"Cancelar reemplazo\"\r\n tooltipPosition=\"top\"\r\n />\r\n }\r\n </div>\r\n}\r\n", styles: [".file-name{display:inline-block;font-size:clamp(.85rem,1vw + .5rem,1.4rem);font-weight:500;color:#2c3e50;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:100%}\n"] }]
|
|
5163
|
+
}], ctorParameters: () => [], propDecorators: { existingFile: [{ type: i0.Input, args: [{ isSignal: true, alias: "existingFile", required: false }] }], existingFileName: [{ type: i0.Input, args: [{ isSignal: true, alias: "existingFileName", required: false }] }], overrideFileName: [{ type: i0.Input, args: [{ isSignal: true, alias: "overrideFileName", required: false }] }], debug: [{ type: i0.Input, args: [{ isSignal: true, alias: "debug", required: false }] }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }], accept: [{ type: i0.Input, args: [{ isSignal: true, alias: "accept", required: false }] }], pTooltipOverride: [{ type: i0.Input, args: [{ isSignal: true, alias: "pTooltipOverride", required: false }] }], tooltipPositionOverride: [{ type: i0.Input, args: [{ isSignal: true, alias: "tooltipPositionOverride", required: false }] }], maxFileSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxFileSize", required: false }] }], invalidSummary: [{ type: i0.Input, args: [{ isSignal: true, alias: "invalidSummary", required: false }] }], invalidDetail: [{ type: i0.Input, args: [{ isSignal: true, alias: "invalidDetail", required: false }] }], invalidSizeSummary: [{ type: i0.Input, args: [{ isSignal: true, alias: "invalidSizeSummary", required: false }] }], invalidSizeDetail: [{ type: i0.Input, args: [{ isSignal: true, alias: "invalidSizeDetail", required: false }] }], fileUpload: [{ type: i0.ViewChild, args: ['fileUpload', { isSignal: true }] }] } });
|
|
5132
5164
|
|
|
5133
5165
|
class JsonHighlightPipe {
|
|
5134
5166
|
/**
|
|
@@ -8112,7 +8144,7 @@ class DsxSelect {
|
|
|
8112
8144
|
optionValue = input(undefined, ...(ngDevMode ? [{ debugName: "optionValue" }] : /* istanbul ignore next */ []));
|
|
8113
8145
|
// Iconos
|
|
8114
8146
|
useIcon = input(true, ...(ngDevMode ? [{ debugName: "useIcon" }] : /* istanbul ignore next */ []));
|
|
8115
|
-
itemIcon = input('
|
|
8147
|
+
itemIcon = input('keyboard_arrow_right', ...(ngDevMode ? [{ debugName: "itemIcon" }] : /* istanbul ignore next */ []));
|
|
8116
8148
|
selectedIcon = input('done_outline', ...(ngDevMode ? [{ debugName: "selectedIcon" }] : /* istanbul ignore next */ []));
|
|
8117
8149
|
// Debug solo consola
|
|
8118
8150
|
debug = input(false, ...(ngDevMode ? [{ debugName: "debug" }] : /* istanbul ignore next */ []));
|
|
@@ -8277,7 +8309,7 @@ class DsxSelect {
|
|
|
8277
8309
|
useExisting: forwardRef(() => DsxSelect),
|
|
8278
8310
|
multi: true,
|
|
8279
8311
|
},
|
|
8280
|
-
], ngImport: i0, template: "<!-- dsx-select.html -->\r\n<p-floatLabel [variant]=\"variant()\">\r\n <p-select\r\n fluid\r\n [options]=\"dataList()\"\r\n [filter]=\"true\"\r\n [filterPlaceholder]=\"filterPlaceholder()\"\r\n [showClear]=\"showClear()\"\r\n [disabled]=\"disabled\"\r\n [optionLabel]=\"resolvedOptionLabel()\"\r\n [optionValue]=\"resolvedOptionValue()\"\r\n [(ngModel)]=\"value\"\r\n (ngModelChange)=\"onValueChange($event)\"\r\n >\r\n <ng-template let-item #item>\r\n <div class=\"flex align-items-center\">\r\n @if (useIcon()) {\r\n <icon-dsx [name]=\"itemIcon()\"
|
|
8312
|
+
], ngImport: i0, template: "<!-- dsx-select.html -->\r\n<p-floatLabel [variant]=\"variant()\">\r\n <p-select\r\n fluid\r\n appendTo=\"body\"\r\n [options]=\"dataList()\"\r\n [filter]=\"true\"\r\n [filterPlaceholder]=\"filterPlaceholder()\"\r\n [showClear]=\"showClear()\"\r\n [disabled]=\"disabled\"\r\n [optionLabel]=\"resolvedOptionLabel()\"\r\n [optionValue]=\"resolvedOptionValue()\"\r\n [(ngModel)]=\"value\"\r\n (ngModelChange)=\"onValueChange($event)\"\r\n >\r\n <ng-template let-item #item>\r\n <div class=\"flex align-items-center\">\r\n @if (useIcon()) {\r\n <icon-dsx [name]=\"itemIcon()\"></icon-dsx>\r\n } {{ item[resolvedOptionLabel()] }}\r\n </div>\r\n </ng-template>\r\n\r\n <ng-template #selectedItem let-selectedOptions>\r\n <div class=\"flex align-items-center\">\r\n @if (useIcon()) {\r\n <icon-dsx\r\n [name]=\"selectedIcon()\"\r\n class=\"text-green-600! mr-1\"\r\n ></icon-dsx>\r\n } {{ selectedOptions?.[resolvedOptionLabel()] }}\r\n </div>\r\n </ng-template>\r\n </p-select>\r\n <label>{{ resolvedLabel() }}</label>\r\n</p-floatLabel>\r\n\r\n<!-- \u2705 Mensaje de error condicional (dentro del floatLabel) -->\r\n@if (showError() && errorControl()) {\r\n<app-message-error [control]=\"errorControl()\" />\r\n}\r\n", styles: ["icon-dsx{font-size:1.5em}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: Select, selector: "p-select", inputs: ["id", "scrollHeight", "filter", "panelStyle", "styleClass", "panelStyleClass", "readonly", "editable", "tabindex", "placeholder", "loadingIcon", "filterPlaceholder", "filterLocale", "inputId", "dataKey", "filterBy", "filterFields", "autofocus", "resetFilterOnHide", "checkmark", "dropdownIcon", "loading", "optionLabel", "optionValue", "optionDisabled", "optionGroupLabel", "optionGroupChildren", "group", "showClear", "emptyFilterMessage", "emptyMessage", "lazy", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "overlayOptions", "ariaFilterLabel", "ariaLabel", "ariaLabelledBy", "filterMatchMode", "tooltip", "tooltipPosition", "tooltipPositionStyle", "tooltipStyleClass", "focusOnHover", "selectOnFocus", "autoOptionFocus", "autofocusFilter", "filterValue", "options", "appendTo", "motionOptions"], outputs: ["onChange", "onFilter", "onFocus", "onBlur", "onClick", "onShow", "onHide", "onClear", "onLazyLoad"] }, { kind: "component", type: FloatLabel, selector: "p-floatlabel, p-floatLabel, p-float-label", inputs: ["variant"] }, { kind: "component", type: IconDsxComponent, selector: "icon-dsx", inputs: ["name", "style", "debug"] }, { kind: "component", type: AppMessageErrorComponent, selector: "app-message-error", inputs: ["control", "form", "debugMode"] }] });
|
|
8281
8313
|
}
|
|
8282
8314
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: DsxSelect, decorators: [{
|
|
8283
8315
|
type: Component,
|
|
@@ -8293,7 +8325,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
|
|
|
8293
8325
|
useExisting: forwardRef(() => DsxSelect),
|
|
8294
8326
|
multi: true,
|
|
8295
8327
|
},
|
|
8296
|
-
], template: "<!-- dsx-select.html -->\r\n<p-floatLabel [variant]=\"variant()\">\r\n <p-select\r\n fluid\r\n [options]=\"dataList()\"\r\n [filter]=\"true\"\r\n [filterPlaceholder]=\"filterPlaceholder()\"\r\n [showClear]=\"showClear()\"\r\n [disabled]=\"disabled\"\r\n [optionLabel]=\"resolvedOptionLabel()\"\r\n [optionValue]=\"resolvedOptionValue()\"\r\n [(ngModel)]=\"value\"\r\n (ngModelChange)=\"onValueChange($event)\"\r\n >\r\n <ng-template let-item #item>\r\n <div class=\"flex align-items-center\">\r\n @if (useIcon()) {\r\n <icon-dsx [name]=\"itemIcon()\"
|
|
8328
|
+
], template: "<!-- dsx-select.html -->\r\n<p-floatLabel [variant]=\"variant()\">\r\n <p-select\r\n fluid\r\n appendTo=\"body\"\r\n [options]=\"dataList()\"\r\n [filter]=\"true\"\r\n [filterPlaceholder]=\"filterPlaceholder()\"\r\n [showClear]=\"showClear()\"\r\n [disabled]=\"disabled\"\r\n [optionLabel]=\"resolvedOptionLabel()\"\r\n [optionValue]=\"resolvedOptionValue()\"\r\n [(ngModel)]=\"value\"\r\n (ngModelChange)=\"onValueChange($event)\"\r\n >\r\n <ng-template let-item #item>\r\n <div class=\"flex align-items-center\">\r\n @if (useIcon()) {\r\n <icon-dsx [name]=\"itemIcon()\"></icon-dsx>\r\n } {{ item[resolvedOptionLabel()] }}\r\n </div>\r\n </ng-template>\r\n\r\n <ng-template #selectedItem let-selectedOptions>\r\n <div class=\"flex align-items-center\">\r\n @if (useIcon()) {\r\n <icon-dsx\r\n [name]=\"selectedIcon()\"\r\n class=\"text-green-600! mr-1\"\r\n ></icon-dsx>\r\n } {{ selectedOptions?.[resolvedOptionLabel()] }}\r\n </div>\r\n </ng-template>\r\n </p-select>\r\n <label>{{ resolvedLabel() }}</label>\r\n</p-floatLabel>\r\n\r\n<!-- \u2705 Mensaje de error condicional (dentro del floatLabel) -->\r\n@if (showError() && errorControl()) {\r\n<app-message-error [control]=\"errorControl()\" />\r\n}\r\n", styles: ["icon-dsx{font-size:1.5em}\n"] }]
|
|
8297
8329
|
}], ctorParameters: () => [], propDecorators: { dataList: [{ type: i0.Input, args: [{ isSignal: true, alias: "dataList", required: true }] }], variant: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], filterPlaceholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "filterPlaceholder", required: false }] }], showClear: [{ type: i0.Input, args: [{ isSignal: true, alias: "showClear", required: false }] }], optionLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "optionLabel", required: false }] }], optionValue: [{ type: i0.Input, args: [{ isSignal: true, alias: "optionValue", required: false }] }], useIcon: [{ type: i0.Input, args: [{ isSignal: true, alias: "useIcon", required: false }] }], itemIcon: [{ type: i0.Input, args: [{ isSignal: true, alias: "itemIcon", required: false }] }], selectedIcon: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectedIcon", required: false }] }], debug: [{ type: i0.Input, args: [{ isSignal: true, alias: "debug", required: false }] }], showError: [{ type: i0.Input, args: [{ isSignal: true, alias: "showError", required: false }] }], selectedValue: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectedValue", required: false }] }, { type: i0.Output, args: ["selectedValueChange"] }] } });
|
|
8298
8330
|
|
|
8299
8331
|
/**
|
|
@@ -9551,15 +9583,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
|
|
|
9551
9583
|
|
|
9552
9584
|
// form-preview.service.ts
|
|
9553
9585
|
class FormPreviewService {
|
|
9554
|
-
/**
|
|
9555
|
-
* Genera resumen HTML desde un objeto plano
|
|
9556
|
-
* @param data - Objeto con los datos (ej: form.value)
|
|
9557
|
-
* @param fields - Array de campos a mostrar
|
|
9558
|
-
* @param options - Opciones adicionales
|
|
9559
|
-
*/
|
|
9560
9586
|
buildObjectSummaryHtml(data, fields, options) {
|
|
9561
9587
|
const debug = options?.debug ?? false;
|
|
9562
|
-
// Modo desarrollo: mostrar información de depuración
|
|
9563
9588
|
if (debug) {
|
|
9564
9589
|
this.debugInputData(data, fields, options);
|
|
9565
9590
|
}
|
|
@@ -9579,16 +9604,31 @@ class FormPreviewService {
|
|
|
9579
9604
|
const cells = [];
|
|
9580
9605
|
const propiedadesNoEncontradas = [];
|
|
9581
9606
|
for (const field of fields) {
|
|
9582
|
-
|
|
9583
|
-
|
|
9607
|
+
let value = this.getNestedValue(data, field.key);
|
|
9608
|
+
// Resolver referencia si existe
|
|
9609
|
+
if (field.referenceMap && value !== undefined && value !== null) {
|
|
9610
|
+
const originalValue = value;
|
|
9611
|
+
value = this.resolveReferenceValue(value, field);
|
|
9612
|
+
if (debug) {
|
|
9613
|
+
console.log(`🔍 Resolviendo referencia para "${field.key}":`, {
|
|
9614
|
+
original: originalValue,
|
|
9615
|
+
resuelto: value,
|
|
9616
|
+
tipoMapa: Array.isArray(field.referenceMap)
|
|
9617
|
+
? 'Array'
|
|
9618
|
+
: field.referenceMap instanceof Map
|
|
9619
|
+
? 'Map'
|
|
9620
|
+
: typeof field.referenceMap === 'function'
|
|
9621
|
+
? 'Función'
|
|
9622
|
+
: 'Objeto',
|
|
9623
|
+
});
|
|
9624
|
+
}
|
|
9625
|
+
}
|
|
9584
9626
|
const valueText = field.format
|
|
9585
9627
|
? field.format(value)
|
|
9586
9628
|
: this.formatValue(value);
|
|
9587
|
-
// Registrar si no se encontró la propiedad
|
|
9588
9629
|
if (value === undefined) {
|
|
9589
9630
|
propiedadesNoEncontradas.push(field.key);
|
|
9590
9631
|
}
|
|
9591
|
-
// Filtrar vacíos
|
|
9592
9632
|
if (!showEmpty && !valueText)
|
|
9593
9633
|
continue;
|
|
9594
9634
|
cells.push({
|
|
@@ -9596,7 +9636,6 @@ class FormPreviewService {
|
|
|
9596
9636
|
value: valueText || '—',
|
|
9597
9637
|
});
|
|
9598
9638
|
}
|
|
9599
|
-
// Modo desarrollo: mostrar advertencias
|
|
9600
9639
|
if (debug) {
|
|
9601
9640
|
if (propiedadesNoEncontradas.length > 0) {
|
|
9602
9641
|
console.warn('⚠️ FormPreview: Propiedades no encontradas:', propiedadesNoEncontradas);
|
|
@@ -9616,6 +9655,56 @@ class FormPreviewService {
|
|
|
9616
9655
|
return '';
|
|
9617
9656
|
return this.generateHtml(title, cells, compact);
|
|
9618
9657
|
}
|
|
9658
|
+
resolveReferenceValue(value, field) {
|
|
9659
|
+
// Si es array (multi-select)
|
|
9660
|
+
if (Array.isArray(value)) {
|
|
9661
|
+
return value.map((item) => this.resolveSingleReference(item, field));
|
|
9662
|
+
}
|
|
9663
|
+
return this.resolveSingleReference(value, field);
|
|
9664
|
+
}
|
|
9665
|
+
resolveSingleReference(value, field) {
|
|
9666
|
+
if (!value)
|
|
9667
|
+
return value;
|
|
9668
|
+
// Si ya es objeto, devolverlo
|
|
9669
|
+
if (typeof value === 'object' && value !== null) {
|
|
9670
|
+
return value;
|
|
9671
|
+
}
|
|
9672
|
+
const map = field.referenceMap;
|
|
9673
|
+
if (!map)
|
|
9674
|
+
return value;
|
|
9675
|
+
let referencedItem = null;
|
|
9676
|
+
// Si es función
|
|
9677
|
+
if (typeof map === 'function') {
|
|
9678
|
+
referencedItem = map(value);
|
|
9679
|
+
}
|
|
9680
|
+
// Si es Map
|
|
9681
|
+
else if (map instanceof Map) {
|
|
9682
|
+
referencedItem = map.get(value);
|
|
9683
|
+
}
|
|
9684
|
+
// Si es Array
|
|
9685
|
+
else if (Array.isArray(map)) {
|
|
9686
|
+
const idKey = field.referenceId || 'id';
|
|
9687
|
+
referencedItem = map.find((item) => item[idKey] === value);
|
|
9688
|
+
}
|
|
9689
|
+
// Si es objeto literal
|
|
9690
|
+
else if (typeof map === 'object') {
|
|
9691
|
+
referencedItem = map[String(value)];
|
|
9692
|
+
}
|
|
9693
|
+
if (referencedItem) {
|
|
9694
|
+
const labelProp = field.referenceLabel || 'nombre';
|
|
9695
|
+
if (typeof referencedItem === 'object' && referencedItem !== null) {
|
|
9696
|
+
// Buscar la propiedad en el objeto
|
|
9697
|
+
if (referencedItem[labelProp] !== undefined &&
|
|
9698
|
+
referencedItem[labelProp] !== null) {
|
|
9699
|
+
return referencedItem[labelProp];
|
|
9700
|
+
}
|
|
9701
|
+
// Si no encuentra la propiedad, devolver el objeto completo
|
|
9702
|
+
return referencedItem;
|
|
9703
|
+
}
|
|
9704
|
+
return referencedItem;
|
|
9705
|
+
}
|
|
9706
|
+
return value;
|
|
9707
|
+
}
|
|
9619
9708
|
getNestedValue(obj, path) {
|
|
9620
9709
|
if (!obj || !path)
|
|
9621
9710
|
return undefined;
|
|
@@ -9635,24 +9724,47 @@ class FormPreviewService {
|
|
|
9635
9724
|
if (value instanceof Date)
|
|
9636
9725
|
return value.toLocaleDateString();
|
|
9637
9726
|
if (typeof value === 'object') {
|
|
9638
|
-
|
|
9639
|
-
|
|
9640
|
-
|
|
9641
|
-
|
|
9642
|
-
|
|
9643
|
-
if (value.name)
|
|
9644
|
-
return String(value.name);
|
|
9645
|
-
if (value.value)
|
|
9646
|
-
return String(value.value);
|
|
9647
|
-
try {
|
|
9648
|
-
return JSON.stringify(value);
|
|
9649
|
-
}
|
|
9650
|
-
catch {
|
|
9651
|
-
return String(value);
|
|
9727
|
+
if (Array.isArray(value)) {
|
|
9728
|
+
return value
|
|
9729
|
+
.map((item) => this.formatSingleValue(item))
|
|
9730
|
+
.filter((v) => v)
|
|
9731
|
+
.join(', ');
|
|
9652
9732
|
}
|
|
9733
|
+
return this.formatSingleValue(value);
|
|
9653
9734
|
}
|
|
9654
9735
|
return String(value);
|
|
9655
9736
|
}
|
|
9737
|
+
formatSingleValue(value) {
|
|
9738
|
+
if (!value || typeof value !== 'object')
|
|
9739
|
+
return String(value);
|
|
9740
|
+
const props = [
|
|
9741
|
+
'label',
|
|
9742
|
+
'nombre',
|
|
9743
|
+
'name',
|
|
9744
|
+
'empresaNombre',
|
|
9745
|
+
'descripcion',
|
|
9746
|
+
'description',
|
|
9747
|
+
'text',
|
|
9748
|
+
'value',
|
|
9749
|
+
];
|
|
9750
|
+
for (const prop of props) {
|
|
9751
|
+
if (value[prop] !== undefined &&
|
|
9752
|
+
value[prop] !== null &&
|
|
9753
|
+
value[prop] !== '') {
|
|
9754
|
+
return String(value[prop]);
|
|
9755
|
+
}
|
|
9756
|
+
}
|
|
9757
|
+
if (value.id !== undefined && value.id !== null) {
|
|
9758
|
+
return `ID: ${value.id}`;
|
|
9759
|
+
}
|
|
9760
|
+
try {
|
|
9761
|
+
const json = JSON.stringify(value);
|
|
9762
|
+
return json.length > 50 ? json.substring(0, 50) + '...' : json;
|
|
9763
|
+
}
|
|
9764
|
+
catch {
|
|
9765
|
+
return '[Objeto]';
|
|
9766
|
+
}
|
|
9767
|
+
}
|
|
9656
9768
|
generateHtml(title, cells, compact) {
|
|
9657
9769
|
if (compact) {
|
|
9658
9770
|
return `
|
|
@@ -9679,7 +9791,6 @@ class FormPreviewService {
|
|
|
9679
9791
|
</div>
|
|
9680
9792
|
`;
|
|
9681
9793
|
}
|
|
9682
|
-
// Versión no compacta (con más padding)
|
|
9683
9794
|
return `
|
|
9684
9795
|
<div style="margin: 12px 0; border: 1px solid #dee2e6; border-radius: 8px; overflow: hidden; background: #ffffff;">
|
|
9685
9796
|
<div style="padding: 12px; background: #f8f9fa; border-bottom: 1px solid #dee2e6; font-weight: 600; color: #495057;">
|
|
@@ -9710,14 +9821,12 @@ class FormPreviewService {
|
|
|
9710
9821
|
console.log('📋 Propiedades disponibles:', data ? Object.keys(data) : 'data es null');
|
|
9711
9822
|
console.log('🎯 Fields solicitados:', fields);
|
|
9712
9823
|
console.log('⚙️ Options:', options);
|
|
9713
|
-
// Verificar cada campo
|
|
9714
9824
|
if (data) {
|
|
9715
9825
|
for (const field of fields) {
|
|
9716
9826
|
const value = this.getNestedValue(data, field.key);
|
|
9717
9827
|
const existe = value !== undefined;
|
|
9718
9828
|
if (!existe) {
|
|
9719
9829
|
console.warn(`❌ Campo "${field.key}" NO existe en data`);
|
|
9720
|
-
// Sugerir propiedades similares
|
|
9721
9830
|
const similares = this.findSimilarProperties(field.key, Object.keys(data));
|
|
9722
9831
|
if (similares.length > 0) {
|
|
9723
9832
|
console.warn(`💡 Quizás quisiste decir: ${similares.join(', ')}`);
|
|
@@ -10376,7 +10485,7 @@ function buildAlreadyExistsMessage(control, options) {
|
|
|
10376
10485
|
* Validador asíncrono que verifica si un valor ya existe mediante una llamada a un servicio.
|
|
10377
10486
|
* Útil para validar unicidad de campos como nombres de usuario, correos electrónicos, etc.
|
|
10378
10487
|
*
|
|
10379
|
-
* Aplica `debounceTime(
|
|
10488
|
+
* Aplica `debounceTime(800)` y `distinctUntilChanged()` para evitar llamadas innecesarias
|
|
10380
10489
|
* al servicio mientras el usuario escribe.
|
|
10381
10490
|
*
|
|
10382
10491
|
* @template T Tipo del valor del control a validar.
|
|
@@ -10384,39 +10493,93 @@ function buildAlreadyExistsMessage(control, options) {
|
|
|
10384
10493
|
* el identificador del registro actual. Debe retornar un `Observable<boolean>`
|
|
10385
10494
|
* emitiendo `true` si el valor ya existe (en otro registro), `false` en caso contrario.
|
|
10386
10495
|
* @param options Opciones del validador:
|
|
10387
|
-
* - `currentId`: Id
|
|
10496
|
+
* - `currentId`: Id fijo del registro en edición para excluirlo en backend.
|
|
10497
|
+
* ⚠️ Útil cuando el ID no cambia durante la vida del validador.
|
|
10498
|
+
* - `getCurrentId`: Función que obtiene el ID en tiempo real.
|
|
10499
|
+
* ✅ **RECOMENDADO** cuando el ID puede cambiar (ej: signals, componentes reactivos).
|
|
10500
|
+
* Si se proporciona, tiene prioridad sobre `currentId`.
|
|
10388
10501
|
* - `fieldName`: Nombre del campo para construir el mensaje dinámico
|
|
10389
10502
|
* (si se omite, se intenta inferir del control).
|
|
10390
10503
|
* - `errorMessage`: Mensaje personalizado (si se omite y se resuelve nombre
|
|
10391
10504
|
* de campo, se usa `El valor {campo} ya existe`).
|
|
10505
|
+
* - `debug`: Si es `true`, muestra logs en consola para depuración.
|
|
10392
10506
|
* @returns Un `AsyncValidatorFn` que emite `null` si el valor no existe o el control está vacío,
|
|
10393
10507
|
* o un objeto `ValidationErrors` con la clave fija `alreadyValueExists` si el valor ya existe.
|
|
10394
10508
|
*
|
|
10395
10509
|
* @example
|
|
10396
10510
|
* ```ts
|
|
10397
|
-
* // Creación
|
|
10511
|
+
* // EJEMPLO 1: Creación (ID fijo o sin ID)
|
|
10398
10512
|
* email: ['', [], asyncExistsValidator(
|
|
10399
10513
|
* (value, id) => this.userService.emailExists({ value, id: Number(id) })
|
|
10400
10514
|
* )]
|
|
10401
10515
|
*
|
|
10402
|
-
* // Edición (
|
|
10516
|
+
* // EJEMPLO 2: Edición con ID fijo (cuando el ID no cambia)
|
|
10403
10517
|
* email: ['', [], asyncExistsValidator(
|
|
10404
10518
|
* (value, id) => this.userService.emailExists(value, id),
|
|
10405
|
-
* { currentId: this.
|
|
10519
|
+
* { currentId: this.userId, fieldName: 'email' }
|
|
10520
|
+
* )]
|
|
10521
|
+
*
|
|
10522
|
+
* // EJEMPLO 3: Edición con ID dinámico (RECOMENDADO con signals)
|
|
10523
|
+
* email: ['', [], asyncExistsValidator(
|
|
10524
|
+
* (value, id) => this.userService.emailExists(value, id),
|
|
10525
|
+
* {
|
|
10526
|
+
* getCurrentId: () => this.id(), // ✅ Obtiene el ID en tiempo real
|
|
10527
|
+
* fieldName: 'email',
|
|
10528
|
+
* debug: true // Para depuración
|
|
10529
|
+
* }
|
|
10530
|
+
* )]
|
|
10531
|
+
*
|
|
10532
|
+
* // EJEMPLO 4: Con mensaje personalizado
|
|
10533
|
+
* codigo: ['', [], asyncExistsValidator(
|
|
10534
|
+
* (value, id) => this.productService.codigoExists(value, id),
|
|
10535
|
+
* {
|
|
10536
|
+
* getCurrentId: () => this.productId(),
|
|
10537
|
+
* errorMessage: 'El código de producto ya está registrado',
|
|
10538
|
+
* fieldName: 'código de producto'
|
|
10539
|
+
* }
|
|
10406
10540
|
* )]
|
|
10407
10541
|
* ```
|
|
10408
10542
|
*/
|
|
10409
10543
|
function asyncExistsValidator(serviceMethod, options = {}) {
|
|
10410
|
-
const { currentId = null, fieldName, errorMessage } = options;
|
|
10544
|
+
const { currentId = null, fieldName, errorMessage, debug = false, getCurrentId, } = options;
|
|
10411
10545
|
const errorKey = 'alreadyValueExists';
|
|
10412
10546
|
return (control) => {
|
|
10413
|
-
if (!control.value)
|
|
10547
|
+
if (!control.value) {
|
|
10548
|
+
if (debug)
|
|
10549
|
+
console.log('[AsyncExistsValidator] Control value is empty, returning null');
|
|
10414
10550
|
return of(null);
|
|
10551
|
+
}
|
|
10552
|
+
// Obtener el ID: prioridad a getCurrentId, luego currentId, luego 0
|
|
10553
|
+
const resolvedId = getCurrentId ? getCurrentId() : currentId;
|
|
10554
|
+
const finalId = resolvedId ?? 0;
|
|
10555
|
+
if (debug) {
|
|
10556
|
+
console.log('[AsyncExistsValidator] Starting validation for:', {
|
|
10557
|
+
value: control.value,
|
|
10558
|
+
currentId: finalId,
|
|
10559
|
+
fieldName,
|
|
10560
|
+
errorMessage,
|
|
10561
|
+
debug,
|
|
10562
|
+
usingGetCurrentId: !!getCurrentId,
|
|
10563
|
+
});
|
|
10564
|
+
}
|
|
10415
10565
|
return of(control.value).pipe(debounceTime$1(800), distinctUntilChanged$1(), switchMap$1((value) => {
|
|
10416
|
-
|
|
10417
|
-
|
|
10566
|
+
if (debug) {
|
|
10567
|
+
console.log('[AsyncExistsValidator] Calling service method with:', {
|
|
10568
|
+
value: value,
|
|
10569
|
+
resolvedId: finalId,
|
|
10570
|
+
});
|
|
10571
|
+
}
|
|
10572
|
+
return serviceMethod(value, finalId);
|
|
10418
10573
|
}), map((exists) => {
|
|
10574
|
+
if (debug) {
|
|
10575
|
+
console.log('[AsyncExistsValidator] Service response:', {
|
|
10576
|
+
exists,
|
|
10577
|
+
value: control.value,
|
|
10578
|
+
});
|
|
10579
|
+
}
|
|
10419
10580
|
if (exists) {
|
|
10581
|
+
if (debug)
|
|
10582
|
+
console.log('[AsyncExistsValidator] Validation failed - value already exists');
|
|
10420
10583
|
return {
|
|
10421
10584
|
[errorKey]: {
|
|
10422
10585
|
message: buildAlreadyExistsMessage(control, {
|
|
@@ -10427,8 +10590,15 @@ function asyncExistsValidator(serviceMethod, options = {}) {
|
|
|
10427
10590
|
},
|
|
10428
10591
|
};
|
|
10429
10592
|
}
|
|
10593
|
+
if (debug)
|
|
10594
|
+
console.log('[AsyncExistsValidator] Validation passed - value is available');
|
|
10430
10595
|
return null;
|
|
10431
|
-
}), catchError(() =>
|
|
10596
|
+
}), catchError((error) => {
|
|
10597
|
+
if (debug) {
|
|
10598
|
+
console.error('[AsyncExistsValidator] Error occurred:', error);
|
|
10599
|
+
}
|
|
10600
|
+
return of(null);
|
|
10601
|
+
}));
|
|
10432
10602
|
};
|
|
10433
10603
|
}
|
|
10434
10604
|
function templateVariablesValidator(allowedKeys) {
|