ngx-dsxlibrary 2.21.72 → 2.21.73
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.
|
@@ -5,7 +5,7 @@ import { FormsModule, NG_VALUE_ACCESSOR, AbstractControl, FormControl, NG_VALIDA
|
|
|
5
5
|
import * as i2 from 'primeng/togglebutton';
|
|
6
6
|
import { ToggleButtonModule } from 'primeng/togglebutton';
|
|
7
7
|
import * as i1$1 from '@angular/common';
|
|
8
|
-
import { CommonModule, AsyncPipe, JsonPipe,
|
|
8
|
+
import { CommonModule, AsyncPipe, JsonPipe, DecimalPipe, DatePipe, Location } from '@angular/common';
|
|
9
9
|
import * as i2$1 from 'primeng/tree';
|
|
10
10
|
import { TreeModule } from 'primeng/tree';
|
|
11
11
|
import * as i3 from 'primeng/api';
|
|
@@ -4301,25 +4301,26 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
|
|
|
4301
4301
|
* | details | Azul índigo | Abrir detalle de registro |
|
|
4302
4302
|
*/
|
|
4303
4303
|
const DSX_PALETTE = {
|
|
4304
|
-
|
|
4305
|
-
warning: '#FF7043',
|
|
4304
|
+
brown: '#8D6E63',
|
|
4306
4305
|
caution: '#FFB300',
|
|
4307
|
-
|
|
4308
|
-
|
|
4309
|
-
|
|
4310
|
-
|
|
4311
|
-
restore: '#B0BEC5',
|
|
4312
|
-
return: '#11438d',
|
|
4313
|
-
view: '#00838F',
|
|
4306
|
+
cyan: '#00BCD4',
|
|
4307
|
+
danger: '#EF5350',
|
|
4308
|
+
details: '#3949AB',
|
|
4309
|
+
download: '#e6763a',
|
|
4314
4310
|
excel: '#217346',
|
|
4315
|
-
download: '#E65100',
|
|
4316
4311
|
import: '#546E7A',
|
|
4317
|
-
|
|
4312
|
+
info: '#26C6DA',
|
|
4318
4313
|
magenta: '#D81B60',
|
|
4319
|
-
|
|
4314
|
+
neutral: '#90A4AE',
|
|
4320
4315
|
olive: '#808000',
|
|
4321
|
-
|
|
4316
|
+
primary: '#0066cc',
|
|
4317
|
+
restore: '#B0BEC5',
|
|
4318
|
+
return: '#11438d',
|
|
4322
4319
|
slate: '#607D8B',
|
|
4320
|
+
success: '#0ba055',
|
|
4321
|
+
upload: '#5C6BC0', // 👈 Agregado: Índigo para contrastar limpiamente con download (naranja)
|
|
4322
|
+
view: '#00838F',
|
|
4323
|
+
warning: '#FF7043',
|
|
4323
4324
|
};
|
|
4324
4325
|
/** Tipos que necesitan un `[id]` mayor a 0 para poder mostrarse. */
|
|
4325
4326
|
const TYPES_REQUIRING_ID = [
|
|
@@ -4932,7 +4933,7 @@ const ACTION_CONFIG = {
|
|
|
4932
4933
|
details: {
|
|
4933
4934
|
label: 'Detalles',
|
|
4934
4935
|
icon: 'list',
|
|
4935
|
-
primeIcon: 'fa-solid fa-list-
|
|
4936
|
+
primeIcon: 'fa-solid fa-list-check',
|
|
4936
4937
|
colorToken: 'details',
|
|
4937
4938
|
tooltip: 'Detalle de registro',
|
|
4938
4939
|
},
|
|
@@ -4960,7 +4961,7 @@ const ACTION_CONFIG = {
|
|
|
4960
4961
|
download: {
|
|
4961
4962
|
label: 'Descargar',
|
|
4962
4963
|
icon: 'download',
|
|
4963
|
-
primeIcon: '
|
|
4964
|
+
primeIcon: 'fa-solid fa-cloud-arrow-down',
|
|
4964
4965
|
colorToken: 'download',
|
|
4965
4966
|
tooltip: 'Descargar archivo',
|
|
4966
4967
|
},
|
|
@@ -5001,12 +5002,8 @@ class FileComponent {
|
|
|
5001
5002
|
// --- Para el manejo de errores del formulario y debug ---
|
|
5002
5003
|
_control = null;
|
|
5003
5004
|
// Computed para el control de errores
|
|
5004
|
-
errorControl = computed(() => {
|
|
5005
|
-
return this._control;
|
|
5006
|
-
}, ...(ngDevMode ? [{ debugName: "errorControl" }] : /* istanbul ignore next */ []));
|
|
5007
|
-
// Signal para errores del control
|
|
5005
|
+
errorControl = computed(() => this._control, ...(ngDevMode ? [{ debugName: "errorControl" }] : /* istanbul ignore next */ []));
|
|
5008
5006
|
controlErrors = signal(null, ...(ngDevMode ? [{ debugName: "controlErrors" }] : /* istanbul ignore next */ []));
|
|
5009
|
-
// Estado del control
|
|
5010
5007
|
controlValid = signal(true, ...(ngDevMode ? [{ debugName: "controlValid" }] : /* istanbul ignore next */ []));
|
|
5011
5008
|
controlTouched = signal(false, ...(ngDevMode ? [{ debugName: "controlTouched" }] : /* istanbul ignore next */ []));
|
|
5012
5009
|
controlDirty = signal(false, ...(ngDevMode ? [{ debugName: "controlDirty" }] : /* istanbul ignore next */ []));
|
|
@@ -5022,33 +5019,44 @@ class FileComponent {
|
|
|
5022
5019
|
return false;
|
|
5023
5020
|
return this._control.errors?.['required'] ?? false;
|
|
5024
5021
|
}
|
|
5025
|
-
//
|
|
5022
|
+
// ============================================
|
|
5023
|
+
// COMPUTED PROPERTIES - LIMPIOS Y CLAROS
|
|
5024
|
+
// ============================================
|
|
5025
|
+
// ✅ Hay archivo guardado en BD (fuente: existingFileName)
|
|
5026
5026
|
hasExistingFile = computed(() => {
|
|
5027
5027
|
if (!this.isViewActive())
|
|
5028
5028
|
return false;
|
|
5029
|
-
const hasFile = !!this.existingFileName() && !this.isReplacing()
|
|
5030
|
-
if (this.debug() && this.isViewActive())
|
|
5031
|
-
this.log('hasExistingFile', {
|
|
5029
|
+
const hasFile = !!this.existingFileName() && !this.isReplacing();
|
|
5030
|
+
if (this.debug() && this.isViewActive()) {
|
|
5031
|
+
this.log('hasExistingFile', {
|
|
5032
|
+
hasFile,
|
|
5033
|
+
existingFileName: this.existingFileName(),
|
|
5034
|
+
isReplacing: this.isReplacing(),
|
|
5035
|
+
});
|
|
5036
|
+
}
|
|
5032
5037
|
return hasFile;
|
|
5033
5038
|
}, ...(ngDevMode ? [{ debugName: "hasExistingFile" }] : /* istanbul ignore next */ []));
|
|
5039
|
+
// ✅ Mostrar estado de edición (archivo guardado SIN archivo seleccionado)
|
|
5034
5040
|
showExistingFile = computed(() => {
|
|
5035
5041
|
if (!this.isViewActive())
|
|
5036
5042
|
return false;
|
|
5037
5043
|
const show = this.hasExistingFile() && !this.isReplacing();
|
|
5038
|
-
if (this.debug() && this.isViewActive())
|
|
5039
|
-
this.log('showExistingFile', {
|
|
5044
|
+
if (this.debug() && this.isViewActive()) {
|
|
5045
|
+
this.log('showExistingFile', {
|
|
5046
|
+
show,
|
|
5047
|
+
hasExistingFile: this.hasExistingFile(),
|
|
5048
|
+
isReplacing: this.isReplacing(),
|
|
5049
|
+
});
|
|
5050
|
+
}
|
|
5040
5051
|
return show;
|
|
5041
5052
|
}, ...(ngDevMode ? [{ debugName: "showExistingFile" }] : /* istanbul ignore next */ []));
|
|
5053
|
+
// ✅ El upload está habilitado solo si el padre no lo deshabilita
|
|
5042
5054
|
isFileUploadEnabled = computed(() => {
|
|
5043
5055
|
if (!this.isViewActive())
|
|
5044
5056
|
return false;
|
|
5045
|
-
|
|
5046
|
-
return false;
|
|
5047
|
-
const enabled = !this.hasExistingFile() || this.isReplacing();
|
|
5048
|
-
if (this.debug() && this.isViewActive())
|
|
5049
|
-
this.log('isFileUploadEnabled', { enabled });
|
|
5050
|
-
return enabled;
|
|
5057
|
+
return !this.disabled();
|
|
5051
5058
|
}, ...(ngDevMode ? [{ debugName: "isFileUploadEnabled" }] : /* istanbul ignore next */ []));
|
|
5059
|
+
// ✅ Botón de reemplazo deshabilitado
|
|
5052
5060
|
isReplaceButtonDisabled = computed(() => {
|
|
5053
5061
|
if (!this.isViewActive())
|
|
5054
5062
|
return true;
|
|
@@ -5058,6 +5066,7 @@ class FileComponent {
|
|
|
5058
5066
|
return true;
|
|
5059
5067
|
return false;
|
|
5060
5068
|
}, ...(ngDevMode ? [{ debugName: "isReplaceButtonDisabled" }] : /* istanbul ignore next */ []));
|
|
5069
|
+
// ✅ Tipo de archivo permitido para mostrar
|
|
5061
5070
|
allowedFileTypeLabel = computed(() => {
|
|
5062
5071
|
if (!this.isViewActive())
|
|
5063
5072
|
return 'archivo';
|
|
@@ -5112,11 +5121,11 @@ class FileComponent {
|
|
|
5112
5121
|
this.isViewActive.set(true);
|
|
5113
5122
|
if (this.debug()) {
|
|
5114
5123
|
console.log('[FileComponent] ✅ View activated');
|
|
5115
|
-
console.log('[FileComponent] 📋 Configuración
|
|
5124
|
+
console.log('[FileComponent] 📋 Configuración:', {
|
|
5116
5125
|
accept: this.accept(),
|
|
5117
5126
|
maxFileSize: this.maxFileSize(),
|
|
5118
5127
|
debug: this.debug(),
|
|
5119
|
-
|
|
5128
|
+
existingFileName: this.existingFileName(),
|
|
5120
5129
|
});
|
|
5121
5130
|
}
|
|
5122
5131
|
});
|
|
@@ -5124,183 +5133,101 @@ class FileComponent {
|
|
|
5124
5133
|
ngOnDestroy() {
|
|
5125
5134
|
this.isViewActive.set(false);
|
|
5126
5135
|
if (this.debug())
|
|
5127
|
-
console.log('[FileComponent] 🗑️
|
|
5136
|
+
console.log('[FileComponent] 🗑️ Destroyed');
|
|
5128
5137
|
}
|
|
5129
|
-
// ---
|
|
5138
|
+
// --- Validación de archivo ---
|
|
5130
5139
|
validateFile(file) {
|
|
5131
5140
|
if (this.debug()) {
|
|
5132
|
-
this.log('🔍 validateFile
|
|
5141
|
+
this.log('🔍 validateFile', {
|
|
5133
5142
|
fileName: file.name,
|
|
5134
5143
|
fileSize: file.size,
|
|
5135
|
-
fileType: file.type,
|
|
5136
5144
|
accept: this.accept(),
|
|
5137
5145
|
maxSize: this.maxFileSize(),
|
|
5138
5146
|
});
|
|
5139
5147
|
}
|
|
5140
|
-
// Validar tipo de archivo
|
|
5141
5148
|
const acceptStr = this.accept();
|
|
5142
5149
|
if (acceptStr) {
|
|
5143
5150
|
const acceptedExtensions = acceptStr
|
|
5144
5151
|
.split(',')
|
|
5145
5152
|
.map((ext) => ext.trim().toLowerCase());
|
|
5146
5153
|
const fileExtension = '.' + file.name.split('.').pop()?.toLowerCase();
|
|
5147
|
-
if (this.debug()) {
|
|
5148
|
-
this.log('🔍 validateFile - Verificando extensión', {
|
|
5149
|
-
fileExtension,
|
|
5150
|
-
acceptedExtensions,
|
|
5151
|
-
matches: acceptedExtensions.includes(fileExtension),
|
|
5152
|
-
});
|
|
5153
|
-
}
|
|
5154
5154
|
if (!acceptedExtensions.includes(fileExtension)) {
|
|
5155
5155
|
const detail = this.invalidDetail().replace('{0}', this.allowedFileTypeLabel());
|
|
5156
|
-
|
|
5157
|
-
if (this.debug())
|
|
5158
|
-
this.log('❌ validateFile - Tipo de archivo no permitido', {
|
|
5159
|
-
message,
|
|
5160
|
-
});
|
|
5161
|
-
return { valid: false, error: message };
|
|
5156
|
+
return { valid: false, error: `${this.invalidSummary()} ${detail}` };
|
|
5162
5157
|
}
|
|
5163
5158
|
}
|
|
5164
|
-
// Validar tamaño
|
|
5165
5159
|
const maxSizeBytes = this.maxFileSize() * 1024 * 1024;
|
|
5166
|
-
if (this.debug()) {
|
|
5167
|
-
this.log('🔍 validateFile - Verificando tamaño', {
|
|
5168
|
-
fileSize: file.size,
|
|
5169
|
-
maxSizeBytes,
|
|
5170
|
-
maxSizeMB: this.maxFileSize(),
|
|
5171
|
-
});
|
|
5172
|
-
}
|
|
5173
5160
|
if (file.size > maxSizeBytes) {
|
|
5174
5161
|
const detail = this.invalidSizeDetail().replace('{0}', `${this.maxFileSize()} MB`);
|
|
5175
|
-
|
|
5176
|
-
if (this.debug())
|
|
5177
|
-
this.log('❌ validateFile - Tamaño excedido', { message });
|
|
5178
|
-
return { valid: false, error: message };
|
|
5162
|
+
return { valid: false, error: `${this.invalidSizeSummary()} ${detail}` };
|
|
5179
5163
|
}
|
|
5180
5164
|
if (this.debug())
|
|
5181
|
-
this.log('✅ validateFile -
|
|
5165
|
+
this.log('✅ validateFile - Válido');
|
|
5182
5166
|
return { valid: true };
|
|
5183
5167
|
}
|
|
5184
|
-
// --- Métodos para el manejo de errores ---
|
|
5185
|
-
showError() {
|
|
5186
|
-
return !!(this._control && this._control.invalid && this._control.touched);
|
|
5187
|
-
}
|
|
5188
|
-
// Actualizar estado del control
|
|
5189
|
-
updateControlState() {
|
|
5190
|
-
if (this._control) {
|
|
5191
|
-
this.controlValid.set(this._control.valid);
|
|
5192
|
-
this.controlTouched.set(this._control.touched);
|
|
5193
|
-
this.controlDirty.set(this._control.dirty);
|
|
5194
|
-
this.controlErrors.set(this._control.errors);
|
|
5195
|
-
}
|
|
5196
|
-
}
|
|
5197
|
-
// Forzar recarga (para debug)
|
|
5198
|
-
forceReload() {
|
|
5199
|
-
if (this.debug()) {
|
|
5200
|
-
console.log('[FileComponent] 🔄 Force reload');
|
|
5201
|
-
if (this._control) {
|
|
5202
|
-
this._control.updateValueAndValidity();
|
|
5203
|
-
this.updateControlState();
|
|
5204
|
-
}
|
|
5205
|
-
this.cdr.detectChanges();
|
|
5206
|
-
}
|
|
5207
|
-
}
|
|
5208
5168
|
// --- Métodos públicos ---
|
|
5209
5169
|
onSelect(event) {
|
|
5210
|
-
const startTime = performance.now();
|
|
5211
5170
|
if (this.debug()) {
|
|
5212
|
-
this.log('📤 onSelect
|
|
5213
|
-
|
|
5214
|
-
|
|
5215
|
-
|
|
5171
|
+
this.log('📤 onSelect', {
|
|
5172
|
+
isReplacing: this.isReplacing(),
|
|
5173
|
+
hasExistingFile: this.hasExistingFile(),
|
|
5174
|
+
disabled: this.disabled(),
|
|
5216
5175
|
});
|
|
5217
5176
|
}
|
|
5218
|
-
if (!this.isViewActive()) {
|
|
5219
|
-
if (this.
|
|
5220
|
-
|
|
5221
|
-
return;
|
|
5222
|
-
}
|
|
5223
|
-
if (!this.isFileUploadEnabled()) {
|
|
5224
|
-
console.warn('[FileComponent] ⚠️ File upload is disabled');
|
|
5177
|
+
if (!this.isViewActive() || this.disabled()) {
|
|
5178
|
+
if (this.disabled())
|
|
5179
|
+
console.warn('[FileComponent] ⚠️ Disabled');
|
|
5225
5180
|
this.fileUpload()?.clear();
|
|
5226
5181
|
return;
|
|
5227
5182
|
}
|
|
5228
5183
|
const file = event.files?.[0] ?? null;
|
|
5229
5184
|
if (!file) {
|
|
5230
5185
|
if (this.debug())
|
|
5231
|
-
this.log('⚠️ No
|
|
5186
|
+
this.log('⚠️ No file selected');
|
|
5232
5187
|
return;
|
|
5233
5188
|
}
|
|
5234
5189
|
if (this.debug()) {
|
|
5235
|
-
this.log('📄
|
|
5190
|
+
this.log('📄 File selected', {
|
|
5236
5191
|
name: file.name,
|
|
5237
|
-
size: file.size,
|
|
5192
|
+
size: this.formatFileSize(file.size),
|
|
5238
5193
|
type: file.type,
|
|
5239
|
-
sizeFormatted: this.formatFileSize(file.size),
|
|
5240
5194
|
});
|
|
5241
5195
|
}
|
|
5242
|
-
// Validar archivo manualmente
|
|
5243
5196
|
const validation = this.validateFile(file);
|
|
5244
5197
|
if (!validation.valid) {
|
|
5245
|
-
// Archivo inválido - mostrar error y limpiar
|
|
5246
5198
|
this.errorMessage.set(validation.error || 'Archivo inválido');
|
|
5247
5199
|
this.fileUpload()?.clear();
|
|
5248
5200
|
this.value = null;
|
|
5249
5201
|
this.onChange(null);
|
|
5250
|
-
if (this.debug()) {
|
|
5251
|
-
this.log('❌ Archivo inválido - Limpiando selección', {
|
|
5252
|
-
error: validation.error,
|
|
5253
|
-
});
|
|
5254
|
-
}
|
|
5255
|
-
// Auto-ocultar error después de 5 segundos
|
|
5256
5202
|
setTimeout(() => {
|
|
5257
5203
|
this.errorMessage.set(null);
|
|
5258
5204
|
if (this.debug())
|
|
5259
|
-
this.log('⏰
|
|
5205
|
+
this.log('⏰ Error auto-ocultado');
|
|
5260
5206
|
}, 5000);
|
|
5261
|
-
// Actualizar estado del control
|
|
5262
5207
|
this.updateControlState();
|
|
5263
5208
|
return;
|
|
5264
5209
|
}
|
|
5265
|
-
// Archivo válido
|
|
5210
|
+
// ✅ Archivo válido
|
|
5266
5211
|
this.errorMessage.set(null);
|
|
5267
5212
|
this.value = file;
|
|
5268
5213
|
this.onChange(file);
|
|
5269
5214
|
this.markAsTouched();
|
|
5270
|
-
|
|
5215
|
+
// ✅ Salir del modo reemplazo si estaba activo
|
|
5216
|
+
if (this.isReplacing()) {
|
|
5271
5217
|
this.isReplacing.set(false);
|
|
5272
5218
|
if (this.debug())
|
|
5273
|
-
this.log('🔄 Reemplazo completado');
|
|
5219
|
+
this.log('🔄 Reemplazo completado', { file: file.name });
|
|
5274
5220
|
}
|
|
5275
5221
|
if (this.control) {
|
|
5276
5222
|
this.control.updateValueAndValidity();
|
|
5277
5223
|
}
|
|
5278
|
-
// Actualizar estado del control
|
|
5279
5224
|
this.updateControlState();
|
|
5280
|
-
const endTime = performance.now();
|
|
5281
|
-
if (this.debug()) {
|
|
5282
|
-
this.log(`⏱️ onSelect completado en ${(endTime - startTime).toFixed(2)}ms`);
|
|
5283
|
-
}
|
|
5284
|
-
}
|
|
5285
|
-
clear() {
|
|
5286
5225
|
if (this.debug())
|
|
5287
|
-
this.log('
|
|
5288
|
-
if (!this.isViewActive())
|
|
5289
|
-
return;
|
|
5290
|
-
this.fileUpload()?.clear();
|
|
5291
|
-
this.value = null;
|
|
5292
|
-
this.errorMessage.set(null);
|
|
5293
|
-
this.onChange(null);
|
|
5294
|
-
this.markAsTouched();
|
|
5295
|
-
if (this.control)
|
|
5296
|
-
this.control.updateValueAndValidity();
|
|
5297
|
-
this.updateControlState();
|
|
5298
|
-
if (this.debug())
|
|
5299
|
-
this.log('✅ Limpieza completada');
|
|
5226
|
+
this.log('⏱️ onSelect completado');
|
|
5300
5227
|
}
|
|
5301
|
-
|
|
5228
|
+
clear() {
|
|
5302
5229
|
if (this.debug())
|
|
5303
|
-
this.log('🧹 clearFile()
|
|
5230
|
+
this.log('🧹 clearFile()');
|
|
5304
5231
|
if (!this.isViewActive())
|
|
5305
5232
|
return;
|
|
5306
5233
|
this.fileUpload()?.clear();
|
|
@@ -5314,46 +5241,23 @@ class FileComponent {
|
|
|
5314
5241
|
if (this.debug())
|
|
5315
5242
|
this.log('✅ Archivo limpiado');
|
|
5316
5243
|
}
|
|
5317
|
-
|
|
5318
|
-
if (!this.isViewActive())
|
|
5319
|
-
return;
|
|
5320
|
-
if (this.debug()) {
|
|
5321
|
-
this.log('✍️ writeValue', {
|
|
5322
|
-
value: value?.name || null,
|
|
5323
|
-
size: value?.size ? this.formatFileSize(value.size) : null,
|
|
5324
|
-
});
|
|
5325
|
-
}
|
|
5326
|
-
this.value = value;
|
|
5327
|
-
}
|
|
5328
|
-
registerOnChange(fn) {
|
|
5329
|
-
if (this.debug())
|
|
5330
|
-
this.log('📝 registerOnChange');
|
|
5331
|
-
this.onChange = fn;
|
|
5332
|
-
}
|
|
5333
|
-
registerOnTouched(fn) {
|
|
5334
|
-
if (this.debug())
|
|
5335
|
-
this.log('📝 registerOnTouched');
|
|
5336
|
-
this.onTouched = fn;
|
|
5337
|
-
}
|
|
5338
|
-
setDisabledState(isDisabled) {
|
|
5339
|
-
if (!this.isViewActive())
|
|
5340
|
-
return;
|
|
5244
|
+
startReplace() {
|
|
5341
5245
|
if (this.debug()) {
|
|
5342
|
-
this.log('
|
|
5343
|
-
|
|
5344
|
-
|
|
5246
|
+
this.log('🔄 startReplace', {
|
|
5247
|
+
hasExistingFile: this.hasExistingFile(),
|
|
5248
|
+
existingFileName: this.existingFileName(),
|
|
5345
5249
|
});
|
|
5346
5250
|
}
|
|
5347
|
-
this.disabled.set(isDisabled);
|
|
5348
|
-
}
|
|
5349
|
-
startReplace() {
|
|
5350
|
-
if (this.debug())
|
|
5351
|
-
this.log('🔄 startReplace - Iniciando reemplazo');
|
|
5352
5251
|
if (!this.isViewActive())
|
|
5353
5252
|
return;
|
|
5354
5253
|
if (this.disabled()) {
|
|
5355
5254
|
if (this.debug())
|
|
5356
|
-
this.log('⛔ Reemplazo cancelado -
|
|
5255
|
+
this.log('⛔ Reemplazo cancelado - disabled');
|
|
5256
|
+
return;
|
|
5257
|
+
}
|
|
5258
|
+
if (!this.hasExistingFile()) {
|
|
5259
|
+
if (this.debug())
|
|
5260
|
+
this.log('⛔ Reemplazo cancelado - no hay archivo existente');
|
|
5357
5261
|
return;
|
|
5358
5262
|
}
|
|
5359
5263
|
this.fileUpload()?.clear();
|
|
@@ -5366,7 +5270,7 @@ class FileComponent {
|
|
|
5366
5270
|
}
|
|
5367
5271
|
cancelReplace() {
|
|
5368
5272
|
if (this.debug())
|
|
5369
|
-
this.log('❌ cancelReplace
|
|
5273
|
+
this.log('❌ cancelReplace');
|
|
5370
5274
|
if (!this.isViewActive())
|
|
5371
5275
|
return;
|
|
5372
5276
|
this.isReplacing.set(false);
|
|
@@ -5380,29 +5284,87 @@ class FileComponent {
|
|
|
5380
5284
|
}
|
|
5381
5285
|
choose(event, chooseCallback) {
|
|
5382
5286
|
if (this.debug())
|
|
5383
|
-
this.log('🔍 choose - Abriendo selector
|
|
5287
|
+
this.log('🔍 choose - Abriendo selector');
|
|
5384
5288
|
chooseCallback();
|
|
5385
5289
|
}
|
|
5290
|
+
// --- ControlValueAccessor ---
|
|
5291
|
+
writeValue(value) {
|
|
5292
|
+
if (!this.isViewActive())
|
|
5293
|
+
return;
|
|
5294
|
+
if (this.debug())
|
|
5295
|
+
this.log('✍️ writeValue', { value: value?.name || null });
|
|
5296
|
+
this.value = value;
|
|
5297
|
+
}
|
|
5298
|
+
registerOnChange(fn) {
|
|
5299
|
+
if (this.debug())
|
|
5300
|
+
this.log('📝 registerOnChange');
|
|
5301
|
+
this.onChange = fn;
|
|
5302
|
+
}
|
|
5303
|
+
registerOnTouched(fn) {
|
|
5304
|
+
if (this.debug())
|
|
5305
|
+
this.log('📝 registerOnTouched');
|
|
5306
|
+
this.onTouched = fn;
|
|
5307
|
+
}
|
|
5308
|
+
setDisabledState(isDisabled) {
|
|
5309
|
+
if (!this.isViewActive())
|
|
5310
|
+
return;
|
|
5311
|
+
if (this.debug())
|
|
5312
|
+
this.log('🔒 setDisabledState', { isDisabled });
|
|
5313
|
+
this.disabled.set(isDisabled);
|
|
5314
|
+
}
|
|
5315
|
+
// --- Helpers ---
|
|
5386
5316
|
formatFileSize(bytes) {
|
|
5387
5317
|
if (!bytes)
|
|
5388
5318
|
return '';
|
|
5389
5319
|
const sizes = ['B', 'KB', 'MB', 'GB'];
|
|
5390
5320
|
const i = Math.floor(Math.log(bytes) / Math.log(1024));
|
|
5391
|
-
|
|
5392
|
-
|
|
5321
|
+
return `${(bytes / Math.pow(1024, i)).toFixed(i > 0 ? 1 : 0)} ${sizes[i]}`;
|
|
5322
|
+
}
|
|
5323
|
+
showError() {
|
|
5324
|
+
return !!(this._control && this._control.invalid && this._control.touched);
|
|
5325
|
+
}
|
|
5326
|
+
updateControlState() {
|
|
5327
|
+
if (this._control) {
|
|
5328
|
+
this.controlValid.set(this._control.valid);
|
|
5329
|
+
this.controlTouched.set(this._control.touched);
|
|
5330
|
+
this.controlDirty.set(this._control.dirty);
|
|
5331
|
+
this.controlErrors.set(this._control.errors);
|
|
5332
|
+
}
|
|
5333
|
+
}
|
|
5334
|
+
// ✅ Método para diagnóstico (solo debug)
|
|
5335
|
+
diagnoseState() {
|
|
5336
|
+
if (this.debug()) {
|
|
5337
|
+
console.log('🔍 === DIAGNÓSTICO ===');
|
|
5338
|
+
console.log('isReplacing:', this.isReplacing());
|
|
5339
|
+
console.log('existingFileName:', this.existingFileName());
|
|
5340
|
+
console.log('hasExistingFile:', this.hasExistingFile());
|
|
5341
|
+
console.log('showExistingFile:', this.showExistingFile());
|
|
5342
|
+
console.log('isFileUploadEnabled:', this.isFileUploadEnabled());
|
|
5343
|
+
console.log('isReplaceButtonDisabled:', this.isReplaceButtonDisabled());
|
|
5344
|
+
console.log('value:', this.value);
|
|
5345
|
+
console.log('disabled:', this.disabled());
|
|
5346
|
+
console.log('isRequired:', this.isRequired());
|
|
5347
|
+
console.log('🔍 === FIN ===');
|
|
5348
|
+
}
|
|
5349
|
+
}
|
|
5350
|
+
forceReload() {
|
|
5351
|
+
if (this.debug()) {
|
|
5352
|
+
console.log('[FileComponent] 🔄 Force reload');
|
|
5353
|
+
if (this._control) {
|
|
5354
|
+
this._control.updateValueAndValidity();
|
|
5355
|
+
this.updateControlState();
|
|
5356
|
+
}
|
|
5357
|
+
this.cdr.detectChanges();
|
|
5358
|
+
}
|
|
5393
5359
|
}
|
|
5394
5360
|
// --- Validación ---
|
|
5395
5361
|
validate(control) {
|
|
5396
|
-
const startTime = performance.now();
|
|
5397
5362
|
this._control = control;
|
|
5398
5363
|
this.control = control;
|
|
5399
|
-
if (!this.isViewActive())
|
|
5400
|
-
if (this.debug())
|
|
5401
|
-
this.log('⚠️ validate - Componente no activo');
|
|
5364
|
+
if (!this.isViewActive())
|
|
5402
5365
|
return null;
|
|
5403
|
-
}
|
|
5404
5366
|
if (this.debug()) {
|
|
5405
|
-
this.log('🔍 validate
|
|
5367
|
+
this.log('🔍 validate', {
|
|
5406
5368
|
isRequired: this.isRequired(),
|
|
5407
5369
|
hasExistingFile: this.hasExistingFile(),
|
|
5408
5370
|
isReplacing: this.isReplacing(),
|
|
@@ -5411,39 +5373,18 @@ class FileComponent {
|
|
|
5411
5373
|
errorMessage: this.errorMessage(),
|
|
5412
5374
|
});
|
|
5413
5375
|
}
|
|
5414
|
-
// Actualizar estado del control
|
|
5415
5376
|
this.updateControlState();
|
|
5416
|
-
// Si hay un mensaje de error, consideramos que la validación falla
|
|
5417
5377
|
if (this.errorMessage()) {
|
|
5418
|
-
if (this.debug())
|
|
5419
|
-
this.log('❌ validate - Error: Hay un mensaje de error activo');
|
|
5420
5378
|
return { invalidFile: true };
|
|
5421
5379
|
}
|
|
5422
5380
|
if (!this.isRequired()) {
|
|
5423
|
-
if (this.debug())
|
|
5424
|
-
this.log('✅ validate - No requerido, pasa validación');
|
|
5425
5381
|
return null;
|
|
5426
5382
|
}
|
|
5427
|
-
|
|
5428
|
-
|
|
5429
|
-
this.log('✅ validate - Archivo existente, pasa validación');
|
|
5383
|
+
// ✅ Pasa si hay archivo guardado O hay archivo seleccionado
|
|
5384
|
+
if (this.hasExistingFile() || this.value) {
|
|
5430
5385
|
return null;
|
|
5431
5386
|
}
|
|
5432
|
-
|
|
5433
|
-
if (this.debug())
|
|
5434
|
-
this.log('❌ validate - Error: Reemplazando pero sin archivo');
|
|
5435
|
-
return { required: true };
|
|
5436
|
-
}
|
|
5437
|
-
if (!this.hasExistingFile() && !this.value) {
|
|
5438
|
-
if (this.debug())
|
|
5439
|
-
this.log('❌ validate - Error: Sin archivo seleccionado');
|
|
5440
|
-
return { required: true };
|
|
5441
|
-
}
|
|
5442
|
-
const endTime = performance.now();
|
|
5443
|
-
if (this.debug()) {
|
|
5444
|
-
this.log(`✅ validate - Validación exitosa en ${(endTime - startTime).toFixed(2)}ms`);
|
|
5445
|
-
}
|
|
5446
|
-
return null;
|
|
5387
|
+
return { required: true };
|
|
5447
5388
|
}
|
|
5448
5389
|
// --- Privados ---
|
|
5449
5390
|
onChange = (_) => { };
|
|
@@ -5453,7 +5394,7 @@ class FileComponent {
|
|
|
5453
5394
|
this.touched = true;
|
|
5454
5395
|
this.onTouched();
|
|
5455
5396
|
if (this.debug())
|
|
5456
|
-
this.log('👆 markAsTouched
|
|
5397
|
+
this.log('👆 markAsTouched');
|
|
5457
5398
|
}
|
|
5458
5399
|
}
|
|
5459
5400
|
log(method, data) {
|
|
@@ -5471,7 +5412,7 @@ class FileComponent {
|
|
|
5471
5412
|
useExisting: forwardRef(() => FileComponent),
|
|
5472
5413
|
multi: true,
|
|
5473
5414
|
},
|
|
5474
|
-
], 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 flex-col gap-1\">\r\n <div class=\"flex items-center gap-2\">\r\n <p-fileUpload\r\n fluid\r\n #fileUpload\r\n chooseIcon=\"fa-solid fa-file-arrow-up\"\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()} ${allowedFileTypeLabel()}`\"\r\n [tooltipPosition]=\"tooltipPositionOverride()\"\r\n >\r\n <ng-template\r\n #header\r\n let-files\r\n let-chooseCallback=\"chooseCallback\"\r\n let-clearCallback=\"clearCallback\"\r\n >\r\n <!-- Mostrar el bot\u00F3n de upload SOLO si NO hay archivo seleccionado -->\r\n @if (!files || files.length === 0) {\r\n <p-button\r\n (onClick)=\"choose($event, chooseCallback)\"\r\n icon=\"fa-solid fa-cloud-arrow-up\"\r\n [rounded]=\"true\"\r\n [outlined]=\"true\"\r\n [disabled]=\"!isFileUploadEnabled()\"\r\n />\r\n }\r\n\r\n <span class=\"file-upload-placeholder\">\r\n <i class=\"fa-regular fa-file-lines placeholder-icon\"></i>\r\n <span class=\"placeholder-text\">\r\n @if (files && files.length > 0) {\r\n <span class=\"file-selected\">\r\n <i class=\"fa-regular fa-file-pdf file-icon\"></i>\r\n {{ files[0]?.name }}\r\n <span class=\"file-size\"\r\n >({{ formatFileSize(files[0]?.size) }})</span\r\n >\r\n </span>\r\n } @else if (allowedFileTypeLabel() !== \"archivo\") {\r\n <span class=\"empty-warning\">Ning\u00FAn</span>\r\n <span class=\"file-type empty-warning-type\">{{\r\n allowedFileTypeLabel()\r\n }}</span>\r\n <span class=\"empty-warning\">seleccionado</span>\r\n } @else {\r\n <span class=\"empty-warning\">Ning\u00FAn archivo seleccionado</span>\r\n }\r\n </span>\r\n </span>\r\n\r\n <!-- Mostrar bot\u00F3n de limpiar SOLO si hay archivo seleccionado -->\r\n @if (files && files.length > 0) {\r\n <p-button\r\n icon=\"fa-solid fa-xmark\"\r\n [rounded]=\"true\"\r\n [outlined]=\"true\"\r\n (onClick)=\"clearFile()\"\r\n [disabled]=\"!isFileUploadEnabled()\"\r\n styleClass=\"clear-button\"\r\n />\r\n }\r\n </ng-template>\r\n <!-- Ocultar la vista previa por defecto -->\r\n <ng-template #content></ng-template>\r\n <ng-template #file></ng-template>\r\n </p-fileUpload>\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 <!-- Mensajes de error (validaci\u00F3n de PrimeNG) -->\r\n @if (errorMessage()) {\r\n <div class=\"file-error-message\">\r\n <i class=\"pi pi-exclamation-circle\"></i>\r\n {{ errorMessage() }}\r\n </div>\r\n }\r\n\r\n <!-- Mensaje de error del formulario (dsx-message-error) -->\r\n @if (showError() && errorControl()) {\r\n <dsx-message-error [control]=\"errorControl()\" />\r\n }\r\n </div>\r\n}\r\n\r\n<!-- Panel de Debug -->\r\n@if (debug() && isDevMode) {\r\n <div class=\"debug-panel\">\r\n <div class=\"debug-header\">\r\n <div class=\"debug-info\">\r\n <strong>\uD83D\uDD0D Debug File Upload:</strong>\r\n <span class=\"debug-item\"\r\n >Archivo: {{ value ? value.name : \"Ninguno\" }}</span\r\n >\r\n <span class=\"debug-item\"\r\n >Tama\u00F1o: {{ value ? formatFileSize(value.size) : \"-\" }}</span\r\n >\r\n <span class=\"debug-item\">Tipo: {{ value ? value.type : \"-\" }}</span>\r\n <span\r\n class=\"debug-item\"\r\n [style.color]=\"controlValid() ? '#10b981' : '#ef4444'\"\r\n >\r\n {{ controlValid() ? \"\u2705 V\u00E1lido\" : \"\u274C Inv\u00E1lido\" }}\r\n </span>\r\n <!-- Cambiar esta l\u00EDnea en el panel de debug -->\r\n <span class=\"debug-item\"\r\n >Required: {{ isRequired() ? \"\u2705\" : \"\u274C\" }}</span\r\n >\r\n <span class=\"debug-item\"\r\n >Reemplazando: {{ isReplacing() ? \"\u2705\" : \"\u274C\" }}</span\r\n >\r\n </div>\r\n <div class=\"debug-actions\">\r\n <button (click)=\"forceReload()\" class=\"debug-btn\" type=\"button\">\r\n \uD83D\uDD04 Recargar\r\n </button>\r\n <button (click)=\"clearFile()\" class=\"debug-btn\" type=\"button\">\r\n \uD83E\uDDF9 Limpiar\r\n </button>\r\n </div>\r\n </div>\r\n @if (errorMessage()) {\r\n <div class=\"debug-error\">\r\n <strong>\u26A0\uFE0F Error activo:</strong> {{ errorMessage() }}\r\n </div>\r\n }\r\n @if (controlErrors()) {\r\n <div class=\"debug-errors\">\r\n <strong>\u274C Errores del formulario:</strong>\r\n <pre>{{ controlErrors() | json }}</pre>\r\n </div>\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%}::ng-deep .p-fileupload .p-fileupload-header{display:flex!important;align-items:center!important;gap:.75rem!important;padding:0!important;border:none!important;background:transparent!important}::ng-deep .p-fileupload .p-fileupload-header .p-button{background:transparent!important;border:2px dashed #d1d5db!important;border-radius:8px!important;padding:.5rem 1rem!important;margin:.5rem!important;min-height:40px!important;min-width:40px!important;transition:all .25s ease!important;color:#6b7280!important}::ng-deep .p-fileupload .p-fileupload-header .p-button:not(:disabled):hover{border-color:#3b82f6!important;background:#eff6ff!important;box-shadow:0 0 0 3px #3b82f61a!important;color:#3b82f6!important}::ng-deep .p-fileupload .p-fileupload-header .p-button:disabled{opacity:.5!important;cursor:not-allowed!important;border-color:#e5e7eb!important;color:#9ca3af!important}::ng-deep .p-fileupload .p-fileupload-header .p-button .p-button-icon{font-size:1.2rem!important;transition:color .25s ease!important}.file-upload-placeholder{display:flex;align-items:center;gap:.75rem;pointer-events:none;white-space:nowrap;padding:0 .5rem}.placeholder-icon{font-size:1.35rem;color:#94a3b8;transition:all .3s ease}.placeholder-text{color:#94a3b8;font-size:.875rem;font-weight:400;transition:all .3s ease;letter-spacing:.01em}.placeholder-text .file-type{color:#64748b;font-size:.8rem;font-weight:600;transition:all .3s ease;letter-spacing:.03em;text-transform:uppercase;background:#f1f5f9;padding:.1rem .4rem;border-radius:4px;margin:0 .1rem}.placeholder-text .empty-warning{color:#d97706;font-weight:500;transition:color .3s ease}.placeholder-text .file-type.empty-warning-type{color:#b45309;background:#fef3c7;font-weight:600}.file-selected{display:flex;align-items:center;gap:.5rem;color:#1f2937;font-weight:500;font-size:.85rem}.file-selected .file-icon{font-size:1.2rem;color:#bb1589}.file-selected .file-size{color:#9ca3af;font-weight:400;font-size:.75rem;margin-left:.25rem}::ng-deep .p-fileupload .p-fileupload-header:has(.p-button:not(:disabled):hover) .placeholder-icon{color:#3b82f6}::ng-deep .p-fileupload .p-fileupload-header:has(.p-button:not(:disabled):hover) .placeholder-text{color:#1f2937}::ng-deep .p-fileupload .p-fileupload-header:has(.p-button:not(:disabled):hover) .file-type{color:#2563eb;background:#dbeafe}::ng-deep .p-fileupload .p-fileupload-header:has(.p-button:not(:disabled):hover) .placeholder-text .empty-warning{color:#2563eb}::ng-deep .p-fileupload .p-fileupload-header:has(.p-button:not(:disabled):hover) .file-type.empty-warning-type{color:#2563eb;background:#dbeafe}::ng-deep .p-fileupload .p-fileupload-buttonbar{display:none!important}::ng-deep .p-fileupload .p-fileupload-content{padding:0!important;border:none!important;background:transparent!important}::ng-deep .p-button.clear-button{background:transparent!important;border:none!important;border-radius:8px!important;padding:.5rem!important;min-width:40px!important;height:40px!important;transition:all .25s ease!important;display:flex!important;align-items:center!important;justify-content:center!important;box-shadow:none!important}::ng-deep .p-fileupload .p-fileupload-header .p-button.clear-button:not(:disabled):hover{background:none!important;border:none!important;box-shadow:none!important;transform:scale(1.05)!important}::ng-deep .p-button.clear-button .p-button-icon{color:#6b7280!important;font-size:1.1rem!important;transition:all .25s ease!important}::ng-deep .p-button.clear-button:not(:disabled):hover .p-button-icon{color:#ef4444!important}::ng-deep .p-button.clear-button:disabled{opacity:.5!important;cursor:not-allowed!important}.file-error-message{display:flex;align-items:center;gap:.5rem;color:#dc2626;font-size:.875rem;font-weight:400;padding:.25rem .75rem;background:#fef2f2;border-radius:6px;border:1px solid #fecaca;animation:slideDown .3s ease}.file-error-message i{font-size:1rem;color:#dc2626;flex-shrink:0}@keyframes slideDown{0%{opacity:0;transform:translateY(-10px)}to{opacity:1;transform:translateY(0)}}.debug-panel{margin-top:8px;font-size:11px;color:#374151;background:#f8fafc;padding:8px 12px;border-radius:6px;font-family:monospace;border:1px solid #e2e8f0;width:100%}.debug-header{display:flex;justify-content:space-between;align-items:center;gap:8px;flex-wrap:wrap}.debug-info{display:flex;align-items:center;gap:12px;flex-wrap:wrap}.debug-item{font-size:11px;color:#475569}.debug-item strong{color:#1e293b}.debug-actions{display:flex;gap:6px}.debug-btn{font-size:10px;padding:2px 10px;border-radius:4px;border:1px solid #cbd5e1;background:#fff;cursor:pointer;transition:all .2s ease;color:#475569;font-family:monospace}.debug-btn:hover{background:#f1f5f9;border-color:#94a3b8}.debug-error,.debug-errors{margin-top:6px;padding:4px 8px;background:#fef2f2;border-radius:4px;color:#dc2626;font-size:11px;border:1px solid #fecaca}.debug-errors pre{margin:4px 0 0;font-size:10px;color:#991b1b;white-space:pre-wrap;word-break:break-all}@media(max-width:640px){.placeholder-icon{font-size:1.1rem!important}.placeholder-text{font-size:.75rem!important}.placeholder-text .file-type{font-size:.7rem!important;padding:.05rem .3rem!important}.file-selected{font-size:.75rem!important}.file-selected .file-icon{font-size:1rem!important}.file-selected .file-size{font-size:.65rem!important}::ng-deep .p-fileupload .p-fileupload-header .p-button{padding:.4rem .75rem!important;min-height:34px!important;min-width:34px!important}::ng-deep .p-button.clear-button{min-width:34px!important;height:34px!important}.file-error-message{font-size:.75rem!important;padding:.2rem .5rem!important}.debug-panel{font-size:10px;padding:6px 8px}.debug-item{font-size:10px}.debug-btn{font-size:9px;padding:2px 6px}}\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"] }, { kind: "component", type: AppMessageErrorComponent, selector: "dsx-message-error", inputs: ["control", "form", "debugMode"] }, { kind: "pipe", type: JsonPipe, name: "json" }] });
|
|
5415
|
+
], 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 flex-col gap-1\">\r\n <div class=\"flex items-center gap-2\">\r\n <p-fileUpload\r\n fluid\r\n #fileUpload\r\n chooseIcon=\"fa-solid fa-file-arrow-up\"\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()} ${allowedFileTypeLabel()}`\"\r\n [tooltipPosition]=\"tooltipPositionOverride()\"\r\n >\r\n <ng-template\r\n #header\r\n let-files\r\n let-chooseCallback=\"chooseCallback\"\r\n let-clearCallback=\"clearCallback\"\r\n >\r\n <!-- Mostrar el bot\u00F3n de upload SOLO si NO hay archivo seleccionado -->\r\n @if (!files || files.length === 0) {\r\n <p-button\r\n (onClick)=\"choose($event, chooseCallback)\"\r\n icon=\"fa-solid fa-cloud-arrow-up\"\r\n [rounded]=\"true\"\r\n [outlined]=\"true\"\r\n [disabled]=\"!isFileUploadEnabled()\"\r\n />\r\n }\r\n\r\n <span class=\"file-upload-placeholder\">\r\n <i class=\"fa-regular fa-file-lines placeholder-icon\"></i>\r\n <span class=\"placeholder-text\">\r\n @if (files && files.length > 0) {\r\n <span class=\"file-selected\">\r\n <i class=\"fa-regular fa-file-pdf file-icon\"></i>\r\n {{ files[0]?.name }}\r\n <span class=\"file-size\"\r\n >({{ formatFileSize(files[0]?.size) }})</span\r\n >\r\n </span>\r\n } @else if (allowedFileTypeLabel() !== \"archivo\") {\r\n <span class=\"empty-warning\">Ning\u00FAn</span>\r\n <span class=\"file-type empty-warning-type\">{{\r\n allowedFileTypeLabel()\r\n }}</span>\r\n <span class=\"empty-warning\">seleccionado</span>\r\n } @else {\r\n <span class=\"empty-warning\">Ning\u00FAn archivo seleccionado</span>\r\n }\r\n </span>\r\n </span>\r\n\r\n <!-- Mostrar bot\u00F3n de limpiar SOLO si hay archivo seleccionado -->\r\n @if (files && files.length > 0) {\r\n <p-button\r\n icon=\"fa-solid fa-xmark\"\r\n [rounded]=\"true\"\r\n [outlined]=\"true\"\r\n (onClick)=\"clear()\"\r\n [disabled]=\"!isFileUploadEnabled()\"\r\n styleClass=\"clear-button\"\r\n />\r\n }\r\n </ng-template>\r\n <!-- Ocultar la vista previa por defecto -->\r\n <ng-template #content></ng-template>\r\n <ng-template #file></ng-template>\r\n </p-fileUpload>\r\n\r\n <!-- Bot\u00F3n para cancelar remplazo -->\r\n @if (isReplacing()) {\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 <!-- Mensajes de error (validaci\u00F3n de PrimeNG) -->\r\n @if (errorMessage()) {\r\n <div class=\"file-error-message\">\r\n <i class=\"pi pi-exclamation-circle\"></i>\r\n {{ errorMessage() }}\r\n </div>\r\n }\r\n\r\n <!-- Mensaje de error del formulario (dsx-message-error) -->\r\n @if (showError() && errorControl()) {\r\n <dsx-message-error [control]=\"errorControl()\" />\r\n }\r\n </div>\r\n}\r\n\r\n<!-- Panel de Debug -->\r\n@if (debug() && isDevMode) {\r\n <div class=\"debug-panel\">\r\n <div class=\"debug-header\">\r\n <div class=\"debug-info\">\r\n <strong>\uD83D\uDD0D Debug File Upload:</strong>\r\n <span class=\"debug-item\"\r\n >Archivo: {{ value ? value.name : \"Ninguno\" }}</span\r\n >\r\n <span class=\"debug-item\"\r\n >Tama\u00F1o: {{ value ? formatFileSize(value.size) : \"-\" }}</span\r\n >\r\n <span class=\"debug-item\">Tipo: {{ value ? value.type : \"-\" }}</span>\r\n <span\r\n class=\"debug-item\"\r\n [style.color]=\"controlValid() ? '#10b981' : '#ef4444'\"\r\n >\r\n {{ controlValid() ? \"\u2705 V\u00E1lido\" : \"\u274C Inv\u00E1lido\" }}\r\n </span>\r\n <span class=\"debug-item\"\r\n >Required: {{ isRequired() ? \"\u2705\" : \"\u274C\" }}</span\r\n >\r\n <span class=\"debug-item\"\r\n >Reemplazando: {{ isReplacing() ? \"\u2705\" : \"\u274C\" }}</span\r\n >\r\n <!-- === ESTADOS ADICIONALES PARA DEBUG === -->\r\n <span\r\n class=\"debug-item\"\r\n style=\"background: #f0f0f0; padding: 0 6px; border-radius: 4px\"\r\n >\r\n \uD83D\uDCCA hasExistingFile: {{ hasExistingFile() ? \"\u2705\" : \"\u274C\" }}\r\n </span>\r\n <span\r\n class=\"debug-item\"\r\n style=\"background: #f0f0f0; padding: 0 6px; border-radius: 4px\"\r\n >\r\n \uD83D\uDCCA existingFileName: {{ existingFileName() || \"null\" }}\r\n </span>\r\n <span\r\n class=\"debug-item\"\r\n style=\"background: #f0f0f0; padding: 0 6px; border-radius: 4px\"\r\n >\r\n \uD83D\uDCCA isFileUploadEnabled: {{ isFileUploadEnabled() ? \"\u2705\" : \"\u274C\" }}\r\n </span>\r\n <span\r\n class=\"debug-item\"\r\n style=\"background: #f0f0f0; padding: 0 6px; border-radius: 4px\"\r\n >\r\n \uD83D\uDCCA showExistingFile: {{ showExistingFile() ? \"\u2705\" : \"\u274C\" }}\r\n </span>\r\n <span\r\n class=\"debug-item\"\r\n style=\"background: #f0f0f0; padding: 0 6px; border-radius: 4px\"\r\n >\r\n \uD83D\uDCCA value: {{ value ? value.name : \"null\" }}\r\n </span>\r\n </div>\r\n <div class=\"debug-actions\">\r\n <button (click)=\"forceReload()\" class=\"debug-btn\" type=\"button\">\r\n \uD83D\uDD04 Recargar\r\n </button>\r\n <button (click)=\"clear()\" class=\"debug-btn\" type=\"button\">\r\n \uD83E\uDDF9 Limpiar\r\n </button>\r\n <button (click)=\"diagnoseState()\" class=\"debug-btn\" type=\"button\">\r\n \uD83D\uDCCA Diagn\u00F3stico\r\n </button>\r\n </div>\r\n </div>\r\n @if (errorMessage()) {\r\n <div class=\"debug-error\">\r\n <strong>\u26A0\uFE0F Error activo:</strong> {{ errorMessage() }}\r\n </div>\r\n }\r\n @if (controlErrors()) {\r\n <div class=\"debug-errors\">\r\n <strong>\u274C Errores del formulario:</strong>\r\n <pre>{{ controlErrors() | json }}</pre>\r\n </div>\r\n }\r\n </div>\r\n}\r\n", styles: [".file-name{display:inline-block;font-weight:500;color:#1d8678;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:100%}::ng-deep .p-fileupload .p-fileupload-header{display:flex!important;align-items:center!important;gap:.75rem!important;padding:0!important;border:none!important;background:transparent!important}::ng-deep .p-fileupload .p-fileupload-header .p-button{background:transparent!important;border:2px dashed #d1d5db!important;border-radius:8px!important;padding:.5rem 1rem!important;margin:.5rem!important;min-height:40px!important;min-width:40px!important;transition:all .25s ease!important;color:#6b7280!important}::ng-deep .p-fileupload .p-fileupload-header .p-button:not(:disabled):hover{border-color:#3b82f6!important;background:#eff6ff!important;box-shadow:0 0 0 3px #3b82f61a!important;color:#3b82f6!important}::ng-deep .p-fileupload .p-fileupload-header .p-button:disabled{opacity:.5!important;cursor:not-allowed!important;border-color:#e5e7eb!important;color:#9ca3af!important}::ng-deep .p-fileupload .p-fileupload-header .p-button .p-button-icon{font-size:1.2rem!important;transition:color .25s ease!important}.file-upload-placeholder{display:flex;align-items:center;gap:.75rem;pointer-events:none;white-space:nowrap;padding:0 .5rem}.placeholder-icon{font-size:1.35rem;color:#94a3b8;transition:all .3s ease}.placeholder-text{color:#94a3b8;font-size:.875rem;font-weight:400;transition:all .3s ease;letter-spacing:.01em}.placeholder-text .file-type{color:#64748b;font-size:.8rem;font-weight:600;transition:all .3s ease;letter-spacing:.03em;text-transform:uppercase;background:#f1f5f9;padding:.1rem .4rem;border-radius:4px;margin:0 .1rem}.placeholder-text .empty-warning{color:#d97706;font-weight:500;transition:color .3s ease}.placeholder-text .file-type.empty-warning-type{color:#b45309;background:#fef3c7;font-weight:600}.file-selected{display:flex;align-items:center;gap:.5rem;color:#1f2937;font-weight:500;font-size:.85rem}.file-selected .file-icon{font-size:1.2rem;color:#22994a}.file-selected .file-size{color:#9ca3af;font-weight:400;font-size:.75rem;margin-left:.25rem}::ng-deep .p-fileupload .p-fileupload-header:has(.p-button:not(:disabled):hover) .placeholder-icon{color:#3b82f6}::ng-deep .p-fileupload .p-fileupload-header:has(.p-button:not(:disabled):hover) .placeholder-text{color:#1f2937}::ng-deep .p-fileupload .p-fileupload-header:has(.p-button:not(:disabled):hover) .file-type{color:#2563eb;background:#dbeafe}::ng-deep .p-fileupload .p-fileupload-header:has(.p-button:not(:disabled):hover) .placeholder-text .empty-warning{color:#2563eb}::ng-deep .p-fileupload .p-fileupload-header:has(.p-button:not(:disabled):hover) .file-type.empty-warning-type{color:#2563eb;background:#dbeafe}::ng-deep .p-fileupload .p-fileupload-buttonbar{display:none!important}::ng-deep .p-fileupload .p-fileupload-content{padding:0!important;border:none!important;background:transparent!important}::ng-deep .p-button.clear-button{background:transparent!important;border:none!important;border-radius:8px!important;padding:.5rem!important;min-width:40px!important;height:40px!important;transition:all .25s ease!important;display:flex!important;align-items:center!important;justify-content:center!important;box-shadow:none!important}::ng-deep .p-fileupload .p-fileupload-header .p-button.clear-button:not(:disabled):hover{background:none!important;border:none!important;box-shadow:none!important;transform:scale(1.05)!important}::ng-deep .p-button.clear-button .p-button-icon{color:#6b7280!important;font-size:1.1rem!important;transition:all .25s ease!important}::ng-deep .p-button.clear-button:not(:disabled):hover .p-button-icon{color:#ef4444!important}::ng-deep .p-button.clear-button:disabled{opacity:.5!important;cursor:not-allowed!important}.file-error-message{display:flex;align-items:center;gap:.5rem;color:#dc2626;font-size:.875rem;font-weight:400;padding:.25rem .75rem;background:#fef2f2;border-radius:6px;border:1px solid #fecaca;animation:slideDown .3s ease}.file-error-message i{font-size:1rem;color:#dc2626;flex-shrink:0}@keyframes slideDown{0%{opacity:0;transform:translateY(-10px)}to{opacity:1;transform:translateY(0)}}.debug-panel{margin-top:8px;font-size:11px;color:#374151;background:#f8fafc;padding:8px 12px;border-radius:6px;font-family:monospace;border:1px solid #e2e8f0;width:100%}.debug-header{display:flex;justify-content:space-between;align-items:center;gap:8px;flex-wrap:wrap}.debug-info{display:flex;align-items:center;gap:12px;flex-wrap:wrap}.debug-item{font-size:11px;color:#475569}.debug-item strong{color:#1e293b}.debug-actions{display:flex;gap:6px}.debug-btn{font-size:10px;padding:2px 10px;border-radius:4px;border:1px solid #cbd5e1;background:#fff;cursor:pointer;transition:all .2s ease;color:#475569;font-family:monospace}.debug-btn:hover{background:#f1f5f9;border-color:#94a3b8}.debug-error,.debug-errors{margin-top:6px;padding:4px 8px;background:#fef2f2;border-radius:4px;color:#dc2626;font-size:11px;border:1px solid #fecaca}.debug-errors pre{margin:4px 0 0;font-size:10px;color:#991b1b;white-space:pre-wrap;word-break:break-all}@media(max-width:640px){.placeholder-icon{font-size:1.1rem!important}.placeholder-text{font-size:.75rem!important}.placeholder-text .file-type{font-size:.7rem!important;padding:.05rem .3rem!important}.file-selected{font-size:.75rem!important}.file-selected .file-icon{font-size:1rem!important}.file-selected .file-size{font-size:.65rem!important}::ng-deep .p-fileupload .p-fileupload-header .p-button{padding:.4rem .75rem!important;min-height:34px!important;min-width:34px!important}::ng-deep .p-button.clear-button{min-width:34px!important;height:34px!important}.file-error-message{font-size:.75rem!important;padding:.2rem .5rem!important}.debug-panel{font-size:10px;padding:6px 8px}.debug-item{font-size:10px}.debug-btn{font-size:9px;padding:2px 6px}}\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"] }, { kind: "component", type: AppMessageErrorComponent, selector: "dsx-message-error", inputs: ["control", "form", "debugMode"] }, { kind: "pipe", type: JsonPipe, name: "json" }] });
|
|
5475
5416
|
}
|
|
5476
5417
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: FileComponent, decorators: [{
|
|
5477
5418
|
type: Component,
|
|
@@ -5486,7 +5427,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImpo
|
|
|
5486
5427
|
useExisting: forwardRef(() => FileComponent),
|
|
5487
5428
|
multi: true,
|
|
5488
5429
|
},
|
|
5489
|
-
], 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 flex-col gap-1\">\r\n <div class=\"flex items-center gap-2\">\r\n <p-fileUpload\r\n fluid\r\n #fileUpload\r\n chooseIcon=\"fa-solid fa-file-arrow-up\"\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()} ${allowedFileTypeLabel()}`\"\r\n [tooltipPosition]=\"tooltipPositionOverride()\"\r\n >\r\n <ng-template\r\n #header\r\n let-files\r\n let-chooseCallback=\"chooseCallback\"\r\n let-clearCallback=\"clearCallback\"\r\n >\r\n <!-- Mostrar el bot\u00F3n de upload SOLO si NO hay archivo seleccionado -->\r\n @if (!files || files.length === 0) {\r\n <p-button\r\n (onClick)=\"choose($event, chooseCallback)\"\r\n icon=\"fa-solid fa-cloud-arrow-up\"\r\n [rounded]=\"true\"\r\n [outlined]=\"true\"\r\n [disabled]=\"!isFileUploadEnabled()\"\r\n />\r\n }\r\n\r\n <span class=\"file-upload-placeholder\">\r\n <i class=\"fa-regular fa-file-lines placeholder-icon\"></i>\r\n <span class=\"placeholder-text\">\r\n @if (files && files.length > 0) {\r\n <span class=\"file-selected\">\r\n <i class=\"fa-regular fa-file-pdf file-icon\"></i>\r\n {{ files[0]?.name }}\r\n <span class=\"file-size\"\r\n >({{ formatFileSize(files[0]?.size) }})</span\r\n >\r\n </span>\r\n } @else if (allowedFileTypeLabel() !== \"archivo\") {\r\n <span class=\"empty-warning\">Ning\u00FAn</span>\r\n <span class=\"file-type empty-warning-type\">{{\r\n allowedFileTypeLabel()\r\n }}</span>\r\n <span class=\"empty-warning\">seleccionado</span>\r\n } @else {\r\n <span class=\"empty-warning\">Ning\u00FAn archivo seleccionado</span>\r\n }\r\n </span>\r\n </span>\r\n\r\n <!-- Mostrar bot\u00F3n de limpiar SOLO si hay archivo seleccionado -->\r\n @if (files && files.length > 0) {\r\n <p-button\r\n icon=\"fa-solid fa-xmark\"\r\n [rounded]=\"true\"\r\n [outlined]=\"true\"\r\n (onClick)=\"clearFile()\"\r\n [disabled]=\"!isFileUploadEnabled()\"\r\n styleClass=\"clear-button\"\r\n />\r\n }\r\n </ng-template>\r\n <!-- Ocultar la vista previa por defecto -->\r\n <ng-template #content></ng-template>\r\n <ng-template #file></ng-template>\r\n </p-fileUpload>\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 <!-- Mensajes de error (validaci\u00F3n de PrimeNG) -->\r\n @if (errorMessage()) {\r\n <div class=\"file-error-message\">\r\n <i class=\"pi pi-exclamation-circle\"></i>\r\n {{ errorMessage() }}\r\n </div>\r\n }\r\n\r\n <!-- Mensaje de error del formulario (dsx-message-error) -->\r\n @if (showError() && errorControl()) {\r\n <dsx-message-error [control]=\"errorControl()\" />\r\n }\r\n </div>\r\n}\r\n\r\n<!-- Panel de Debug -->\r\n@if (debug() && isDevMode) {\r\n <div class=\"debug-panel\">\r\n <div class=\"debug-header\">\r\n <div class=\"debug-info\">\r\n <strong>\uD83D\uDD0D Debug File Upload:</strong>\r\n <span class=\"debug-item\"\r\n >Archivo: {{ value ? value.name : \"Ninguno\" }}</span\r\n >\r\n <span class=\"debug-item\"\r\n >Tama\u00F1o: {{ value ? formatFileSize(value.size) : \"-\" }}</span\r\n >\r\n <span class=\"debug-item\">Tipo: {{ value ? value.type : \"-\" }}</span>\r\n <span\r\n class=\"debug-item\"\r\n [style.color]=\"controlValid() ? '#10b981' : '#ef4444'\"\r\n >\r\n {{ controlValid() ? \"\u2705 V\u00E1lido\" : \"\u274C Inv\u00E1lido\" }}\r\n </span>\r\n <!-- Cambiar esta l\u00EDnea en el panel de debug -->\r\n <span class=\"debug-item\"\r\n >Required: {{ isRequired() ? \"\u2705\" : \"\u274C\" }}</span\r\n >\r\n <span class=\"debug-item\"\r\n >Reemplazando: {{ isReplacing() ? \"\u2705\" : \"\u274C\" }}</span\r\n >\r\n </div>\r\n <div class=\"debug-actions\">\r\n <button (click)=\"forceReload()\" class=\"debug-btn\" type=\"button\">\r\n \uD83D\uDD04 Recargar\r\n </button>\r\n <button (click)=\"clearFile()\" class=\"debug-btn\" type=\"button\">\r\n \uD83E\uDDF9 Limpiar\r\n </button>\r\n </div>\r\n </div>\r\n @if (errorMessage()) {\r\n <div class=\"debug-error\">\r\n <strong>\u26A0\uFE0F Error activo:</strong> {{ errorMessage() }}\r\n </div>\r\n }\r\n @if (controlErrors()) {\r\n <div class=\"debug-errors\">\r\n <strong>\u274C Errores del formulario:</strong>\r\n <pre>{{ controlErrors() | json }}</pre>\r\n </div>\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%}::ng-deep .p-fileupload .p-fileupload-header{display:flex!important;align-items:center!important;gap:.75rem!important;padding:0!important;border:none!important;background:transparent!important}::ng-deep .p-fileupload .p-fileupload-header .p-button{background:transparent!important;border:2px dashed #d1d5db!important;border-radius:8px!important;padding:.5rem 1rem!important;margin:.5rem!important;min-height:40px!important;min-width:40px!important;transition:all .25s ease!important;color:#6b7280!important}::ng-deep .p-fileupload .p-fileupload-header .p-button:not(:disabled):hover{border-color:#3b82f6!important;background:#eff6ff!important;box-shadow:0 0 0 3px #3b82f61a!important;color:#3b82f6!important}::ng-deep .p-fileupload .p-fileupload-header .p-button:disabled{opacity:.5!important;cursor:not-allowed!important;border-color:#e5e7eb!important;color:#9ca3af!important}::ng-deep .p-fileupload .p-fileupload-header .p-button .p-button-icon{font-size:1.2rem!important;transition:color .25s ease!important}.file-upload-placeholder{display:flex;align-items:center;gap:.75rem;pointer-events:none;white-space:nowrap;padding:0 .5rem}.placeholder-icon{font-size:1.35rem;color:#94a3b8;transition:all .3s ease}.placeholder-text{color:#94a3b8;font-size:.875rem;font-weight:400;transition:all .3s ease;letter-spacing:.01em}.placeholder-text .file-type{color:#64748b;font-size:.8rem;font-weight:600;transition:all .3s ease;letter-spacing:.03em;text-transform:uppercase;background:#f1f5f9;padding:.1rem .4rem;border-radius:4px;margin:0 .1rem}.placeholder-text .empty-warning{color:#d97706;font-weight:500;transition:color .3s ease}.placeholder-text .file-type.empty-warning-type{color:#b45309;background:#fef3c7;font-weight:600}.file-selected{display:flex;align-items:center;gap:.5rem;color:#1f2937;font-weight:500;font-size:.85rem}.file-selected .file-icon{font-size:1.2rem;color:#bb1589}.file-selected .file-size{color:#9ca3af;font-weight:400;font-size:.75rem;margin-left:.25rem}::ng-deep .p-fileupload .p-fileupload-header:has(.p-button:not(:disabled):hover) .placeholder-icon{color:#3b82f6}::ng-deep .p-fileupload .p-fileupload-header:has(.p-button:not(:disabled):hover) .placeholder-text{color:#1f2937}::ng-deep .p-fileupload .p-fileupload-header:has(.p-button:not(:disabled):hover) .file-type{color:#2563eb;background:#dbeafe}::ng-deep .p-fileupload .p-fileupload-header:has(.p-button:not(:disabled):hover) .placeholder-text .empty-warning{color:#2563eb}::ng-deep .p-fileupload .p-fileupload-header:has(.p-button:not(:disabled):hover) .file-type.empty-warning-type{color:#2563eb;background:#dbeafe}::ng-deep .p-fileupload .p-fileupload-buttonbar{display:none!important}::ng-deep .p-fileupload .p-fileupload-content{padding:0!important;border:none!important;background:transparent!important}::ng-deep .p-button.clear-button{background:transparent!important;border:none!important;border-radius:8px!important;padding:.5rem!important;min-width:40px!important;height:40px!important;transition:all .25s ease!important;display:flex!important;align-items:center!important;justify-content:center!important;box-shadow:none!important}::ng-deep .p-fileupload .p-fileupload-header .p-button.clear-button:not(:disabled):hover{background:none!important;border:none!important;box-shadow:none!important;transform:scale(1.05)!important}::ng-deep .p-button.clear-button .p-button-icon{color:#6b7280!important;font-size:1.1rem!important;transition:all .25s ease!important}::ng-deep .p-button.clear-button:not(:disabled):hover .p-button-icon{color:#ef4444!important}::ng-deep .p-button.clear-button:disabled{opacity:.5!important;cursor:not-allowed!important}.file-error-message{display:flex;align-items:center;gap:.5rem;color:#dc2626;font-size:.875rem;font-weight:400;padding:.25rem .75rem;background:#fef2f2;border-radius:6px;border:1px solid #fecaca;animation:slideDown .3s ease}.file-error-message i{font-size:1rem;color:#dc2626;flex-shrink:0}@keyframes slideDown{0%{opacity:0;transform:translateY(-10px)}to{opacity:1;transform:translateY(0)}}.debug-panel{margin-top:8px;font-size:11px;color:#374151;background:#f8fafc;padding:8px 12px;border-radius:6px;font-family:monospace;border:1px solid #e2e8f0;width:100%}.debug-header{display:flex;justify-content:space-between;align-items:center;gap:8px;flex-wrap:wrap}.debug-info{display:flex;align-items:center;gap:12px;flex-wrap:wrap}.debug-item{font-size:11px;color:#475569}.debug-item strong{color:#1e293b}.debug-actions{display:flex;gap:6px}.debug-btn{font-size:10px;padding:2px 10px;border-radius:4px;border:1px solid #cbd5e1;background:#fff;cursor:pointer;transition:all .2s ease;color:#475569;font-family:monospace}.debug-btn:hover{background:#f1f5f9;border-color:#94a3b8}.debug-error,.debug-errors{margin-top:6px;padding:4px 8px;background:#fef2f2;border-radius:4px;color:#dc2626;font-size:11px;border:1px solid #fecaca}.debug-errors pre{margin:4px 0 0;font-size:10px;color:#991b1b;white-space:pre-wrap;word-break:break-all}@media(max-width:640px){.placeholder-icon{font-size:1.1rem!important}.placeholder-text{font-size:.75rem!important}.placeholder-text .file-type{font-size:.7rem!important;padding:.05rem .3rem!important}.file-selected{font-size:.75rem!important}.file-selected .file-icon{font-size:1rem!important}.file-selected .file-size{font-size:.65rem!important}::ng-deep .p-fileupload .p-fileupload-header .p-button{padding:.4rem .75rem!important;min-height:34px!important;min-width:34px!important}::ng-deep .p-button.clear-button{min-width:34px!important;height:34px!important}.file-error-message{font-size:.75rem!important;padding:.2rem .5rem!important}.debug-panel{font-size:10px;padding:6px 8px}.debug-item{font-size:10px}.debug-btn{font-size:9px;padding:2px 6px}}\n"] }]
|
|
5430
|
+
], 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 flex-col gap-1\">\r\n <div class=\"flex items-center gap-2\">\r\n <p-fileUpload\r\n fluid\r\n #fileUpload\r\n chooseIcon=\"fa-solid fa-file-arrow-up\"\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()} ${allowedFileTypeLabel()}`\"\r\n [tooltipPosition]=\"tooltipPositionOverride()\"\r\n >\r\n <ng-template\r\n #header\r\n let-files\r\n let-chooseCallback=\"chooseCallback\"\r\n let-clearCallback=\"clearCallback\"\r\n >\r\n <!-- Mostrar el bot\u00F3n de upload SOLO si NO hay archivo seleccionado -->\r\n @if (!files || files.length === 0) {\r\n <p-button\r\n (onClick)=\"choose($event, chooseCallback)\"\r\n icon=\"fa-solid fa-cloud-arrow-up\"\r\n [rounded]=\"true\"\r\n [outlined]=\"true\"\r\n [disabled]=\"!isFileUploadEnabled()\"\r\n />\r\n }\r\n\r\n <span class=\"file-upload-placeholder\">\r\n <i class=\"fa-regular fa-file-lines placeholder-icon\"></i>\r\n <span class=\"placeholder-text\">\r\n @if (files && files.length > 0) {\r\n <span class=\"file-selected\">\r\n <i class=\"fa-regular fa-file-pdf file-icon\"></i>\r\n {{ files[0]?.name }}\r\n <span class=\"file-size\"\r\n >({{ formatFileSize(files[0]?.size) }})</span\r\n >\r\n </span>\r\n } @else if (allowedFileTypeLabel() !== \"archivo\") {\r\n <span class=\"empty-warning\">Ning\u00FAn</span>\r\n <span class=\"file-type empty-warning-type\">{{\r\n allowedFileTypeLabel()\r\n }}</span>\r\n <span class=\"empty-warning\">seleccionado</span>\r\n } @else {\r\n <span class=\"empty-warning\">Ning\u00FAn archivo seleccionado</span>\r\n }\r\n </span>\r\n </span>\r\n\r\n <!-- Mostrar bot\u00F3n de limpiar SOLO si hay archivo seleccionado -->\r\n @if (files && files.length > 0) {\r\n <p-button\r\n icon=\"fa-solid fa-xmark\"\r\n [rounded]=\"true\"\r\n [outlined]=\"true\"\r\n (onClick)=\"clear()\"\r\n [disabled]=\"!isFileUploadEnabled()\"\r\n styleClass=\"clear-button\"\r\n />\r\n }\r\n </ng-template>\r\n <!-- Ocultar la vista previa por defecto -->\r\n <ng-template #content></ng-template>\r\n <ng-template #file></ng-template>\r\n </p-fileUpload>\r\n\r\n <!-- Bot\u00F3n para cancelar remplazo -->\r\n @if (isReplacing()) {\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 <!-- Mensajes de error (validaci\u00F3n de PrimeNG) -->\r\n @if (errorMessage()) {\r\n <div class=\"file-error-message\">\r\n <i class=\"pi pi-exclamation-circle\"></i>\r\n {{ errorMessage() }}\r\n </div>\r\n }\r\n\r\n <!-- Mensaje de error del formulario (dsx-message-error) -->\r\n @if (showError() && errorControl()) {\r\n <dsx-message-error [control]=\"errorControl()\" />\r\n }\r\n </div>\r\n}\r\n\r\n<!-- Panel de Debug -->\r\n@if (debug() && isDevMode) {\r\n <div class=\"debug-panel\">\r\n <div class=\"debug-header\">\r\n <div class=\"debug-info\">\r\n <strong>\uD83D\uDD0D Debug File Upload:</strong>\r\n <span class=\"debug-item\"\r\n >Archivo: {{ value ? value.name : \"Ninguno\" }}</span\r\n >\r\n <span class=\"debug-item\"\r\n >Tama\u00F1o: {{ value ? formatFileSize(value.size) : \"-\" }}</span\r\n >\r\n <span class=\"debug-item\">Tipo: {{ value ? value.type : \"-\" }}</span>\r\n <span\r\n class=\"debug-item\"\r\n [style.color]=\"controlValid() ? '#10b981' : '#ef4444'\"\r\n >\r\n {{ controlValid() ? \"\u2705 V\u00E1lido\" : \"\u274C Inv\u00E1lido\" }}\r\n </span>\r\n <span class=\"debug-item\"\r\n >Required: {{ isRequired() ? \"\u2705\" : \"\u274C\" }}</span\r\n >\r\n <span class=\"debug-item\"\r\n >Reemplazando: {{ isReplacing() ? \"\u2705\" : \"\u274C\" }}</span\r\n >\r\n <!-- === ESTADOS ADICIONALES PARA DEBUG === -->\r\n <span\r\n class=\"debug-item\"\r\n style=\"background: #f0f0f0; padding: 0 6px; border-radius: 4px\"\r\n >\r\n \uD83D\uDCCA hasExistingFile: {{ hasExistingFile() ? \"\u2705\" : \"\u274C\" }}\r\n </span>\r\n <span\r\n class=\"debug-item\"\r\n style=\"background: #f0f0f0; padding: 0 6px; border-radius: 4px\"\r\n >\r\n \uD83D\uDCCA existingFileName: {{ existingFileName() || \"null\" }}\r\n </span>\r\n <span\r\n class=\"debug-item\"\r\n style=\"background: #f0f0f0; padding: 0 6px; border-radius: 4px\"\r\n >\r\n \uD83D\uDCCA isFileUploadEnabled: {{ isFileUploadEnabled() ? \"\u2705\" : \"\u274C\" }}\r\n </span>\r\n <span\r\n class=\"debug-item\"\r\n style=\"background: #f0f0f0; padding: 0 6px; border-radius: 4px\"\r\n >\r\n \uD83D\uDCCA showExistingFile: {{ showExistingFile() ? \"\u2705\" : \"\u274C\" }}\r\n </span>\r\n <span\r\n class=\"debug-item\"\r\n style=\"background: #f0f0f0; padding: 0 6px; border-radius: 4px\"\r\n >\r\n \uD83D\uDCCA value: {{ value ? value.name : \"null\" }}\r\n </span>\r\n </div>\r\n <div class=\"debug-actions\">\r\n <button (click)=\"forceReload()\" class=\"debug-btn\" type=\"button\">\r\n \uD83D\uDD04 Recargar\r\n </button>\r\n <button (click)=\"clear()\" class=\"debug-btn\" type=\"button\">\r\n \uD83E\uDDF9 Limpiar\r\n </button>\r\n <button (click)=\"diagnoseState()\" class=\"debug-btn\" type=\"button\">\r\n \uD83D\uDCCA Diagn\u00F3stico\r\n </button>\r\n </div>\r\n </div>\r\n @if (errorMessage()) {\r\n <div class=\"debug-error\">\r\n <strong>\u26A0\uFE0F Error activo:</strong> {{ errorMessage() }}\r\n </div>\r\n }\r\n @if (controlErrors()) {\r\n <div class=\"debug-errors\">\r\n <strong>\u274C Errores del formulario:</strong>\r\n <pre>{{ controlErrors() | json }}</pre>\r\n </div>\r\n }\r\n </div>\r\n}\r\n", styles: [".file-name{display:inline-block;font-weight:500;color:#1d8678;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:100%}::ng-deep .p-fileupload .p-fileupload-header{display:flex!important;align-items:center!important;gap:.75rem!important;padding:0!important;border:none!important;background:transparent!important}::ng-deep .p-fileupload .p-fileupload-header .p-button{background:transparent!important;border:2px dashed #d1d5db!important;border-radius:8px!important;padding:.5rem 1rem!important;margin:.5rem!important;min-height:40px!important;min-width:40px!important;transition:all .25s ease!important;color:#6b7280!important}::ng-deep .p-fileupload .p-fileupload-header .p-button:not(:disabled):hover{border-color:#3b82f6!important;background:#eff6ff!important;box-shadow:0 0 0 3px #3b82f61a!important;color:#3b82f6!important}::ng-deep .p-fileupload .p-fileupload-header .p-button:disabled{opacity:.5!important;cursor:not-allowed!important;border-color:#e5e7eb!important;color:#9ca3af!important}::ng-deep .p-fileupload .p-fileupload-header .p-button .p-button-icon{font-size:1.2rem!important;transition:color .25s ease!important}.file-upload-placeholder{display:flex;align-items:center;gap:.75rem;pointer-events:none;white-space:nowrap;padding:0 .5rem}.placeholder-icon{font-size:1.35rem;color:#94a3b8;transition:all .3s ease}.placeholder-text{color:#94a3b8;font-size:.875rem;font-weight:400;transition:all .3s ease;letter-spacing:.01em}.placeholder-text .file-type{color:#64748b;font-size:.8rem;font-weight:600;transition:all .3s ease;letter-spacing:.03em;text-transform:uppercase;background:#f1f5f9;padding:.1rem .4rem;border-radius:4px;margin:0 .1rem}.placeholder-text .empty-warning{color:#d97706;font-weight:500;transition:color .3s ease}.placeholder-text .file-type.empty-warning-type{color:#b45309;background:#fef3c7;font-weight:600}.file-selected{display:flex;align-items:center;gap:.5rem;color:#1f2937;font-weight:500;font-size:.85rem}.file-selected .file-icon{font-size:1.2rem;color:#22994a}.file-selected .file-size{color:#9ca3af;font-weight:400;font-size:.75rem;margin-left:.25rem}::ng-deep .p-fileupload .p-fileupload-header:has(.p-button:not(:disabled):hover) .placeholder-icon{color:#3b82f6}::ng-deep .p-fileupload .p-fileupload-header:has(.p-button:not(:disabled):hover) .placeholder-text{color:#1f2937}::ng-deep .p-fileupload .p-fileupload-header:has(.p-button:not(:disabled):hover) .file-type{color:#2563eb;background:#dbeafe}::ng-deep .p-fileupload .p-fileupload-header:has(.p-button:not(:disabled):hover) .placeholder-text .empty-warning{color:#2563eb}::ng-deep .p-fileupload .p-fileupload-header:has(.p-button:not(:disabled):hover) .file-type.empty-warning-type{color:#2563eb;background:#dbeafe}::ng-deep .p-fileupload .p-fileupload-buttonbar{display:none!important}::ng-deep .p-fileupload .p-fileupload-content{padding:0!important;border:none!important;background:transparent!important}::ng-deep .p-button.clear-button{background:transparent!important;border:none!important;border-radius:8px!important;padding:.5rem!important;min-width:40px!important;height:40px!important;transition:all .25s ease!important;display:flex!important;align-items:center!important;justify-content:center!important;box-shadow:none!important}::ng-deep .p-fileupload .p-fileupload-header .p-button.clear-button:not(:disabled):hover{background:none!important;border:none!important;box-shadow:none!important;transform:scale(1.05)!important}::ng-deep .p-button.clear-button .p-button-icon{color:#6b7280!important;font-size:1.1rem!important;transition:all .25s ease!important}::ng-deep .p-button.clear-button:not(:disabled):hover .p-button-icon{color:#ef4444!important}::ng-deep .p-button.clear-button:disabled{opacity:.5!important;cursor:not-allowed!important}.file-error-message{display:flex;align-items:center;gap:.5rem;color:#dc2626;font-size:.875rem;font-weight:400;padding:.25rem .75rem;background:#fef2f2;border-radius:6px;border:1px solid #fecaca;animation:slideDown .3s ease}.file-error-message i{font-size:1rem;color:#dc2626;flex-shrink:0}@keyframes slideDown{0%{opacity:0;transform:translateY(-10px)}to{opacity:1;transform:translateY(0)}}.debug-panel{margin-top:8px;font-size:11px;color:#374151;background:#f8fafc;padding:8px 12px;border-radius:6px;font-family:monospace;border:1px solid #e2e8f0;width:100%}.debug-header{display:flex;justify-content:space-between;align-items:center;gap:8px;flex-wrap:wrap}.debug-info{display:flex;align-items:center;gap:12px;flex-wrap:wrap}.debug-item{font-size:11px;color:#475569}.debug-item strong{color:#1e293b}.debug-actions{display:flex;gap:6px}.debug-btn{font-size:10px;padding:2px 10px;border-radius:4px;border:1px solid #cbd5e1;background:#fff;cursor:pointer;transition:all .2s ease;color:#475569;font-family:monospace}.debug-btn:hover{background:#f1f5f9;border-color:#94a3b8}.debug-error,.debug-errors{margin-top:6px;padding:4px 8px;background:#fef2f2;border-radius:4px;color:#dc2626;font-size:11px;border:1px solid #fecaca}.debug-errors pre{margin:4px 0 0;font-size:10px;color:#991b1b;white-space:pre-wrap;word-break:break-all}@media(max-width:640px){.placeholder-icon{font-size:1.1rem!important}.placeholder-text{font-size:.75rem!important}.placeholder-text .file-type{font-size:.7rem!important;padding:.05rem .3rem!important}.file-selected{font-size:.75rem!important}.file-selected .file-icon{font-size:1rem!important}.file-selected .file-size{font-size:.65rem!important}::ng-deep .p-fileupload .p-fileupload-header .p-button{padding:.4rem .75rem!important;min-height:34px!important;min-width:34px!important}::ng-deep .p-button.clear-button{min-width:34px!important;height:34px!important}.file-error-message{font-size:.75rem!important;padding:.2rem .5rem!important}.debug-panel{font-size:10px;padding:6px 8px}.debug-item{font-size:10px}.debug-btn{font-size:9px;padding:2px 6px}}\n"] }]
|
|
5490
5431
|
}], 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 }] }], 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 }] }] } });
|
|
5491
5432
|
|
|
5492
5433
|
function uid() {
|
|
@@ -5495,10 +5436,11 @@ function uid() {
|
|
|
5495
5436
|
class JsonValuesDebujComponent {
|
|
5496
5437
|
form = input(null, ...(ngDevMode ? [{ debugName: "form" }] : /* istanbul ignore next */ []));
|
|
5497
5438
|
debug = input(false, ...(ngDevMode ? [{ debugName: "debug" }] : /* istanbul ignore next */ []));
|
|
5498
|
-
debounceTime = input(300, ...(ngDevMode ? [{ debugName: "debounceTime" }] : /* istanbul ignore next */ []));
|
|
5439
|
+
debounceTime = input(300, ...(ngDevMode ? [{ debugName: "debounceTime" }] : /* istanbul ignore next */ []));
|
|
5499
5440
|
debugValue = signal(null, ...(ngDevMode ? [{ debugName: "debugValue" }] : /* istanbul ignore next */ []));
|
|
5500
5441
|
serializedValue = signal('', ...(ngDevMode ? [{ debugName: "serializedValue" }] : /* istanbul ignore next */ []));
|
|
5501
5442
|
fileInfo = signal(null, ...(ngDevMode ? [{ debugName: "fileInfo" }] : /* istanbul ignore next */ []));
|
|
5443
|
+
filesSummary = signal('', ...(ngDevMode ? [{ debugName: "filesSummary" }] : /* istanbul ignore next */ []));
|
|
5502
5444
|
isDevModeSignal = computed(() => isDevMode(), ...(ngDevMode ? [{ debugName: "isDevModeSignal" }] : /* istanbul ignore next */ []));
|
|
5503
5445
|
isDebugEnabledSignal = computed(() => {
|
|
5504
5446
|
const isDev = this.isDevModeSignal();
|
|
@@ -5521,7 +5463,6 @@ class JsonValuesDebujComponent {
|
|
|
5521
5463
|
subscription;
|
|
5522
5464
|
changesCount = 0;
|
|
5523
5465
|
isInitialized = false;
|
|
5524
|
-
lastLogTime = 0;
|
|
5525
5466
|
shouldShowVisual = computed(() => {
|
|
5526
5467
|
const show = this.isDevModeSignal();
|
|
5527
5468
|
if (this._lastVisualState !== show) {
|
|
@@ -5594,17 +5535,17 @@ class JsonValuesDebujComponent {
|
|
|
5594
5535
|
this.updateSerializedValue(rawValue);
|
|
5595
5536
|
this.updateFileInfo(rawValue);
|
|
5596
5537
|
if (this.shouldShowLogs()) {
|
|
5538
|
+
const filesFound = this.findFilesInObject(rawValue);
|
|
5597
5539
|
console.log(`[JsonDebug:${this.id}] 📊 Procesamiento inicial`, {
|
|
5598
5540
|
hasFile: !!rawValue?.file,
|
|
5599
5541
|
fileType: rawValue?.file ? typeof rawValue.file : 'N/A',
|
|
5600
5542
|
serializedLength: this.serializedValue().length,
|
|
5543
|
+
filesFound: filesFound.length,
|
|
5544
|
+
filesSummary: filesFound.map((f) => f.path).join(', '),
|
|
5601
5545
|
});
|
|
5602
5546
|
}
|
|
5603
|
-
// ✅ Aplicar debounce y distinctUntilChanged para reducir logs
|
|
5604
5547
|
this.subscription = form.valueChanges
|
|
5605
|
-
.pipe(debounceTime(this.debounceTime()),
|
|
5606
|
-
distinctUntilChanged((prev, curr) => {
|
|
5607
|
-
// ✅ Comparar si los valores son iguales
|
|
5548
|
+
.pipe(debounceTime(this.debounceTime()), distinctUntilChanged((prev, curr) => {
|
|
5608
5549
|
return JSON.stringify(prev) === JSON.stringify(curr);
|
|
5609
5550
|
}))
|
|
5610
5551
|
.subscribe(() => {
|
|
@@ -5617,10 +5558,15 @@ class JsonValuesDebujComponent {
|
|
|
5617
5558
|
const endTime = performance.now();
|
|
5618
5559
|
if (this.shouldShowLogs()) {
|
|
5619
5560
|
const elapsed = endTime - startTime;
|
|
5561
|
+
const filesFound = this.findFilesInObject(rawValue);
|
|
5620
5562
|
console.log(`[JsonDebug:${this.id}] 🔄 Cambio #${this.changesCount}`, {
|
|
5621
5563
|
tiempoMs: elapsed.toFixed(2),
|
|
5622
5564
|
hasFile: !!rawValue?.file,
|
|
5623
5565
|
serializedLength: this.serializedValue().length,
|
|
5566
|
+
filesFound: filesFound.length,
|
|
5567
|
+
filesSummary: filesFound
|
|
5568
|
+
.map((f) => `${f.path} (${f.file?.name || 'sin nombre'})`)
|
|
5569
|
+
.join(', '),
|
|
5624
5570
|
warning: elapsed > 10 ? '⚠️ Cambio lento' : '✅ OK',
|
|
5625
5571
|
});
|
|
5626
5572
|
if (this.changesCount % 10 === 0) {
|
|
@@ -5643,34 +5589,51 @@ class JsonValuesDebujComponent {
|
|
|
5643
5589
|
});
|
|
5644
5590
|
});
|
|
5645
5591
|
}
|
|
5592
|
+
// ✅ Método recursivo para encontrar archivos en toda la estructura
|
|
5593
|
+
findFilesInObject(obj, path = 'root') {
|
|
5594
|
+
const files = [];
|
|
5595
|
+
if (!obj || typeof obj !== 'object') {
|
|
5596
|
+
return files;
|
|
5597
|
+
}
|
|
5598
|
+
// Verificar si el objeto actual tiene un archivo
|
|
5599
|
+
if (obj.file && (obj.file instanceof File || obj.file instanceof Blob)) {
|
|
5600
|
+
files.push({
|
|
5601
|
+
path: path,
|
|
5602
|
+
file: obj.file,
|
|
5603
|
+
name: obj.file.name || 'sin nombre',
|
|
5604
|
+
size: obj.file.size || 0,
|
|
5605
|
+
type: obj.file.type || 'desconocido',
|
|
5606
|
+
});
|
|
5607
|
+
}
|
|
5608
|
+
// Si es un array, recorrer sus elementos
|
|
5609
|
+
if (Array.isArray(obj)) {
|
|
5610
|
+
obj.forEach((item, index) => {
|
|
5611
|
+
const childFiles = this.findFilesInObject(item, `${path}[${index}]`);
|
|
5612
|
+
files.push(...childFiles);
|
|
5613
|
+
});
|
|
5614
|
+
}
|
|
5615
|
+
// Si es un objeto, recorrer sus propiedades
|
|
5616
|
+
else if (typeof obj === 'object') {
|
|
5617
|
+
Object.keys(obj).forEach((key) => {
|
|
5618
|
+
// Saltar la propiedad 'file' si ya la procesamos y es un File
|
|
5619
|
+
if (key === 'file' &&
|
|
5620
|
+
(obj.file instanceof File || obj.file instanceof Blob)) {
|
|
5621
|
+
return;
|
|
5622
|
+
}
|
|
5623
|
+
const childFiles = this.findFilesInObject(obj[key], `${path}.${key}`);
|
|
5624
|
+
files.push(...childFiles);
|
|
5625
|
+
});
|
|
5626
|
+
}
|
|
5627
|
+
return files;
|
|
5628
|
+
}
|
|
5646
5629
|
updateSerializedValue(value) {
|
|
5647
5630
|
if (!value) {
|
|
5648
5631
|
this.serializedValue.set('');
|
|
5649
5632
|
return;
|
|
5650
5633
|
}
|
|
5651
5634
|
try {
|
|
5652
|
-
|
|
5653
|
-
|
|
5654
|
-
const fileProps = {};
|
|
5655
|
-
if ('name' in copy.file && copy.file.name !== undefined) {
|
|
5656
|
-
fileProps.name = copy.file.name;
|
|
5657
|
-
}
|
|
5658
|
-
if ('size' in copy.file && copy.file.size !== undefined) {
|
|
5659
|
-
fileProps.size = copy.file.size;
|
|
5660
|
-
}
|
|
5661
|
-
if ('type' in copy.file && copy.file.type !== undefined) {
|
|
5662
|
-
fileProps.type = copy.file.type;
|
|
5663
|
-
}
|
|
5664
|
-
if ('lastModified' in copy.file &&
|
|
5665
|
-
copy.file.lastModified !== undefined) {
|
|
5666
|
-
fileProps.lastModified = copy.file.lastModified;
|
|
5667
|
-
}
|
|
5668
|
-
const otherProps = Object.keys(copy.file).filter((key) => !['name', 'size', 'type', 'lastModified'].includes(key));
|
|
5669
|
-
otherProps.forEach((key) => {
|
|
5670
|
-
fileProps[key] = copy.file[key];
|
|
5671
|
-
});
|
|
5672
|
-
copy.file = fileProps;
|
|
5673
|
-
}
|
|
5635
|
+
// ✅ Clonar y procesar archivos en toda la estructura
|
|
5636
|
+
const copy = this.cloneWithFileProcessing(value);
|
|
5674
5637
|
this.serializedValue.set(JSON.stringify(copy, null, 2));
|
|
5675
5638
|
}
|
|
5676
5639
|
catch (error) {
|
|
@@ -5680,41 +5643,104 @@ class JsonValuesDebujComponent {
|
|
|
5680
5643
|
}
|
|
5681
5644
|
}
|
|
5682
5645
|
}
|
|
5646
|
+
// ✅ Clonar objeto procesando archivos recursivamente
|
|
5647
|
+
cloneWithFileProcessing(obj) {
|
|
5648
|
+
if (!obj || typeof obj !== 'object') {
|
|
5649
|
+
return obj;
|
|
5650
|
+
}
|
|
5651
|
+
// Si es un File o Blob, extraer sus propiedades
|
|
5652
|
+
if (obj instanceof File || obj instanceof Blob) {
|
|
5653
|
+
const fileProps = {
|
|
5654
|
+
__type: obj instanceof File ? 'File' : 'Blob',
|
|
5655
|
+
};
|
|
5656
|
+
if ('name' in obj && obj.name !== undefined) {
|
|
5657
|
+
fileProps.name = obj.name;
|
|
5658
|
+
}
|
|
5659
|
+
if ('size' in obj && obj.size !== undefined) {
|
|
5660
|
+
fileProps.size = obj.size;
|
|
5661
|
+
}
|
|
5662
|
+
if ('type' in obj && obj.type !== undefined) {
|
|
5663
|
+
fileProps.type = obj.type;
|
|
5664
|
+
}
|
|
5665
|
+
if ('lastModified' in obj && obj.lastModified !== undefined) {
|
|
5666
|
+
fileProps.lastModified = obj.lastModified;
|
|
5667
|
+
}
|
|
5668
|
+
return fileProps;
|
|
5669
|
+
}
|
|
5670
|
+
// Si es un array, procesar cada elemento
|
|
5671
|
+
if (Array.isArray(obj)) {
|
|
5672
|
+
return obj.map((item) => this.cloneWithFileProcessing(item));
|
|
5673
|
+
}
|
|
5674
|
+
// Si es un objeto, procesar cada propiedad
|
|
5675
|
+
const result = {};
|
|
5676
|
+
Object.keys(obj).forEach((key) => {
|
|
5677
|
+
// Si la propiedad es 'file' y es un File/Blob, procesarla
|
|
5678
|
+
if (key === 'file' &&
|
|
5679
|
+
(obj[key] instanceof File || obj[key] instanceof Blob)) {
|
|
5680
|
+
result[key] = this.cloneWithFileProcessing(obj[key]);
|
|
5681
|
+
}
|
|
5682
|
+
else {
|
|
5683
|
+
result[key] = this.cloneWithFileProcessing(obj[key]);
|
|
5684
|
+
}
|
|
5685
|
+
});
|
|
5686
|
+
return result;
|
|
5687
|
+
}
|
|
5683
5688
|
updateFileInfo(value) {
|
|
5684
|
-
if (!value
|
|
5689
|
+
if (!value) {
|
|
5685
5690
|
this.fileInfo.set(null);
|
|
5691
|
+
this.filesSummary.set('');
|
|
5686
5692
|
return;
|
|
5687
5693
|
}
|
|
5688
|
-
|
|
5694
|
+
// ✅ Buscar todos los archivos en la estructura
|
|
5695
|
+
const files = this.findFilesInObject(value);
|
|
5696
|
+
if (files.length === 0) {
|
|
5697
|
+
this.fileInfo.set({
|
|
5698
|
+
exists: false,
|
|
5699
|
+
isEmpty: true,
|
|
5700
|
+
message: 'No hay archivos seleccionados',
|
|
5701
|
+
count: 0,
|
|
5702
|
+
});
|
|
5703
|
+
this.filesSummary.set('📭 Sin archivos');
|
|
5704
|
+
return;
|
|
5705
|
+
}
|
|
5706
|
+
// ✅ Resumir información de archivos
|
|
5707
|
+
const summary = files
|
|
5708
|
+
.map((f) => {
|
|
5709
|
+
const name = f.file?.name || 'sin nombre';
|
|
5710
|
+
const size = f.file?.size || 0;
|
|
5711
|
+
const sizeStr = size > 0 ? `${(size / 1024).toFixed(1)} KB` : '0 KB';
|
|
5712
|
+
return `${name} (${sizeStr}) en ${f.path}`;
|
|
5713
|
+
})
|
|
5714
|
+
.join('; ');
|
|
5715
|
+
this.filesSummary.set(`📁 ${files.length} archivo(s): ${summary}`);
|
|
5716
|
+
// ✅ Información detallada
|
|
5689
5717
|
const info = {
|
|
5690
5718
|
exists: true,
|
|
5691
|
-
|
|
5692
|
-
|
|
5693
|
-
|
|
5694
|
-
|
|
5695
|
-
|
|
5696
|
-
|
|
5719
|
+
count: files.length,
|
|
5720
|
+
files: files.map((f) => ({
|
|
5721
|
+
path: f.path,
|
|
5722
|
+
name: f.name,
|
|
5723
|
+
size: f.size,
|
|
5724
|
+
type: f.type,
|
|
5725
|
+
})),
|
|
5726
|
+
summary: summary,
|
|
5697
5727
|
};
|
|
5698
|
-
if ('name' in file && file.name !== undefined) {
|
|
5699
|
-
info.name = file.name;
|
|
5700
|
-
}
|
|
5701
|
-
if ('size' in file && file.size !== undefined) {
|
|
5702
|
-
info.size = file.size;
|
|
5703
|
-
}
|
|
5704
|
-
if ('type' in file && file.type !== undefined) {
|
|
5705
|
-
info.mimeType = file.type;
|
|
5706
|
-
}
|
|
5707
|
-
if ('lastModified' in file && file.lastModified !== undefined) {
|
|
5708
|
-
info.lastModified = file.lastModified;
|
|
5709
|
-
}
|
|
5710
5728
|
this.fileInfo.set(info);
|
|
5711
5729
|
}
|
|
5712
|
-
|
|
5713
|
-
|
|
5730
|
+
hasFileProperty() {
|
|
5731
|
+
const value = this.debugValue();
|
|
5732
|
+
if (!value)
|
|
5733
|
+
return false;
|
|
5734
|
+
// ✅ Buscar archivos en toda la estructura
|
|
5735
|
+
const files = this.findFilesInObject(value);
|
|
5736
|
+
return files.length > 0;
|
|
5714
5737
|
}
|
|
5715
5738
|
getFileInfo() {
|
|
5716
5739
|
return this.fileInfo();
|
|
5717
5740
|
}
|
|
5741
|
+
getFilesSummary() {
|
|
5742
|
+
return this.filesSummary();
|
|
5743
|
+
}
|
|
5718
5744
|
ngOnDestroy() {
|
|
5719
5745
|
if (this.shouldShowLogs()) {
|
|
5720
5746
|
console.log(`[JsonDebug:${this.id}] 💀 Destroy`, {
|
|
@@ -5728,11 +5754,11 @@ class JsonValuesDebujComponent {
|
|
|
5728
5754
|
}
|
|
5729
5755
|
}
|
|
5730
5756
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JsonValuesDebujComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
5731
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.17", type: JsonValuesDebujComponent, isStandalone: true, selector: "app-json-values-debuj", inputs: { form: { classPropertyName: "form", publicName: "form", isSignal: true, isRequired: false, transformFunction: null }, debug: { classPropertyName: "debug", publicName: "debug", isSignal: true, isRequired: false, transformFunction: null }, debounceTime: { classPropertyName: "debounceTime", publicName: "debounceTime", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<!-- json-values-debuj.component.html -->\r\n@if (shouldShowVisual()) {\r\n <div class=\"json-debug-container\">\r\n <div class=\"json-debug-header\">\r\n <span class=\"json-debug-id\">\uD83D\uDD0D Debug #{{ id }}</span>\r\n <span class=\"json-debug-info\">\r\n @if (debugValue()) {\r\n <span class=\"badge badge-success\">\u2713 Formulario activo</span>\r\n } @else {\r\n <span class=\"badge badge-danger\">\u2717 Sin formulario</span>\r\n }\r\n </span>\r\n </div>\r\n\r\n @if (debugValue()) {\r\n <div class=\"json-debug-content\">\r\n <!-- Informaci\u00F3n
|
|
5757
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.17", type: JsonValuesDebujComponent, isStandalone: true, selector: "app-json-values-debuj", inputs: { form: { classPropertyName: "form", publicName: "form", isSignal: true, isRequired: false, transformFunction: null }, debug: { classPropertyName: "debug", publicName: "debug", isSignal: true, isRequired: false, transformFunction: null }, debounceTime: { classPropertyName: "debounceTime", publicName: "debounceTime", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<!-- json-values-debuj.component.html -->\r\n@if (shouldShowVisual()) {\r\n <div class=\"json-debug-container\">\r\n <div class=\"json-debug-header\">\r\n <span class=\"json-debug-id\">\uD83D\uDD0D Debug #{{ id }}</span>\r\n <span class=\"json-debug-info\">\r\n @if (debugValue()) {\r\n <span class=\"badge badge-success\">\u2713 Formulario activo</span>\r\n } @else {\r\n <span class=\"badge badge-danger\">\u2717 Sin formulario</span>\r\n }\r\n </span>\r\n </div>\r\n\r\n @if (debugValue()) {\r\n <div class=\"json-debug-content\">\r\n <!-- \u2705 Informaci\u00F3n de archivos encontrados en toda la estructura -->\r\n @if (hasFileProperty()) {\r\n <div class=\"file-info-box\">\r\n <div class=\"file-info-header\">\r\n \uD83D\uDCC1 Archivos encontrados ({{ getFileInfo()?.count || 0 }})\r\n </div>\r\n <div class=\"file-info-grid\">\r\n @for (file of getFileInfo()?.files || []; track file.path) {\r\n <div class=\"file-info-item file-item\">\r\n <div class=\"file-path\">\uD83D\uDCC4 {{ file.path }}</div>\r\n <div class=\"file-details\">\r\n <span class=\"label\">Nombre:</span>\r\n <span class=\"value\">{{ file.name }}</span>\r\n </div>\r\n <div class=\"file-details\">\r\n <span class=\"label\">Tama\u00F1o:</span>\r\n <span class=\"value\"\r\n >{{ file.size / 1024 | number: \"1.1-1\" }} KB</span\r\n >\r\n </div>\r\n <div class=\"file-details\">\r\n <span class=\"label\">Tipo:</span>\r\n <span class=\"value\">{{ file.type || \"Desconocido\" }}</span>\r\n </div>\r\n </div>\r\n }\r\n </div>\r\n </div>\r\n } @else {\r\n <div class=\"file-info-box file-empty\">\r\n <div class=\"file-info-header\">\uD83D\uDCED Sin archivos seleccionados</div>\r\n </div>\r\n }\r\n\r\n <!-- JSON -->\r\n <div class=\"json-display\">\r\n <pre class=\"json-colored\">{{ serializedValue() }}</pre>\r\n </div>\r\n </div>\r\n }\r\n </div>\r\n}\r\n", styles: [".json-debug-container{margin:10px 0;border:1px solid #dee2e6;border-radius:8px;background-color:#f8f9fa;font-family:Consolas,Monaco,Courier New,monospace;font-size:13px;box-shadow:0 2px 8px #0000001a}.json-debug-header{display:flex;justify-content:space-between;align-items:center;padding:12px 20px;background:linear-gradient(135deg,#667eea,#764ba2);border-radius:8px 8px 0 0;color:#fff}.json-debug-id{font-weight:700;font-size:14px;color:#fff;text-shadow:0 1px 2px rgba(0,0,0,.2)}.badge{padding:4px 14px;border-radius:20px;font-size:11px;font-weight:600;text-transform:uppercase;letter-spacing:.5px}.badge-success{background-color:#10b981;color:#fff;box-shadow:0 2px 4px #10b9814d}.badge-danger{background-color:#ef4444;color:#fff;box-shadow:0 2px 4px #ef44444d}.json-debug-content{padding:16px 20px}.file-info-box{background:linear-gradient(135deg,#f0f9ff,#e0f2fe);border:1px solid #bae6fd;border-radius:6px;padding:12px 16px;margin-bottom:16px}.file-info-header{font-weight:600;color:#0369a1;font-size:13px;margin-bottom:8px}.file-info-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:6px}.file-info-item{padding:4px 8px;background-color:#fff;border-radius:4px;border:1px solid #e5e7eb}.file-info-item .label{font-weight:600;color:#6b7280;margin-right:8px;font-size:12px}.file-info-item .value{color:#0369a1;font-family:Consolas,Monaco,Courier New,monospace;font-size:12px}.json-display{margin-top:0}.json-colored{margin:0;padding:16px 20px;background-color:#1e1e1e;border-radius:6px;overflow:auto;font-size:13px;line-height:1.7;color:#d4d4d4;min-height:50px;max-height:500px;font-family:Consolas,Monaco,Courier New,monospace;white-space:pre}.json-colored::-webkit-scrollbar{width:10px;height:10px}.json-colored::-webkit-scrollbar-track{background:#2d2d2d;border-radius:4px}.json-colored::-webkit-scrollbar-thumb{background:#666;border-radius:4px}.json-colored::-webkit-scrollbar-thumb:hover{background:#888}@media(max-width:768px){.json-debug-header{flex-direction:column;gap:8px;padding:10px 16px}.json-debug-content{padding:12px 16px}.file-info-grid{grid-template-columns:1fr}.json-colored{font-size:11px;padding:12px 14px;max-height:300px}}\n"], dependencies: [{ kind: "pipe", type: DecimalPipe, name: "number" }], encapsulation: i0.ViewEncapsulation.None });
|
|
5732
5758
|
}
|
|
5733
5759
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: JsonValuesDebujComponent, decorators: [{
|
|
5734
5760
|
type: Component,
|
|
5735
|
-
args: [{ selector: 'app-json-values-debuj', standalone: true, imports: [DatePipe, DecimalPipe], encapsulation: ViewEncapsulation.None, template: "<!-- json-values-debuj.component.html -->\r\n@if (shouldShowVisual()) {\r\n <div class=\"json-debug-container\">\r\n <div class=\"json-debug-header\">\r\n <span class=\"json-debug-id\">\uD83D\uDD0D Debug #{{ id }}</span>\r\n <span class=\"json-debug-info\">\r\n @if (debugValue()) {\r\n <span class=\"badge badge-success\">\u2713 Formulario activo</span>\r\n } @else {\r\n <span class=\"badge badge-danger\">\u2717 Sin formulario</span>\r\n }\r\n </span>\r\n </div>\r\n\r\n @if (debugValue()) {\r\n <div class=\"json-debug-content\">\r\n <!-- Informaci\u00F3n
|
|
5761
|
+
args: [{ selector: 'app-json-values-debuj', standalone: true, imports: [DatePipe, DecimalPipe], encapsulation: ViewEncapsulation.None, template: "<!-- json-values-debuj.component.html -->\r\n@if (shouldShowVisual()) {\r\n <div class=\"json-debug-container\">\r\n <div class=\"json-debug-header\">\r\n <span class=\"json-debug-id\">\uD83D\uDD0D Debug #{{ id }}</span>\r\n <span class=\"json-debug-info\">\r\n @if (debugValue()) {\r\n <span class=\"badge badge-success\">\u2713 Formulario activo</span>\r\n } @else {\r\n <span class=\"badge badge-danger\">\u2717 Sin formulario</span>\r\n }\r\n </span>\r\n </div>\r\n\r\n @if (debugValue()) {\r\n <div class=\"json-debug-content\">\r\n <!-- \u2705 Informaci\u00F3n de archivos encontrados en toda la estructura -->\r\n @if (hasFileProperty()) {\r\n <div class=\"file-info-box\">\r\n <div class=\"file-info-header\">\r\n \uD83D\uDCC1 Archivos encontrados ({{ getFileInfo()?.count || 0 }})\r\n </div>\r\n <div class=\"file-info-grid\">\r\n @for (file of getFileInfo()?.files || []; track file.path) {\r\n <div class=\"file-info-item file-item\">\r\n <div class=\"file-path\">\uD83D\uDCC4 {{ file.path }}</div>\r\n <div class=\"file-details\">\r\n <span class=\"label\">Nombre:</span>\r\n <span class=\"value\">{{ file.name }}</span>\r\n </div>\r\n <div class=\"file-details\">\r\n <span class=\"label\">Tama\u00F1o:</span>\r\n <span class=\"value\"\r\n >{{ file.size / 1024 | number: \"1.1-1\" }} KB</span\r\n >\r\n </div>\r\n <div class=\"file-details\">\r\n <span class=\"label\">Tipo:</span>\r\n <span class=\"value\">{{ file.type || \"Desconocido\" }}</span>\r\n </div>\r\n </div>\r\n }\r\n </div>\r\n </div>\r\n } @else {\r\n <div class=\"file-info-box file-empty\">\r\n <div class=\"file-info-header\">\uD83D\uDCED Sin archivos seleccionados</div>\r\n </div>\r\n }\r\n\r\n <!-- JSON -->\r\n <div class=\"json-display\">\r\n <pre class=\"json-colored\">{{ serializedValue() }}</pre>\r\n </div>\r\n </div>\r\n }\r\n </div>\r\n}\r\n", styles: [".json-debug-container{margin:10px 0;border:1px solid #dee2e6;border-radius:8px;background-color:#f8f9fa;font-family:Consolas,Monaco,Courier New,monospace;font-size:13px;box-shadow:0 2px 8px #0000001a}.json-debug-header{display:flex;justify-content:space-between;align-items:center;padding:12px 20px;background:linear-gradient(135deg,#667eea,#764ba2);border-radius:8px 8px 0 0;color:#fff}.json-debug-id{font-weight:700;font-size:14px;color:#fff;text-shadow:0 1px 2px rgba(0,0,0,.2)}.badge{padding:4px 14px;border-radius:20px;font-size:11px;font-weight:600;text-transform:uppercase;letter-spacing:.5px}.badge-success{background-color:#10b981;color:#fff;box-shadow:0 2px 4px #10b9814d}.badge-danger{background-color:#ef4444;color:#fff;box-shadow:0 2px 4px #ef44444d}.json-debug-content{padding:16px 20px}.file-info-box{background:linear-gradient(135deg,#f0f9ff,#e0f2fe);border:1px solid #bae6fd;border-radius:6px;padding:12px 16px;margin-bottom:16px}.file-info-header{font-weight:600;color:#0369a1;font-size:13px;margin-bottom:8px}.file-info-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:6px}.file-info-item{padding:4px 8px;background-color:#fff;border-radius:4px;border:1px solid #e5e7eb}.file-info-item .label{font-weight:600;color:#6b7280;margin-right:8px;font-size:12px}.file-info-item .value{color:#0369a1;font-family:Consolas,Monaco,Courier New,monospace;font-size:12px}.json-display{margin-top:0}.json-colored{margin:0;padding:16px 20px;background-color:#1e1e1e;border-radius:6px;overflow:auto;font-size:13px;line-height:1.7;color:#d4d4d4;min-height:50px;max-height:500px;font-family:Consolas,Monaco,Courier New,monospace;white-space:pre}.json-colored::-webkit-scrollbar{width:10px;height:10px}.json-colored::-webkit-scrollbar-track{background:#2d2d2d;border-radius:4px}.json-colored::-webkit-scrollbar-thumb{background:#666;border-radius:4px}.json-colored::-webkit-scrollbar-thumb:hover{background:#888}@media(max-width:768px){.json-debug-header{flex-direction:column;gap:8px;padding:10px 16px}.json-debug-content{padding:12px 16px}.file-info-grid{grid-template-columns:1fr}.json-colored{font-size:11px;padding:12px 14px;max-height:300px}}\n"] }]
|
|
5736
5762
|
}], ctorParameters: () => [], propDecorators: { form: [{ type: i0.Input, args: [{ isSignal: true, alias: "form", required: false }] }], debug: [{ type: i0.Input, args: [{ isSignal: true, alias: "debug", required: false }] }], debounceTime: [{ type: i0.Input, args: [{ isSignal: true, alias: "debounceTime", required: false }] }] } });
|
|
5737
5763
|
|
|
5738
5764
|
class IcoLabel {
|