frontend-plus-react 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  // src/components/grid/GenericDataGrid.tsx
2
- import { useState as useState12, useEffect as useEffect3, useMemo as useMemo8, useRef as useRef3 } from "react";
2
+ import { useState as useState12, useEffect as useEffect5, useCallback as useCallback11, useContext as useContext4, useMemo as useMemo9, useRef as useRef6 } from "react";
3
3
  import { DataGrid } from "react-data-grid";
4
4
  import "react-data-grid/lib/styles.css";
5
5
 
@@ -66,12 +66,27 @@ var useSnackbar = () => {
66
66
  return context;
67
67
  };
68
68
 
69
+ // src/utils/errores.ts
70
+ function mensajeDeError(error, porDefecto = "Error desconocido") {
71
+ if (error instanceof Error) return error.message || porDefecto;
72
+ if (typeof error === "string" && error !== "") return error;
73
+ return porDefecto;
74
+ }
75
+ function requerido(valor, descripcion) {
76
+ if (valor === null || valor === void 0) {
77
+ throw new Error(`El servidor no devolvi\xF3 ${descripcion}`);
78
+ }
79
+ return valor;
80
+ }
81
+
69
82
  // src/env.ts
70
83
  var getEnvVar = (key) => {
71
- if (typeof import.meta !== "undefined" && import.meta.env) {
84
+ const viteEnv = import.meta.env;
85
+ if (viteEnv) {
72
86
  const viteKey = `VITE_${key}`;
73
- if (import.meta.env[viteKey]) {
74
- return import.meta.env[viteKey];
87
+ const valor = viteEnv[viteKey];
88
+ if (valor) {
89
+ return valor;
75
90
  }
76
91
  }
77
92
  if (typeof process !== "undefined" && process.env) {
@@ -93,61 +108,89 @@ var envConfig = {
93
108
 
94
109
  // src/utils/fetchApi.ts
95
110
  import JSON4all from "json4all";
111
+ var obtenerDefinicionesDeProcedimientos = () => void 0;
112
+ function registrarFuenteDeProcedimientos(fuente) {
113
+ obtenerDefinicionesDeProcedimientos = fuente;
114
+ }
115
+ function codificarParametro(valor, encoding, procedureName, paramName) {
116
+ switch (encoding ?? "JSON4all") {
117
+ case "plain":
118
+ if (typeof valor === "object" && valor !== null) {
119
+ throw new Error(`El par\xE1metro '${paramName}' de '${procedureName}' es plain y no admite objetos`);
120
+ }
121
+ return String(valor);
122
+ case "JSON":
123
+ return JSON.stringify(valor);
124
+ case "JSON4all":
125
+ return JSON4all.stringify(valor);
126
+ default:
127
+ throw new Error(`Encoding '${encoding}' no soportado para el par\xE1metro '${paramName}' de '${procedureName}'`);
128
+ }
129
+ }
130
+ function codificarParametros(procedureName, params) {
131
+ const definicion = obtenerDefinicionesDeProcedimientos()?.[procedureName];
132
+ const codificados = {};
133
+ if (!definicion) {
134
+ for (const [nombre, valor] of Object.entries(params)) {
135
+ if (valor === void 0) continue;
136
+ codificados[nombre] = typeof valor === "object" && valor !== null ? JSON4all.stringify(valor) : String(valor);
137
+ }
138
+ return { codificados, method: "post" };
139
+ }
140
+ const declarados = new Set(definicion.parameters.map((p) => p.name));
141
+ for (const nombre of Object.keys(params)) {
142
+ if (!declarados.has(nombre)) {
143
+ console.warn(`El par\xE1metro '${nombre}' no est\xE1 declarado en el procedimiento '${procedureName}' y no se env\xEDa`);
144
+ }
145
+ }
146
+ for (const paramDef of definicion.parameters) {
147
+ const valor = params[paramDef.name];
148
+ if (valor === void 0) continue;
149
+ codificados[paramDef.name] = codificarParametro(valor, paramDef.encoding, procedureName, paramDef.name);
150
+ }
151
+ return { codificados, method: definicion.method ?? "post" };
152
+ }
96
153
  async function fetchApi(endPoint, options) {
97
154
  const BACKEND_URL = envConfig.backendUrl;
98
- const defaultHeaders = {
99
- "Content-Type": "application/x-www-form-urlencoded"
100
- };
155
+ const { sinContentType, ...opcionesDeFetch } = options;
156
+ const headers = new Headers(opcionesDeFetch.headers);
157
+ if (!sinContentType && !headers.has("Content-Type")) {
158
+ headers.set("Content-Type", "application/x-www-form-urlencoded");
159
+ }
101
160
  const config = {
102
- ...options,
103
- headers: {
104
- ...options?.headers && "Content-Type" in options.headers && options.headers["Content-Type"] === void 0 ? {} : { "Content-Type": "application/x-www-form-urlencoded" },
105
- ...options?.headers
106
- },
161
+ ...opcionesDeFetch,
162
+ headers,
107
163
  credentials: "include"
108
164
  };
109
- if (config.headers && config.headers["Content-Type"] === void 0) {
110
- delete config.headers["Content-Type"];
111
- }
112
165
  if (config.method === "GET" || config.method === "HEAD") {
113
166
  delete config.body;
114
167
  }
115
168
  return await fetch(BACKEND_URL + endPoint, config);
116
169
  }
117
- var executeBackendProcedure = async (procedureName, params) => {
118
- function stringifyObjectsAndArraysInParams(params2) {
119
- const newParams = {};
120
- for (const key in params2) {
121
- if (Object.prototype.hasOwnProperty.call(params2, key)) {
122
- const value = params2[key];
123
- if (typeof value === "object" && value !== null) {
124
- try {
125
- newParams[key] = JSON.stringify(value);
126
- } catch (e) {
127
- console.warn(`Warning: Could not stringify value for key '${key}'. Keeping original value. Error:`, e);
128
- newParams[key] = value;
129
- }
130
- } else {
131
- newParams[key] = value;
132
- }
133
- }
134
- }
135
- return newParams;
170
+ function esRespuestaConError(resultado) {
171
+ if (typeof resultado !== "object" || resultado === null || !("error" in resultado)) return false;
172
+ const { error } = resultado;
173
+ return typeof error === "object" && error !== null && "message" in error;
174
+ }
175
+ function resultadoDeProcedimiento(texto) {
176
+ const resultado = parseBackendResponse(texto);
177
+ if (esRespuestaConError(resultado)) {
178
+ throw new Error(resultado.error.message);
136
179
  }
137
- const body = new URLSearchParams(stringifyObjectsAndArraysInParams(params));
138
- const response = await fetchApi(`/${procedureName}`, { body, method: "POST" });
180
+ return resultado;
181
+ }
182
+ async function ejecutar(descripcion, procedureName, pedido) {
183
+ const response = await pedido;
139
184
  if (response.ok) {
140
- const rawResponseText = await response.text();
141
- const result = parseBackendResponse(rawResponseText);
142
- if (result.error) {
143
- throw new Error(result.error.message);
144
- } else {
145
- return result;
146
- }
147
- } else {
148
- const errorTextDefinition = await response.text();
149
- throw new Error(`Error al ejecutar procedure '${procedureName}': ${response.status} - ${errorTextDefinition}`);
185
+ return resultadoDeProcedimiento(await response.text());
150
186
  }
187
+ const errorTextDefinition = await response.text();
188
+ throw new Error(`Error al ejecutar ${descripcion} '${procedureName}': ${response.status} - ${errorTextDefinition}`);
189
+ }
190
+ var executeBackendProcedure = async (procedureName, params) => {
191
+ const { codificados, method } = codificarParametros(procedureName, params);
192
+ const query = new URLSearchParams(codificados);
193
+ return ejecutar("procedure", procedureName, method === "get" ? fetchApi(`/${procedureName}?${query}`, { method: "GET" }) : fetchApi(`/${procedureName}`, { body: query, method: "POST" }));
151
194
  };
152
195
  function parseBackendResponse(text) {
153
196
  const trimmedText = text.trim();
@@ -178,45 +221,21 @@ function parseBackendResponse(text) {
178
221
  }
179
222
  }
180
223
  }
181
- throw new Error(`No se pudo parsear la respuesta del servidor: ${e.message}`);
224
+ throw new Error(`No se pudo parsear la respuesta del servidor: ${mensajeDeError(e)}`);
182
225
  }
183
226
  }
184
227
  var executeBackendUpload = async (procedureName, file, params) => {
185
228
  const formData = new FormData();
186
229
  formData.append("file", file);
187
- for (const key in params) {
188
- if (Object.prototype.hasOwnProperty.call(params, key)) {
189
- const value = params[key];
190
- if (typeof value === "object" && value !== null) {
191
- formData.append(key, JSON.stringify(value));
192
- } else {
193
- formData.append(key, value);
194
- }
195
- }
196
- }
197
- const response = await fetchApi(`/${procedureName}`, {
198
- body: formData,
199
- method: "POST",
200
- headers: {
201
- "Content-Type": void 0
202
- // Dejamos que el navegador establezca el boundary
203
- }
204
- });
205
- if (response.ok) {
206
- const rawResponseText = await response.text();
207
- const result = parseBackendResponse(rawResponseText);
208
- if (result.error) {
209
- throw new Error(result.error.message);
210
- } else {
211
- return result;
212
- }
213
- } else {
214
- const errorTextDefinition = await response.text();
215
- throw new Error(`Error al ejecutar upload '${procedureName}': ${response.status} - ${errorTextDefinition}`);
230
+ const { codificados } = codificarParametros(procedureName, params);
231
+ for (const [key, value] of Object.entries(codificados)) {
232
+ formData.append(key, value);
216
233
  }
234
+ return ejecutar("upload", procedureName, fetchApi(`/${procedureName}`, { body: formData, method: "POST", sinContentType: true }));
217
235
  };
218
236
 
219
237
  // src/hooks/useApiCall.ts
238
+ var comoError = (err) => err instanceof Error ? err : new Error(mensajeDeError(err));
220
239
  var useApiCall = () => {
221
240
  const { showSnackbar } = useSnackbar();
222
241
  const [loading, setLoading] = useState2(false);
@@ -228,7 +247,7 @@ var useApiCall = () => {
228
247
  const result = await executeBackendProcedure(procedureName, params);
229
248
  return result === null ? void 0 : result;
230
249
  } catch (err) {
231
- if (opts.isCritical) setError(err);
250
+ if (opts.isCritical) setError(comoError(err));
232
251
  let snackbarMessage = `Error inesperado al ejecutar '${procedureName}'.`;
233
252
  if (err instanceof TypeError) {
234
253
  snackbarMessage = `Problema de conexi\xF3n: ${err.message}. Por favor, revisa tu internet o intenta de nuevo.`;
@@ -248,7 +267,7 @@ var useApiCall = () => {
248
267
  const result = await executeBackendUpload(procedureName, file, params);
249
268
  return result === null ? void 0 : result;
250
269
  } catch (err) {
251
- if (opts.isCritical) setError(err);
270
+ if (opts.isCritical) setError(comoError(err));
252
271
  let snackbarMessage = `Error inesperado al subir archivo en '${procedureName}'.`;
253
272
  if (err instanceof TypeError) {
254
273
  snackbarMessage = `Problema de conexi\xF3n: ${err.message}. Por favor, revisa tu internet o intenta de nuevo.`;
@@ -266,28 +285,28 @@ var useApiCall = () => {
266
285
  var useApiCallWithoutSnackbar = () => {
267
286
  const [loading, setLoading] = useState2(false);
268
287
  const [error, setError] = useState2(null);
269
- const callApi = useCallback2(async (procedureName, params, opts = { isCritical: true }) => {
288
+ const callApi = useCallback2(async (procedureName, params, _opts = { isCritical: true }) => {
270
289
  setLoading(true);
271
290
  setError(null);
272
291
  try {
273
292
  const result = await executeBackendProcedure(procedureName, params);
274
293
  return result === null ? void 0 : result;
275
294
  } catch (err) {
276
- setError(err);
295
+ setError(comoError(err));
277
296
  console.error(`Error en la llamada API (WithoutSnackbar) para ${procedureName}:`, err);
278
297
  throw err;
279
298
  } finally {
280
299
  setLoading(false);
281
300
  }
282
301
  }, []);
283
- const callApiUpload = useCallback2(async (procedureName, file, params, opts = { isCritical: true }) => {
302
+ const callApiUpload = useCallback2(async (procedureName, file, params, _opts = { isCritical: true }) => {
284
303
  setLoading(true);
285
304
  setError(null);
286
305
  try {
287
306
  const result = await executeBackendUpload(procedureName, file, params);
288
307
  return result === null ? void 0 : result;
289
308
  } catch (err) {
290
- setError(err);
309
+ setError(comoError(err));
291
310
  console.error(`Error en la subida API (WithoutSnackbar) para ${procedureName}:`, err);
292
311
  throw err;
293
312
  } finally {
@@ -300,6 +319,207 @@ var useApiCallWithoutSnackbar = () => {
300
319
  // src/components/grid/GenericDataGrid.tsx
301
320
  import { CircularProgress as CircularProgress4, Typography as Typography8, Box as Box12, Alert as Alert2, useTheme as useTheme4, Dialog as Dialog4 } from "@mui/material";
302
321
 
322
+ // src/store/index.ts
323
+ import { configureStore, combineReducers } from "@reduxjs/toolkit";
324
+ import {
325
+ persistStore,
326
+ persistReducer,
327
+ FLUSH,
328
+ REHYDRATE,
329
+ PAUSE,
330
+ PERSIST,
331
+ PURGE,
332
+ REGISTER
333
+ } from "redux-persist";
334
+ import storage from "redux-persist/lib/storage";
335
+
336
+ // src/store/clientContextSlice.ts
337
+ import { createSlice, createAsyncThunk } from "@reduxjs/toolkit";
338
+ var initialState = {
339
+ menu: [],
340
+ procedure: {},
341
+ procedures: [],
342
+ config: {},
343
+ // Inicializa con un objeto vacío o valores por defecto adecuados
344
+ useragent: {},
345
+ // Igual aquí
346
+ username: "",
347
+ status: "idle",
348
+ // Por defecto, sin carga
349
+ error: null
350
+ // Sin error
351
+ };
352
+ var fetchClientContext = createAsyncThunk(
353
+ "clientContext/fetchClientContext",
354
+ async (_, { rejectWithValue }) => {
355
+ try {
356
+ const setupResponse = await fetchApi("/client-setup", { method: "GET" });
357
+ if (!setupResponse.ok) {
358
+ const errorData = await setupResponse.text();
359
+ throw new Error(errorData || "Error al obtener configuraci\xF3n del cliente");
360
+ }
361
+ const clientSetup = await setupResponse.json();
362
+ return clientSetup;
363
+ } catch (error) {
364
+ return rejectWithValue(mensajeDeError(error, "Error desconocido al cargar el contexto"));
365
+ }
366
+ }
367
+ );
368
+ var clientContextSlice = createSlice({
369
+ name: "clientContext",
370
+ initialState,
371
+ reducers: {
372
+ // Un reducer para limpiar el contexto del cliente (ej. al cerrar sesión)
373
+ clearClientContext: (state) => {
374
+ Object.assign(state, initialState);
375
+ }
376
+ // Puedes añadir otros reducers aquí si necesitas modificar partes del clientContext directamente
377
+ // pero el thunk es la forma preferida para la carga inicial.
378
+ },
379
+ // **extraReducers maneja las acciones del thunk asíncrono**
380
+ extraReducers: (builder) => {
381
+ builder.addCase(fetchClientContext.pending, (state) => {
382
+ state.status = "loading";
383
+ state.error = null;
384
+ }).addCase(fetchClientContext.fulfilled, (state, action) => {
385
+ state.status = "succeeded";
386
+ state.menu = action.payload.menu;
387
+ state.procedure = action.payload.procedure;
388
+ state.procedures = action.payload.procedures;
389
+ state.config = action.payload.config;
390
+ state.useragent = action.payload.useragent;
391
+ state.username = action.payload.username;
392
+ state.error = null;
393
+ }).addCase(fetchClientContext.rejected, (state, action) => {
394
+ state.status = "failed";
395
+ state.error = action.payload || "Fallo al cargar el contexto del cliente";
396
+ });
397
+ }
398
+ });
399
+ var { clearClientContext } = clientContextSlice.actions;
400
+ var clientContextSlice_default = clientContextSlice.reducer;
401
+
402
+ // src/store/routerSlice.ts
403
+ import { createSlice as createSlice2 } from "@reduxjs/toolkit";
404
+ var initialState2 = {
405
+ currentPath: "/",
406
+ previousPath: null,
407
+ redirectPath: null
408
+ // <--- Inicializamos en null
409
+ };
410
+ var routerSlice = createSlice2({
411
+ name: "router",
412
+ initialState: initialState2,
413
+ reducers: {
414
+ setCurrentPath: (state, action) => {
415
+ state.previousPath = state.currentPath;
416
+ state.currentPath = action.payload;
417
+ },
418
+ setRedirectPath: (state, action) => {
419
+ state.redirectPath = action.payload;
420
+ },
421
+ resetRouterState: (state) => {
422
+ state.currentPath = "/";
423
+ state.previousPath = null;
424
+ state.redirectPath = null;
425
+ }
426
+ }
427
+ });
428
+ var { setCurrentPath, setRedirectPath, resetRouterState } = routerSlice.actions;
429
+ var routerSlice_default = routerSlice.reducer;
430
+
431
+ // src/store/menuUiSlice.ts
432
+ import { createSlice as createSlice3 } from "@reduxjs/toolkit";
433
+ var initialState3 = {
434
+ isDrawerOpen: false,
435
+ subMenuOpenStates: {}
436
+ };
437
+ var menuUiSlice = createSlice3({
438
+ name: "menuUi",
439
+ initialState: initialState3,
440
+ reducers: {
441
+ setDrawerOpen: (state, action) => {
442
+ state.isDrawerOpen = action.payload;
443
+ },
444
+ toggleDrawer: (state) => {
445
+ state.isDrawerOpen = !state.isDrawerOpen;
446
+ },
447
+ setSubMenuOpen: (state, action) => {
448
+ state.subMenuOpenStates[action.payload.menuName] = action.payload.isOpen;
449
+ },
450
+ toggleSubMenu: (state, action) => {
451
+ state.subMenuOpenStates[action.payload] = !state.subMenuOpenStates[action.payload];
452
+ },
453
+ // --- NUEVO REDUCER: Establecer el estado de todos los submenús ---
454
+ setAllSubMenusOpen: (state, action) => {
455
+ for (const menuName in state.subMenuOpenStates) {
456
+ if (Object.prototype.hasOwnProperty.call(state.subMenuOpenStates, menuName)) {
457
+ state.subMenuOpenStates[menuName] = action.payload;
458
+ }
459
+ }
460
+ },
461
+ resetMenuUiState: (state) => {
462
+ Object.assign(state, initialState3);
463
+ }
464
+ }
465
+ });
466
+ var {
467
+ setDrawerOpen,
468
+ toggleDrawer,
469
+ setSubMenuOpen,
470
+ toggleSubMenu,
471
+ setAllSubMenusOpen,
472
+ // ¡Exportamos la nueva acción!
473
+ resetMenuUiState
474
+ } = menuUiSlice.actions;
475
+ var menuUiSlice_default = menuUiSlice.reducer;
476
+
477
+ // src/store/index.ts
478
+ import { useDispatch, useSelector } from "react-redux";
479
+ var rootReducer = combineReducers({
480
+ clientContext: clientContextSlice_default,
481
+ router: routerSlice_default,
482
+ menuUi: menuUiSlice_default
483
+ // ...otros slices
484
+ });
485
+ var persistConfig = {
486
+ key: "root",
487
+ storage,
488
+ whitelist: ["clientContext", "router", "menuUi"]
489
+ };
490
+ var persistedReducer = persistReducer(persistConfig, rootReducer);
491
+ var store = configureStore({
492
+ reducer: persistedReducer,
493
+ middleware: (getDefaultMiddleware) => getDefaultMiddleware({
494
+ serializableCheck: {
495
+ ignoredActions: [FLUSH, REHYDRATE, PAUSE, PERSIST, PURGE, REGISTER]
496
+ }
497
+ })
498
+ });
499
+ var persistor = persistStore(store);
500
+ registrarFuenteDeProcedimientos(() => {
501
+ const { procedure, procedures } = store.getState().clientContext;
502
+ if (procedure && Object.keys(procedure).length > 0) return procedure;
503
+ return procedures?.length ? Object.fromEntries(procedures.map((p) => [p.action, p])) : void 0;
504
+ });
505
+ var useAppDispatch = useDispatch;
506
+ var useAppSelector = useSelector;
507
+ var useClientContext = () => {
508
+ return useAppSelector((state) => state.clientContext);
509
+ };
510
+ var useClientContextStatus = () => {
511
+ return useAppSelector((state) => state.clientContext.status);
512
+ };
513
+ var useIsDrawerOpen = () => {
514
+ return useAppSelector((state) => state.menuUi.isDrawerOpen);
515
+ };
516
+ var useSubMenuOpenState = (menuName) => {
517
+ return useAppSelector((state) => state.menuUi.subMenuOpenStates[menuName] || false);
518
+ };
519
+ var useRedirectPath = () => {
520
+ return useAppSelector((state) => state.router.redirectPath);
521
+ };
522
+
303
523
  // src/components/ConfirmDialog.tsx
304
524
  import Dialog from "@mui/material/Dialog";
305
525
  import DialogTitle from "@mui/material/DialogTitle";
@@ -443,20 +663,42 @@ var DataGridOptionsDialog = ({
443
663
  };
444
664
 
445
665
  // src/components/grid/utils/helpers.ts
446
- var NEW_ROW_INDICATOR = "$new";
447
- var DOM_TEMP_ID = Symbol("domTempId");
448
- var getPrimaryKeyValues = (row, primaryKey) => {
449
- if (row[DOM_TEMP_ID]) return String(row[DOM_TEMP_ID]);
450
- return primaryKey.map((key) => {
451
- return row[key] !== void 0 && row[key] !== null ? String(row[key]) : "NULL_OR_UNDEFINED";
452
- }).join("|");
453
- };
454
- var sameValue = (a, b) => {
455
- if (a === b) return true;
456
- if (a instanceof Date && b instanceof Date) return a.getTime() === b.getTime();
457
- const isAEmpty = a === null || a === void 0;
458
- const isBEmpty = b === null || b === void 0;
459
- if (isAEmpty && isBEmpty) return true;
666
+ import typeStore from "type-store";
667
+
668
+ // src/utils/routeUtils.ts
669
+ import { Children, isValidElement } from "react";
670
+ var extractPathsFromRoutes = (node) => {
671
+ const paths = [];
672
+ Children.forEach(node, (child) => {
673
+ if (!isValidElement(child)) return;
674
+ if (child.props.path) {
675
+ paths.push(child.props.path);
676
+ }
677
+ if (child.props.children) {
678
+ paths.push(...extractPathsFromRoutes(child.props.children));
679
+ }
680
+ });
681
+ return paths;
682
+ };
683
+
684
+ // src/types/index.ts
685
+ var DOM_TEMP_ID = Symbol("domTempId");
686
+
687
+ // src/components/grid/utils/helpers.ts
688
+ var typerFrom = (fieldDef) => typeStore.typerFrom(fieldDef);
689
+ var NEW_ROW_INDICATOR = "$new";
690
+ var getPrimaryKeyValues = (row, primaryKey) => {
691
+ if (row[DOM_TEMP_ID]) return String(row[DOM_TEMP_ID]);
692
+ return primaryKey.map((key) => {
693
+ return row[key] !== void 0 && row[key] !== null ? String(row[key]) : "NULL_OR_UNDEFINED";
694
+ }).join("|");
695
+ };
696
+ var sameValue = (a, b) => {
697
+ if (a === b) return true;
698
+ if (a instanceof Date && b instanceof Date) return a.getTime() === b.getTime();
699
+ const isAEmpty = a === null || a === void 0;
700
+ const isBEmpty = b === null || b === void 0;
701
+ if (isAEmpty && isBEmpty) return true;
460
702
  return false;
461
703
  };
462
704
  var isNumericType = (typeName) => {
@@ -466,6 +708,16 @@ var isDateTimeType = (typeName) => {
466
708
  const t = typeName?.toLowerCase() || "";
467
709
  return ["date", "time", "timestamp", "interval", "tsrange", "time_range", "daterange"].some((type) => t.includes(type));
468
710
  };
711
+ var compararValores = (a, b) => {
712
+ if (typeof a === "number" && typeof b === "number") return a - b;
713
+ if (a instanceof Date && b instanceof Date) return a.getTime() - b.getTime();
714
+ if (typeof a === "string" && typeof b === "string") return a < b ? -1 : a > b ? 1 : 0;
715
+ if (typeof a === "bigint" && typeof b === "bigint") return a < b ? -1 : a > b ? 1 : 0;
716
+ const esNumerico = (v) => typeof v === "string" && v.trim() !== "" && !Number.isNaN(Number(v));
717
+ if (typeof a === "number" && esNumerico(b)) return a - Number(b);
718
+ if (esNumerico(a) && typeof b === "number") return Number(a) - b;
719
+ return null;
720
+ };
469
721
  var filterOperators = [
470
722
  { value: "=", label: "=" },
471
723
  { value: "~", label: "~" },
@@ -632,7 +884,7 @@ var useGridActions = ({
632
884
  }, 500);
633
885
  } catch (err) {
634
886
  console.error(`Error al eliminar la fila '${rowId}':`, err);
635
- showError(`Error al eliminar la fila '${rowId}': ${err.message || "Error desconocido"}`);
887
+ showError(`Error al eliminar la fila '${rowId}': ${mensajeDeError(err, "Error desconocido")}`);
636
888
  setExitingRowIds((prev) => {
637
889
  const newSet = new Set(prev);
638
890
  newSet.delete(rowId);
@@ -670,19 +922,19 @@ var useGridActions = ({
670
922
  if (updated > 0) messages.push(`${updated} fila(s) actualizada(s).`);
671
923
  if (skipped > 0) messages.push(`${skipped} fila(s) omitida(s).`);
672
924
  if (deleted > 0) messages.push(`${deleted} fila(s) eliminada(s).`);
673
- if (skippedColumns?.length > 0) messages.push(`Columnas omitidas: ${skippedColumns.join(", ")}`);
925
+ if (skippedColumns && skippedColumns.length > 0) messages.push(`Columnas omitidas: ${skippedColumns.join(", ")}`);
674
926
  showSuccess(messages.join("\n") || "Importaci\xF3n finalizada sin cambios detectados.");
675
- const newData = await callApi("table_data", {
927
+ const newData = requerido(await callApi("table_data", {
676
928
  table: tableName,
677
929
  fixedFields
678
- });
930
+ }), "los datos de la tabla");
679
931
  setTableData(newData);
680
932
  } else if (result && result.message) {
681
933
  showSuccess(result.message);
682
934
  }
683
935
  } catch (err) {
684
936
  console.error("Error durante la importaci\xF3n:", err);
685
- showError(`Importaci\xF3n cancelada: ${err.message || "Error desconocido"}`);
937
+ showError(`Importaci\xF3n cancelada: ${mensajeDeError(err, "Error desconocido")}`);
686
938
  }
687
939
  }, [tableName, fixedFields, callApiUpload, callApi, showSuccess, showError, setTableData]);
688
940
  return {
@@ -701,8 +953,8 @@ var useGridActions = ({
701
953
  };
702
954
 
703
955
  // src/hooks/grid/useGridDataView.ts
704
- import { useState as useState5, useCallback as useCallback4, useMemo } from "react";
705
- import typeStore from "type-store";
956
+ import { useState as useState5, useCallback as useCallback4, useMemo, useRef } from "react";
957
+ import typeStore2 from "type-store";
706
958
 
707
959
  // src/components/grid/utils/typedControls.ts
708
960
  var BestControls = {
@@ -723,7 +975,7 @@ var BestControls = {
723
975
  if (plainValue === null || plainValue === void 0) {
724
976
  return plainValue;
725
977
  }
726
- return typer.fromUserInput(plainValue);
978
+ return typer.fromUserInput(String(plainValue));
727
979
  }
728
980
  },
729
981
  number: {
@@ -756,7 +1008,7 @@ var BestControls = {
756
1008
  }
757
1009
  },
758
1010
  date: {
759
- getTypedValue: (plainValue, typer) => {
1011
+ getTypedValue: (plainValue) => {
760
1012
  if (plainValue === null || plainValue === void 0 || plainValue === "") return null;
761
1013
  if (plainValue instanceof Date) return plainValue;
762
1014
  const parts = String(plainValue).trim().split(/[-\/]/).map((s) => s.trim());
@@ -774,15 +1026,14 @@ var BestControls = {
774
1026
  }
775
1027
  const date = new Date(year, month, day);
776
1028
  if (date.getFullYear() === year && date.getMonth() === month && date.getDate() === day) {
777
- date.isRealDate = true;
778
- return date;
1029
+ return Object.assign(date, { isRealDate: true });
779
1030
  }
780
1031
  return null;
781
1032
  }
782
1033
  }
783
1034
  };
784
- var getBestTypedValue = (value, typer) => {
785
- value = value === "" ? typer.emptyValue : value;
1035
+ var getBestTypedValue = (valor, typer) => {
1036
+ const value = valor === "" ? typer.emptyValue : valor;
786
1037
  const typeName = typer.typeName;
787
1038
  if (["integer", "bigint", "decimal", "double", "float", "number"].includes(typeName)) {
788
1039
  return BestControls.number.getTypedValue(value);
@@ -791,12 +1042,13 @@ var getBestTypedValue = (value, typer) => {
791
1042
  return BestControls.boolean.getTypedValue(value);
792
1043
  }
793
1044
  if (typeName === "date" || typeName && typeName.toLowerCase().includes("timestamp")) {
794
- return BestControls.date.getTypedValue(value, typer);
1045
+ return BestControls.date.getTypedValue(value);
795
1046
  }
796
1047
  return BestControls.text.getTypedValue(value, typer);
797
1048
  };
798
1049
 
799
1050
  // src/hooks/grid/useGridDataView.ts
1051
+ var MAXIMO_FILAS_EDICION_PUNTUAL = 3;
800
1052
  var useGridDataView = ({ tableData, tableDefinition }) => {
801
1053
  const [sortColumns, setSortColumns] = useState5([]);
802
1054
  const getInitialSortColumns = useCallback4((def) => {
@@ -835,7 +1087,20 @@ var useGridDataView = ({ tableData, tableDefinition }) => {
835
1087
  return !prev;
836
1088
  });
837
1089
  }, []);
1090
+ const vistaAnteriorRef = useRef(null);
838
1091
  const filteredRows = useMemo(() => {
1092
+ const anterior = vistaAnteriorRef.current;
1093
+ if (anterior && anterior.filters === filters && anterior.isFilterRowVisible === isFilterRowVisible && anterior.sortColumns === sortColumns && anterior.tableDefinition === tableDefinition && anterior.tableData.length === tableData.length) {
1094
+ const reemplazos = /* @__PURE__ */ new Map();
1095
+ for (let i = 0; i < tableData.length && reemplazos.size <= MAXIMO_FILAS_EDICION_PUNTUAL; i++) {
1096
+ if (anterior.tableData[i] !== tableData[i]) reemplazos.set(anterior.tableData[i], tableData[i]);
1097
+ }
1098
+ if (reemplazos.size <= MAXIMO_FILAS_EDICION_PUNTUAL) {
1099
+ const filas = reemplazos.size === 0 ? anterior.filas : anterior.filas.map((fila) => reemplazos.get(fila) ?? fila);
1100
+ vistaAnteriorRef.current = { ...anterior, tableData, filas };
1101
+ return filas;
1102
+ }
1103
+ }
839
1104
  let rows = [...tableData];
840
1105
  if (isFilterRowVisible) {
841
1106
  Object.keys(filters).forEach((key) => {
@@ -851,7 +1116,7 @@ var useGridDataView = ({ tableData, tableDefinition }) => {
851
1116
  }
852
1117
  if (filterValue === "" && operator !== "\u2205" && operator !== "!=\u2205") return;
853
1118
  const fieldDef = tableDefinition?.fields.find((f) => f.name === key);
854
- const typer = fieldDef ? typeStore.typerFrom(fieldDef) : null;
1119
+ const typer = fieldDef ? typeStore2.typerFrom(fieldDef) : null;
855
1120
  let parsedFilterValue = filterValue;
856
1121
  if (typer && filterValue !== "" && !["~", "!~", "\u2205", "!=\u2205"].includes(operator)) {
857
1122
  try {
@@ -885,14 +1150,22 @@ var useGridDataView = ({ tableData, tableDefinition }) => {
885
1150
  return rawValue === null || rawValue === void 0 || rawValue === "";
886
1151
  case "!=\u2205":
887
1152
  return rawValue !== null && rawValue !== void 0 && rawValue !== "";
888
- case ">":
889
- return rawValue !== null && rawValue !== void 0 && rawValue > parsedFilterValue;
890
- case ">=":
891
- return rawValue !== null && rawValue !== void 0 && rawValue >= parsedFilterValue;
892
- case "<":
893
- return rawValue !== null && rawValue !== void 0 && rawValue < parsedFilterValue;
894
- case "<=":
895
- return rawValue !== null && rawValue !== void 0 && rawValue <= parsedFilterValue;
1153
+ case ">": {
1154
+ const orden = compararValores(rawValue, parsedFilterValue);
1155
+ return orden !== null && orden > 0;
1156
+ }
1157
+ case ">=": {
1158
+ const orden = compararValores(rawValue, parsedFilterValue);
1159
+ return orden !== null && orden >= 0;
1160
+ }
1161
+ case "<": {
1162
+ const orden = compararValores(rawValue, parsedFilterValue);
1163
+ return orden !== null && orden < 0;
1164
+ }
1165
+ case "<=": {
1166
+ const orden = compararValores(rawValue, parsedFilterValue);
1167
+ return orden !== null && orden <= 0;
1168
+ }
896
1169
  default:
897
1170
  return cellValue.includes(fValLower);
898
1171
  }
@@ -919,6 +1192,7 @@ var useGridDataView = ({ tableData, tableDefinition }) => {
919
1192
  return 0;
920
1193
  });
921
1194
  }
1195
+ vistaAnteriorRef.current = { tableData, filas: rows, filters, isFilterRowVisible, sortColumns, tableDefinition };
922
1196
  return rows;
923
1197
  }, [tableData, filters, isFilterRowVisible, tableDefinition, sortColumns]);
924
1198
  const summaryData = useMemo(() => {
@@ -931,10 +1205,10 @@ var useGridDataView = ({ tableData, tableDefinition }) => {
931
1205
  if (values.length === 0 && agg !== "count" && agg !== "countTrue") return;
932
1206
  switch (agg) {
933
1207
  case "sum":
934
- result[field.name] = { type: "sum", value: values.reduce((a, b) => Number(a) + Number(b), 0) };
1208
+ result[field.name] = { type: "sum", value: values.reduce((a, b) => a + Number(b), 0) };
935
1209
  break;
936
1210
  case "avg":
937
- const sum = values.reduce((a, b) => Number(a) + Number(b), 0);
1211
+ const sum = values.reduce((a, b) => a + Number(b), 0);
938
1212
  result[field.name] = { type: "avg", value: sum / values.length };
939
1213
  break;
940
1214
  case "min":
@@ -979,29 +1253,195 @@ var useGridDataView = ({ tableData, tableDefinition }) => {
979
1253
  };
980
1254
 
981
1255
  // src/hooks/grid/useGridEvents.ts
982
- import { useCallback as useCallback5 } from "react";
1256
+ import { useCallback as useCallback5, useRef as useRef3 } from "react";
1257
+
1258
+ // src/components/grid/detalles.tsx
1259
+ import { createContext as createContext2, useContext as useContext2, useEffect as useEffect2, useMemo as useMemo2, useRef as useRef2 } from "react";
1260
+ import { IconButton, Tooltip } from "@mui/material";
1261
+ import KeyboardArrowRightIcon from "@mui/icons-material/KeyboardArrowRight";
1262
+ import KeyboardArrowDownIcon from "@mui/icons-material/KeyboardArrowDown";
1263
+
1264
+ // src/pages/WScreens.tsx
1265
+ import { Box as Box2, Typography, Paper as Paper2 } from "@mui/material";
1266
+ import ConstructionIcon from "@mui/icons-material/Construction";
1267
+ import WarningAmberIcon from "@mui/icons-material/WarningAmber";
1268
+ import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
1269
+ var MyCustomDashboard = ({ screenName }) => {
1270
+ return /* @__PURE__ */ jsx4(Box2, { sx: { p: 4, display: "flex", flexDirection: "column", alignItems: "center", justifyContent: "center", height: "100%" }, children: /* @__PURE__ */ jsxs4(Paper2, { elevation: 3, sx: { p: 4, textAlign: "center", maxWidth: 600 }, children: [
1271
+ /* @__PURE__ */ jsxs4(Typography, { variant: "h5", component: "h1", gutterBottom: true, children: [
1272
+ "\xA1Bienvenido a tu WScreen: ",
1273
+ screenName,
1274
+ "!"
1275
+ ] }),
1276
+ /* @__PURE__ */ jsx4(Typography, { variant: "body1", color: "text.secondary", children: "Esta es una pantalla de interfaz de usuario personalizada." }),
1277
+ /* @__PURE__ */ jsx4(Box2, { sx: { mt: 3 }, children: /* @__PURE__ */ jsx4(ConstructionIcon, { sx: { fontSize: 80, color: "primary.main" } }) })
1278
+ ] }) });
1279
+ };
1280
+ var FallbackWScreen = ({ screenName }) => {
1281
+ return /* @__PURE__ */ jsx4(Box2, { sx: { p: 4, display: "flex", flexDirection: "column", alignItems: "center", justifyContent: "center", height: "100%" }, children: /* @__PURE__ */ jsxs4(Paper2, { elevation: 3, sx: { p: 4, textAlign: "center", maxWidth: 600, backgroundColor: "warning.light", border: "1px solid orange" }, children: [
1282
+ /* @__PURE__ */ jsx4(Typography, { variant: "h5", component: "h1", gutterBottom: true, color: "warning.dark", children: "WScreen No Implementada" }),
1283
+ /* @__PURE__ */ jsxs4(Typography, { variant: "body1", color: "warning.dark", children: [
1284
+ 'No se encontr\xF3 un componente implementado para la **WScreen**: **`"$',
1285
+ screenName,
1286
+ '"`**. Por favor, verifica el `menuType` en la definici\xF3n del men\xFA o aseg\xFArate de que el componente est\xE9 correctamente importado y mapeado en el frontend.'
1287
+ ] }),
1288
+ /* @__PURE__ */ jsx4(Box2, { sx: { mt: 3 }, children: /* @__PURE__ */ jsx4(WarningAmberIcon, { sx: { fontSize: 80, color: "warning.dark" } }) })
1289
+ ] }) });
1290
+ };
1291
+ var wScreens = {
1292
+ "MyCustomDashboard": MyCustomDashboard
1293
+ // Agrega más componentes de wScreen aquí:
1294
+ // 'AnotherWScreen': AnotherWScreenComponent,
1295
+ };
1296
+ var extendWScreens = (newWScreens) => {
1297
+ wScreens = { ...wScreens, ...newWScreens };
1298
+ console.log("wScreens extendidos:", wScreens);
1299
+ };
1300
+
1301
+ // src/components/grid/condiciones.ts
1302
+ var condiciones = {};
1303
+ var extendConditions = (nuevas) => {
1304
+ condiciones = { ...condiciones, ...nuevas };
1305
+ };
1306
+ var avisadas = /* @__PURE__ */ new Set();
1307
+ function cumpleCondicion(nombre, fila) {
1308
+ if (!nombre) return true;
1309
+ const condicion = condiciones[nombre];
1310
+ if (!condicion) {
1311
+ if (!avisadas.has(nombre)) {
1312
+ avisadas.add(nombre);
1313
+ console.warn(`La condici\xF3n '${nombre}' de un detalle no est\xE1 registrada (extendConditions / myConditions): se muestra el detalle.`);
1314
+ }
1315
+ return true;
1316
+ }
1317
+ return condicion(fila);
1318
+ }
1319
+
1320
+ // src/components/grid/detalles.tsx
1321
+ import { Fragment as Fragment2, jsx as jsx5 } from "react/jsx-runtime";
1322
+ var DETALLE = Symbol("detalle");
1323
+ var esFilaDetalle = (row) => typeof row === "object" && row !== null && row[DETALLE] === true;
1324
+ var claveDetalle = (rowId, detailTable) => `${rowId}|${detailTable.abr}`;
1325
+ var ALTO_INICIAL_DETALLE = 140;
1326
+ var ALTO_MINIMO_DETALLE = 80;
1327
+ var normalizarCampoDeDetalle = (campo) => {
1328
+ if (typeof campo === "string") return { target: campo, source: campo, tieneValor: false };
1329
+ if ("value" in campo) return { target: campo.target, value: campo.value, tieneValor: true, until: campo.until };
1330
+ return { target: campo.target, source: campo.source, tieneValor: false, nullMeansAll: campo.nullMeansAll, until: campo.until };
1331
+ };
1332
+ function calcularFixedFieldsDetalle(detailTable, row) {
1333
+ return detailTable.fields.map(normalizarCampoDeDetalle).filter((campo) => !campo.nullMeansAll || campo.source !== void 0 && row[campo.source] != null).map((campo) => {
1334
+ const fixedField = {
1335
+ fieldName: campo.target,
1336
+ value: campo.tieneValor ? campo.value : row[campo.source]
1337
+ };
1338
+ if (campo.until !== void 0) fixedField.until = campo.until;
1339
+ return fixedField;
1340
+ });
1341
+ }
1342
+ var CacheGrillasContext = createContext2(null);
1343
+ var DetallesGrillaContext = createContext2(null);
1344
+ var useDetallesGrilla = () => {
1345
+ const detalles = useContext2(DetallesGrillaContext);
1346
+ if (!detalles) throw new Error("falta DetallesGrillaContext.Provider");
1347
+ return detalles;
1348
+ };
1349
+ function BotonDetalle({ row, rowId, detailTable, deshabilitado }) {
1350
+ const { abiertos, alternarDetalle } = useDetallesGrilla();
1351
+ if (!cumpleCondicion(detailTable.condition, row)) return /* @__PURE__ */ jsx5("div", { className: "fpr-boton-detalle" });
1352
+ const abierto = abiertos.has(claveDetalle(rowId, detailTable));
1353
+ const titulo = deshabilitado ? "Grab\xE1 la fila para ver sus detalles" : `${detailTable.label || detailTable.abr}${abierto ? " (replegar)" : ""} \u2014 Ctrl+click: en otra pesta\xF1a`;
1354
+ return /* @__PURE__ */ jsx5(Tooltip, { title: titulo, children: /* @__PURE__ */ jsx5("span", { className: "fpr-boton-detalle", children: /* @__PURE__ */ jsx5(
1355
+ IconButton,
1356
+ {
1357
+ size: "small",
1358
+ disabled: deshabilitado,
1359
+ onClick: (e) => alternarDetalle(row, rowId, detailTable, e.ctrlKey || e.metaKey),
1360
+ onAuxClick: (e) => {
1361
+ if (e.button === 1) alternarDetalle(row, rowId, detailTable, true);
1362
+ },
1363
+ children: abierto ? /* @__PURE__ */ jsx5(KeyboardArrowDownIcon, { fontSize: "small" }) : /* @__PURE__ */ jsx5(KeyboardArrowRightIcon, { fontSize: "small" })
1364
+ }
1365
+ ) }) });
1366
+ }
1367
+ var AltoDisponibleContext = createContext2(void 0);
1368
+ var MARGEN_VERTICAL_DETALLE = 8;
1369
+ function DetalleWScreen({ fila, altoMaximo, onAlto, onAncho }) {
1370
+ const nombre = fila.detailTable.wScreen ?? "";
1371
+ const Pantalla = wScreens[nombre];
1372
+ const params = useMemo2(
1373
+ () => Object.fromEntries(fila.fixedFields.map((fixedField) => [fixedField.fieldName, fixedField.value])),
1374
+ [fila.fixedFields]
1375
+ );
1376
+ const contenido = useRef2(null);
1377
+ useEffect2(() => {
1378
+ const elemento = contenido.current;
1379
+ if (!elemento) return;
1380
+ const medir = () => {
1381
+ onAlto(elemento.offsetHeight + MARGEN_VERTICAL_DETALLE);
1382
+ onAncho(elemento.offsetWidth);
1383
+ };
1384
+ medir();
1385
+ const observador = new ResizeObserver(medir);
1386
+ observador.observe(elemento);
1387
+ return () => observador.disconnect();
1388
+ }, [onAlto, onAncho]);
1389
+ return /* @__PURE__ */ jsx5(AltoDisponibleContext.Provider, { value: altoMaximo === void 0 ? void 0 : altoMaximo - MARGEN_VERTICAL_DETALLE, children: /* @__PURE__ */ jsx5("div", { className: "fpr-detalle-wscreen", children: /* @__PURE__ */ jsx5("div", { ref: contenido, className: "fpr-detalle-wscreen-contenido", children: Pantalla ? /* @__PURE__ */ jsx5(Pantalla, { screenName: nombre, params }) : /* @__PURE__ */ jsx5(FallbackWScreen, { screenName: nombre }) }) }) });
1390
+ }
1391
+ function CeldaDetalle({ fila }) {
1392
+ const { renderDetalle } = useDetallesGrilla();
1393
+ return /* @__PURE__ */ jsx5(Fragment2, { children: renderDetalle(fila) });
1394
+ }
1395
+
1396
+ // src/hooks/grid/useGridEvents.ts
1397
+ var VIGENCIA_TECLA_PENDIENTE = 400;
1398
+ var VIGENCIA_VALOR_PENDIENTE_F4 = 1e3;
983
1399
  var useGridEvents = ({ dataGridRef, tableDefinition, filteredRows, tableData, fixedFields, setSelectedCell, setTableData, setSortColumns }) => {
1400
+ const filteredRowsRef = useRef3(filteredRows);
1401
+ filteredRowsRef.current = filteredRows;
1402
+ const tableDefinitionRef = useRef3(tableDefinition);
1403
+ tableDefinitionRef.current = tableDefinition;
1404
+ const valoresF4Pendientes = useRef3(/* @__PURE__ */ new Map());
1405
+ const teclasPendientes = useRef3([]);
1406
+ const editorActivo = useRef3(null);
1407
+ const registrarEditor = useCallback5((procesar) => {
1408
+ editorActivo.current = procesar;
1409
+ const cola = teclasPendientes.current;
1410
+ while (cola.length > 0 && Date.now() - cola[0].cuando > VIGENCIA_TECLA_PENDIENTE) cola.shift();
1411
+ const pendiente = cola.shift();
1412
+ if (pendiente) procesar(pendiente.key);
1413
+ return () => {
1414
+ if (editorActivo.current === procesar) editorActivo.current = null;
1415
+ };
1416
+ }, []);
984
1417
  const handleKeyPressInEditor = useCallback5((rowIndex, columnKey, event, currentColumns, handleCommit) => {
985
- if (dataGridRef.current && tableDefinition) {
1418
+ const tableDefinition2 = tableDefinitionRef.current;
1419
+ const filteredRows2 = filteredRowsRef.current;
1420
+ if (dataGridRef.current && tableDefinition2) {
986
1421
  const currentColumnIndex = currentColumns.findIndex((col) => col.key === columnKey);
987
1422
  const editableColumns = currentColumns.filter((col) => {
988
- const fieldDefinition = tableDefinition.fields.find((f) => f.name === col.key);
989
- return col.key !== "actionsColumn" && col.customType !== "detail" && (fieldDefinition?.editable !== false && !fieldDefinition?.clientSide);
1423
+ const fieldDefinition = tableDefinition2.fields.find((f) => f.name === col.key);
1424
+ return col.key !== "actionsColumn" && !(esColumnaPropia(col) && col.customType === "detail") && (fieldDefinition?.editable !== false && !fieldDefinition?.clientSide);
990
1425
  });
991
1426
  const { key, target } = event;
992
1427
  const input = target;
993
1428
  if (currentColumnIndex !== -1 && editableColumns.length > 0) {
994
1429
  const editableColumnKeys = editableColumns.map((col) => col.key);
995
1430
  let currentEditableColumnIndex = editableColumnKeys.indexOf(columnKey);
996
- const hacerFoco = ({ rowIdx, idx }) => setTimeout(() => dataGridRef.current?.selectCell({ rowIdx, idx }, { enableEditor: true, shouldFocusCell: true }), 10);
1431
+ const hacerFoco = ({ rowIdx, idx }) => dataGridRef.current?.selectCell({ rowIdx, idx }, { enableEditor: true, shouldFocusCell: true });
1432
+ const filaDeDatos = (desde, paso) => {
1433
+ let i = desde + paso;
1434
+ while (i >= 0 && i < filteredRows2.length && esFilaDetalle(filteredRows2[i])) i += paso;
1435
+ return i >= 0 && i < filteredRows2.length ? i : -1;
1436
+ };
997
1437
  const calcularColumnaSiguiente = () => {
998
1438
  let nextEditableColumnIndex = currentEditableColumnIndex + 1;
999
1439
  let nextRowIndex = rowIndex;
1000
1440
  if (nextEditableColumnIndex >= editableColumns.length) {
1001
1441
  nextEditableColumnIndex = 0;
1002
- nextRowIndex++;
1003
- if (nextRowIndex >= filteredRows.length) {
1004
- nextRowIndex = 0;
1442
+ nextRowIndex = filaDeDatos(rowIndex, 1);
1443
+ if (nextRowIndex === -1) {
1444
+ nextRowIndex = filaDeDatos(-1, 1);
1005
1445
  }
1006
1446
  }
1007
1447
  const nextColumnKey = editableColumnKeys[nextEditableColumnIndex];
@@ -1019,20 +1459,12 @@ var useGridEvents = ({ dataGridRef, tableDefinition, filteredRows, tableData, fi
1019
1459
  return { rowIdx: nextRowIndex, idx: nextColumnIndex };
1020
1460
  };
1021
1461
  const calcularFilaSiguiente = () => {
1022
- let nextRowIndex = rowIndex;
1023
- nextRowIndex++;
1024
- if (nextRowIndex >= filteredRows.length) {
1025
- return { rowIdx: rowIndex, idx: currentColumnIndex };
1026
- }
1027
- return { rowIdx: nextRowIndex, idx: currentColumnIndex };
1462
+ const nextRowIndex = filaDeDatos(rowIndex, 1);
1463
+ return { rowIdx: nextRowIndex === -1 ? rowIndex : nextRowIndex, idx: currentColumnIndex };
1028
1464
  };
1029
1465
  const calcularFilaAnterior = () => {
1030
- let nextRowIndex = rowIndex;
1031
- nextRowIndex--;
1032
- if (nextRowIndex < 0) {
1033
- return { rowIdx: rowIndex, idx: currentColumnIndex };
1034
- }
1035
- return { rowIdx: nextRowIndex, idx: currentColumnIndex };
1466
+ const nextRowIndex = filaDeDatos(rowIndex, -1);
1467
+ return { rowIdx: nextRowIndex === -1 ? rowIndex : nextRowIndex, idx: currentColumnIndex };
1036
1468
  };
1037
1469
  if (currentEditableColumnIndex !== -1) {
1038
1470
  switch (true) {
@@ -1068,11 +1500,16 @@ var useGridEvents = ({ dataGridRef, tableDefinition, filteredRows, tableData, fi
1068
1500
  break;
1069
1501
  }
1070
1502
  case key === "F4": {
1071
- setSortColumns([]);
1072
1503
  const { rowIdx, idx } = calcularFilaSiguiente();
1073
- const previousRow = filteredRows[rowIndex - 1];
1504
+ const indiceAnterior = filaDeDatos(rowIndex, -1);
1505
+ const previousRow = indiceAnterior === -1 ? void 0 : filteredRows2[indiceAnterior];
1074
1506
  if (previousRow) {
1075
- handleCommit(previousRow[columnKey], true, true).then(() => hacerFoco({ rowIdx, idx }));
1507
+ const pendiente = valoresF4Pendientes.current.get(`${indiceAnterior}|${columnKey}`);
1508
+ const valorACopiar = pendiente && Date.now() - pendiente.cuando < VIGENCIA_VALOR_PENDIENTE_F4 ? pendiente.valor : previousRow[columnKey];
1509
+ valoresF4Pendientes.current.set(`${rowIndex}|${columnKey}`, { valor: valorACopiar, cuando: Date.now() });
1510
+ void handleCommit(valorACopiar, true, true);
1511
+ editorActivo.current = null;
1512
+ hacerFoco({ rowIdx, idx });
1076
1513
  }
1077
1514
  break;
1078
1515
  }
@@ -1082,8 +1519,17 @@ var useGridEvents = ({ dataGridRef, tableDefinition, filteredRows, tableData, fi
1082
1519
  }
1083
1520
  }
1084
1521
  }
1085
- }, [filteredRows, tableDefinition, tableData, dataGridRef]);
1522
+ }, [dataGridRef]);
1086
1523
  const handleCellKeyDown = useCallback5((args, event) => {
1524
+ if (event.key === "F4" && !(event.target instanceof HTMLInputElement) && !esFilaDetalle(args.row)) {
1525
+ const fieldDefinition = tableDefinitionRef.current?.fields.find((f) => f.name === args.column.key);
1526
+ if (fieldDefinition && fieldDefinition.editable !== false && !fieldDefinition.clientSide) {
1527
+ if (editorActivo.current) editorActivo.current(event.key);
1528
+ else teclasPendientes.current.push({ key: event.key, cuando: Date.now() });
1529
+ event.preventGridDefault();
1530
+ return;
1531
+ }
1532
+ }
1087
1533
  if (["Enter", "Tab", "ArrowDown", "ArrowUp", "ArrowRight", "ArrowLeft"].includes(event.key)) {
1088
1534
  event.preventGridDefault();
1089
1535
  }
@@ -1098,23 +1544,27 @@ var useGridEvents = ({ dataGridRef, tableDefinition, filteredRows, tableData, fi
1098
1544
  setSelectedCell(args);
1099
1545
  }, [setSelectedCell]);
1100
1546
  const handleCellClick = useCallback5((args, _event) => {
1547
+ if (esFilaDetalle(args.row)) return;
1101
1548
  const fieldDefinition = tableDefinition?.fields.find((f) => f.name === args.column.key);
1102
1549
  const isFixedField = fixedFields?.some((f) => f.fieldName === args.column.key);
1103
1550
  const isEditable = fieldDefinition?.editable !== false && !isFixedField;
1104
1551
  if (isEditable) {
1105
- setSortColumns([]);
1106
1552
  args.selectCell(true);
1107
1553
  }
1108
- }, [tableDefinition, fixedFields, setSortColumns]);
1554
+ }, [tableDefinition, fixedFields]);
1109
1555
  const handleRowsChange = useCallback5((updatedRows, data) => {
1556
+ const reemplazos = /* @__PURE__ */ new Map();
1110
1557
  data.indexes.forEach((index) => {
1111
1558
  const oldRow = filteredRows[index];
1112
1559
  const newRow = updatedRows[index];
1113
- if (oldRow && newRow && oldRow[DOM_TEMP_ID] && !newRow[DOM_TEMP_ID]) {
1560
+ if (!oldRow || !newRow || esFilaDetalle(oldRow)) return;
1561
+ if (oldRow[DOM_TEMP_ID] && !newRow[DOM_TEMP_ID]) {
1114
1562
  newRow[DOM_TEMP_ID] = oldRow[DOM_TEMP_ID];
1115
1563
  }
1564
+ reemplazos.set(oldRow, newRow);
1116
1565
  });
1117
- setTableData(updatedRows);
1566
+ if (reemplazos.size === 0) return;
1567
+ setTableData((prevData) => prevData.map((row) => reemplazos.get(row) ?? row));
1118
1568
  }, [setTableData, filteredRows]);
1119
1569
  return {
1120
1570
  handleCellMouseDown,
@@ -1122,33 +1572,42 @@ var useGridEvents = ({ dataGridRef, tableDefinition, filteredRows, tableData, fi
1122
1572
  handleCellClick,
1123
1573
  handleCellKeyDown,
1124
1574
  handleKeyPressInEditor,
1575
+ registrarEditor,
1125
1576
  handleSelectedCellChange,
1126
1577
  handleRowsChange
1127
1578
  };
1128
1579
  };
1129
1580
 
1130
1581
  // src/hooks/grid/useGridLayout.ts
1131
- import { useMemo as useMemo2 } from "react";
1582
+ import { useMemo as useMemo3 } from "react";
1132
1583
  var useGridLayout = ({
1133
1584
  filteredRows,
1134
1585
  isFilterRowVisible,
1135
1586
  tableData,
1136
1587
  summaryData,
1137
1588
  filters,
1138
- setFilters
1589
+ setFilters,
1590
+ altoDetalles = 0,
1591
+ altoMinimoCuerpo = MIN_BODY_HEIGHT,
1592
+ // 24 px de margen inferior de la caja que contiene la grilla + lo que ocupa una barra de scroll horizontal (que le quita
1593
+ // alto a la grilla y, si no sobra lugar, hace aparecer una barra vertical aunque haya una sola fila)
1594
+ holgura = 24 + 24,
1595
+ filasVisiblesMax,
1596
+ conPie = true
1139
1597
  }) => {
1140
- const gridHeight = useMemo2(() => {
1598
+ const gridHeight = useMemo3(() => {
1141
1599
  const filterHeight2 = isFilterRowVisible ? FILTER_ROW_HEIGHT : 0;
1142
- let calculatedHeight = filteredRows.length * ROW_HEIGHT + HEADER_ROW_HEIGHT + filterHeight2 + SUMMARY_ROW_HEIGHT + 40;
1600
+ const filasParaAlto = filasVisiblesMax === void 0 ? filteredRows.length : Math.min(filteredRows.length, filasVisiblesMax);
1601
+ let calculatedHeight = filasParaAlto * ROW_HEIGHT + altoDetalles + HEADER_ROW_HEIGHT + filterHeight2 + (conPie ? SUMMARY_ROW_HEIGHT : 0) + holgura;
1143
1602
  if (tableData.length > 0 && filteredRows.length === 0 && isFilterRowVisible || tableData.length === 0) {
1144
- calculatedHeight = Math.max(calculatedHeight, MIN_BODY_HEIGHT) + filterHeight2;
1603
+ calculatedHeight = Math.max(calculatedHeight, altoMinimoCuerpo) + filterHeight2;
1145
1604
  }
1146
1605
  return calculatedHeight;
1147
- }, [filteredRows.length, isFilterRowVisible, tableData.length]);
1148
- const bottomSummaryRow = useMemo2(() => {
1149
- return { id: "bottomSummaryRow", ...summaryData };
1606
+ }, [filteredRows.length, isFilterRowVisible, tableData.length, altoDetalles, altoMinimoCuerpo, holgura, filasVisiblesMax, conPie]);
1607
+ const bottomSummaryRow = useMemo3(() => {
1608
+ return { id: "bottomSummaryRow", totales: summaryData };
1150
1609
  }, [summaryData]);
1151
- const summaryRows = useMemo2(() => {
1610
+ const summaryRows = useMemo3(() => {
1152
1611
  if (!isFilterRowVisible) return void 0;
1153
1612
  return [{ id: "filterRow", filters, setFilters }];
1154
1613
  }, [isFilterRowVisible, filters, setFilters]);
@@ -1157,7 +1616,7 @@ var useGridLayout = ({
1157
1616
  };
1158
1617
 
1159
1618
  // src/hooks/grid/useGridMenu.ts
1160
- import React2, { useMemo as useMemo3 } from "react";
1619
+ import React4, { useMemo as useMemo4 } from "react";
1161
1620
  import RefreshIcon from "@mui/icons-material/Refresh";
1162
1621
  import ViewColumnIcon from "@mui/icons-material/ViewColumn";
1163
1622
  import VisibilityOffIcon from "@mui/icons-material/VisibilityOff";
@@ -1176,21 +1635,21 @@ var useGridMenu = ({
1176
1635
  triggerExport
1177
1636
  }) => {
1178
1637
  const { showSuccess, showError, showWarning } = useSnackbar();
1179
- const menuOptions = useMemo3(() => {
1638
+ const menuOptions = useMemo4(() => {
1180
1639
  if (!tableDefinition) return [];
1181
1640
  const options = [];
1182
1641
  options.push({
1183
1642
  id: "refresh",
1184
1643
  label: "refrescar la grilla desde la base de datos",
1185
- icon: React2.createElement(RefreshIcon),
1644
+ icon: React4.createElement(RefreshIcon),
1186
1645
  handler: async () => {
1187
1646
  try {
1188
- const data = await callApi("table_data", { table: tableName, fixedFields });
1647
+ const data = requerido(await callApi("table_data", { table: tableName, fixedFields }), "los datos de la tabla");
1189
1648
  setTableData(data);
1190
1649
  if (resetSorting) resetSorting();
1191
1650
  showSuccess("Grilla refrescada correctamente");
1192
1651
  } catch (err) {
1193
- showError(`Error al refrescar: ${err.message || "Error desconocido"}`);
1652
+ showError(`Error al refrescar: ${mensajeDeError(err, "Error desconocido")}`);
1194
1653
  }
1195
1654
  },
1196
1655
  visible: true
@@ -1198,7 +1657,7 @@ var useGridMenu = ({
1198
1657
  options.push({
1199
1658
  id: "showColumns",
1200
1659
  label: "mostrar las columnas relacionadas",
1201
- icon: React2.createElement(ViewColumnIcon),
1660
+ icon: React4.createElement(ViewColumnIcon),
1202
1661
  handler: async () => {
1203
1662
  console.log("Mostrar columnas relacionadas");
1204
1663
  },
@@ -1207,7 +1666,7 @@ var useGridMenu = ({
1207
1666
  options.push({
1208
1667
  id: "hideColumns",
1209
1668
  label: "ocultar o mostrar columnas",
1210
- icon: React2.createElement(VisibilityOffIcon),
1669
+ icon: React4.createElement(VisibilityOffIcon),
1211
1670
  handler: async () => {
1212
1671
  console.log("Ocultar/mostrar columnas");
1213
1672
  },
@@ -1217,7 +1676,7 @@ var useGridMenu = ({
1217
1676
  options.push({
1218
1677
  id: "export",
1219
1678
  label: "exportar",
1220
- icon: React2.createElement(FileDownloadIcon),
1679
+ icon: React4.createElement(FileDownloadIcon),
1221
1680
  handler: async () => {
1222
1681
  if (triggerExport) triggerExport();
1223
1682
  else showWarning("La funcionalidad de exportaci\xF3n no est\xE1 disponible en este momento.");
@@ -1229,7 +1688,7 @@ var useGridMenu = ({
1229
1688
  options.push({
1230
1689
  id: "import",
1231
1690
  label: "importar (Excel/Tab)",
1232
- icon: React2.createElement(FileUploadIcon),
1691
+ icon: React4.createElement(FileUploadIcon),
1233
1692
  handler: async () => {
1234
1693
  if (triggerImport) triggerImport();
1235
1694
  else showWarning("La funcionalidad de importaci\xF3n no est\xE1 disponible en este momento.");
@@ -1241,7 +1700,7 @@ var useGridMenu = ({
1241
1700
  options.push({
1242
1701
  id: "deleteAll",
1243
1702
  label: "borrar todos los registros",
1244
- icon: React2.createElement(DeleteSweepIcon),
1703
+ icon: React4.createElement(DeleteSweepIcon),
1245
1704
  handler: async () => {
1246
1705
  showWarning("Esta operaci\xF3n eliminar\xE1 TODOS los registros de la tabla");
1247
1706
  },
@@ -1251,7 +1710,7 @@ var useGridMenu = ({
1251
1710
  options.push({
1252
1711
  id: "completeTable",
1253
1712
  label: "tabla completa y filtrada",
1254
- icon: React2.createElement(FilterAltIcon),
1713
+ icon: React4.createElement(FilterAltIcon),
1255
1714
  handler: async () => {
1256
1715
  console.log("Toggle tabla completa/filtrada");
1257
1716
  },
@@ -1263,220 +1722,77 @@ var useGridMenu = ({
1263
1722
  };
1264
1723
 
1265
1724
  // src/hooks/grid/useGridColumns.ts
1266
- import { useMemo as useMemo6 } from "react";
1725
+ import React9, { useMemo as useMemo7 } from "react";
1267
1726
 
1268
1727
  // src/utils/functions.tsx
1269
1728
  import * as JSON4all2 from "json4all";
1729
+ var cambiarGuionesBajosPorEspacios = (texto) => texto.replace(/_/g, " ");
1270
1730
 
1271
- // src/store/index.ts
1272
- import { configureStore, combineReducers } from "@reduxjs/toolkit";
1273
- import {
1274
- persistStore,
1275
- persistReducer,
1276
- FLUSH,
1277
- REHYDRATE,
1278
- PAUSE,
1279
- PERSIST,
1280
- PURGE,
1281
- REGISTER
1282
- } from "redux-persist";
1283
- import storage from "redux-persist/lib/storage";
1731
+ // src/components/grid/renderers/headerCellRenderers.tsx
1732
+ import { Box as Box3, IconButton as IconButton2, Tooltip as Tooltip2, Typography as Typography2 } from "@mui/material";
1733
+ import SearchIcon from "@mui/icons-material/Search";
1734
+ import SearchOffIcon from "@mui/icons-material/SearchOff";
1735
+ import MoreVertIcon from "@mui/icons-material/MoreVert";
1736
+ import AddIcon from "@mui/icons-material/Add";
1284
1737
 
1285
- // src/store/clientContextSlice.ts
1286
- import { createSlice, createAsyncThunk } from "@reduxjs/toolkit";
1287
- var initialState = {
1288
- menu: [],
1289
- procedure: {},
1290
- procedures: [],
1291
- config: {},
1292
- // Inicializa con un objeto vacío o valores por defecto adecuados
1293
- useragent: {},
1294
- // Igual aquí
1295
- username: "",
1296
- status: "idle",
1297
- // Por defecto, sin carga
1298
- error: null
1299
- // Sin error
1300
- };
1301
- var fetchClientContext = createAsyncThunk(
1302
- "clientContext/fetchClientContext",
1303
- async (_, { rejectWithValue }) => {
1304
- try {
1305
- const setupResponse = await fetchApi("/client-setup", { method: "GET" });
1306
- if (!setupResponse.ok) {
1307
- const errorData = await setupResponse.text();
1308
- throw new Error(errorData || "Error al obtener configuraci\xF3n del cliente");
1738
+ // src/components/grid/estadoGrilla.ts
1739
+ import { createContext as createContext3, useContext as useContext3, useSyncExternalStore } from "react";
1740
+ function crearEstadoGrilla() {
1741
+ let feedback = /* @__PURE__ */ new Map();
1742
+ let cambiosLocales = /* @__PURE__ */ new Map();
1743
+ const suscriptores = /* @__PURE__ */ new Set();
1744
+ const avisar = () => suscriptores.forEach((alCambiar) => alCambiar());
1745
+ return {
1746
+ obtenerFeedback: () => feedback,
1747
+ obtenerCambiosLocales: () => cambiosLocales,
1748
+ setFeedback(actualizacion) {
1749
+ const nuevo = typeof actualizacion === "function" ? actualizacion(feedback) : actualizacion;
1750
+ if (nuevo !== feedback) {
1751
+ feedback = nuevo;
1752
+ avisar();
1309
1753
  }
1310
- const clientSetup = await setupResponse.json();
1311
- return clientSetup;
1312
- } catch (error) {
1313
- return rejectWithValue(error.message || "Error desconocido al cargar el contexto");
1314
- }
1315
- }
1316
- );
1317
- var clientContextSlice = createSlice({
1318
- name: "clientContext",
1319
- initialState,
1320
- reducers: {
1321
- // Un reducer para limpiar el contexto del cliente (ej. al cerrar sesión)
1322
- clearClientContext: (state) => {
1323
- Object.assign(state, initialState);
1324
- }
1325
- // Puedes añadir otros reducers aquí si necesitas modificar partes del clientContext directamente
1326
- // pero el thunk es la forma preferida para la carga inicial.
1327
- },
1328
- // **extraReducers maneja las acciones del thunk asíncrono**
1329
- extraReducers: (builder) => {
1330
- builder.addCase(fetchClientContext.pending, (state) => {
1331
- state.status = "loading";
1332
- state.error = null;
1333
- }).addCase(fetchClientContext.fulfilled, (state, action) => {
1334
- state.status = "succeeded";
1335
- state.menu = action.payload.menu;
1336
- state.procedure = action.payload.procedure;
1337
- state.procedures = action.payload.procedures;
1338
- state.config = action.payload.config;
1339
- state.useragent = action.payload.useragent;
1340
- state.username = action.payload.username;
1341
- state.error = null;
1342
- }).addCase(fetchClientContext.rejected, (state, action) => {
1343
- state.status = "failed";
1344
- state.error = action.payload || "Fallo al cargar el contexto del cliente";
1345
- });
1346
- }
1347
- });
1348
- var { clearClientContext } = clientContextSlice.actions;
1349
- var clientContextSlice_default = clientContextSlice.reducer;
1350
-
1351
- // src/store/routerSlice.ts
1352
- import { createSlice as createSlice2 } from "@reduxjs/toolkit";
1353
- var initialState2 = {
1354
- currentPath: "/",
1355
- previousPath: null,
1356
- redirectPath: null
1357
- // <--- Inicializamos en null
1358
- };
1359
- var routerSlice = createSlice2({
1360
- name: "router",
1361
- initialState: initialState2,
1362
- reducers: {
1363
- setCurrentPath: (state, action) => {
1364
- state.previousPath = state.currentPath;
1365
- state.currentPath = action.payload;
1366
- },
1367
- setRedirectPath: (state, action) => {
1368
- state.redirectPath = action.payload;
1369
- },
1370
- resetRouterState: (state) => {
1371
- state.currentPath = "/";
1372
- state.previousPath = null;
1373
- state.redirectPath = null;
1374
- }
1375
- }
1376
- });
1377
- var { setCurrentPath, setRedirectPath, resetRouterState } = routerSlice.actions;
1378
- var routerSlice_default = routerSlice.reducer;
1379
-
1380
- // src/store/menuUiSlice.ts
1381
- import { createSlice as createSlice3 } from "@reduxjs/toolkit";
1382
- var initialState3 = {
1383
- isDrawerOpen: false,
1384
- subMenuOpenStates: {}
1385
- };
1386
- var menuUiSlice = createSlice3({
1387
- name: "menuUi",
1388
- initialState: initialState3,
1389
- reducers: {
1390
- setDrawerOpen: (state, action) => {
1391
- state.isDrawerOpen = action.payload;
1392
- },
1393
- toggleDrawer: (state) => {
1394
- state.isDrawerOpen = !state.isDrawerOpen;
1395
- },
1396
- setSubMenuOpen: (state, action) => {
1397
- state.subMenuOpenStates[action.payload.menuName] = action.payload.isOpen;
1398
1754
  },
1399
- toggleSubMenu: (state, action) => {
1400
- state.subMenuOpenStates[action.payload] = !state.subMenuOpenStates[action.payload];
1401
- },
1402
- // --- NUEVO REDUCER: Establecer el estado de todos los submenús ---
1403
- setAllSubMenusOpen: (state, action) => {
1404
- for (const menuName in state.subMenuOpenStates) {
1405
- if (Object.prototype.hasOwnProperty.call(state.subMenuOpenStates, menuName)) {
1406
- state.subMenuOpenStates[menuName] = action.payload;
1407
- }
1755
+ setCambiosLocales(actualizacion) {
1756
+ const nuevo = typeof actualizacion === "function" ? actualizacion(cambiosLocales) : actualizacion;
1757
+ if (nuevo !== cambiosLocales) {
1758
+ cambiosLocales = nuevo;
1759
+ avisar();
1408
1760
  }
1409
1761
  },
1410
- resetMenuUiState: (state) => {
1411
- Object.assign(state, initialState3);
1762
+ suscribir(alCambiar) {
1763
+ suscriptores.add(alCambiar);
1764
+ return () => {
1765
+ suscriptores.delete(alCambiar);
1766
+ };
1412
1767
  }
1768
+ };
1769
+ }
1770
+ var EstadoGrillaContext = createContext3(null);
1771
+ function useEstadoGrilla() {
1772
+ const estado = useContext3(EstadoGrillaContext);
1773
+ if (!estado) {
1774
+ throw new Error("useEstadoGrilla debe usarse dentro de EstadoGrillaContext.Provider");
1413
1775
  }
1414
- });
1415
- var {
1416
- setDrawerOpen,
1417
- toggleDrawer,
1418
- setSubMenuOpen,
1419
- toggleSubMenu,
1420
- setAllSubMenusOpen,
1421
- // ¡Exportamos la nueva acción!
1422
- resetMenuUiState
1423
- } = menuUiSlice.actions;
1424
- var menuUiSlice_default = menuUiSlice.reducer;
1425
-
1426
- // src/store/index.ts
1427
- import { useDispatch, useSelector } from "react-redux";
1428
- var rootReducer = combineReducers({
1429
- clientContext: clientContextSlice_default,
1430
- router: routerSlice_default,
1431
- menuUi: menuUiSlice_default
1432
- // ...otros slices
1433
- });
1434
- var persistConfig = {
1435
- key: "root",
1436
- storage,
1437
- whitelist: ["clientContext", "router", "menuUi"]
1438
- };
1439
- var persistedReducer = persistReducer(persistConfig, rootReducer);
1440
- var store = configureStore({
1441
- reducer: persistedReducer,
1442
- middleware: (getDefaultMiddleware) => getDefaultMiddleware({
1443
- serializableCheck: {
1444
- ignoredActions: [FLUSH, REHYDRATE, PAUSE, PERSIST, PURGE, REGISTER]
1445
- }
1446
- })
1447
- });
1448
- var persistor = persistStore(store);
1449
- var useAppDispatch = useDispatch;
1450
- var useAppSelector = useSelector;
1451
- var useClientContextStatus = () => {
1452
- return useAppSelector((state) => state.clientContext.status);
1453
- };
1454
- var useIsDrawerOpen = () => {
1455
- return useAppSelector((state) => state.menuUi.isDrawerOpen);
1456
- };
1457
- var useSubMenuOpenState = (menuName) => {
1458
- return useAppSelector((state) => state.menuUi.subMenuOpenStates[menuName] || false);
1459
- };
1460
- var useRedirectPath = () => {
1461
- return useAppSelector((state) => state.router.redirectPath);
1462
- };
1463
-
1464
- // src/utils/functions.tsx
1465
- var cambiarGuionesBajosPorEspacios = (texto) => texto.replace(/_/g, " ");
1776
+ return estado;
1777
+ }
1778
+ function useFeedbackCelda(cellKey) {
1779
+ const estado = useEstadoGrilla();
1780
+ return useSyncExternalStore(estado.suscribir, () => estado.obtenerFeedback().get(cellKey));
1781
+ }
1782
+ function useCeldaPendiente(rowId, columnKey) {
1783
+ const estado = useEstadoGrilla();
1784
+ return useSyncExternalStore(estado.suscribir, () => estado.obtenerCambiosLocales().get(rowId)?.has(columnKey) ?? false);
1785
+ }
1786
+ var VistaGrillaContext = createContext3({ isFilterRowVisible: false });
1787
+ var useVistaGrilla = () => useContext3(VistaGrillaContext);
1466
1788
 
1467
- // src/components/grid/renderers/headerCellRenderers.tsx
1468
- import { Box as Box2, IconButton, Tooltip, Typography } from "@mui/material";
1469
- import SearchIcon from "@mui/icons-material/Search";
1470
- import SearchOffIcon from "@mui/icons-material/SearchOff";
1471
- import MoreVertIcon from "@mui/icons-material/MoreVert";
1472
- import AddIcon from "@mui/icons-material/Add";
1473
- import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
1789
+ // src/components/grid/renderers/headerCellRenderers.tsx
1790
+ import { jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
1474
1791
  var defaultColumnHeaderCellRenderer = (props, fieldDef) => {
1475
- const { column, sortColumns } = props;
1792
+ const { column, sortDirection, priority } = props;
1476
1793
  const isPrimaryKey = fieldDef.isPk;
1477
- const sortIndex = sortColumns?.findIndex((s) => s.columnKey === column.key);
1478
- const sorted = sortIndex !== void 0 && sortIndex !== -1;
1479
- const sortColumn = sorted ? sortColumns[sortIndex] : null;
1794
+ const sorted = sortDirection !== void 0;
1795
+ const sortIndex = (priority ?? 1) - 1;
1480
1796
  const getSortColor = (index) => {
1481
1797
  if (index === 0) return "#000000";
1482
1798
  if (index === 1) return "#555555";
@@ -1484,8 +1800,8 @@ var defaultColumnHeaderCellRenderer = (props, fieldDef) => {
1484
1800
  return "#AAAAAA";
1485
1801
  };
1486
1802
  const sortColor = sorted ? getSortColor(sortIndex) : "transparent";
1487
- return /* @__PURE__ */ jsxs4(
1488
- Box2,
1803
+ return /* @__PURE__ */ jsxs5(
1804
+ Box3,
1489
1805
  {
1490
1806
  sx: {
1491
1807
  display: "flex",
@@ -1497,8 +1813,8 @@ var defaultColumnHeaderCellRenderer = (props, fieldDef) => {
1497
1813
  width: "100%"
1498
1814
  },
1499
1815
  children: [
1500
- /* @__PURE__ */ jsx4(
1501
- Typography,
1816
+ /* @__PURE__ */ jsx6(
1817
+ Typography2,
1502
1818
  {
1503
1819
  variant: "body2",
1504
1820
  sx: {
@@ -1514,55 +1830,61 @@ var defaultColumnHeaderCellRenderer = (props, fieldDef) => {
1514
1830
  children: column.name
1515
1831
  }
1516
1832
  ),
1517
- sorted && /* @__PURE__ */ jsx4(Box2, { sx: { color: sortColor, display: "flex", alignItems: "center", ml: 0.5, fontSize: "0.7rem" }, children: sortColumn?.direction === "ASC" ? "\u25B2" : "\u25BC" })
1833
+ sorted && /* @__PURE__ */ jsx6(Box3, { sx: { color: sortColor, display: "flex", alignItems: "center", ml: 0.5, fontSize: "0.7rem" }, children: sortDirection === "ASC" ? "\u25B2" : "\u25BC" })
1518
1834
  ]
1519
1835
  }
1520
1836
  );
1521
1837
  };
1522
- var actionsColumnHeaderCellRenderer = (props, isFilterRowVisible, toggleFilterVisibility, handleDataGridOptions, handleAddRow, allowInsert) => {
1523
- return /* @__PURE__ */ jsxs4(Box2, { sx: { display: "flex", flexDirection: "row", alignItems: "center", justifyContent: "center", gap: 0.2 }, children: [
1524
- allowInsert && /* @__PURE__ */ jsx4(
1525
- IconButton,
1838
+ var ActionsColumnHeaderCell = ({
1839
+ toggleFilterVisibility,
1840
+ handleDataGridOptions,
1841
+ handleAddRow,
1842
+ allowInsert
1843
+ }) => {
1844
+ const { isFilterRowVisible } = useVistaGrilla();
1845
+ return /* @__PURE__ */ jsxs5(Box3, { sx: { display: "flex", flexDirection: "row", alignItems: "center", justifyContent: "center", gap: 0.2 }, children: [
1846
+ allowInsert && /* @__PURE__ */ jsx6(
1847
+ IconButton2,
1526
1848
  {
1527
1849
  color: "inherit",
1528
- onClick: handleAddRow,
1850
+ onClick: () => handleAddRow(),
1529
1851
  size: "small",
1530
1852
  title: "A\xF1adir registro",
1531
1853
  sx: { p: 0.25 },
1532
- children: /* @__PURE__ */ jsx4(AddIcon, { sx: { fontSize: 18, color: "success.main" } })
1854
+ children: /* @__PURE__ */ jsx6(AddIcon, { sx: { fontSize: 18, color: "success.main" } })
1533
1855
  }
1534
1856
  ),
1535
- /* @__PURE__ */ jsx4(
1536
- IconButton,
1857
+ /* @__PURE__ */ jsx6(
1858
+ IconButton2,
1537
1859
  {
1538
1860
  color: "inherit",
1539
1861
  onClick: toggleFilterVisibility,
1540
1862
  size: "small",
1541
1863
  title: isFilterRowVisible ? "Ocultar filtros" : "Mostrar filtros",
1542
1864
  sx: { p: 0.25 },
1543
- children: isFilterRowVisible ? /* @__PURE__ */ jsx4(SearchOffIcon, { sx: { fontSize: 18 } }) : /* @__PURE__ */ jsx4(SearchIcon, { sx: { fontSize: 18 } })
1865
+ children: isFilterRowVisible ? /* @__PURE__ */ jsx6(SearchOffIcon, { sx: { fontSize: 18 } }) : /* @__PURE__ */ jsx6(SearchIcon, { sx: { fontSize: 18 } })
1544
1866
  }
1545
1867
  ),
1546
- /* @__PURE__ */ jsx4(
1547
- IconButton,
1868
+ /* @__PURE__ */ jsx6(
1869
+ IconButton2,
1548
1870
  {
1549
1871
  onClick: (event) => handleDataGridOptions(event),
1550
1872
  size: "small",
1551
1873
  title: "Opciones de esta tabla",
1552
1874
  sx: { p: 0.25 },
1553
- children: /* @__PURE__ */ jsx4(MoreVertIcon, { sx: { fontSize: 20, variant: "filled", size: "small" } })
1875
+ children: /* @__PURE__ */ jsx6(MoreVertIcon, { sx: { fontSize: 20, variant: "filled", size: "small" } })
1554
1876
  }
1555
1877
  )
1556
1878
  ] });
1557
1879
  };
1558
- var detailColumnCellHeaderRenderer = (props, detailTable) => /* @__PURE__ */ jsx4(Tooltip, { title: detailTable.label, children: /* @__PURE__ */ jsx4(Typography, { variant: "caption", sx: { fontSize: "0.75rem", fontWeight: "bold" }, children: detailTable.abr.toUpperCase() }) });
1880
+ var detailColumnCellHeaderRenderer = (props, detailTable) => /* @__PURE__ */ jsx6(Tooltip2, { title: detailTable.label, children: /* @__PURE__ */ jsx6(Typography2, { variant: "caption", sx: { fontSize: "0.75rem", fontWeight: "bold" }, children: detailTable.abr.toUpperCase() }) });
1559
1881
 
1560
1882
  // src/components/grid/FilterInputRender.tsx
1561
- import { InputBase, Box as Box3 } from "@mui/material";
1562
- import React4 from "react";
1883
+ import { InputBase, Box as Box4 } from "@mui/material";
1884
+ import React6 from "react";
1563
1885
 
1564
1886
  // src/components/forms/TypedField.tsx
1565
- import { useState as useState7, useEffect as useEffect2, useMemo as useMemo4, useCallback as useCallback7 } from "react";
1887
+ import { useState as useState7, useEffect as useEffect3, useMemo as useMemo5, useCallback as useCallback7 } from "react";
1566
1888
  import {
1567
1889
  TextField,
1568
1890
  FormControl,
@@ -1573,12 +1895,12 @@ import {
1573
1895
  InputAdornment,
1574
1896
  useTheme
1575
1897
  } from "@mui/material";
1576
- import typeStore2 from "type-store";
1577
- import { useRef } from "react";
1578
- import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
1898
+ import typeStore3 from "type-store";
1899
+ import { useRef as useRef4 } from "react";
1900
+ import { jsx as jsx7, jsxs as jsxs6 } from "react/jsx-runtime";
1579
1901
  var TypedField = ({ fieldDef, value, onChange, onCommit, disabled, isFilterMode = false, feedback, isMandatory = false }) => {
1580
1902
  const theme = useTheme();
1581
- const typer = useMemo4(() => typeStore2.typerFrom(fieldDef), [fieldDef]);
1903
+ const typer = useMemo5(() => typeStore3.typerFrom(fieldDef), [fieldDef]);
1582
1904
  const isBoolean = fieldDef.typeName === "boolean";
1583
1905
  const [localString, setLocalString] = useState7(() => {
1584
1906
  if (isBoolean) return "";
@@ -1590,9 +1912,9 @@ var TypedField = ({ fieldDef, value, onChange, onCommit, disabled, isFilterMode
1590
1912
  }
1591
1913
  });
1592
1914
  const [errorMsg, setErrorMsg] = useState7(null);
1593
- const lastValueRef = useRef(value);
1594
- const lastCommittedStringRef = useRef(localString);
1595
- useEffect2(() => {
1915
+ const lastValueRef = useRef4(value);
1916
+ const lastCommittedStringRef = useRef4(localString);
1917
+ useEffect3(() => {
1596
1918
  if (!isBoolean) {
1597
1919
  if (value !== lastValueRef.current) {
1598
1920
  lastValueRef.current = value;
@@ -1623,7 +1945,7 @@ var TypedField = ({ fieldDef, value, onChange, onCommit, disabled, isFilterMode
1623
1945
  typer.validateTypedData(parsedValue);
1624
1946
  } catch (err) {
1625
1947
  isValid = false;
1626
- pErrorMsg = err.message;
1948
+ pErrorMsg = mensajeDeError(err);
1627
1949
  }
1628
1950
  }
1629
1951
  setErrorMsg(pErrorMsg);
@@ -1682,28 +2004,28 @@ var TypedField = ({ fieldDef, value, onChange, onCommit, disabled, isFilterMode
1682
2004
  }
1683
2005
  const cellBackgroundColor2 = feedback === "error" ? theme.palette.error.light : feedback === "success" ? theme.palette.success.light : defaultBgColor;
1684
2006
  const transitionStyle2 = "background-color 0.3s ease-in-out";
1685
- return /* @__PURE__ */ jsxs5(FormControl, { fullWidth: true, error: !!errorMsg && !isFilterMode, disabled: isDisabled, size: "small", margin: "dense", children: [
1686
- !isFilterMode && /* @__PURE__ */ jsx5(InputLabel, { shrink: true, children: fieldDef.name }),
1687
- /* @__PURE__ */ jsxs5(
2007
+ return /* @__PURE__ */ jsxs6(FormControl, { fullWidth: true, error: !!errorMsg && !isFilterMode, disabled: isDisabled, size: "small", margin: "dense", children: [
2008
+ !isFilterMode && /* @__PURE__ */ jsx7(InputLabel, { shrink: true, children: fieldDef.name }),
2009
+ /* @__PURE__ */ jsxs6(
1688
2010
  Select,
1689
2011
  {
1690
2012
  value: boolVal,
1691
2013
  label: !isFilterMode ? fieldDef.name : void 0,
1692
2014
  onChange: handleBooleanChange,
1693
- startAdornment: isMandatory && isEmpty && !isFilterMode ? /* @__PURE__ */ jsx5(InputAdornment, { position: "start", sx: { color: "text.secondary", ml: 0.5 }, children: "*" }) : void 0,
2015
+ startAdornment: isMandatory && isEmpty && !isFilterMode ? /* @__PURE__ */ jsx7(InputAdornment, { position: "start", sx: { color: "text.secondary", ml: 0.5 }, children: "*" }) : void 0,
1694
2016
  displayEmpty: true,
1695
2017
  sx: isFilterMode ? { height: 25, fontSize: "0.8rem", backgroundColor: "background.paper" } : {
1696
2018
  backgroundColor: cellBackgroundColor2,
1697
2019
  transition: transitionStyle2
1698
2020
  },
1699
2021
  children: [
1700
- fieldDef.nullable !== false && /* @__PURE__ */ jsx5(MenuItem, { value: "", children: /* @__PURE__ */ jsx5("em", { children: "Nulo / Sin Especificar" }) }),
1701
- /* @__PURE__ */ jsx5(MenuItem, { value: "true", children: "S\xED (Verdadero)" }),
1702
- /* @__PURE__ */ jsx5(MenuItem, { value: "false", children: "No (Falso)" })
2022
+ fieldDef.nullable !== false && /* @__PURE__ */ jsx7(MenuItem, { value: "", children: /* @__PURE__ */ jsx7("em", { children: "Nulo / Sin Especificar" }) }),
2023
+ /* @__PURE__ */ jsx7(MenuItem, { value: "true", children: "S\xED (Verdadero)" }),
2024
+ /* @__PURE__ */ jsx7(MenuItem, { value: "false", children: "No (Falso)" })
1703
2025
  ]
1704
2026
  }
1705
2027
  ),
1706
- errorMsg && !isFilterMode && /* @__PURE__ */ jsx5(FormHelperText, { children: errorMsg })
2028
+ errorMsg && !isFilterMode && /* @__PURE__ */ jsx7(FormHelperText, { children: errorMsg })
1707
2029
  ] });
1708
2030
  }
1709
2031
  let inputType = "text";
@@ -1717,7 +2039,7 @@ var TypedField = ({ fieldDef, value, onChange, onCommit, disabled, isFilterMode
1717
2039
  }
1718
2040
  const cellBackgroundColor = feedback === "error" ? theme.palette.error.light : feedback === "success" ? theme.palette.success.light : defaultTextBgColor;
1719
2041
  const transitionStyle = "background-color 0.3s ease-in-out";
1720
- return /* @__PURE__ */ jsx5(
2042
+ return /* @__PURE__ */ jsx7(
1721
2043
  TextField,
1722
2044
  {
1723
2045
  fullWidth: true,
@@ -1733,7 +2055,7 @@ var TypedField = ({ fieldDef, value, onChange, onCommit, disabled, isFilterMode
1733
2055
  helperText: !isFilterMode ? errorMsg || (isMandatory ? "Obligatorio" : "") : void 0,
1734
2056
  InputLabelProps: !isFilterMode ? { shrink: true } : void 0,
1735
2057
  InputProps: !isFilterMode && isMandatory && isEmptyText ? {
1736
- startAdornment: /* @__PURE__ */ jsx5(InputAdornment, { position: "start", sx: { color: "text.secondary", mr: 0.5 }, children: "*" })
2058
+ startAdornment: /* @__PURE__ */ jsx7(InputAdornment, { position: "start", sx: { color: "text.secondary", mr: 0.5 }, children: "*" })
1737
2059
  } : {},
1738
2060
  inputProps: {
1739
2061
  style: {
@@ -1764,7 +2086,7 @@ var TypedField = ({ fieldDef, value, onChange, onCommit, disabled, isFilterMode
1764
2086
  };
1765
2087
 
1766
2088
  // src/components/grid/FilterInputRender.tsx
1767
- import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
2089
+ import { jsx as jsx8, jsxs as jsxs7 } from "react/jsx-runtime";
1768
2090
  function FilterInputRenderer({
1769
2091
  columnKey,
1770
2092
  currentFilter,
@@ -1787,8 +2109,8 @@ function FilterInputRenderer({
1787
2109
  [columnKey]: { operator: newOp, value: formattedVal }
1788
2110
  }));
1789
2111
  };
1790
- return /* @__PURE__ */ jsxs6(Box3, { sx: { mt: 0, display: "flex", alignItems: "center", gap: 0.5, pr: 1 }, children: [
1791
- /* @__PURE__ */ jsx6(
2112
+ return /* @__PURE__ */ jsxs7(Box4, { sx: { mt: 0, display: "flex", alignItems: "center", gap: 0.5, pr: 1 }, children: [
2113
+ /* @__PURE__ */ jsx8(
1792
2114
  "select",
1793
2115
  {
1794
2116
  value: operator,
@@ -1804,10 +2126,10 @@ function FilterInputRenderer({
1804
2126
  textAlign: "center",
1805
2127
  cursor: "pointer"
1806
2128
  },
1807
- children: filterOperators.map((op) => /* @__PURE__ */ jsx6("option", { value: op.value, children: op.label }, op.value))
2129
+ children: filterOperators.map((op) => /* @__PURE__ */ jsx8("option", { value: op.value, children: op.label }, op.value))
1808
2130
  }
1809
2131
  ),
1810
- /* @__PURE__ */ jsx6(
2132
+ /* @__PURE__ */ jsx8(
1811
2133
  TypedField,
1812
2134
  {
1813
2135
  fieldDef,
@@ -1818,7 +2140,7 @@ function FilterInputRenderer({
1818
2140
  )
1819
2141
  ] });
1820
2142
  }
1821
- return /* @__PURE__ */ jsx6(
2143
+ return /* @__PURE__ */ jsx8(
1822
2144
  InputBase,
1823
2145
  {
1824
2146
  value: currentFilter || "",
@@ -1841,19 +2163,19 @@ function FilterInputRenderer({
1841
2163
  }
1842
2164
  );
1843
2165
  }
1844
- var FilterInputRender_default = React4.memo(FilterInputRenderer);
2166
+ var FilterInputRender_default = React6.memo(FilterInputRenderer);
1845
2167
 
1846
2168
  // src/components/grid/renderers/summaryCellRenderers.tsx
1847
- import { Box as Box4 } from "@mui/material";
1848
- import { jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
1849
- var defaultColumnSummaryCellRenderer = (props, fixedFields, isFilterRowVisible) => {
2169
+ import { Box as Box5 } from "@mui/material";
2170
+ import { jsx as jsx9, jsxs as jsxs8 } from "react/jsx-runtime";
2171
+ var defaultColumnSummaryCellRenderer = (props, fixedFields) => {
1850
2172
  const { column, row } = props;
1851
2173
  if (row.id === "filterRow") {
1852
2174
  const { filters, setFilters } = row;
1853
2175
  const fixedFieldEntry = fixedFields?.find((f) => f.fieldName === column.key);
1854
- if (fixedFieldEntry && fixedFieldEntry.until === void 0 || !isFilterRowVisible) return null;
1855
- const fieldDef = column.fieldDef;
1856
- return /* @__PURE__ */ jsx7(Box4, { sx: { width: "100%", height: "100%", display: "flex", alignItems: "center" }, children: /* @__PURE__ */ jsx7(
2176
+ if (fixedFieldEntry && fixedFieldEntry.until === void 0) return null;
2177
+ const fieldDef = esColumnaPropia(column) && column.customType === "default" ? column.fieldDef : void 0;
2178
+ return /* @__PURE__ */ jsx9(Box5, { sx: { width: "100%", height: "100%", display: "flex", alignItems: "center" }, children: /* @__PURE__ */ jsx9(
1857
2179
  FilterInputRender_default,
1858
2180
  {
1859
2181
  columnKey: column.key,
@@ -1863,8 +2185,8 @@ var defaultColumnSummaryCellRenderer = (props, fixedFields, isFilterRowVisible)
1863
2185
  }
1864
2186
  ) });
1865
2187
  }
1866
- const summaryData = row[column.key];
1867
- if (!summaryData || typeof summaryData !== "object") return null;
2188
+ const summaryData = row.totales[column.key];
2189
+ if (!summaryData) return null;
1868
2190
  const { type, value } = summaryData;
1869
2191
  let label = "";
1870
2192
  let formattedValue = value;
@@ -1895,7 +2217,7 @@ var defaultColumnSummaryCellRenderer = (props, fixedFields, isFilterRowVisible)
1895
2217
  label = "Cant S\xED: ";
1896
2218
  break;
1897
2219
  }
1898
- return /* @__PURE__ */ jsxs7(Box4, { sx: {
2220
+ return /* @__PURE__ */ jsxs8(Box5, { sx: {
1899
2221
  px: 0,
1900
2222
  fontWeight: "bold",
1901
2223
  fontSize: "0.875rem",
@@ -1909,40 +2231,40 @@ var defaultColumnSummaryCellRenderer = (props, fixedFields, isFilterRowVisible)
1909
2231
  formattedValue
1910
2232
  ] });
1911
2233
  };
1912
- var actionsColumnSummaryCellRenderer = (props) => null;
1913
- var detailColumnCellSummaryRenderer = (props) => null;
2234
+ var actionsColumnSummaryCellRenderer = (_props) => null;
2235
+ var detailColumnCellSummaryRenderer = (_props) => null;
1914
2236
 
1915
2237
  // src/components/grid/renderers/cellRenderers.tsx
1916
- import { Box as Box7, Button as Button2, IconButton as IconButton2, Tooltip as Tooltip3, Typography as Typography4, useTheme as useTheme2 } from "@mui/material";
1917
- import KeyboardArrowRightIcon from "@mui/icons-material/KeyboardArrowRight";
2238
+ import React7 from "react";
2239
+ import { Box as Box8, Button as Button2, Tooltip as Tooltip4, useTheme as useTheme2 } from "@mui/material";
1918
2240
  import ViewHeadlineIcon from "@mui/icons-material/ViewHeadline";
1919
2241
  import DeleteIcon from "@mui/icons-material/Delete";
1920
2242
  import AddIcon2 from "@mui/icons-material/Add";
1921
2243
 
1922
2244
  // src/components/grid/ExampleClientSideComponent.tsx
1923
- import { Box as Box5, Typography as Typography2 } from "@mui/material";
1924
- import { jsx as jsx8 } from "react/jsx-runtime";
2245
+ import { Box as Box6, Typography as Typography3 } from "@mui/material";
2246
+ import { jsx as jsx10 } from "react/jsx-runtime";
1925
2247
  var ExampleClientSideComponent = ({ row, column, fieldDefinition }) => {
1926
2248
  const value = row[column.key];
1927
- return /* @__PURE__ */ jsx8(Box5, { sx: {
2249
+ return /* @__PURE__ */ jsx10(Box6, { sx: {
1928
2250
  padding: 0.5,
1929
2251
  width: "100%",
1930
2252
  height: "100%",
1931
2253
  display: "flex",
1932
2254
  alignItems: "center",
1933
2255
  backgroundColor: value === "Special" ? "lightblue" : "transparent"
1934
- }, children: /* @__PURE__ */ jsx8(Typography2, { variant: "body2", sx: { fontWeight: "bold" }, children: value ? `CS: ${value}` : "N/A" }) });
2256
+ }, children: /* @__PURE__ */ jsx10(Typography3, { variant: "body2", sx: { fontWeight: "bold" }, children: value ? `CS: ${value}` : "N/A" }) });
1935
2257
  };
1936
2258
  var ExampleClientSideComponent_default = ExampleClientSideComponent;
1937
2259
 
1938
2260
  // src/components/grid/FallbackClientSideRenderer.tsx
1939
- import { Box as Box6, Typography as Typography3, Tooltip as Tooltip2 } from "@mui/material";
1940
- import WarningAmberIcon from "@mui/icons-material/WarningAmber";
1941
- import { jsx as jsx9, jsxs as jsxs8 } from "react/jsx-runtime";
2261
+ import { Box as Box7, Typography as Typography4, Tooltip as Tooltip3 } from "@mui/material";
2262
+ import WarningAmberIcon2 from "@mui/icons-material/WarningAmber";
2263
+ import { jsx as jsx11, jsxs as jsxs9 } from "react/jsx-runtime";
1942
2264
  var FallbackClientSideRenderer = ({ column, row, fieldDefinition }) => {
1943
2265
  const clientSideName = fieldDefinition?.clientSide || "Desconocido";
1944
- return /* @__PURE__ */ jsx9(Tooltip2, { title: `Componente clientSide '${clientSideName}' no implementado. Mostrando valor por defecto.`, children: /* @__PURE__ */ jsxs8(
1945
- Box6,
2266
+ return /* @__PURE__ */ jsx11(Tooltip3, { title: `Componente clientSide '${clientSideName}' no implementado. Mostrando valor por defecto.`, children: /* @__PURE__ */ jsxs9(
2267
+ Box7,
1946
2268
  {
1947
2269
  sx: {
1948
2270
  display: "flex",
@@ -1962,9 +2284,9 @@ var FallbackClientSideRenderer = ({ column, row, fieldDefinition }) => {
1962
2284
  // Evita que el contenido se desborde
1963
2285
  },
1964
2286
  children: [
1965
- /* @__PURE__ */ jsx9(Typography3, { variant: "body2", noWrap: true, sx: { flexGrow: 1 }, children: clientSideName + " not found" }),
1966
- /* @__PURE__ */ jsx9(
1967
- WarningAmberIcon,
2287
+ /* @__PURE__ */ jsx11(Typography4, { variant: "body2", noWrap: true, sx: { flexGrow: 1 }, children: clientSideName + " not found" }),
2288
+ /* @__PURE__ */ jsx11(
2289
+ WarningAmberIcon2,
1968
2290
  {
1969
2291
  sx: {
1970
2292
  fontSize: 18,
@@ -1991,91 +2313,71 @@ var extendClientSides = (newRenderers) => {
1991
2313
  };
1992
2314
 
1993
2315
  // src/components/grid/renderers/cellRenderers.tsx
1994
- import typeStore3 from "type-store";
1995
- import { jsx as jsx10 } from "react/jsx-runtime";
1996
- var allColumnsCellRenderer = (props, onOpenDetail, ancestors = [], currentFixedFields = []) => {
2316
+ import { jsx as jsx12 } from "react/jsx-runtime";
2317
+ var CeldaDato = React7.memo(function CeldaDato2({ row, columnKey, defaultColumn }) {
1997
2318
  const theme = useTheme2();
1998
- const column = props.column;
1999
- const { row } = props;
2319
+ const { primaryKey, fixedFields, typer, isMandatory, isNumeric } = defaultColumn;
2320
+ const rowId = getPrimaryKeyValues(row, primaryKey);
2321
+ const currentCellFeedback = useFeedbackCelda(`${rowId}-${columnKey}`);
2322
+ const pendiente = useCeldaPendiente(rowId, columnKey);
2323
+ const value = row[columnKey];
2324
+ const hasValue = value !== null && value !== void 0 && String(value).trim() !== "";
2325
+ let cellBackgroundColor = "transparent";
2326
+ if (currentCellFeedback) {
2327
+ cellBackgroundColor = currentCellFeedback.type === "error" ? theme.palette.error.light : theme.palette.success.light;
2328
+ } else if (fixedFields?.some((f) => f.fieldName === columnKey)) {
2329
+ cellBackgroundColor = theme.palette.action.selected;
2330
+ } else if (isMandatory && !hasValue || pendiente) {
2331
+ cellBackgroundColor = "#e3f2fd";
2332
+ }
2333
+ let displayValue = value !== null && value !== void 0 ? typer.toLocalString(value) : "";
2334
+ if (!hasValue && isMandatory) {
2335
+ displayValue = "* " + displayValue;
2336
+ }
2337
+ const signal = displayValue === "--" ? "typed-controls-signal-no-data" : displayValue === "//" ? "typed-controls-signal-unknown-data" : "";
2338
+ const celda = /* @__PURE__ */ jsx12(
2339
+ "div",
2340
+ {
2341
+ className: `fpr-celda ${isNumeric ? "fpr-celda-numerica" : ""} ${signal} ${row[NEW_ROW_INDICATOR] ? "new-row-cell-animation" : ""}`,
2342
+ style: { backgroundColor: cellBackgroundColor },
2343
+ children: displayValue
2344
+ }
2345
+ );
2346
+ return currentCellFeedback?.message ? /* @__PURE__ */ jsx12(Tooltip4, { title: currentCellFeedback.message, children: celda }) : celda;
2347
+ });
2348
+ var allColumnsCellRenderer = (props) => {
2349
+ const { row, column } = props;
2350
+ if (!esColumnaPropia(column)) return void 0;
2351
+ if (esFilaDetalle(row)) {
2352
+ return column.customType === "action" ? /* @__PURE__ */ jsx12(CeldaDetalle, { fila: row }) : null;
2353
+ }
2000
2354
  switch (column.customType) {
2001
2355
  case "default": {
2002
2356
  const defaultColumn = column;
2003
- const { fieldDef, tableDefinition, primaryKey, cellFeedbackMap, fixedFields, localCellChanges } = defaultColumn;
2004
- const rowId = getPrimaryKeyValues(row, primaryKey);
2005
- const cellKey = `${rowId}-${props.column.key}`;
2006
- const currentCellFeedback = cellFeedbackMap.get(cellKey);
2357
+ const { fieldDef, tableDefinition, primaryKey } = defaultColumn;
2007
2358
  if (fieldDef?.clientSide) {
2008
2359
  const ClientSideComponent = clientSides[fieldDef.clientSide];
2009
2360
  if (ClientSideComponent) {
2010
- return /* @__PURE__ */ jsx10(ClientSideComponent, { ...props, fieldDefinition: fieldDef, tableDefinition, primaryKey });
2011
- }
2012
- return /* @__PURE__ */ jsx10(FallbackClientSideRenderer_default, { ...props, fieldDefinition: fieldDef, tableDefinition, primaryKey });
2013
- }
2014
- let cellBackgroundColor = "transparent";
2015
- const isMandatory = tableDefinition.primaryKey.includes(props.column.key) || tableDefinition.fields.find((f) => f.name === props.column.key)?.nullable === false;
2016
- const hasValue = row[props.column.key] !== null && row[props.column.key] !== void 0 && String(row[props.column.key]).trim() !== "";
2017
- if (currentCellFeedback) {
2018
- cellBackgroundColor = currentCellFeedback.type === "error" ? theme.palette.error.light : theme.palette.success.light;
2019
- } else {
2020
- const isNewRowLocalCheck = row[NEW_ROW_INDICATOR2];
2021
- const isFixedFieldCurrent = fixedFields?.some((f) => f.fieldName === props.column.key);
2022
- if (isFixedFieldCurrent) {
2023
- cellBackgroundColor = theme.palette.action.selected;
2024
- } else if (isMandatory && !hasValue || localCellChanges.has(rowId) && localCellChanges.get(rowId)?.has(props.column.key)) {
2025
- cellBackgroundColor = "#e3f2fd";
2361
+ return /* @__PURE__ */ jsx12(ClientSideComponent, { ...props, fieldDefinition: fieldDef, tableDefinition, primaryKey });
2026
2362
  }
2363
+ return /* @__PURE__ */ jsx12(FallbackClientSideRenderer_default, { ...props, fieldDefinition: fieldDef, tableDefinition, primaryKey });
2027
2364
  }
2028
- const value = row[props.column.key];
2029
- const typer = typeStore3.typerFrom(fieldDef);
2030
- let displayValue = value !== null ? typer.toLocalString(value) : "";
2031
- const isNumeric = isNumericType(fieldDef?.typeName);
2032
- if (!hasValue && isMandatory) {
2033
- displayValue = "* " + displayValue;
2034
- }
2035
- return /* @__PURE__ */ jsx10(Tooltip3, { title: currentCellFeedback?.message || "", children: /* @__PURE__ */ jsx10(
2036
- Box7,
2037
- {
2038
- className: `${displayValue === "--" ? "typed-controls-signal-no-data" : displayValue === "//" ? "typed-controls-signal-unknown-data" : ""} ${row[NEW_ROW_INDICATOR2] ? "new-row-cell-animation" : ""}`,
2039
- sx: { position: "absolute", top: 0, left: 0, width: "100%", height: "100%", backgroundColor: cellBackgroundColor, transition: "background-color 0.3s ease-in-out", display: "flex", alignItems: "center", justifyContent: isNumeric ? "flex-end" : "flex-start", paddingLeft: "8px", paddingRight: "12px", boxSizing: "border-box" },
2040
- children: /* @__PURE__ */ jsx10(Typography4, { variant: "body2", sx: { fontSize: "0.875rem", whiteSpace: "nowrap" }, children: displayValue })
2041
- }
2042
- ) });
2365
+ return /* @__PURE__ */ jsx12(CeldaDato, { row, columnKey: props.column.key, defaultColumn });
2043
2366
  }
2044
2367
  case "detail": {
2045
- const detailColumn = column;
2046
- const { detailTable, primaryKey, tableData, setTableData, detailKey, tableDefinition } = detailColumn;
2047
- return /* @__PURE__ */ jsx10(Tooltip3, { title: detailTable.label, children: /* @__PURE__ */ jsx10(Box7, { sx: { display: "flex", justifyContent: "center", alignItems: "center", height: "100%" }, children: /* @__PURE__ */ jsx10(
2048
- IconButton2,
2368
+ const { detailTable, primaryKey } = column;
2369
+ return /* @__PURE__ */ jsx12(
2370
+ BotonDetalle,
2049
2371
  {
2050
- onClick: () => {
2051
- if (detailTable && onOpenDetail) {
2052
- const detailFixedFields = detailTable.fields.map((f) => {
2053
- if (typeof f === "string") return { fieldName: f, value: row[f] };
2054
- if ("source" in f) return { fieldName: f.target, value: row[f.source] };
2055
- return { fieldName: f.target, value: f.value };
2056
- });
2057
- const rawFixedFields = [...currentFixedFields, ...detailFixedFields];
2058
- const deduplicatedMap = /* @__PURE__ */ new Map();
2059
- rawFixedFields.forEach((ff) => deduplicatedMap.set(ff.fieldName, ff));
2060
- const allFixedFields = Array.from(deduplicatedMap.values());
2061
- const filterDescription = allFixedFields.map((ff) => `${cambiarGuionesBajosPorEspacios(ff.fieldName)}: ${ff.value}`).join(", ");
2062
- const label = `${cambiarGuionesBajosPorEspacios(detailTable.table).toUpperCase()} (${filterDescription})`;
2063
- const newAncestors = [...ancestors, {
2064
- tableName: tableDefinition.name,
2065
- row,
2066
- tableDefinition,
2067
- fixedFields: allFixedFields
2068
- }];
2069
- onOpenDetail(detailTable.table, allFixedFields, label, newAncestors);
2070
- }
2071
- },
2072
- children: /* @__PURE__ */ jsx10(KeyboardArrowRightIcon, {})
2372
+ row,
2373
+ rowId: getPrimaryKeyValues(row, primaryKey),
2374
+ detailTable,
2375
+ deshabilitado: !!row[NEW_ROW_INDICATOR]
2073
2376
  }
2074
- ) }) });
2377
+ );
2075
2378
  }
2076
2379
  case "action": {
2077
- const actionColumn = column;
2078
- const { tableDefinition, handleDeleteRow, handleAddRow, handleVerticalEditRow } = actionColumn;
2380
+ const { tableDefinition, handleDeleteRow, handleAddRow, handleVerticalEditRow } = column;
2079
2381
  const gridActionButtons = [
2080
2382
  {
2081
2383
  action: "insert",
@@ -2099,7 +2401,7 @@ var allColumnsCellRenderer = (props, onOpenDetail, ancestors = [], currentFixedF
2099
2401
  color: "primary"
2100
2402
  }
2101
2403
  ];
2102
- return /* @__PURE__ */ jsx10(Box7, { sx: { display: "flex", justifyContent: "center", alignItems: "center", height: "100%", gap: 0.5 }, children: gridActionButtons.map((actionDef) => tableDefinition.allow[actionDef.action] ? /* @__PURE__ */ jsx10(
2404
+ return /* @__PURE__ */ jsx12(Box8, { sx: { display: "flex", justifyContent: "center", alignItems: "center", height: "100%", gap: 0.5 }, children: gridActionButtons.map((actionDef) => tableDefinition.allow[actionDef.action] ? /* @__PURE__ */ jsx12(
2103
2405
  Button2,
2104
2406
  {
2105
2407
  variant: "outlined",
@@ -2108,7 +2410,7 @@ var allColumnsCellRenderer = (props, onOpenDetail, ancestors = [], currentFixedF
2108
2410
  onClick: () => actionDef.handler(row),
2109
2411
  title: actionDef.title,
2110
2412
  sx: { width: 22, minWidth: 22, height: 22, "& .MuiButton-startIcon": { m: 0 } },
2111
- children: /* @__PURE__ */ jsx10(actionDef.icon, { sx: { fontSize: 18 } })
2413
+ children: /* @__PURE__ */ jsx12(actionDef.icon, { sx: { fontSize: 18 } })
2112
2414
  },
2113
2415
  actionDef.action
2114
2416
  ) : null) });
@@ -2119,7 +2421,7 @@ var allColumnsCellRenderer = (props, onOpenDetail, ancestors = [], currentFixedF
2119
2421
  };
2120
2422
 
2121
2423
  // src/components/grid/InputRenderer.tsx
2122
- import React5, { useCallback as useCallback9, useMemo as useMemo5, useState as useState8 } from "react";
2424
+ import React8, { useCallback as useCallback9, useEffect as useEffect4, useMemo as useMemo6, useState as useState8 } from "react";
2123
2425
 
2124
2426
  // src/hooks/useTableRecordSave.ts
2125
2427
  import { useCallback as useCallback8 } from "react";
@@ -2167,16 +2469,16 @@ var useTableRecordSave = () => {
2167
2469
  oldRow: isNewRow ? {} : initialData,
2168
2470
  status
2169
2471
  });
2170
- return response;
2472
+ return requerido(response, "la respuesta del guardado");
2171
2473
  }, [callApi]);
2172
2474
  return { saveRecord, loading, error };
2173
2475
  };
2174
2476
 
2175
2477
  // src/components/grid/InputRenderer.tsx
2176
2478
  import InputBase2 from "@mui/material/InputBase";
2177
- import { useTheme as useTheme3 } from "@mui/material";
2479
+ import { Tooltip as Tooltip5, useTheme as useTheme3 } from "@mui/material";
2178
2480
  import typeStore4 from "type-store";
2179
- import { jsx as jsx11 } from "react/jsx-runtime";
2481
+ import { jsx as jsx13 } from "react/jsx-runtime";
2180
2482
  function findChangedValues(oldRowData, newRowData, isNewRow) {
2181
2483
  let changes = [];
2182
2484
  for (const key in newRowData) {
@@ -2193,27 +2495,25 @@ function InputRenderer({
2193
2495
  tableDefinition,
2194
2496
  onRowChange,
2195
2497
  onClose,
2196
- cellFeedbackMap,
2197
- // Tipo: CellFeedbackMap
2198
- setCellFeedbackMap,
2199
- // Tipo: Dispatch<SetStateAction<CellFeedbackMap>>
2200
2498
  onKeyPress,
2499
+ registrarEditor,
2201
2500
  setTableData,
2202
- setLocalCellChanges,
2203
- localCellChanges,
2204
2501
  primaryKey
2205
2502
  }) {
2206
- const fieldDefinition = tableDefinition.fields.find((f) => f.name === column.key);
2207
- const typer = useMemo5(() => typeStore4.typerFrom(fieldDefinition), [fieldDefinition]);
2503
+ const estadoGrilla = useEstadoGrilla();
2504
+ const setCellFeedbackMap = estadoGrilla.setFeedback;
2505
+ const setLocalCellChanges = estadoGrilla.setCambiosLocales;
2506
+ const fieldDefinition = requerido(tableDefinition.fields.find((f) => f.name === column.key), `el campo '${column.key}'`);
2507
+ const typer = useMemo6(() => typeStore4.typerFrom(fieldDefinition), [fieldDefinition]);
2208
2508
  const [editingValue, setEditingValue] = useState8(() => row[column.key] !== null ? isNumericType(fieldDefinition?.typeName) ? row[column.key] : typer.toLocalString(row[column.key]) : null);
2209
- const isCommitInProgress = React5.useRef(false);
2509
+ const isCommitInProgress = React8.useRef(false);
2210
2510
  const theme = useTheme3();
2211
2511
  const { showSuccess, showError } = useSnackbar();
2212
2512
  const { saveRecord } = useTableRecordSave();
2213
2513
  const tableName = tableDefinition.tableName;
2214
2514
  const rowId = getPrimaryKeyValues(row, primaryKey);
2215
2515
  const cellKey = `${rowId}-${column.key}`;
2216
- const currentCellFeedback = cellFeedbackMap.get(cellKey);
2516
+ const currentCellFeedback = useFeedbackCelda(cellKey);
2217
2517
  const isMandatory = tableDefinition.primaryKey.includes(column.key) || fieldDefinition?.nullable === false;
2218
2518
  const isEmpty = editingValue === null || editingValue === void 0 || String(editingValue).trim() === "";
2219
2519
  let cellBackgroundColor;
@@ -2222,7 +2522,7 @@ function InputRenderer({
2222
2522
  cellBackgroundColor = currentCellFeedback.type === "error" ? theme.palette.error.light : theme.palette.success.light;
2223
2523
  cellBorderColor = currentCellFeedback.type === "error" ? theme.palette.error.main : theme.palette.success.main;
2224
2524
  }
2225
- const initialRowId = useMemo5(() => getPrimaryKeyValues(row, primaryKey), [row, primaryKey]);
2525
+ const initialRowId = useMemo6(() => getPrimaryKeyValues(row, primaryKey), [row, primaryKey]);
2226
2526
  const handleCommit = useCallback9(async (currentValue, closeEditor, focusNextCell) => {
2227
2527
  if (isCommitInProgress.current) return;
2228
2528
  isCommitInProgress.current = true;
@@ -2231,7 +2531,7 @@ function InputRenderer({
2231
2531
  processedNewValue = getBestTypedValue(currentValue, typer);
2232
2532
  typer.validateTypedData(processedNewValue);
2233
2533
  } catch (err) {
2234
- showError(err.message);
2534
+ showError(mensajeDeError(err));
2235
2535
  isCommitInProgress.current = false;
2236
2536
  return;
2237
2537
  }
@@ -2239,7 +2539,7 @@ function InputRenderer({
2239
2539
  const arePKValuesFilled = tableDefinition.primaryKey.every(
2240
2540
  (key) => potentialUpdatedRow[key] !== void 0 && potentialUpdatedRow[key] !== null && String(potentialUpdatedRow[key]).trim() !== ""
2241
2541
  );
2242
- const isNewRow = !arePKValuesFilled || potentialUpdatedRow[NEW_ROW_INDICATOR2];
2542
+ const isNewRow = !arePKValuesFilled || !!potentialUpdatedRow[NEW_ROW_INDICATOR];
2243
2543
  const isMandatoryField = tableDefinition.primaryKey.includes(column.key) || tableDefinition.fields.find((f) => f.name === column.key)?.nullable === false;
2244
2544
  const isMandatoryFieldEmpty = isNewRow && isMandatoryField && (processedNewValue === null || processedNewValue === void 0 || String(processedNewValue).trim() === "");
2245
2545
  if (sameValue(processedNewValue, row[column.key]) && !isNewRow && !isMandatoryFieldEmpty) {
@@ -2295,7 +2595,7 @@ function InputRenderer({
2295
2595
  initialData: oldRowData,
2296
2596
  targetFieldName: column.key
2297
2597
  });
2298
- const responseRow = response.row;
2598
+ const responseRow = response.row ?? potentialUpdatedRow;
2299
2599
  let finalRowIdForFeedback;
2300
2600
  let persistedRowData;
2301
2601
  if (response.row && isNewRow) {
@@ -2320,7 +2620,8 @@ function InputRenderer({
2320
2620
  persistedRowData = responseRow;
2321
2621
  const isPrimaryKeyColumn = tableDefinition.primaryKey.includes(column.key);
2322
2622
  finalRowIdForFeedback = isPrimaryKeyColumn ? getPrimaryKeyValues(potentialUpdatedRow, tableDefinition.primaryKey) : currentRowIdBeforeUpdate;
2323
- onRowChange({ ...responseRow }, true);
2623
+ const mismaFila = (fila) => tableDefinition.primaryKey.every((k) => fila[k] === potentialUpdatedRow[k]);
2624
+ setTableData((prevData) => prevData.map((fila) => mismaFila(fila) ? { ...fila, ...responseRow } : fila));
2324
2625
  }
2325
2626
  const changes = findChangedValues(oldRowData, responseRow, isNewRow);
2326
2627
  setCellFeedbackMap((prevFeedback) => {
@@ -2340,7 +2641,7 @@ function InputRenderer({
2340
2641
  rowId: currentRowIdBeforeUpdate,
2341
2642
  columnKey: column.key,
2342
2643
  type: "error",
2343
- message: err.message
2644
+ message: mensajeDeError(err)
2344
2645
  });
2345
2646
  return newFeedback;
2346
2647
  });
@@ -2362,7 +2663,6 @@ function InputRenderer({
2362
2663
  onClose,
2363
2664
  setTableData,
2364
2665
  setLocalCellChanges,
2365
- localCellChanges,
2366
2666
  initialRowId,
2367
2667
  typer
2368
2668
  ]);
@@ -2375,18 +2675,26 @@ function InputRenderer({
2375
2675
  return;
2376
2676
  }
2377
2677
  if (["Enter", "Tab", "ArrowDown", "ArrowUp", "ArrowRight", "ArrowLeft"].includes(event.key)) {
2378
- await handleCommit(editingValue, true, true);
2678
+ void handleCommit(editingValue, true, true);
2379
2679
  if (onKeyPress) {
2380
2680
  onKeyPress(rowIdx, column.key, event, handleCommit);
2381
2681
  }
2382
2682
  }
2383
2683
  }, [handleCommit, editingValue, column.key, rowIdx, onKeyPress]);
2684
+ const procesarTecla = React8.useRef(() => {
2685
+ });
2686
+ procesarTecla.current = (key) => {
2687
+ if (key === "F4" && onKeyPress) {
2688
+ onKeyPress(rowIdx, column.key, { key, target: document.activeElement ?? document.body }, handleCommit);
2689
+ }
2690
+ };
2691
+ useEffect4(() => registrarEditor?.((key) => procesarTecla.current(key)), []);
2384
2692
  const handleBlur = useCallback9(() => {
2385
2693
  handleCommit(editingValue, true, false);
2386
2694
  }, [handleCommit, editingValue]);
2387
2695
  const isFieldEditable = fieldDefinition?.editable !== false;
2388
2696
  const isNumeric = isNumericType(fieldDefinition?.typeName);
2389
- return /* @__PURE__ */ jsx11(
2697
+ const editor = /* @__PURE__ */ jsx13(
2390
2698
  InputBase2,
2391
2699
  {
2392
2700
  autoFocus: true,
@@ -2413,14 +2721,15 @@ function InputRenderer({
2413
2721
  disabled: !isFieldEditable
2414
2722
  }
2415
2723
  );
2724
+ return currentCellFeedback?.message ? /* @__PURE__ */ jsx13(Tooltip5, { title: currentCellFeedback.message, children: /* @__PURE__ */ jsx13("div", { style: { width: "100%" }, children: editor }) }) : editor;
2416
2725
  }
2417
2726
  var InputRenderer_default = InputRenderer;
2418
2727
 
2419
2728
  // src/components/grid/renderers/editCellRenderers.tsx
2420
- import { Box as Box8, Tooltip as Tooltip4 } from "@mui/material";
2421
- import { jsx as jsx12 } from "react/jsx-runtime";
2729
+ import { jsx as jsx14 } from "react/jsx-runtime";
2422
2730
  var allColumnsEditCellRenderer = (props, allColumns) => {
2423
2731
  const column = props.column;
2732
+ if (!esColumnaPropia(column)) return void 0;
2424
2733
  switch (column.customType) {
2425
2734
  case "default": {
2426
2735
  const defaultColumn = column;
@@ -2429,11 +2738,8 @@ var allColumnsEditCellRenderer = (props, allColumns) => {
2429
2738
  fixedFields,
2430
2739
  primaryKey,
2431
2740
  setTableData,
2432
- cellFeedbackMap,
2433
- setCellFeedbackMap,
2434
2741
  handleKeyPressInEditor,
2435
- localCellChanges,
2436
- setLocalCellChanges
2742
+ registrarEditor
2437
2743
  } = defaultColumn;
2438
2744
  if (column.editable) {
2439
2745
  const fieldDefinition = tableDefinition.fields.find((f) => f.name === column.key);
@@ -2442,25 +2748,16 @@ var allColumnsEditCellRenderer = (props, allColumns) => {
2442
2748
  if (!isFieldEditableByUI) {
2443
2749
  return void 0;
2444
2750
  }
2445
- const rowId = getPrimaryKeyValues(props.row, primaryKey);
2446
- const cellKey = `${rowId}-${props.column.key}`;
2447
- const currentCellFeedback = cellFeedbackMap.get ? cellFeedbackMap.get(cellKey) : cellFeedbackMap[cellKey];
2448
- return (
2449
- // --- TOOLTIP ADAPTADO: Lee el mensaje de error desde el Mapa ---
2450
- /* @__PURE__ */ jsx12(Tooltip4, { title: currentCellFeedback?.message || "", children: /* @__PURE__ */ jsx12(Box8, { children: /* @__PURE__ */ jsx12(
2451
- InputRenderer_default,
2452
- {
2453
- ...props,
2454
- tableDefinition,
2455
- setCellFeedbackMap,
2456
- cellFeedbackMap,
2457
- onKeyPress: (rowIndex, columnKey, event, handleCommit) => handleKeyPressInEditor(rowIndex, columnKey, event, allColumns, handleCommit),
2458
- setTableData,
2459
- setLocalCellChanges,
2460
- localCellChanges,
2461
- primaryKey
2462
- }
2463
- ) }) })
2751
+ return /* @__PURE__ */ jsx14(
2752
+ InputRenderer_default,
2753
+ {
2754
+ ...props,
2755
+ tableDefinition,
2756
+ onKeyPress: (rowIndex, columnKey, event, handleCommit) => handleKeyPressInEditor(rowIndex, columnKey, event, allColumns, handleCommit),
2757
+ registrarEditor,
2758
+ setTableData,
2759
+ primaryKey
2760
+ }
2464
2761
  );
2465
2762
  }
2466
2763
  return void 0;
@@ -2477,79 +2774,81 @@ var allColumnsEditCellRenderer = (props, allColumns) => {
2477
2774
  };
2478
2775
 
2479
2776
  // src/hooks/grid/useGridColumns.ts
2480
- import typeStore5 from "type-store";
2777
+ var estimateTextWidth = (text) => text.length * 8 + 16;
2778
+ var calcularAnchosDeColumnas = (tableDefinition, filas) => {
2779
+ const anchos = /* @__PURE__ */ new Map();
2780
+ const muestra = filas.slice(0, 50);
2781
+ tableDefinition.fields.forEach((fieldDef) => {
2782
+ const headerLabel = fieldDef.label || fieldDef.name;
2783
+ const type = fieldDef.typeName?.toLowerCase() || "";
2784
+ let typeMinWidth = 60;
2785
+ if (type.includes("boolean") || type.includes("checkbox")) typeMinWidth = 60;
2786
+ else if (type.includes("date") || type.includes("timestamp")) typeMinWidth = 110;
2787
+ else if (type.includes("integer") || type.includes("numeric")) typeMinWidth = 80;
2788
+ const headerWidth = estimateTextWidth(headerLabel) + 20;
2789
+ const typer = typerFrom(fieldDef);
2790
+ const maxDataWidth = muestra.reduce((maxW, row) => {
2791
+ const valor = row[fieldDef.name];
2792
+ if (valor === null || valor === void 0) return maxW;
2793
+ let texto;
2794
+ try {
2795
+ texto = typer.toLocalString(valor);
2796
+ } catch {
2797
+ texto = String(valor);
2798
+ }
2799
+ return Math.max(maxW, estimateTextWidth(texto));
2800
+ }, 0);
2801
+ anchos.set(fieldDef.name, Math.min(Math.max(headerWidth, maxDataWidth, typeMinWidth), 500));
2802
+ });
2803
+ return anchos;
2804
+ };
2481
2805
  var useGridColumns = ({
2482
2806
  tableDefinition,
2483
- tableData,
2807
+ anchosCalculados,
2484
2808
  fixedFields,
2485
- isFilterRowVisible,
2486
- sortColumns,
2487
2809
  primaryKey,
2488
- localCellChanges,
2489
- cellFeedbackMap,
2490
- setCellFeedbackMap,
2491
2810
  setTableData,
2492
- setLocalCellChanges,
2493
2811
  handleKeyPressInEditor,
2812
+ registrarEditor,
2494
2813
  handleDeleteRow,
2495
2814
  handleAddRow,
2496
2815
  handleVerticalEditRow,
2497
2816
  toggleFilterVisibility,
2498
- setDataGridOptionsAnchorEl,
2499
- setOpenDataGridOptions,
2500
- onOpenDetail,
2501
- ancestors
2817
+ abrirOpcionesDeGrilla
2502
2818
  }) => {
2503
- const columns = useMemo6(() => {
2819
+ const columns = useMemo7(() => {
2504
2820
  if (!tableDefinition) return [];
2505
2821
  const fieldsToShow = tableDefinition.fields.filter((field) => {
2506
2822
  const isFixedField = fixedFields?.some((f) => f.fieldName === field.name);
2507
2823
  return !isFixedField && field.visible !== false;
2508
2824
  });
2509
- const estimateTextWidth = (text) => text.length * 8 + 16;
2510
- const getColumnWidthFromData = (fieldDef) => {
2511
- const headerLabel = fieldDef.label || fieldDef.name;
2512
- const type = fieldDef.typeName?.toLowerCase() || "";
2513
- let typeMinWidth = 60;
2514
- if (type.includes("boolean") || type.includes("checkbox")) typeMinWidth = 60;
2515
- else if (type.includes("date") || type.includes("timestamp")) typeMinWidth = 110;
2516
- else if (type.includes("integer") || type.includes("numeric")) typeMinWidth = 80;
2517
- const headerWidth = estimateTextWidth(headerLabel) + 20;
2518
- const sampleRows = tableData.slice(0, 50);
2519
- const maxDataWidth = sampleRows.reduce((maxW, row) => {
2520
- const typer = typeStore5.typerFrom(fieldDef);
2521
- const cellValue = row[fieldDef.name] !== null && typer.toLocalString(row[fieldDef.name]);
2522
- if (cellValue === null || cellValue === void 0) return maxW;
2523
- return Math.max(maxW, estimateTextWidth(String(cellValue)));
2524
- }, 0);
2525
- return Math.min(Math.max(headerWidth, maxDataWidth, typeMinWidth), 500);
2526
- };
2527
2825
  const defaultColumns = fieldsToShow.map((fieldDef) => {
2528
2826
  const isFixedField = fixedFields?.some((f) => f.fieldName === fieldDef.name);
2529
2827
  const isFieldEditable = fieldDef.editable !== false && !isFixedField;
2530
- const colWidth = getColumnWidthFromData(fieldDef);
2531
- return {
2828
+ const colWidth = anchosCalculados.get(fieldDef.name) ?? estimateTextWidth(fieldDef.label || fieldDef.name) + 20;
2829
+ const column = {
2532
2830
  key: fieldDef.name,
2533
2831
  customType: "default",
2534
2832
  tableDefinition,
2535
2833
  fieldDef,
2536
- cellFeedbackMap,
2537
- setCellFeedbackMap,
2834
+ typer: typerFrom(fieldDef),
2835
+ isMandatory: tableDefinition.primaryKey.includes(fieldDef.name) || fieldDef.nullable === false,
2836
+ isNumeric: isNumericType(fieldDef.typeName),
2538
2837
  primaryKey,
2539
2838
  fixedFields,
2540
- localCellChanges,
2541
- setLocalCellChanges,
2542
2839
  setTableData,
2543
2840
  name: fieldDef.label || cambiarGuionesBajosPorEspacios(fieldDef.name),
2544
2841
  resizable: true,
2545
2842
  sortable: true,
2546
2843
  editable: isFieldEditable,
2547
2844
  handleKeyPressInEditor,
2845
+ registrarEditor,
2548
2846
  width: colWidth,
2549
- minWidth: colWidth,
2550
- renderHeaderCell: (props) => defaultColumnHeaderCellRenderer({ ...props, sortColumns }, fieldDef),
2551
- renderSummaryCell: (props) => defaultColumnSummaryCellRenderer(props, fixedFields, isFilterRowVisible)
2847
+ minWidth: 40,
2848
+ renderHeaderCell: (props) => defaultColumnHeaderCellRenderer(props, fieldDef),
2849
+ renderSummaryCell: (props) => defaultColumnSummaryCellRenderer(props, fixedFields)
2552
2850
  };
2851
+ return column;
2553
2852
  });
2554
2853
  const availableActions = [
2555
2854
  tableDefinition.allow?.insert,
@@ -2569,51 +2868,45 @@ var useGridColumns = ({
2569
2868
  editable: false,
2570
2869
  resizable: false,
2571
2870
  sortable: false,
2572
- renderHeaderCell: (props) => actionsColumnHeaderCellRenderer(
2573
- props,
2574
- isFilterRowVisible,
2871
+ renderHeaderCell: () => React9.createElement(ActionsColumnHeaderCell, {
2575
2872
  toggleFilterVisibility,
2576
- (e) => {
2577
- setDataGridOptionsAnchorEl(e.currentTarget);
2578
- setOpenDataGridOptions(true);
2579
- },
2873
+ handleDataGridOptions: (e) => abrirOpcionesDeGrilla(e.currentTarget),
2580
2874
  handleAddRow,
2581
- tableDefinition.allow?.insert
2582
- ),
2875
+ allowInsert: tableDefinition.allow?.insert
2876
+ }),
2583
2877
  renderSummaryCell: (props) => actionsColumnSummaryCellRenderer(props)
2584
2878
  };
2585
- const detailColumns = [];
2586
- if (tableDefinition.detailTables && tableDefinition.detailTables.length > 0) {
2587
- tableDefinition.detailTables.forEach((detailTable) => {
2588
- const detailKey = `detail_${detailTable.abr}`;
2589
- detailColumns.push({
2590
- key: detailKey,
2591
- customType: "detail",
2592
- tableDefinition,
2593
- detailTable,
2594
- primaryKey,
2595
- tableData,
2596
- setTableData,
2597
- detailKey,
2598
- name: detailTable.label || `Detalle ${detailTable.abr}`,
2599
- resizable: false,
2600
- sortable: false,
2601
- editable: false,
2602
- width: 30,
2603
- minWidth: 30,
2604
- renderHeaderCell: (props) => detailColumnCellHeaderRenderer(props, detailTable),
2605
- renderSummaryCell: (props) => detailColumnCellSummaryRenderer(props)
2606
- });
2607
- });
2608
- }
2879
+ const detailColumns = (tableDefinition.detailTables ?? []).map((detailTable) => {
2880
+ const detailKey = `detail_${detailTable.abr}`;
2881
+ const column = {
2882
+ key: detailKey,
2883
+ customType: "detail",
2884
+ tableDefinition,
2885
+ detailTable,
2886
+ primaryKey,
2887
+ detailKey,
2888
+ name: detailTable.label || `Detalle ${detailTable.abr}`,
2889
+ resizable: false,
2890
+ sortable: false,
2891
+ editable: false,
2892
+ width: 30,
2893
+ minWidth: 30,
2894
+ renderHeaderCell: (props) => detailColumnCellHeaderRenderer(props, detailTable),
2895
+ renderSummaryCell: (props) => detailColumnCellSummaryRenderer(props)
2896
+ };
2897
+ return column;
2898
+ });
2609
2899
  const allColumns = [actionsColumn, ...detailColumns, ...defaultColumns];
2900
+ const cantidadDeColumnas = allColumns.length;
2901
+ const colSpanDetalle = (args) => args.type === "ROW" && esFilaDetalle(args.row) ? cantidadDeColumnas : void 0;
2610
2902
  return allColumns.map((col) => ({
2611
2903
  ...col,
2904
+ colSpan: col.customType === "action" ? colSpanDetalle : col.colSpan,
2612
2905
  editorOptions: { closeOnExternalRowChange: false },
2613
2906
  renderEditCell: (props) => allColumnsEditCellRenderer(props, allColumns),
2614
- renderCell: (props) => allColumnsCellRenderer(props, onOpenDetail, ancestors, fixedFields)
2907
+ renderCell: (props) => allColumnsCellRenderer(props)
2615
2908
  }));
2616
- }, [tableDefinition, fixedFields, isFilterRowVisible, primaryKey, localCellChanges, handleKeyPressInEditor, handleDeleteRow, handleAddRow, handleVerticalEditRow, toggleFilterVisibility, tableData, cellFeedbackMap, sortColumns, setDataGridOptionsAnchorEl, setOpenDataGridOptions]);
2909
+ }, [tableDefinition, anchosCalculados, fixedFields, primaryKey, setTableData, handleKeyPressInEditor, registrarEditor, handleDeleteRow, handleAddRow, handleVerticalEditRow, toggleFilterVisibility, abrirOpcionesDeGrilla]);
2617
2910
  return { columns };
2618
2911
  };
2619
2912
 
@@ -2633,7 +2926,7 @@ import {
2633
2926
  Divider
2634
2927
  } from "@mui/material";
2635
2928
  import FileUploadIcon2 from "@mui/icons-material/FileUpload";
2636
- import { jsx as jsx13, jsxs as jsxs9 } from "react/jsx-runtime";
2929
+ import { jsx as jsx15, jsxs as jsxs10 } from "react/jsx-runtime";
2637
2930
  var ImportDialog = ({ open, onClose, onImport, loading }) => {
2638
2931
  const [file, setFile] = useState9(null);
2639
2932
  const [options, setOptions] = useState9({
@@ -2655,15 +2948,15 @@ var ImportDialog = ({ open, onClose, onImport, loading }) => {
2655
2948
  onClose();
2656
2949
  }
2657
2950
  };
2658
- return /* @__PURE__ */ jsxs9(Dialog2, { open, onClose: loading ? void 0 : onClose, maxWidth: "sm", fullWidth: true, children: [
2659
- /* @__PURE__ */ jsxs9(DialogTitle2, { sx: { display: "flex", alignItems: "center", gap: 1 }, children: [
2660
- /* @__PURE__ */ jsx13(FileUploadIcon2, { color: "primary" }),
2951
+ return /* @__PURE__ */ jsxs10(Dialog2, { open, onClose: loading ? void 0 : onClose, maxWidth: "sm", fullWidth: true, children: [
2952
+ /* @__PURE__ */ jsxs10(DialogTitle2, { sx: { display: "flex", alignItems: "center", gap: 1 }, children: [
2953
+ /* @__PURE__ */ jsx15(FileUploadIcon2, { color: "primary" }),
2661
2954
  "Importar datos desde archivo"
2662
2955
  ] }),
2663
- /* @__PURE__ */ jsx13(DialogContent2, { dividers: true, children: /* @__PURE__ */ jsxs9(Stack, { spacing: 3, sx: { mt: 1 }, children: [
2664
- /* @__PURE__ */ jsxs9(Box9, { children: [
2665
- /* @__PURE__ */ jsx13(Typography5, { variant: "subtitle2", gutterBottom: true, fontWeight: "bold", children: "Seleccionar archivo" }),
2666
- /* @__PURE__ */ jsxs9(
2956
+ /* @__PURE__ */ jsx15(DialogContent2, { dividers: true, children: /* @__PURE__ */ jsxs10(Stack, { spacing: 3, sx: { mt: 1 }, children: [
2957
+ /* @__PURE__ */ jsxs10(Box9, { children: [
2958
+ /* @__PURE__ */ jsx15(Typography5, { variant: "subtitle2", gutterBottom: true, fontWeight: "bold", children: "Seleccionar archivo" }),
2959
+ /* @__PURE__ */ jsxs10(
2667
2960
  Box9,
2668
2961
  {
2669
2962
  sx: {
@@ -2676,7 +2969,7 @@ var ImportDialog = ({ open, onClose, onImport, loading }) => {
2676
2969
  position: "relative"
2677
2970
  },
2678
2971
  children: [
2679
- /* @__PURE__ */ jsx13(
2972
+ /* @__PURE__ */ jsx15(
2680
2973
  "input",
2681
2974
  {
2682
2975
  type: "file",
@@ -2693,19 +2986,19 @@ var ImportDialog = ({ open, onClose, onImport, loading }) => {
2693
2986
  }
2694
2987
  }
2695
2988
  ),
2696
- /* @__PURE__ */ jsx13(Typography5, { variant: "body2", color: file ? "textPrimary" : "textSecondary", children: file ? file.name : "Haz clic aqu\xED para seleccionar un archivo" })
2989
+ /* @__PURE__ */ jsx15(Typography5, { variant: "body2", color: file ? "textPrimary" : "textSecondary", children: file ? file.name : "Haz clic aqu\xED para seleccionar un archivo" })
2697
2990
  ]
2698
2991
  }
2699
2992
  )
2700
2993
  ] }),
2701
- /* @__PURE__ */ jsx13(Divider, {}),
2702
- /* @__PURE__ */ jsxs9(Box9, { children: [
2703
- /* @__PURE__ */ jsx13(Typography5, { variant: "subtitle2", gutterBottom: true, fontWeight: "bold", children: "Opciones de importaci\xF3n" }),
2704
- /* @__PURE__ */ jsxs9(Stack, { children: [
2705
- /* @__PURE__ */ jsx13(
2994
+ /* @__PURE__ */ jsx15(Divider, {}),
2995
+ /* @__PURE__ */ jsxs10(Box9, { children: [
2996
+ /* @__PURE__ */ jsx15(Typography5, { variant: "subtitle2", gutterBottom: true, fontWeight: "bold", children: "Opciones de importaci\xF3n" }),
2997
+ /* @__PURE__ */ jsxs10(Stack, { children: [
2998
+ /* @__PURE__ */ jsx15(
2706
2999
  FormControlLabel,
2707
3000
  {
2708
- control: /* @__PURE__ */ jsx13(
3001
+ control: /* @__PURE__ */ jsx15(
2709
3002
  Checkbox,
2710
3003
  {
2711
3004
  checked: options.skipUnknownFieldsAtImport,
@@ -2713,13 +3006,13 @@ var ImportDialog = ({ open, onClose, onImport, loading }) => {
2713
3006
  size: "small"
2714
3007
  }
2715
3008
  ),
2716
- label: /* @__PURE__ */ jsx13(Typography5, { variant: "body2", children: "Omitir campos desconocidos al importar" })
3009
+ label: /* @__PURE__ */ jsx15(Typography5, { variant: "body2", children: "Omitir campos desconocidos al importar" })
2717
3010
  }
2718
3011
  ),
2719
- /* @__PURE__ */ jsx13(
3012
+ /* @__PURE__ */ jsx15(
2720
3013
  FormControlLabel,
2721
3014
  {
2722
- control: /* @__PURE__ */ jsx13(
3015
+ control: /* @__PURE__ */ jsx15(
2723
3016
  Checkbox,
2724
3017
  {
2725
3018
  checked: options.simplificateSpaces,
@@ -2727,13 +3020,13 @@ var ImportDialog = ({ open, onClose, onImport, loading }) => {
2727
3020
  size: "small"
2728
3021
  }
2729
3022
  ),
2730
- label: /* @__PURE__ */ jsx13(Typography5, { variant: "body2", children: "Simplificar espacios" })
3023
+ label: /* @__PURE__ */ jsx15(Typography5, { variant: "body2", children: "Simplificar espacios" })
2731
3024
  }
2732
3025
  ),
2733
- /* @__PURE__ */ jsx13(
3026
+ /* @__PURE__ */ jsx15(
2734
3027
  FormControlLabel,
2735
3028
  {
2736
- control: /* @__PURE__ */ jsx13(
3029
+ control: /* @__PURE__ */ jsx15(
2737
3030
  Checkbox,
2738
3031
  {
2739
3032
  checked: options.replaceNewLineWithSpace,
@@ -2741,21 +3034,21 @@ var ImportDialog = ({ open, onClose, onImport, loading }) => {
2741
3034
  size: "small"
2742
3035
  }
2743
3036
  ),
2744
- label: /* @__PURE__ */ jsx13(Typography5, { variant: "body2", children: "Reemplazar saltos de l\xEDnea con espacios" })
3037
+ label: /* @__PURE__ */ jsx15(Typography5, { variant: "body2", children: "Reemplazar saltos de l\xEDnea con espacios" })
2745
3038
  }
2746
3039
  )
2747
3040
  ] })
2748
3041
  ] })
2749
3042
  ] }) }),
2750
- /* @__PURE__ */ jsxs9(DialogActions2, { sx: { px: 3, py: 2 }, children: [
2751
- /* @__PURE__ */ jsx13(Button3, { onClick: onClose, disabled: loading, children: "Cancelar" }),
2752
- /* @__PURE__ */ jsx13(
3043
+ /* @__PURE__ */ jsxs10(DialogActions2, { sx: { px: 3, py: 2 }, children: [
3044
+ /* @__PURE__ */ jsx15(Button3, { onClick: onClose, disabled: loading, children: "Cancelar" }),
3045
+ /* @__PURE__ */ jsx15(
2753
3046
  Button3,
2754
3047
  {
2755
3048
  onClick: handleConfirm,
2756
3049
  variant: "contained",
2757
3050
  disabled: !file || loading,
2758
- startIcon: /* @__PURE__ */ jsx13(FileUploadIcon2, {}),
3051
+ startIcon: /* @__PURE__ */ jsx15(FileUploadIcon2, {}),
2759
3052
  children: loading ? "Procesando..." : "Confirmar Importaci\xF3n"
2760
3053
  }
2761
3054
  )
@@ -2783,8 +3076,8 @@ import {
2783
3076
  CircularProgress as CircularProgress2
2784
3077
  } from "@mui/material";
2785
3078
  import * as XLSX from "xlsx";
2786
- import typeStore6 from "type-store";
2787
- import { jsx as jsx14, jsxs as jsxs10 } from "react/jsx-runtime";
3079
+ import typeStore5 from "type-store";
3080
+ import { jsx as jsx16, jsxs as jsxs11 } from "react/jsx-runtime";
2788
3081
  var ExportDialog = ({
2789
3082
  open,
2790
3083
  onClose,
@@ -2853,7 +3146,7 @@ var ExportDialog = ({
2853
3146
  data.push(fieldsToExport.map((fieldDef) => {
2854
3147
  const value = row[fieldDef.name];
2855
3148
  if (value == null) return "";
2856
- return typeStore6.typerFrom(fieldDef).toPlainString(value);
3149
+ return typeStore5.typerFrom(fieldDef).toPlainString(value);
2857
3150
  }));
2858
3151
  });
2859
3152
  const content = data.map((line) => line.map(replacer).join(separator)).join("\r\n");
@@ -2872,7 +3165,7 @@ var ExportDialog = ({
2872
3165
  fieldsToExport.forEach((fieldDef, iColumn) => {
2873
3166
  const value = row[fieldDef.name];
2874
3167
  if (value != null) {
2875
- const typer = typeStore6.typerFrom(fieldDef);
3168
+ const typer = typeStore5.typerFrom(fieldDef);
2876
3169
  const excelValue = typer.toExcelValue(value);
2877
3170
  const excelType = typer.toExcelType(value);
2878
3171
  const cell = { t: excelType, v: excelValue };
@@ -2929,63 +3222,63 @@ var ExportDialog = ({
2929
3222
  URL.revokeObjectURL(url);
2930
3223
  }, 0);
2931
3224
  };
2932
- return /* @__PURE__ */ jsxs10(Dialog3, { open, onClose, maxWidth: "xs", fullWidth: true, children: [
2933
- /* @__PURE__ */ jsx14(DialogTitle3, { children: "Exportar Datos" }),
2934
- /* @__PURE__ */ jsx14(DialogContent3, { children: isPreparing ? /* @__PURE__ */ jsxs10(Box10, { display: "flex", flexDirection: "column", alignItems: "center", py: 4, children: [
2935
- /* @__PURE__ */ jsx14(CircularProgress2, {}),
2936
- /* @__PURE__ */ jsx14(Typography6, { sx: { mt: 2 }, children: "Preparando exportaci\xF3n..." })
2937
- ] }) : /* @__PURE__ */ jsxs10(Box10, { sx: { mt: 1 }, children: [
2938
- /* @__PURE__ */ jsxs10(FormControl2, { component: "fieldset", children: [
2939
- /* @__PURE__ */ jsx14(FormLabel, { component: "legend", children: "Formato" }),
2940
- /* @__PURE__ */ jsxs10(
3225
+ return /* @__PURE__ */ jsxs11(Dialog3, { open, onClose, maxWidth: "xs", fullWidth: true, children: [
3226
+ /* @__PURE__ */ jsx16(DialogTitle3, { children: "Exportar Datos" }),
3227
+ /* @__PURE__ */ jsx16(DialogContent3, { children: isPreparing ? /* @__PURE__ */ jsxs11(Box10, { display: "flex", flexDirection: "column", alignItems: "center", py: 4, children: [
3228
+ /* @__PURE__ */ jsx16(CircularProgress2, {}),
3229
+ /* @__PURE__ */ jsx16(Typography6, { sx: { mt: 2 }, children: "Preparando exportaci\xF3n..." })
3230
+ ] }) : /* @__PURE__ */ jsxs11(Box10, { sx: { mt: 1 }, children: [
3231
+ /* @__PURE__ */ jsxs11(FormControl2, { component: "fieldset", children: [
3232
+ /* @__PURE__ */ jsx16(FormLabel, { component: "legend", children: "Formato" }),
3233
+ /* @__PURE__ */ jsxs11(
2941
3234
  RadioGroup,
2942
3235
  {
2943
3236
  value: format,
2944
3237
  onChange: (e) => setFormat(e.target.value),
2945
3238
  children: [
2946
- /* @__PURE__ */ jsx14(FormControlLabel2, { value: "xlsx", control: /* @__PURE__ */ jsx14(Radio, {}), label: "Excel (.xlsx)" }),
2947
- /* @__PURE__ */ jsx14(FormControlLabel2, { value: "tab", control: /* @__PURE__ */ jsx14(Radio, {}), label: "Tabulado (.tab | )" }),
2948
- /* @__PURE__ */ jsx14(FormControlLabel2, { value: "csv", control: /* @__PURE__ */ jsx14(Radio, {}), label: "CSV (.csv , )" })
3239
+ /* @__PURE__ */ jsx16(FormControlLabel2, { value: "xlsx", control: /* @__PURE__ */ jsx16(Radio, {}), label: "Excel (.xlsx)" }),
3240
+ /* @__PURE__ */ jsx16(FormControlLabel2, { value: "tab", control: /* @__PURE__ */ jsx16(Radio, {}), label: "Tabulado (.tab | )" }),
3241
+ /* @__PURE__ */ jsx16(FormControlLabel2, { value: "csv", control: /* @__PURE__ */ jsx16(Radio, {}), label: "CSV (.csv , )" })
2949
3242
  ]
2950
3243
  }
2951
3244
  )
2952
3245
  ] }),
2953
- /* @__PURE__ */ jsxs10(Box10, { sx: { mt: 3 }, children: [
2954
- /* @__PURE__ */ jsx14(Typography6, { variant: "subtitle2", gutterBottom: true, children: "Opciones de campos:" }),
2955
- /* @__PURE__ */ jsxs10(FormGroup, { children: [
2956
- /* @__PURE__ */ jsx14(
3246
+ /* @__PURE__ */ jsxs11(Box10, { sx: { mt: 3 }, children: [
3247
+ /* @__PURE__ */ jsx16(Typography6, { variant: "subtitle2", gutterBottom: true, children: "Opciones de campos:" }),
3248
+ /* @__PURE__ */ jsxs11(FormGroup, { children: [
3249
+ /* @__PURE__ */ jsx16(
2957
3250
  FormControlLabel2,
2958
3251
  {
2959
- control: /* @__PURE__ */ jsx14(Checkbox2, { checked: options.fromOtherTables, onChange: handleOptionChange, name: "fromOtherTables" }),
3252
+ control: /* @__PURE__ */ jsx16(Checkbox2, { checked: options.fromOtherTables, onChange: handleOptionChange, name: "fromOtherTables" }),
2960
3253
  label: "Desde otras tablas"
2961
3254
  }
2962
3255
  ),
2963
- /* @__PURE__ */ jsx14(
3256
+ /* @__PURE__ */ jsx16(
2964
3257
  FormControlLabel2,
2965
3258
  {
2966
- control: /* @__PURE__ */ jsx14(Checkbox2, { checked: options.readOnly, onChange: handleOptionChange, name: "readOnly" }),
3259
+ control: /* @__PURE__ */ jsx16(Checkbox2, { checked: options.readOnly, onChange: handleOptionChange, name: "readOnly" }),
2967
3260
  label: "Solo lectura"
2968
3261
  }
2969
3262
  ),
2970
- /* @__PURE__ */ jsx14(
3263
+ /* @__PURE__ */ jsx16(
2971
3264
  FormControlLabel2,
2972
3265
  {
2973
- control: /* @__PURE__ */ jsx14(Checkbox2, { checked: options.hiddens, onChange: handleOptionChange, name: "hiddens" }),
3266
+ control: /* @__PURE__ */ jsx16(Checkbox2, { checked: options.hiddens, onChange: handleOptionChange, name: "hiddens" }),
2974
3267
  label: "Ocultos"
2975
3268
  }
2976
3269
  )
2977
3270
  ] })
2978
3271
  ] })
2979
3272
  ] }) }),
2980
- /* @__PURE__ */ jsxs10(DialogActions3, { children: [
2981
- /* @__PURE__ */ jsx14(Button4, { onClick: onClose, disabled: isPreparing, children: "Cancelar" }),
2982
- /* @__PURE__ */ jsx14(Button4, { onClick: handlePrepareExport, variant: "contained", disabled: isPreparing, children: "Descargar" })
3273
+ /* @__PURE__ */ jsxs11(DialogActions3, { children: [
3274
+ /* @__PURE__ */ jsx16(Button4, { onClick: onClose, disabled: isPreparing, children: "Cancelar" }),
3275
+ /* @__PURE__ */ jsx16(Button4, { onClick: handlePrepareExport, variant: "contained", disabled: isPreparing, children: "Descargar" })
2983
3276
  ] })
2984
3277
  ] });
2985
3278
  };
2986
3279
 
2987
3280
  // src/pages/VerticalEditorPage.tsx
2988
- import { useState as useState11, useCallback as useCallback10, useMemo as useMemo7, useRef as useRef2 } from "react";
3281
+ import { useState as useState11, useCallback as useCallback10, useMemo as useMemo8, useRef as useRef5 } from "react";
2989
3282
  import {
2990
3283
  DialogTitle as DialogTitle4,
2991
3284
  DialogContent as DialogContent4,
@@ -2998,7 +3291,7 @@ import {
2998
3291
  Typography as Typography7
2999
3292
  } from "@mui/material";
3000
3293
  import CloseIcon from "@mui/icons-material/Close";
3001
- import { jsx as jsx15, jsxs as jsxs11 } from "react/jsx-runtime";
3294
+ import { jsx as jsx17, jsxs as jsxs12 } from "react/jsx-runtime";
3002
3295
  var VerticalEditorPage = ({
3003
3296
  tableName,
3004
3297
  tableDefinition,
@@ -3016,13 +3309,13 @@ var VerticalEditorPage = ({
3016
3309
  const [globalError, setGlobalError] = useState11(null);
3017
3310
  const [isSaving, setIsSaving] = useState11(false);
3018
3311
  const [fieldFeedback, setFieldFeedback] = useState11({});
3019
- const feedbackTimersRef = useRef2({});
3312
+ const feedbackTimersRef = useRef5({});
3020
3313
  const handleFieldChange = useCallback10((fieldName, newValue, isValid) => {
3021
3314
  setFormData((prev) => ({ ...prev, [fieldName]: newValue }));
3022
3315
  setValidityMap((prev) => ({ ...prev, [fieldName]: isValid }));
3023
3316
  setGlobalError(null);
3024
3317
  }, []);
3025
- const isFormValid = useMemo7(() => {
3318
+ const isFormValid = useMemo8(() => {
3026
3319
  for (const key in validityMap) {
3027
3320
  if (validityMap[key] === false) return false;
3028
3321
  }
@@ -3103,7 +3396,7 @@ var VerticalEditorPage = ({
3103
3396
  }
3104
3397
  onSaveSuccess(responseRow, wasNewItem);
3105
3398
  } catch (err) {
3106
- setGlobalError(err.message || "Error desconocido al guardar.");
3399
+ setGlobalError(mensajeDeError(err, "Error desconocido al guardar."));
3107
3400
  setFieldFeedback((prev) => ({ ...prev, [fieldName]: "error" }));
3108
3401
  if (feedbackTimersRef.current[fieldName]) clearTimeout(feedbackTimersRef.current[fieldName]);
3109
3402
  feedbackTimersRef.current[fieldName] = setTimeout(
@@ -3126,21 +3419,21 @@ var VerticalEditorPage = ({
3126
3419
  tableDefinition,
3127
3420
  onSaveSuccess
3128
3421
  ]);
3129
- return /* @__PURE__ */ jsxs11(Box11, { sx: { p: 2, display: "flex", flexDirection: "column", height: "100%" }, children: [
3130
- /* @__PURE__ */ jsxs11(DialogTitle4, { sx: { px: 0, pt: 0, display: "flex", justifyContent: "space-between", alignItems: "center" }, children: [
3131
- /* @__PURE__ */ jsxs11(Typography7, { component: "div", variant: "h6", children: [
3422
+ return /* @__PURE__ */ jsxs12(Box11, { sx: { p: 2, display: "flex", flexDirection: "column", height: "100%" }, children: [
3423
+ /* @__PURE__ */ jsxs12(DialogTitle4, { sx: { px: 0, pt: 0, display: "flex", justifyContent: "space-between", alignItems: "center" }, children: [
3424
+ /* @__PURE__ */ jsxs12(Typography7, { component: "div", variant: "h6", children: [
3132
3425
  isNewRow ? "Nuevo Registro" : "Editar Registro",
3133
3426
  " - ",
3134
3427
  tableDefinition.title || tableName
3135
3428
  ] }),
3136
- /* @__PURE__ */ jsx15(IconButton3, { onClick: onClose, size: "small", edge: "end", children: /* @__PURE__ */ jsx15(CloseIcon, {}) })
3429
+ /* @__PURE__ */ jsx17(IconButton3, { onClick: onClose, size: "small", edge: "end", children: /* @__PURE__ */ jsx17(CloseIcon, {}) })
3137
3430
  ] }),
3138
- /* @__PURE__ */ jsxs11(DialogContent4, { dividers: true, sx: { px: 2, flexGrow: 1, py: 1 }, children: [
3139
- globalError && /* @__PURE__ */ jsx15(Alert, { severity: "error", sx: { mb: 2 }, children: globalError }),
3140
- /* @__PURE__ */ jsx15(Box11, { sx: { display: "flex", flexDirection: "column", gap: 0.5 }, children: tableDefinition.fields.map((field) => {
3431
+ /* @__PURE__ */ jsxs12(DialogContent4, { dividers: true, sx: { px: 2, flexGrow: 1, py: 1 }, children: [
3432
+ globalError && /* @__PURE__ */ jsx17(Alert, { severity: "error", sx: { mb: 2 }, children: globalError }),
3433
+ /* @__PURE__ */ jsx17(Box11, { sx: { display: "flex", flexDirection: "column", gap: 0.5 }, children: tableDefinition.fields.map((field) => {
3141
3434
  const isFixed = fixedFields?.some((ff) => ff.fieldName === field.name);
3142
3435
  const isMandatory = field.nullable === false || tableDefinition.primaryKey.includes(field.name);
3143
- return /* @__PURE__ */ jsx15(Box11, { sx: { width: "100%", maxWidth: "100%" }, children: /* @__PURE__ */ jsx15(
3436
+ return /* @__PURE__ */ jsx17(Box11, { sx: { width: "100%", maxWidth: "100%" }, children: /* @__PURE__ */ jsx17(
3144
3437
  TypedField,
3145
3438
  {
3146
3439
  fieldDef: field,
@@ -3154,29 +3447,39 @@ var VerticalEditorPage = ({
3154
3447
  ) }, field.name);
3155
3448
  }) })
3156
3449
  ] }),
3157
- /* @__PURE__ */ jsxs11(DialogActions4, { sx: { px: 0, pb: 0, pt: 2, justifyContent: "space-between", alignItems: "center" }, children: [
3158
- /* @__PURE__ */ jsxs11(Box11, { children: [
3159
- isSaving && /* @__PURE__ */ jsx15(CircularProgress3, { size: 20, sx: { ml: 2 } }),
3160
- /* @__PURE__ */ jsx15("span", { style: { marginLeft: 10, fontSize: "0.8rem", color: "#666" }, children: isSaving ? "Guardando..." : "Cambios auto-guardados" })
3450
+ /* @__PURE__ */ jsxs12(DialogActions4, { sx: { px: 0, pb: 0, pt: 2, justifyContent: "space-between", alignItems: "center" }, children: [
3451
+ /* @__PURE__ */ jsxs12(Box11, { children: [
3452
+ isSaving && /* @__PURE__ */ jsx17(CircularProgress3, { size: 20, sx: { ml: 2 } }),
3453
+ /* @__PURE__ */ jsx17("span", { style: { marginLeft: 10, fontSize: "0.8rem", color: "#666" }, children: isSaving ? "Guardando..." : "Cambios auto-guardados" })
3161
3454
  ] }),
3162
- /* @__PURE__ */ jsx15(Button5, { variant: "outlined", onClick: onClose, children: "Cerrar" })
3455
+ /* @__PURE__ */ jsx17(Button5, { variant: "outlined", onClick: onClose, children: "Cerrar" })
3163
3456
  ] })
3164
3457
  ] });
3165
3458
  };
3166
3459
 
3167
3460
  // src/components/grid/GenericDataGrid.tsx
3168
- import { jsx as jsx16, jsxs as jsxs12 } from "react/jsx-runtime";
3461
+ import { jsx as jsx18, jsxs as jsxs13 } from "react/jsx-runtime";
3169
3462
  var SUMMARY_ROW_HEIGHT = 35;
3170
3463
  var FILTER_ROW_HEIGHT = 35;
3171
3464
  var HEADER_ROW_HEIGHT = 30;
3172
3465
  var ROW_HEIGHT = 30;
3173
3466
  var MIN_BODY_HEIGHT = 260;
3174
- var NEW_ROW_INDICATOR2 = "$new";
3175
- var StaticAncestorGrid = ({ ancestor, index, fieldsToHide, callApi, showSuccess, showError }) => {
3467
+ var DURACION_FEEDBACK_EXITO = 3e3;
3468
+ var ALTO_TITULO_ANIDADA = 26;
3469
+ var ALTO_MINIMO_CUERPO_ANIDADA = 120;
3470
+ var HOLGURA_ANIDADA = 24;
3471
+ var ANCHO_MINIMO_ANIDADA = 240;
3472
+ var SANGRIA_DETALLE = 28 + 8 + 3;
3473
+ var MARGEN_INFERIOR_PAGINA = 24;
3474
+ var PRIMERAS_FILAS_ANIDADA = 20;
3475
+ var LIMITE_PRIMERAS_FILAS_ANIDADA = 30;
3476
+ var esColumnaPropia = (columna) => "customType" in columna;
3477
+ var SIN_ANCESTROS = [];
3478
+ var cargasEnCurso = /* @__PURE__ */ new Map();
3479
+ var StaticAncestorGrid = ({ ancestor, index, fieldsToHide }) => {
3176
3480
  const theme = useTheme4();
3177
3481
  const { tableDefinition, row } = ancestor;
3178
- const [rowData, setRowData] = useState12(row);
3179
- const columns = useMemo8(() => {
3482
+ const columns = useMemo9(() => {
3180
3483
  const filteredFields = tableDefinition.fields.filter(
3181
3484
  (field) => !fieldsToHide?.some((ff) => ff.fieldName === field.name)
3182
3485
  );
@@ -3186,8 +3489,8 @@ var StaticAncestorGrid = ({ ancestor, index, fieldsToHide, callApi, showSuccess,
3186
3489
  key: field.name,
3187
3490
  name: field.label || cambiarGuionesBajosPorEspacios(field.name),
3188
3491
  width: 150,
3189
- editable: field.editable !== false,
3190
- renderHeaderCell: () => /* @__PURE__ */ jsx16(Box12, { sx: { p: 0.5, height: "100%", display: "flex", alignItems: "center" }, children: /* @__PURE__ */ jsx16(
3492
+ editable: false,
3493
+ renderHeaderCell: () => /* @__PURE__ */ jsx18(Box12, { sx: { p: 0.5, height: "100%", display: "flex", alignItems: "center" }, children: /* @__PURE__ */ jsx18(
3191
3494
  Typography8,
3192
3495
  {
3193
3496
  variant: "caption",
@@ -3199,25 +3502,11 @@ var StaticAncestorGrid = ({ ancestor, index, fieldsToHide, callApi, showSuccess,
3199
3502
  children: field.label || cambiarGuionesBajosPorEspacios(field.name)
3200
3503
  }
3201
3504
  ) }),
3202
- renderCell: (props) => /* @__PURE__ */ jsx16(Box12, { sx: { px: 1, height: "100%", display: "flex", alignItems: "center" }, children: /* @__PURE__ */ jsx16(Typography8, { variant: "body2", sx: { fontSize: "0.875rem" }, noWrap: true, children: String(props.row[field.name] ?? "") }) })
3505
+ renderCell: (props) => /* @__PURE__ */ jsx18(Box12, { sx: { px: 1, height: "100%", display: "flex", alignItems: "center" }, children: /* @__PURE__ */ jsx18(Typography8, { variant: "body2", sx: { fontSize: "0.875rem" }, noWrap: true, children: String(props.row[field.name] ?? "") }) })
3203
3506
  };
3204
3507
  });
3205
3508
  }, [tableDefinition, fieldsToHide]);
3206
- const handleRowsChange = async (newRows) => {
3207
- const updatedRow = newRows[0];
3208
- setRowData(updatedRow);
3209
- try {
3210
- await callApi("table_data_save", {
3211
- table: ancestor.tableName,
3212
- row: updatedRow
3213
- });
3214
- showSuccess(`Registro de ${cambiarGuionesBajosPorEspacios(ancestor.tableName)} actualizado.`);
3215
- } catch (err) {
3216
- showError(`Error al actualizar padre: ${err.message}`);
3217
- setRowData(row);
3218
- }
3219
- };
3220
- return /* @__PURE__ */ jsxs12(Box12, { sx: {
3509
+ return /* @__PURE__ */ jsxs13(Box12, { sx: {
3221
3510
  mb: 1.5,
3222
3511
  ml: index * 4,
3223
3512
  // El primer ancestro (index 0) no tiene margen, los siguientes sí
@@ -3228,7 +3517,7 @@ var StaticAncestorGrid = ({ ancestor, index, fieldsToHide, callApi, showSuccess,
3228
3517
  boxShadow: theme.shadows[1],
3229
3518
  bgcolor: "background.paper"
3230
3519
  }, children: [
3231
- /* @__PURE__ */ jsx16(Box12, { sx: {
3520
+ /* @__PURE__ */ jsx18(Box12, { sx: {
3232
3521
  bgcolor: "primary.main",
3233
3522
  color: "primary.contrastText",
3234
3523
  px: 1.5,
@@ -3239,14 +3528,13 @@ var StaticAncestorGrid = ({ ancestor, index, fieldsToHide, callApi, showSuccess,
3239
3528
  alignItems: "center",
3240
3529
  fontWeight: "bold",
3241
3530
  gap: 1
3242
- }, children: /* @__PURE__ */ jsx16(Typography8, { variant: "subtitle2", component: "div", children: cambiarGuionesBajosPorEspacios(ancestor.tableName) }) }),
3243
- /* @__PURE__ */ jsx16(
3531
+ }, children: /* @__PURE__ */ jsx18(Typography8, { variant: "subtitle2", component: "div", children: cambiarGuionesBajosPorEspacios(ancestor.tableName) }) }),
3532
+ /* @__PURE__ */ jsx18(
3244
3533
  DataGrid,
3245
3534
  {
3246
3535
  className: "rdg-light",
3247
3536
  columns,
3248
- rows: [rowData],
3249
- onRowsChange: handleRowsChange,
3537
+ rows: [row],
3250
3538
  headerRowHeight: HEADER_ROW_HEIGHT,
3251
3539
  rowHeight: ROW_HEIGHT,
3252
3540
  rowKeyGetter: () => "single-row",
@@ -3257,32 +3545,49 @@ var StaticAncestorGrid = ({ ancestor, index, fieldsToHide, callApi, showSuccess,
3257
3545
  };
3258
3546
  var GenericDataGrid = ({
3259
3547
  tableName,
3260
- fixedFields,
3548
+ fixedFields: fixedFieldsRecibidos,
3261
3549
  gridStyles,
3262
3550
  onOpenDetail,
3263
- ancestors = []
3551
+ ancestors = SIN_ANCESTROS,
3552
+ anidada = false,
3553
+ titulo,
3554
+ claveCache,
3555
+ onAltoDeseado,
3556
+ onAnchoDeseado,
3557
+ altoDisponible,
3558
+ altoMaximoDetalle
3264
3559
  }) => {
3265
- const [tableDefinition, setTableDefinition] = useState12(null);
3266
- const [tableData, setTableData] = useState12([]);
3560
+ const claveFixedFields = JSON.stringify(fixedFieldsRecibidos ?? null);
3561
+ const fixedFields = useMemo9(() => fixedFieldsRecibidos, [claveFixedFields]);
3562
+ const cacheHeredado = useContext4(CacheGrillasContext);
3563
+ const [cachePropio] = useState12(() => /* @__PURE__ */ new Map());
3564
+ const cache = cacheHeredado ?? cachePropio;
3565
+ const [guardada] = useState12(() => claveCache ? cache.get(claveCache) : void 0);
3566
+ const claveCargadaRef = useRef6(guardada ? `${tableName}|${claveFixedFields}` : null);
3567
+ const [tableDefinition, setTableDefinition] = useState12(guardada?.tableDefinition ?? null);
3568
+ const [tableData, setTableData] = useState12(guardada?.tableData ?? []);
3569
+ const [cargandoInicial, setCargandoInicial] = useState12(!guardada);
3570
+ const [errorDeCarga, setErrorDeCarga] = useState12(null);
3571
+ const [anchosCalculados, setAnchosCalculados] = useState12(() => guardada?.anchosCalculados ?? /* @__PURE__ */ new Map());
3572
+ const [detallesAbiertos, setDetallesAbiertos] = useState12(guardada?.detallesAbiertos ?? []);
3573
+ const [altosDetalle, setAltosDetalle] = useState12(() => guardada?.altosDetalle ?? /* @__PURE__ */ new Map());
3574
+ const [anchosDetalle, setAnchosDetalle] = useState12(() => /* @__PURE__ */ new Map());
3267
3575
  const [selectedRows, setSelectedRows] = useState12(() => /* @__PURE__ */ new Set());
3268
- const [selectedCell, setSelectedCell] = useState12(void 0);
3269
- const [cellFeedbackMap, setCellFeedbackMap] = useState12(/* @__PURE__ */ new Map());
3270
- const [localCellChanges, setLocalCellChanges] = useState12(/* @__PURE__ */ new Map());
3576
+ const [, setSelectedCell] = useState12(void 0);
3577
+ const [estadoGrilla] = useState12(crearEstadoGrilla);
3271
3578
  const theme = useTheme4();
3272
3579
  const [openDataGridOptions, setOpenDataGridOptions] = useState12(false);
3273
3580
  const [dataGridOptionsAnchorEl, setDataGridOptionsAnchorEl] = useState12(null);
3274
3581
  const [exitingRowIds, setExitingRowIds] = useState12(/* @__PURE__ */ new Set());
3275
- const { showSuccess, showError, showWarning, showInfo } = useSnackbar();
3276
- const feedbackTimerRef = useRef3(null);
3277
- const dataGridRef = useRef3(null);
3278
- const rowAtEditStartRef = useRef3(null);
3582
+ const { showError } = useSnackbar();
3583
+ const { username: usuario } = useClientContext();
3584
+ const dataGridRef = useRef6(null);
3585
+ const rowAtEditStartRef = useRef6(null);
3279
3586
  const [openImportDialog, setOpenImportDialog] = useState12(false);
3280
3587
  const [openExportDialog, setOpenExportDialog] = useState12(false);
3281
3588
  const [columnWidths, setColumnWidths] = useState12(() => /* @__PURE__ */ new Map());
3282
- const { callApi, callApiUpload, loading, error } = useApiCall();
3283
- const getRowCount = () => tableData.length;
3284
- const getFilteredRowCount = () => filteredRows.length;
3285
- const primaryKey = useMemo8(() => {
3589
+ const { callApi, callApiUpload, loading } = useApiCall();
3590
+ const primaryKey = useMemo9(() => {
3286
3591
  if (!tableDefinition) return ["id"];
3287
3592
  return tableDefinition.primaryKey && tableDefinition.primaryKey.length > 0 ? tableDefinition.primaryKey : ["id"];
3288
3593
  }, [tableDefinition]);
@@ -3300,6 +3605,40 @@ var GenericDataGrid = ({
3300
3605
  summaryData,
3301
3606
  resetView
3302
3607
  } = useGridDataView({ tableData, tableDefinition });
3608
+ const abiertos = useMemo9(() => new Set(detallesAbiertos), [detallesAbiertos]);
3609
+ const filasDetalleRef = useRef6(/* @__PURE__ */ new Map());
3610
+ const filasMostradas = useMemo9(() => {
3611
+ const detailTables = tableDefinition?.detailTables ?? [];
3612
+ if (abiertos.size === 0 || detailTables.length === 0) return filteredRows;
3613
+ const anteriores = filasDetalleRef.current;
3614
+ const nuevas = /* @__PURE__ */ new Map();
3615
+ const filas = [];
3616
+ filteredRows.forEach((row) => {
3617
+ filas.push(row);
3618
+ const rowId = getPrimaryKeyValues(row, primaryKey);
3619
+ detailTables.forEach((detailTable) => {
3620
+ const clave = claveDetalle(rowId, detailTable);
3621
+ if (!abiertos.has(clave)) return;
3622
+ const anterior = anteriores.get(clave);
3623
+ const filaDetalle = anterior && anterior.filaPadre === row ? anterior : {
3624
+ [DETALLE]: true,
3625
+ clave,
3626
+ filaPadre: row,
3627
+ detailTable,
3628
+ fixedFields: calcularFixedFieldsDetalle(detailTable, row)
3629
+ };
3630
+ nuevas.set(clave, filaDetalle);
3631
+ filas.push(filaDetalle);
3632
+ });
3633
+ });
3634
+ filasDetalleRef.current = nuevas;
3635
+ return filas;
3636
+ }, [filteredRows, abiertos, tableDefinition, primaryKey]);
3637
+ const altoDeDetalle = useCallback11((clave) => altosDetalle.get(clave) ?? ALTO_INICIAL_DETALLE, [altosDetalle]);
3638
+ const altoDetalles = useMemo9(
3639
+ () => filasMostradas.reduce((total, row) => esFilaDetalle(row) ? total + altoDeDetalle(row.clave) : total, 0),
3640
+ [filasMostradas, altoDeDetalle]
3641
+ );
3303
3642
  const {
3304
3643
  handleAddRow,
3305
3644
  handleConfirmDelete,
@@ -3318,24 +3657,33 @@ var GenericDataGrid = ({
3318
3657
  primaryKey,
3319
3658
  fixedFields,
3320
3659
  setExitingRowIds,
3321
- setLocalCellChanges,
3660
+ setLocalCellChanges: estadoGrilla.setCambiosLocales,
3322
3661
  setSelectedRows,
3323
3662
  setTableData,
3324
3663
  callApi,
3325
3664
  callApiUpload,
3326
3665
  resetView
3327
3666
  });
3667
+ const firstDisplayCount = tableDefinition?.firstDisplayCount ?? PRIMERAS_FILAS_ANIDADA;
3668
+ const firstDisplayOverLimit = tableDefinition?.firstDisplayOverLimit ?? LIMITE_PRIMERAS_FILAS_ANIDADA;
3669
+ const filasVisiblesMax = anidada ? filteredRows.length <= firstDisplayOverLimit ? filteredRows.length : firstDisplayCount : void 0;
3670
+ const conPie = !anidada || !!tableDefinition?.fields.some((field) => field.aggregate);
3328
3671
  const { gridHeight, bottomSummaryRow, summaryRows, filterHeight } = useGridLayout({
3329
3672
  filteredRows,
3330
3673
  isFilterRowVisible,
3331
3674
  tableData,
3332
3675
  summaryData,
3333
3676
  filters,
3334
- setFilters
3677
+ setFilters,
3678
+ altoDetalles,
3679
+ altoMinimoCuerpo: anidada ? ALTO_MINIMO_CUERPO_ANIDADA : MIN_BODY_HEIGHT,
3680
+ holgura: anidada ? HOLGURA_ANIDADA : void 0,
3681
+ filasVisiblesMax,
3682
+ conPie
3335
3683
  });
3336
- const { handleCellDoubleClick, handleCellClick, handleCellKeyDown, handleCellMouseDown, handleKeyPressInEditor, handleSelectedCellChange, handleRowsChange } = useGridEvents({
3684
+ const { handleCellDoubleClick, handleCellClick, handleCellKeyDown, handleCellMouseDown, handleKeyPressInEditor, registrarEditor, handleSelectedCellChange, handleRowsChange } = useGridEvents({
3337
3685
  dataGridRef,
3338
- filteredRows,
3686
+ filteredRows: filasMostradas,
3339
3687
  fixedFields,
3340
3688
  tableData,
3341
3689
  tableDefinition,
@@ -3343,103 +3691,273 @@ var GenericDataGrid = ({
3343
3691
  setTableData,
3344
3692
  setSortColumns
3345
3693
  });
3346
- useEffect3(() => {
3694
+ const tableNameAnteriorRef = useRef6(tableName);
3695
+ useEffect5(() => {
3696
+ if (tableNameAnteriorRef.current === tableName) return;
3697
+ tableNameAnteriorRef.current = tableName;
3698
+ setDetallesAbiertos([]);
3699
+ setAltosDetalle(/* @__PURE__ */ new Map());
3347
3700
  resetView();
3348
3701
  setSelectedRows(/* @__PURE__ */ new Set());
3349
3702
  setTableDefinition(null);
3350
3703
  setTableData([]);
3351
- setCellFeedbackMap(/* @__PURE__ */ new Map());
3352
- setLocalCellChanges(/* @__PURE__ */ new Map());
3704
+ estadoGrilla.setFeedback(/* @__PURE__ */ new Map());
3705
+ estadoGrilla.setCambiosLocales(/* @__PURE__ */ new Map());
3353
3706
  setExitingRowIds(/* @__PURE__ */ new Set());
3354
3707
  setColumnWidths(/* @__PURE__ */ new Map());
3355
- if (feedbackTimerRef.current) {
3356
- clearTimeout(feedbackTimerRef.current);
3708
+ }, [tableName, estadoGrilla, resetView]);
3709
+ useEffect5(() => {
3710
+ const claveCarga = `${tableName}|${claveFixedFields}`;
3711
+ if (claveCargadaRef.current === claveCarga) {
3712
+ if (guardada) setSortColumns(guardada.sortColumns);
3713
+ return;
3357
3714
  }
3358
- }, [tableName]);
3359
- useEffect3(() => {
3715
+ let vigente = true;
3360
3716
  const fetchDataAndDefinition = async () => {
3717
+ setCargandoInicial(true);
3718
+ setErrorDeCarga(null);
3361
3719
  try {
3362
- const definition = await callApi("table_structure", { table: tableName }, { isCritical: true });
3720
+ const clavePedido = `${tableName}|${claveFixedFields}`;
3721
+ let pedido = cargasEnCurso.get(clavePedido);
3722
+ if (!pedido) {
3723
+ const nuevo = (async () => {
3724
+ const definition2 = requerido(
3725
+ await callApi("table_structure", { table: tableName }, { isCritical: true }),
3726
+ `la estructura de '${tableName}'`
3727
+ );
3728
+ const validFixedFields = fixedFields?.filter(
3729
+ (ff) => definition2.fields.some((field) => field.name === ff.fieldName)
3730
+ );
3731
+ const data2 = requerido(
3732
+ await callApi("table_data", {
3733
+ table: tableName,
3734
+ fixedFields: validFixedFields ?? []
3735
+ }, { isCritical: true }),
3736
+ `los datos de '${tableName}'`
3737
+ );
3738
+ return { definition: definition2, data: data2 };
3739
+ })();
3740
+ cargasEnCurso.set(clavePedido, nuevo);
3741
+ const sacar = () => {
3742
+ cargasEnCurso.delete(clavePedido);
3743
+ };
3744
+ nuevo.then(sacar, sacar);
3745
+ pedido = nuevo;
3746
+ }
3747
+ const { definition, data } = await pedido;
3748
+ if (!vigente) return;
3749
+ claveCargadaRef.current = claveCarga;
3363
3750
  setTableDefinition(definition);
3364
3751
  setSortColumns(getInitialSortColumns(definition));
3365
- const validFixedFields = fixedFields?.filter(
3366
- (ff) => definition.fields.some((field) => field.name === ff.fieldName)
3367
- );
3368
- const data = await callApi("table_data", {
3369
- table: tableName,
3370
- fixedFields: validFixedFields
3371
- }, { isCritical: true });
3752
+ setAnchosCalculados(calcularAnchosDeColumnas(definition, data));
3372
3753
  setTableData(data);
3373
3754
  } catch (err) {
3755
+ if (!vigente) return;
3374
3756
  setTableDefinition(null);
3375
3757
  setTableData([]);
3376
- showError(`Error al cargar datos para la tabla '${tableName}': ${err.message || "Error desconocido"}`);
3758
+ const mensaje = `Error al cargar datos para la tabla '${tableName}': ${mensajeDeError(err)}`;
3759
+ setErrorDeCarga(mensaje);
3760
+ showError(mensaje);
3761
+ } finally {
3762
+ if (vigente) setCargandoInicial(false);
3377
3763
  }
3378
3764
  };
3379
3765
  fetchDataAndDefinition();
3380
- }, [tableName, fixedFields, showError]);
3381
- useEffect3(() => {
3382
- if (cellFeedbackMap.size > 0) {
3383
- if (feedbackTimerRef.current) {
3384
- clearTimeout(feedbackTimerRef.current);
3385
- }
3386
- const timerDuration = 3e3;
3387
- feedbackTimerRef.current = setTimeout(() => {
3388
- setCellFeedbackMap((prevMap) => {
3389
- const newMap = new Map(prevMap);
3390
- let mapChanged = false;
3391
- for (const [cellId, feedback] of prevMap.entries()) {
3766
+ return () => {
3767
+ vigente = false;
3768
+ };
3769
+ }, [tableName, claveFixedFields, fixedFields, showError, callApi, getInitialSortColumns, setSortColumns, guardada]);
3770
+ useEffect5(() => {
3771
+ if (!claveCache || !tableDefinition || cargandoInicial) return;
3772
+ cache.set(claveCache, { tableDefinition, tableData, anchosCalculados, sortColumns, detallesAbiertos, altosDetalle });
3773
+ }, [cache, claveCache, tableDefinition, tableData, anchosCalculados, sortColumns, detallesAbiertos, altosDetalle, cargandoInicial]);
3774
+ useEffect5(() => {
3775
+ let timer = null;
3776
+ const desuscribir = estadoGrilla.suscribir(() => {
3777
+ const hayExitos = Array.from(estadoGrilla.obtenerFeedback().values()).some((f) => f.type === "success");
3778
+ if (!hayExitos || timer) return;
3779
+ timer = setTimeout(() => {
3780
+ timer = null;
3781
+ estadoGrilla.setFeedback((anterior) => {
3782
+ const nuevo = new Map(anterior);
3783
+ let cambio = false;
3784
+ for (const [cellId, feedback] of anterior.entries()) {
3392
3785
  if (feedback.type === "success") {
3393
- newMap.delete(cellId);
3394
- mapChanged = true;
3786
+ nuevo.delete(cellId);
3787
+ cambio = true;
3395
3788
  }
3396
3789
  }
3397
- return mapChanged ? newMap : prevMap;
3790
+ return cambio ? nuevo : anterior;
3398
3791
  });
3399
- feedbackTimerRef.current = null;
3400
- }, timerDuration);
3401
- }
3792
+ }, DURACION_FEEDBACK_EXITO);
3793
+ });
3402
3794
  return () => {
3403
- if (feedbackTimerRef.current) {
3404
- clearTimeout(feedbackTimerRef.current);
3405
- }
3795
+ desuscribir();
3796
+ if (timer) clearTimeout(timer);
3406
3797
  };
3407
- }, [cellFeedbackMap]);
3798
+ }, [estadoGrilla]);
3799
+ const resetSortingDeLaTabla = useCallback11(() => {
3800
+ if (tableDefinition) resetSorting(tableDefinition);
3801
+ }, [tableDefinition, resetSorting]);
3802
+ const abrirImportacion = useCallback11(() => setOpenImportDialog(true), []);
3803
+ const abrirExportacion = useCallback11(() => setOpenExportDialog(true), []);
3408
3804
  const { menuOptions } = useGridMenu({
3409
3805
  tableDefinition,
3410
3806
  tableName,
3411
3807
  fixedFields,
3412
3808
  setTableData,
3413
3809
  callApi,
3414
- resetSorting: tableDefinition ? () => resetSorting(tableDefinition) : void 0,
3415
- triggerImport: () => setOpenImportDialog(true),
3416
- triggerExport: () => setOpenExportDialog(true)
3810
+ resetSorting: tableDefinition ? resetSortingDeLaTabla : void 0,
3811
+ triggerImport: abrirImportacion,
3812
+ triggerExport: abrirExportacion
3417
3813
  });
3814
+ const abrirOpcionesDeGrilla = useCallback11((anchorEl) => {
3815
+ setDataGridOptionsAnchorEl(anchorEl);
3816
+ setOpenDataGridOptions(true);
3817
+ }, []);
3818
+ const editarEnFicha = useCallback11((row) => {
3819
+ rowAtEditStartRef.current = { ...row };
3820
+ handleVerticalEditRow(row);
3821
+ }, [handleVerticalEditRow]);
3418
3822
  const { columns } = useGridColumns({
3419
3823
  tableDefinition,
3420
- tableData,
3824
+ anchosCalculados,
3421
3825
  fixedFields,
3422
- isFilterRowVisible,
3423
- sortColumns,
3424
3826
  primaryKey,
3425
- localCellChanges,
3426
- cellFeedbackMap,
3427
- setCellFeedbackMap,
3428
3827
  setTableData,
3429
- setLocalCellChanges,
3430
3828
  handleKeyPressInEditor,
3829
+ registrarEditor,
3431
3830
  handleDeleteRow,
3432
3831
  handleAddRow,
3433
- handleVerticalEditRow: (row) => {
3434
- rowAtEditStartRef.current = { ...row };
3435
- handleVerticalEditRow(row);
3436
- },
3832
+ handleVerticalEditRow: editarEnFicha,
3437
3833
  toggleFilterVisibility,
3438
- setDataGridOptionsAnchorEl,
3439
- setOpenDataGridOptions,
3440
- onOpenDetail,
3441
- ancestors: ancestors ?? []
3834
+ abrirOpcionesDeGrilla
3442
3835
  });
3836
+ const abrirDetalleEnPestana = useCallback11((row, detailTable) => {
3837
+ if (!onOpenDetail || !tableDefinition || !detailTable.table) return;
3838
+ const porCampo = /* @__PURE__ */ new Map();
3839
+ [...fixedFields ?? [], ...calcularFixedFieldsDetalle(detailTable, row)].forEach((ff) => porCampo.set(ff.fieldName, ff));
3840
+ const allFixedFields = Array.from(porCampo.values());
3841
+ const filterDescription = allFixedFields.map((ff) => `${cambiarGuionesBajosPorEspacios(ff.fieldName)}: ${ff.value}`).join(", ");
3842
+ const label = `${cambiarGuionesBajosPorEspacios(detailTable.table).toUpperCase()} (${filterDescription})`;
3843
+ const newAncestors = [...ancestors, { tableName: tableDefinition.name, row, tableDefinition, fixedFields: allFixedFields }];
3844
+ onOpenDetail(detailTable.table, allFixedFields, label, newAncestors);
3845
+ }, [onOpenDetail, tableDefinition, fixedFields, ancestors]);
3846
+ const abrirWScreenEnPestana = useCallback11((row, detailTable) => {
3847
+ const parametros = new URLSearchParams();
3848
+ calcularFixedFieldsDetalle(detailTable, row).forEach((ff) => parametros.set(ff.fieldName, String(ff.value)));
3849
+ window.open(`${window.location.origin}/wScreens/${detailTable.wScreen}?${parametros}`, "_blank");
3850
+ }, []);
3851
+ const alternarDetalle = useCallback11((row, rowId, detailTable, enOtraPestana) => {
3852
+ if (enOtraPestana && detailTable.wScreen) {
3853
+ abrirWScreenEnPestana(row, detailTable);
3854
+ return;
3855
+ }
3856
+ if (enOtraPestana && onOpenDetail) {
3857
+ abrirDetalleEnPestana(row, detailTable);
3858
+ return;
3859
+ }
3860
+ const clave = claveDetalle(rowId, detailTable);
3861
+ setDetallesAbiertos((anteriores) => anteriores.includes(clave) ? anteriores.filter((c) => c !== clave) : [...anteriores, clave]);
3862
+ }, [onOpenDetail, abrirDetalleEnPestana, abrirWScreenEnPestana]);
3863
+ const [medidas, setMedidas] = useState12(null);
3864
+ useEffect5(() => {
3865
+ const elemento = dataGridRef.current?.element;
3866
+ if (!elemento) return;
3867
+ const medir = () => setMedidas((anteriores) => {
3868
+ const nuevas = { ancho: elemento.clientWidth, alto: elemento.clientHeight, barra: elemento.offsetWidth - elemento.clientWidth };
3869
+ return anteriores && anteriores.ancho === nuevas.ancho && anteriores.alto === nuevas.alto && anteriores.barra === nuevas.barra ? anteriores : nuevas;
3870
+ });
3871
+ medir();
3872
+ const observador = new ResizeObserver(medir);
3873
+ observador.observe(elemento);
3874
+ return () => observador.disconnect();
3875
+ }, [tableDefinition, cargandoInicial]);
3876
+ const anchoVisible = medidas?.ancho ?? null;
3877
+ const [altoDeVentana, setAltoDeVentana] = useState12(null);
3878
+ useEffect5(() => {
3879
+ if (anidada) return;
3880
+ const elemento = dataGridRef.current?.element;
3881
+ if (!elemento) return;
3882
+ const calcular = () => setAltoDeVentana(Math.max(0, Math.round(window.innerHeight - elemento.getBoundingClientRect().top - MARGEN_INFERIOR_PAGINA)));
3883
+ calcular();
3884
+ window.addEventListener("resize", calcular);
3885
+ return () => window.removeEventListener("resize", calcular);
3886
+ }, [anidada, tableDefinition, cargandoInicial]);
3887
+ const altoDeContexto = useContext4(AltoDisponibleContext);
3888
+ const altoDeEstaGrilla = anidada ? altoDisponible ?? (altoDeContexto === void 0 ? void 0 : altoDeContexto - ALTO_TITULO_ANIDADA) : altoDeVentana ?? void 0;
3889
+ const altoMaximoDetalleEfectivo = altoMaximoDetalle ?? (altoDeEstaGrilla !== void 0 ? Math.max(ALTO_MINIMO_DETALLE, altoDeEstaGrilla - HEADER_ROW_HEIGHT - (conPie ? SUMMARY_ROW_HEIGHT : 0) - ROW_HEIGHT - (isFilterRowVisible ? FILTER_ROW_HEIGHT : 0)) : void 0);
3890
+ const cambiarAnchoDetalle = useCallback11((clave, ancho) => {
3891
+ setAnchosDetalle((anteriores) => anteriores.get(clave) === ancho ? anteriores : new Map(anteriores).set(clave, ancho));
3892
+ }, []);
3893
+ const cambiarAltoDetalle = useCallback11((clave, altoDeseado2) => {
3894
+ const alto = Math.min(Math.max(Math.round(altoDeseado2), ALTO_MINIMO_DETALLE), altoMaximoDetalleEfectivo ?? Infinity);
3895
+ setAltosDetalle((anteriores) => anteriores.get(clave) === alto ? anteriores : new Map(anteriores).set(clave, alto));
3896
+ }, [altoMaximoDetalleEfectivo]);
3897
+ const renderDetalle = useCallback11((fila) => {
3898
+ const { detailTable } = fila;
3899
+ return /* @__PURE__ */ jsx18(
3900
+ "div",
3901
+ {
3902
+ className: "fpr-detalle",
3903
+ style: { maxWidth: anchoVisible ? anchoVisible - 2 : void 0 },
3904
+ onKeyDown: (e) => e.stopPropagation(),
3905
+ children: detailTable.table ? /* @__PURE__ */ jsx18(
3906
+ GenericDataGrid,
3907
+ {
3908
+ tableName: detailTable.table,
3909
+ fixedFields: fila.fixedFields,
3910
+ anidada: true,
3911
+ claveCache: `${claveCache ?? tableName}>${fila.clave}`,
3912
+ onAltoDeseado: (alto) => cambiarAltoDetalle(fila.clave, alto),
3913
+ onAnchoDeseado: (ancho) => cambiarAnchoDetalle(fila.clave, ancho),
3914
+ altoDisponible: altoMaximoDetalleEfectivo === void 0 ? void 0 : altoMaximoDetalleEfectivo - ALTO_TITULO_ANIDADA - 8,
3915
+ onOpenDetail,
3916
+ ancestors: tableDefinition ? [...ancestors, { tableName: tableDefinition.name, row: fila.filaPadre, tableDefinition, fixedFields: fila.fixedFields }] : ancestors
3917
+ }
3918
+ ) : detailTable.wScreen ? /* @__PURE__ */ jsx18(
3919
+ DetalleWScreen,
3920
+ {
3921
+ fila,
3922
+ altoMaximo: altoMaximoDetalleEfectivo,
3923
+ onAlto: (alto) => cambiarAltoDetalle(fila.clave, alto),
3924
+ onAncho: (ancho) => cambiarAnchoDetalle(fila.clave, ancho)
3925
+ }
3926
+ ) : /* @__PURE__ */ jsxs13(Alert2, { severity: "warning", children: [
3927
+ "El detalle '",
3928
+ detailTable.abr,
3929
+ "' no tiene ni tabla ni wScreen."
3930
+ ] })
3931
+ }
3932
+ );
3933
+ }, [anchoVisible, claveCache, tableName, cambiarAltoDetalle, cambiarAnchoDetalle, altoMaximoDetalleEfectivo, onOpenDetail, tableDefinition, ancestors]);
3934
+ const detallesGrilla = useMemo9(() => ({ abiertos, alternarDetalle, renderDetalle }), [abiertos, alternarDetalle, renderDetalle]);
3935
+ const altoDeseado = cargandoInicial ? ALTO_INICIAL_DETALLE : gridHeight + ALTO_TITULO_ANIDADA + 8;
3936
+ useEffect5(() => {
3937
+ onAltoDeseado?.(altoDeseado);
3938
+ }, [onAltoDeseado, altoDeseado]);
3939
+ const rowKeyGetter = useCallback11((row) => esFilaDetalle(row) ? `detalle:${row.clave}` : getPrimaryKeyValues(row, primaryKey), [primaryKey]);
3940
+ const rowHeight = useCallback11((row) => esFilaDetalle(row) ? altoDeDetalle(row.clave) : ROW_HEIGHT, [altoDeDetalle]);
3941
+ const rowClass = useCallback11(
3942
+ (row) => esFilaDetalle(row) ? "fpr-fila-detalle" : exitingRowIds.has(getPrimaryKeyValues(row, primaryKey)) ? "fpr-fila-saliendo" : void 0,
3943
+ [exitingRowIds, primaryKey]
3944
+ );
3945
+ const anchoContenido = useMemo9(() => {
3946
+ if (!anidada || columns.length === 0) return void 0;
3947
+ const sumaColumnas = columns.reduce((total, col) => {
3948
+ const medido = columnWidths.get(col.key)?.width;
3949
+ return total + (typeof medido === "number" ? medido : typeof col.width === "number" ? col.width : 100);
3950
+ }, 0);
3951
+ const propio = sumaColumnas + (medidas?.barra ?? 0) + 2;
3952
+ const anchoDetalleMax = detallesAbiertos.reduce((max, clave) => Math.max(max, anchosDetalle.get(clave) ?? 0), 0);
3953
+ return Math.max(ANCHO_MINIMO_ANIDADA, propio, anchoDetalleMax > 0 ? anchoDetalleMax + SANGRIA_DETALLE + (medidas?.barra ?? 0) + 2 : 0);
3954
+ }, [anidada, columns, columnWidths, medidas?.barra, detallesAbiertos, anchosDetalle]);
3955
+ useEffect5(() => {
3956
+ if (anchoContenido !== void 0) onAnchoDeseado?.(anchoContenido);
3957
+ }, [onAnchoDeseado, anchoContenido]);
3958
+ const estiloGrilla = useMemo9(() => ({ height: "100%", width: "100%", boxSizing: "border-box", ...gridStyles }), [gridStyles]);
3959
+ const bottomSummaryRows = useMemo9(() => conPie ? [bottomSummaryRow] : [], [conPie, bottomSummaryRow]);
3960
+ const vistaGrilla = useMemo9(() => ({ isFilterRowVisible }), [isFilterRowVisible]);
3443
3961
  const getFallBackMessage = () => {
3444
3962
  if (tableData.length === 0) {
3445
3963
  return "No hay filas para mostrar";
@@ -3450,32 +3968,29 @@ var GenericDataGrid = ({
3450
3968
  return null;
3451
3969
  };
3452
3970
  const fallBackMessage = getFallBackMessage();
3453
- if (loading) {
3454
- return /* @__PURE__ */ jsxs12(Box12, { display: "flex", justifyContent: "center", alignItems: "center", minHeight: "200px", children: [
3455
- /* @__PURE__ */ jsx16(CircularProgress4, {}),
3456
- /* @__PURE__ */ jsx16(Typography8, { variant: "h6", sx: { ml: 2 }, children: "Cargando tabla..." })
3971
+ if (cargandoInicial) {
3972
+ return /* @__PURE__ */ jsxs13(Box12, { display: "flex", justifyContent: "center", alignItems: "center", minHeight: "200px", children: [
3973
+ /* @__PURE__ */ jsx18(CircularProgress4, {}),
3974
+ /* @__PURE__ */ jsx18(Typography8, { variant: "h6", sx: { ml: 2 }, children: "Cargando tabla..." })
3457
3975
  ] });
3458
3976
  }
3459
- if (error) {
3460
- return /* @__PURE__ */ jsx16(Box12, { display: "flex", justifyContent: "center", alignItems: "center", minHeight: "200px", children: /* @__PURE__ */ jsx16(Alert2, { severity: "error", children: error.message }) });
3977
+ if (errorDeCarga) {
3978
+ return /* @__PURE__ */ jsx18(Box12, { display: "flex", justifyContent: "center", alignItems: "center", minHeight: "200px", children: /* @__PURE__ */ jsx18(Alert2, { severity: "error", children: errorDeCarga }) });
3461
3979
  }
3462
3980
  if (!tableDefinition) {
3463
- return /* @__PURE__ */ jsx16(Box12, { display: "flex", justifyContent: "center", alignItems: "center", minHeight: "200px", children: /* @__PURE__ */ jsx16(Alert2, { severity: "warning", children: "No se pudo cargar la definici\xF3n de la tabla." }) });
3981
+ return /* @__PURE__ */ jsx18(Box12, { display: "flex", justifyContent: "center", alignItems: "center", minHeight: "200px", children: /* @__PURE__ */ jsx18(Alert2, { severity: "warning", children: "No se pudo cargar la definici\xF3n de la tabla." }) });
3464
3982
  }
3465
- return /* @__PURE__ */ jsxs12(Box12, { sx: { pt: 2, display: "flex", flexDirection: "column", height: "100%", boxSizing: "border-box" }, children: [
3466
- ancestors && ancestors.length > 0 && /* @__PURE__ */ jsx16(Box12, { sx: { px: 2, pt: 0, pb: 1, display: "flex", flexDirection: "column" }, children: ancestors.map((ancestor, index) => /* @__PURE__ */ jsx16(
3983
+ return /* @__PURE__ */ jsx18(CacheGrillasContext.Provider, { value: cache, children: /* @__PURE__ */ jsxs13(Box12, { sx: { pt: anidada ? 0 : 2, display: "flex", flexDirection: "column", height: "100%", boxSizing: "border-box", width: anchoContenido ?? void 0, maxWidth: "100%" }, children: [
3984
+ !anidada && ancestors.length > 0 && /* @__PURE__ */ jsx18(Box12, { sx: { px: 2, pt: 0, pb: 1, display: "flex", flexDirection: "column" }, children: ancestors.map((ancestor, index) => /* @__PURE__ */ jsx18(
3467
3985
  StaticAncestorGrid,
3468
3986
  {
3469
3987
  ancestor,
3470
3988
  index,
3471
- fieldsToHide: index > 0 ? ancestors[index - 1].fixedFields : [],
3472
- callApi,
3473
- showSuccess,
3474
- showError
3989
+ fieldsToHide: index > 0 ? ancestors[index - 1].fixedFields : []
3475
3990
  },
3476
3991
  index
3477
3992
  )) }),
3478
- /* @__PURE__ */ jsx16(
3993
+ /* @__PURE__ */ jsxs13(
3479
3994
  Box12,
3480
3995
  {
3481
3996
  sx: {
@@ -3488,75 +4003,81 @@ var GenericDataGrid = ({
3488
4003
  borderBottom: `1px solid ${theme.palette.divider}`,
3489
4004
  borderTopLeftRadius: theme.shape.borderRadius,
3490
4005
  borderTopRightRadius: theme.shape.borderRadius,
3491
- ml: 2 + ancestors.length * 4,
4006
+ ml: anidada ? 0 : 2 + ancestors.length * 4,
3492
4007
  // Margen dinámico basado en jerarquía
3493
- mr: 2
4008
+ mr: anidada ? 0 : 2,
4009
+ minHeight: anidada ? ALTO_TITULO_ANIDADA : void 0,
4010
+ boxSizing: "border-box",
4011
+ display: "flex",
4012
+ alignItems: "center",
4013
+ gap: 1
3494
4014
  },
3495
- children: /* @__PURE__ */ jsxs12(Typography8, { variant: "subtitle2", component: "div", children: [
3496
- cambiarGuionesBajosPorEspacios(tableDefinition.title || tableDefinition.name),
3497
- " - ",
3498
- getFilteredRowCount() === getRowCount() ? `${getRowCount()} registros` : `${getFilteredRowCount()} (F)`
3499
- ] })
4015
+ children: [
4016
+ /* @__PURE__ */ jsxs13(Typography8, { variant: "subtitle2", component: "div", children: [
4017
+ titulo ?? cambiarGuionesBajosPorEspacios(tableDefinition.title || tableDefinition.name),
4018
+ " - ",
4019
+ filteredRows.length === tableData.length ? `${tableData.length} registros` : `${filteredRows.length} (F)`
4020
+ ] }),
4021
+ loading && /* @__PURE__ */ jsx18(CircularProgress4, { size: 14, color: "inherit" })
4022
+ ]
3500
4023
  }
3501
4024
  ),
3502
- /* @__PURE__ */ jsxs12(
4025
+ /* @__PURE__ */ jsxs13(
3503
4026
  Box12,
3504
4027
  {
3505
4028
  sx: {
3506
- height: `min(${gridHeight}px, 100%)`,
3507
- // Altura dinámica aquí
4029
+ // Una grilla anidada se acota con px (el alto que le dio la de arriba, o el de una wScreen): una wScreen
4030
+ // tiene alto automático y ahí un porcentaje no se resuelve. La principal ocupa lo que quede de la pantalla.
4031
+ height: anidada ? `${altoDeEstaGrilla === void 0 ? gridHeight : Math.min(gridHeight, altoDeEstaGrilla)}px` : `min(${gridHeight}px, 100%)`,
3508
4032
  maxHeight: "100%",
3509
4033
  boxSizing: "border-box",
3510
4034
  position: "relative",
3511
4035
  // CRÍTICO para el centrado del fallback
3512
4036
  overflowX: "auto",
3513
4037
  overflowY: "auto",
3514
- px: 2,
3515
- ml: ancestors.length * 4,
4038
+ px: anidada ? 0 : 2,
4039
+ ml: anidada ? 0 : ancestors.length * 4,
3516
4040
  // Indentación de la grilla principal
3517
- pb: 3
4041
+ pb: anidada ? 0 : 3
3518
4042
  },
3519
4043
  children: [
3520
- /* @__PURE__ */ jsx16(
4044
+ /* @__PURE__ */ jsx18(EstadoGrillaContext.Provider, { value: estadoGrilla, children: /* @__PURE__ */ jsx18(VistaGrillaContext.Provider, { value: vistaGrilla, children: /* @__PURE__ */ jsx18(DetallesGrillaContext.Provider, { value: detallesGrilla, children: /* @__PURE__ */ jsx18(
3521
4045
  DataGrid,
3522
4046
  {
3523
4047
  className: "rdg-light",
3524
4048
  ref: dataGridRef,
3525
4049
  columns,
3526
- rows: filteredRows.map((row) => ({
3527
- ...row,
3528
- style: exitingRowIds.has(getPrimaryKeyValues(row, primaryKey)) ? { maxHeight: 0, opacity: 0, overflow: "hidden" } : { maxHeight: "35px", opacity: 1 }
3529
- })),
4050
+ rows: filasMostradas,
4051
+ rowClass,
3530
4052
  columnWidths,
3531
4053
  onColumnWidthsChange: setColumnWidths,
3532
4054
  enableVirtualization: true,
3533
- rowKeyGetter: (row) => getPrimaryKeyValues(row, primaryKey),
4055
+ rowKeyGetter,
3534
4056
  onSelectedRowsChange: setSelectedRows,
3535
4057
  onSelectedCellChange: handleSelectedCellChange,
3536
4058
  onRowsChange: handleRowsChange,
3537
4059
  sortColumns,
3538
4060
  onSortColumnsChange: handleSortColumnsChange,
3539
4061
  selectedRows,
3540
- rowHeight: (_row) => ROW_HEIGHT,
3541
- style: { ...{ height: "100%", width: "100%", boxSizing: "border-box" }, ...gridStyles },
4062
+ rowHeight,
4063
+ style: estiloGrilla,
3542
4064
  headerRowHeight: HEADER_ROW_HEIGHT,
3543
4065
  topSummaryRows: summaryRows,
3544
- bottomSummaryRows: [bottomSummaryRow],
4066
+ bottomSummaryRows,
3545
4067
  summaryRowHeight: SUMMARY_ROW_HEIGHT,
3546
- renderers: void 0,
3547
4068
  onCellMouseDown: handleCellMouseDown,
3548
4069
  onCellDoubleClick: handleCellDoubleClick,
3549
4070
  onCellClick: handleCellClick,
3550
4071
  onCellKeyDown: handleCellKeyDown
3551
4072
  }
3552
- ),
3553
- fallBackMessage && /* @__PURE__ */ jsx16(
4073
+ ) }) }) }),
4074
+ fallBackMessage && /* @__PURE__ */ jsx18(
3554
4075
  Box12,
3555
4076
  {
3556
4077
  sx: {
3557
4078
  position: "absolute",
3558
4079
  top: filterHeight + HEADER_ROW_HEIGHT + 1,
3559
- bottom: 102,
4080
+ bottom: anidada ? (conPie ? SUMMARY_ROW_HEIGHT : 0) + 4 : 102,
3560
4081
  left: 18,
3561
4082
  right: 0,
3562
4083
  display: "flex",
@@ -3567,13 +4088,13 @@ var GenericDataGrid = ({
3567
4088
  zIndex: tableData.length === 0 ? 10 : 1
3568
4089
  // Mantenemos el zIndex superior para el estado vacío total
3569
4090
  },
3570
- children: /* @__PURE__ */ jsx16(Typography8, { variant: "body2", color: "textSecondary", children: fallBackMessage })
4091
+ children: /* @__PURE__ */ jsx18(Typography8, { variant: "body2", color: "textSecondary", children: fallBackMessage })
3571
4092
  }
3572
4093
  )
3573
4094
  ]
3574
4095
  }
3575
4096
  ),
3576
- /* @__PURE__ */ jsx16(
4097
+ /* @__PURE__ */ jsx18(
3577
4098
  ExportDialog,
3578
4099
  {
3579
4100
  open: openExportDialog,
@@ -3581,19 +4102,19 @@ var GenericDataGrid = ({
3581
4102
  tableDefinition,
3582
4103
  tableData,
3583
4104
  filteredRows,
3584
- username: window.my?.config?.username || "anonymous"
4105
+ username: usuario || "anonymous"
3585
4106
  }
3586
4107
  ),
3587
- /* @__PURE__ */ jsx16(
4108
+ /* @__PURE__ */ jsx18(
3588
4109
  ConfirmDialog,
3589
4110
  {
3590
4111
  open: openConfirmDialog,
3591
4112
  onClose: handleConfirmDelete,
3592
4113
  title: "Confirmar Eliminaci\xF3n",
3593
- message: rowToDelete && rowToDelete[NEW_ROW_INDICATOR2] ? `\xBFEst\xE1s seguro de que quieres eliminar esta nueva fila (ID: ${getPrimaryKeyValues(rowToDelete, primaryKey)}) localmente?` : rowToDelete ? `\xBFEst\xE1s seguro de que quieres eliminar la fila con ID: ${getPrimaryKeyValues(rowToDelete, primaryKey)} de la base de datos? Esta acci\xF3n es irreversible.` : "\xBFEst\xE1s seguro de que quieres eliminar este registro? Esta acci\xF3n es irreversible."
4114
+ message: rowToDelete && rowToDelete[NEW_ROW_INDICATOR] ? `\xBFEst\xE1s seguro de que quieres eliminar esta nueva fila (ID: ${getPrimaryKeyValues(rowToDelete, primaryKey)}) localmente?` : rowToDelete ? `\xBFEst\xE1s seguro de que quieres eliminar la fila con ID: ${getPrimaryKeyValues(rowToDelete, primaryKey)} de la base de datos? Esta acci\xF3n es irreversible.` : "\xBFEst\xE1s seguro de que quieres eliminar este registro? Esta acci\xF3n es irreversible."
3594
4115
  }
3595
4116
  ),
3596
- /* @__PURE__ */ jsx16(
4117
+ /* @__PURE__ */ jsx18(
3597
4118
  DataGridOptionsDialog,
3598
4119
  {
3599
4120
  open: openDataGridOptions,
@@ -3602,7 +4123,7 @@ var GenericDataGrid = ({
3602
4123
  anchorEl: dataGridOptionsAnchorEl
3603
4124
  }
3604
4125
  ),
3605
- /* @__PURE__ */ jsx16(
4126
+ /* @__PURE__ */ jsx18(
3606
4127
  ImportDialog,
3607
4128
  {
3608
4129
  open: openImportDialog,
@@ -3611,21 +4132,21 @@ var GenericDataGrid = ({
3611
4132
  loading
3612
4133
  }
3613
4134
  ),
3614
- tableDefinition && /* @__PURE__ */ jsx16(
4135
+ /* @__PURE__ */ jsx18(
3615
4136
  Dialog4,
3616
4137
  {
3617
4138
  open: openVerticalEditDialog,
3618
4139
  onClose: () => setOpenVerticalEditDialog(false),
3619
4140
  maxWidth: "sm",
3620
4141
  fullWidth: true,
3621
- children: rowToEditVertical && /* @__PURE__ */ jsx16(
4142
+ children: rowToEditVertical && /* @__PURE__ */ jsx18(
3622
4143
  VerticalEditorPage,
3623
4144
  {
3624
4145
  tableName,
3625
4146
  tableDefinition,
3626
4147
  initialData: rowToEditVertical,
3627
4148
  fixedFields,
3628
- isNewRow: !!rowToEditVertical[NEW_ROW_INDICATOR2],
4149
+ isNewRow: !!rowToEditVertical[NEW_ROW_INDICATOR],
3629
4150
  onSaveSuccess: (savedRow, isNewItem) => {
3630
4151
  setRowToEditVertical(savedRow);
3631
4152
  setTableData((prevData) => {
@@ -3643,11 +4164,11 @@ var GenericDataGrid = ({
3643
4164
  onClose: () => {
3644
4165
  const originalRow = rowAtEditStartRef.current;
3645
4166
  const serverRow = rowToEditVertical;
3646
- if (originalRow && serverRow && tableDefinition) {
4167
+ if (originalRow && serverRow) {
3647
4168
  const rowId = getPrimaryKeyValues(serverRow, primaryKey);
3648
4169
  const changedFields = tableDefinition.fields.filter((f) => !sameValue(originalRow[f.name], serverRow[f.name])).map((f) => f.name);
3649
4170
  if (changedFields.length > 0) {
3650
- setCellFeedbackMap((prev) => {
4171
+ estadoGrilla.setFeedback((prev) => {
3651
4172
  const next = new Map(prev);
3652
4173
  changedFields.forEach((fieldName) => {
3653
4174
  next.set(`${rowId}-${fieldName}`, { rowId, columnKey: fieldName, type: "success" });
@@ -3663,23 +4184,23 @@ var GenericDataGrid = ({
3663
4184
  )
3664
4185
  }
3665
4186
  )
3666
- ] });
4187
+ ] }) });
3667
4188
  };
3668
4189
  var GenericDataGrid_default = GenericDataGrid;
3669
4190
 
3670
4191
  // src/App.tsx
3671
- import React22, { useEffect as useEffect11 } from "react";
4192
+ import React25, { useEffect as useEffect13, useMemo as useMemo14 } from "react";
3672
4193
  import { BrowserRouter, Routes, Route, useLocation as useLocation6, Navigate as Navigate2, Outlet as Outlet2 } from "react-router-dom";
3673
4194
 
3674
4195
  // src/components/MainLayout.tsx
3675
- import { useEffect as useEffect6 } from "react";
4196
+ import { useEffect as useEffect8 } from "react";
3676
4197
  import { Outlet } from "react-router-dom";
3677
4198
  import {
3678
- Box as Box15,
4199
+ Box as Box14,
3679
4200
  AppBar,
3680
4201
  Toolbar,
3681
- Typography as Typography11,
3682
- Button as Button7,
4202
+ Typography as Typography10,
4203
+ Button as Button6,
3683
4204
  Drawer,
3684
4205
  CssBaseline,
3685
4206
  IconButton as IconButton4,
@@ -3688,13 +4209,13 @@ import {
3688
4209
  } from "@mui/material";
3689
4210
 
3690
4211
  // src/contexts/AppContext.tsx
3691
- import { createContext as createContext2, useContext as useContext2, useState as useState13, useEffect as useEffect4, useCallback as useCallback12, useMemo as useMemo9, useRef as useRef4 } from "react";
4212
+ import { createContext as createContext4, useContext as useContext5, useState as useState13, useEffect as useEffect6, useCallback as useCallback12, useMemo as useMemo10, useRef as useRef7 } from "react";
3692
4213
  import { useLocation, useNavigate } from "react-router-dom";
3693
4214
  import { useSelector as useSelector2, useDispatch as useDispatch2 } from "react-redux";
3694
- import { jsx as jsx17 } from "react/jsx-runtime";
3695
- var AuthContext = createContext2(void 0);
4215
+ import { jsx as jsx19 } from "react/jsx-runtime";
4216
+ var AuthContext = createContext4(void 0);
3696
4217
  var useApp = () => {
3697
- const context = useContext2(AuthContext);
4218
+ const context = useContext5(AuthContext);
3698
4219
  if (!context) {
3699
4220
  throw new Error("useApp must be used within an AppProvider");
3700
4221
  }
@@ -3705,9 +4226,11 @@ var AppProvider = ({ children, publicPaths = [] }) => {
3705
4226
  console.log("AppProvider rendered/re-rendered");
3706
4227
  const [isLoggedIn, setIsLoggedIn] = useState13(false);
3707
4228
  const [showSessionExpiredMessage, setShowSessionExpiredMessage] = useState13(false);
3708
- const isRedirectingRef = useRef4(false);
4229
+ const isRedirectingRef = useRef7(false);
4230
+ const huboSesionRef = useRef7(false);
3709
4231
  const dispatch = useDispatch2();
3710
4232
  const clientContext = useSelector2((state) => state.clientContext);
4233
+ if (clientContext.status === "succeeded") huboSesionRef.current = true;
3711
4234
  const navigate = useNavigate();
3712
4235
  const handleExpiredSessionRedirect = useCallback12(() => {
3713
4236
  isRedirectingRef.current = true;
@@ -3729,6 +4252,7 @@ var AppProvider = ({ children, publicPaths = [] }) => {
3729
4252
  const response = await fetchApi("/keep-alive.json", { method: "GET" });
3730
4253
  if (isRedirectingRef.current) return;
3731
4254
  if (response.ok) {
4255
+ huboSesionRef.current = true;
3732
4256
  setIsLoggedIn(true);
3733
4257
  setShowSessionExpiredMessage(false);
3734
4258
  if (clientContext.status === "idle" || clientContext.status === "failed") {
@@ -3743,11 +4267,11 @@ var AppProvider = ({ children, publicPaths = [] }) => {
3743
4267
  } else {
3744
4268
  setIsLoggedIn(false);
3745
4269
  dispatch(clearClientContext());
3746
- if (!showSessionExpiredMessage && !isCurrentPathPublic()) {
4270
+ if (!showSessionExpiredMessage && !isCurrentPathPublic() && huboSesionRef.current) {
3747
4271
  console.warn("Sesi\xF3n inv\xE1lida en ruta protegida. Mostrando modal.");
3748
4272
  setShowSessionExpiredMessage(true);
3749
4273
  } else {
3750
- console.log("Sesi\xF3n inv\xE1lida, pero estamos en ruta p\xFAblica. Todo bien.");
4274
+ console.log("Sesi\xF3n inv\xE1lida, pero no hay nada que avisar (ruta p\xFAblica o nunca hubo sesi\xF3n).");
3751
4275
  }
3752
4276
  }
3753
4277
  } catch (error) {
@@ -3755,19 +4279,19 @@ var AppProvider = ({ children, publicPaths = [] }) => {
3755
4279
  setIsLoggedIn(false);
3756
4280
  dispatch(clearClientContext());
3757
4281
  const isPublic = publicPaths.some((p) => location.pathname === p || location.pathname.startsWith(p + "/"));
3758
- if (!showSessionExpiredMessage && !isCurrentPathPublic()) {
4282
+ if (!showSessionExpiredMessage && !isCurrentPathPublic() && huboSesionRef.current) {
3759
4283
  setShowSessionExpiredMessage(true);
3760
4284
  }
3761
4285
  }
3762
- }, [dispatch, clientContext.status, showSessionExpiredMessage]);
3763
- useEffect4(() => {
4286
+ }, [dispatch, clientContext.status, showSessionExpiredMessage, isCurrentPathPublic]);
4287
+ useEffect6(() => {
3764
4288
  checkSession();
3765
4289
  const intervalId = setInterval(checkSession, 15 * 1e3);
3766
4290
  return () => {
3767
4291
  clearInterval(intervalId);
3768
4292
  };
3769
4293
  }, [checkSession]);
3770
- const authContextValue = useMemo9(() => ({
4294
+ const authContextValue = useMemo10(() => ({
3771
4295
  isLoggedIn,
3772
4296
  setIsLoggedIn,
3773
4297
  checkSession,
@@ -3782,7 +4306,7 @@ var AppProvider = ({ children, publicPaths = [] }) => {
3782
4306
  setShowSessionExpiredMessage,
3783
4307
  handleExpiredSessionRedirect
3784
4308
  ]);
3785
- return /* @__PURE__ */ jsx17(AuthContext.Provider, { value: authContextValue, children });
4309
+ return /* @__PURE__ */ jsx19(AuthContext.Provider, { value: authContextValue, children });
3786
4310
  };
3787
4311
 
3788
4312
  // src/components/MainLayout.tsx
@@ -3791,8 +4315,8 @@ import MenuIcon from "@mui/icons-material/Menu";
3791
4315
  import ChevronLeftIcon from "@mui/icons-material/ChevronLeft";
3792
4316
 
3793
4317
  // src/components/SideMenu.tsx
3794
- import React12, { useEffect as useEffect5 } from "react";
3795
- import { List as List2, ListItem, ListItemButton as ListItemButton2, ListItemIcon as ListItemIcon2, ListItemText as ListItemText2, Divider as Divider2, Box as Box14, Typography as Typography10, Collapse } from "@mui/material";
4318
+ import React15, { useEffect as useEffect7 } from "react";
4319
+ import { List as List2, ListItem, ListItemButton as ListItemButton2, ListItemIcon as ListItemIcon2, ListItemText as ListItemText2, Divider as Divider2, Box as Box13, Typography as Typography9, Collapse } from "@mui/material";
3796
4320
  import ExpandLess from "@mui/icons-material/ExpandLess";
3797
4321
  import ExpandMore from "@mui/icons-material/ExpandMore";
3798
4322
  import TableChartIcon from "@mui/icons-material/TableChart";
@@ -3805,46 +4329,7 @@ import UnfoldMoreIcon from "@mui/icons-material/UnfoldMore";
3805
4329
  import UnfoldLessIcon from "@mui/icons-material/UnfoldLess";
3806
4330
  import { useNavigate as useNavigate2, useLocation as useLocation2 } from "react-router-dom";
3807
4331
  import { blue, orange, teal, red, grey } from "@mui/material/colors";
3808
-
3809
- // src/pages/WScreens.tsx
3810
- import { Box as Box13, Typography as Typography9, Paper as Paper2 } from "@mui/material";
3811
- import ConstructionIcon from "@mui/icons-material/Construction";
3812
- import WarningAmberIcon2 from "@mui/icons-material/WarningAmber";
3813
- import { jsx as jsx18, jsxs as jsxs13 } from "react/jsx-runtime";
3814
- var MyCustomDashboard = ({ screenName }) => {
3815
- return /* @__PURE__ */ jsx18(Box13, { sx: { p: 4, display: "flex", flexDirection: "column", alignItems: "center", justifyContent: "center", height: "100%" }, children: /* @__PURE__ */ jsxs13(Paper2, { elevation: 3, sx: { p: 4, textAlign: "center", maxWidth: 600 }, children: [
3816
- /* @__PURE__ */ jsxs13(Typography9, { variant: "h5", component: "h1", gutterBottom: true, children: [
3817
- "\xA1Bienvenido a tu WScreen: ",
3818
- screenName,
3819
- "!"
3820
- ] }),
3821
- /* @__PURE__ */ jsx18(Typography9, { variant: "body1", color: "text.secondary", children: "Esta es una pantalla de interfaz de usuario personalizada." }),
3822
- /* @__PURE__ */ jsx18(Box13, { sx: { mt: 3 }, children: /* @__PURE__ */ jsx18(ConstructionIcon, { sx: { fontSize: 80, color: "primary.main" } }) })
3823
- ] }) });
3824
- };
3825
- var FallbackWScreen = ({ screenName }) => {
3826
- return /* @__PURE__ */ jsx18(Box13, { sx: { p: 4, display: "flex", flexDirection: "column", alignItems: "center", justifyContent: "center", height: "100%" }, children: /* @__PURE__ */ jsxs13(Paper2, { elevation: 3, sx: { p: 4, textAlign: "center", maxWidth: 600, backgroundColor: "warning.light", border: "1px solid orange" }, children: [
3827
- /* @__PURE__ */ jsx18(Typography9, { variant: "h5", component: "h1", gutterBottom: true, color: "warning.dark", children: "WScreen No Implementada" }),
3828
- /* @__PURE__ */ jsxs13(Typography9, { variant: "body1", color: "warning.dark", children: [
3829
- 'No se encontr\xF3 un componente implementado para la **WScreen**: **`"$',
3830
- screenName,
3831
- '"`**. Por favor, verifica el `menuType` en la definici\xF3n del men\xFA o aseg\xFArate de que el componente est\xE9 correctamente importado y mapeado en el frontend.'
3832
- ] }),
3833
- /* @__PURE__ */ jsx18(Box13, { sx: { mt: 3 }, children: /* @__PURE__ */ jsx18(WarningAmberIcon2, { sx: { fontSize: 80, color: "warning.dark" } }) })
3834
- ] }) });
3835
- };
3836
- var wScreens = {
3837
- "MyCustomDashboard": MyCustomDashboard
3838
- // Agrega más componentes de wScreen aquí:
3839
- // 'AnotherWScreen': AnotherWScreenComponent,
3840
- };
3841
- var extendWScreens = (newWScreens) => {
3842
- wScreens = { ...wScreens, ...newWScreens };
3843
- console.log("wScreens extendidos:", wScreens);
3844
- };
3845
-
3846
- // src/components/SideMenu.tsx
3847
- import { jsx as jsx19, jsxs as jsxs14 } from "react/jsx-runtime";
4332
+ import { jsx as jsx20, jsxs as jsxs14 } from "react/jsx-runtime";
3848
4333
  var MenuListItem = ({ item, level, onMenuItemClick }) => {
3849
4334
  const navigate = useNavigate2();
3850
4335
  const location = useLocation2();
@@ -3885,17 +4370,17 @@ var MenuListItem = ({ item, level, onMenuItemClick }) => {
3885
4370
  const getIcon = (item2) => {
3886
4371
  switch (item2.menuType) {
3887
4372
  case "table":
3888
- return /* @__PURE__ */ jsx19(TableChartIcon, { sx: { color: blue[700] } });
4373
+ return /* @__PURE__ */ jsx20(TableChartIcon, { sx: { color: blue[700] } });
3889
4374
  case "proc":
3890
- return /* @__PURE__ */ jsx19(DnsIcon, { sx: { color: teal[700] } });
4375
+ return /* @__PURE__ */ jsx20(DnsIcon, { sx: { color: teal[700] } });
3891
4376
  case "menu":
3892
- return /* @__PURE__ */ jsx19(FolderIcon, { sx: { color: orange[800] } });
4377
+ return /* @__PURE__ */ jsx20(FolderIcon, { sx: { color: orange[800] } });
3893
4378
  default:
3894
4379
  const WScreenComponent = wScreens[item2.menuType];
3895
4380
  if (WScreenComponent !== void 0) {
3896
- return /* @__PURE__ */ jsx19(DesktopWindowsIcon, { sx: { color: grey[700] } });
4381
+ return /* @__PURE__ */ jsx20(DesktopWindowsIcon, { sx: { color: grey[700] } });
3897
4382
  }
3898
- return /* @__PURE__ */ jsx19(WarningAmberIcon3, { sx: { color: red[500] } });
4383
+ return /* @__PURE__ */ jsx20(WarningAmberIcon3, { sx: { color: red[500] } });
3899
4384
  }
3900
4385
  };
3901
4386
  const currentPath = location.pathname;
@@ -3909,8 +4394,8 @@ var MenuListItem = ({ item, level, onMenuItemClick }) => {
3909
4394
  } else if (item.menuType !== "menu") {
3910
4395
  isSelected = currentPath.startsWith(`/wScreens/${item.menuType}`) || currentPath.startsWith(`/wScreens-fallback/${item.menuType}`);
3911
4396
  }
3912
- const itemRef = React12.useRef(null);
3913
- useEffect5(() => {
4397
+ const itemRef = React15.useRef(null);
4398
+ useEffect7(() => {
3914
4399
  if (isSelected && itemRef.current) {
3915
4400
  itemRef.current.scrollIntoView({ behavior: "smooth", block: "nearest" });
3916
4401
  }
@@ -3923,13 +4408,13 @@ var MenuListItem = ({ item, level, onMenuItemClick }) => {
3923
4408
  sx: { pl: level * 2 },
3924
4409
  selected: isSelected,
3925
4410
  children: [
3926
- /* @__PURE__ */ jsx19(ListItemIcon2, { sx: { minWidth: "38px" }, children: getIcon(item) }),
3927
- /* @__PURE__ */ jsx19(ListItemText2, { primary: item.label || item.name }),
3928
- item.menuType === "menu" ? open ? /* @__PURE__ */ jsx19(ExpandLess, {}) : /* @__PURE__ */ jsx19(ExpandMore, {}) : null
4411
+ /* @__PURE__ */ jsx20(ListItemIcon2, { sx: { minWidth: "38px" }, children: getIcon(item) }),
4412
+ /* @__PURE__ */ jsx20(ListItemText2, { primary: item.label || item.name }),
4413
+ item.menuType === "menu" ? open ? /* @__PURE__ */ jsx20(ExpandLess, {}) : /* @__PURE__ */ jsx20(ExpandMore, {}) : null
3929
4414
  ]
3930
4415
  }
3931
4416
  ),
3932
- item.menuType === "menu" && /* @__PURE__ */ jsx19(Collapse, { in: open, timeout: "auto", unmountOnExit: true, children: /* @__PURE__ */ jsx19(List2, { component: "div", disablePadding: true, children: item.menuContent.map((subItem) => /* @__PURE__ */ jsx19(
4417
+ item.menuType === "menu" && /* @__PURE__ */ jsx20(Collapse, { in: open, timeout: "auto", unmountOnExit: true, children: /* @__PURE__ */ jsx20(List2, { component: "div", disablePadding: true, children: item.menuContent.map((subItem) => /* @__PURE__ */ jsx20(
3933
4418
  MenuListItem,
3934
4419
  {
3935
4420
  item: subItem,
@@ -3959,10 +4444,10 @@ var SideMenu = ({ onMenuItemClick }) => {
3959
4444
  dispatch(setAllSubMenusOpen(!isMostlyOpen));
3960
4445
  };
3961
4446
  if (!clientContext || !clientContext.menu) {
3962
- return /* @__PURE__ */ jsx19(Box14, { sx: { p: 2, textAlign: "center" }, children: /* @__PURE__ */ jsx19(Typography10, { variant: "body2", color: "text.secondary", children: "Cargando men\xFA..." }) });
4447
+ return /* @__PURE__ */ jsx20(Box13, { sx: { p: 2, textAlign: "center" }, children: /* @__PURE__ */ jsx20(Typography9, { variant: "body2", color: "text.secondary", children: "Cargando men\xFA..." }) });
3963
4448
  }
3964
4449
  const isHomeSelected = location.pathname === "/home";
3965
- useEffect5(() => {
4450
+ useEffect7(() => {
3966
4451
  if (!clientContext?.menu) return;
3967
4452
  const expandParents = (items, targetPath, parentNames = []) => {
3968
4453
  const pathParts = targetPath.split("/");
@@ -3991,19 +4476,19 @@ var SideMenu = ({ onMenuItemClick }) => {
3991
4476
  };
3992
4477
  expandParents(clientContext.menu, location.pathname);
3993
4478
  }, [location.pathname, clientContext, dispatch]);
3994
- return /* @__PURE__ */ jsxs14(Box14, { sx: { width: "100%", flexShrink: 0 }, children: [
3995
- clientContext.menu.some((item) => item.menuType === "menu") && /* @__PURE__ */ jsx19(ListItem, { disablePadding: true, children: /* @__PURE__ */ jsxs14(ListItemButton2, { onClick: handleToggleAllSubMenus, children: [
3996
- /* @__PURE__ */ jsx19(ListItemIcon2, { sx: { minWidth: "38px" }, children: isMostlyOpen ? /* @__PURE__ */ jsx19(UnfoldLessIcon, {}) : /* @__PURE__ */ jsx19(UnfoldMoreIcon, {}) }),
3997
- /* @__PURE__ */ jsx19(ListItemText2, { primary: isMostlyOpen ? "colapsar " : "expandir" })
4479
+ return /* @__PURE__ */ jsxs14(Box13, { sx: { width: "100%", flexShrink: 0 }, children: [
4480
+ clientContext.menu.some((item) => item.menuType === "menu") && /* @__PURE__ */ jsx20(ListItem, { disablePadding: true, children: /* @__PURE__ */ jsxs14(ListItemButton2, { onClick: handleToggleAllSubMenus, children: [
4481
+ /* @__PURE__ */ jsx20(ListItemIcon2, { sx: { minWidth: "38px" }, children: isMostlyOpen ? /* @__PURE__ */ jsx20(UnfoldLessIcon, {}) : /* @__PURE__ */ jsx20(UnfoldMoreIcon, {}) }),
4482
+ /* @__PURE__ */ jsx20(ListItemText2, { primary: isMostlyOpen ? "colapsar " : "expandir" })
3998
4483
  ] }) }),
3999
- /* @__PURE__ */ jsx19(Divider2, {}),
4484
+ /* @__PURE__ */ jsx20(Divider2, {}),
4000
4485
  /* @__PURE__ */ jsxs14(List2, { children: [
4001
- /* @__PURE__ */ jsx19(ListItem, { disablePadding: true, children: /* @__PURE__ */ jsxs14(ListItemButton2, { onClick: handleHomeClick, selected: isHomeSelected, children: [
4002
- /* @__PURE__ */ jsx19(ListItemIcon2, { sx: { minWidth: "38px" }, children: /* @__PURE__ */ jsx19(HomeIcon, {}) }),
4003
- /* @__PURE__ */ jsx19(ListItemText2, { primary: "Inicio" })
4486
+ /* @__PURE__ */ jsx20(ListItem, { disablePadding: true, children: /* @__PURE__ */ jsxs14(ListItemButton2, { onClick: handleHomeClick, selected: isHomeSelected, children: [
4487
+ /* @__PURE__ */ jsx20(ListItemIcon2, { sx: { minWidth: "38px" }, children: /* @__PURE__ */ jsx20(HomeIcon, {}) }),
4488
+ /* @__PURE__ */ jsx20(ListItemText2, { primary: "Inicio" })
4004
4489
  ] }) }),
4005
- /* @__PURE__ */ jsx19(Divider2, {}),
4006
- clientContext.menu.map((menuItem) => /* @__PURE__ */ jsx19(
4490
+ /* @__PURE__ */ jsx20(Divider2, {}),
4491
+ clientContext.menu.map((menuItem) => /* @__PURE__ */ jsx20(
4007
4492
  MenuListItem,
4008
4493
  {
4009
4494
  item: menuItem,
@@ -4046,7 +4531,7 @@ var useLogout = () => {
4046
4531
  var useLogout_default = useLogout;
4047
4532
 
4048
4533
  // src/components/MainLayout.tsx
4049
- import { jsx as jsx20, jsxs as jsxs15 } from "react/jsx-runtime";
4534
+ import { jsx as jsx21, jsxs as jsxs15 } from "react/jsx-runtime";
4050
4535
  var drawerWidth = 240;
4051
4536
  var MainLayout = () => {
4052
4537
  const { clientContext } = useApp();
@@ -4055,7 +4540,7 @@ var MainLayout = () => {
4055
4540
  const dispatch = useAppDispatch();
4056
4541
  const theme = useTheme5();
4057
4542
  const isMobile = useMediaQuery(theme.breakpoints.down("sm"));
4058
- useEffect6(() => {
4543
+ useEffect8(() => {
4059
4544
  if (isMobile && isDrawerOpen) {
4060
4545
  dispatch(setDrawerOpen(false));
4061
4546
  }
@@ -4069,12 +4554,12 @@ var MainLayout = () => {
4069
4554
  }
4070
4555
  };
4071
4556
  if (!clientContext) {
4072
- return /* @__PURE__ */ jsx20(Box15, { sx: { display: "flex", justifyContent: "center", alignItems: "center", height: "100vh" }, children: /* @__PURE__ */ jsx20(Typography11, { children: "Cargando dise\xF1o de la aplicaci\xF3n..." }) });
4557
+ return /* @__PURE__ */ jsx21(Box14, { sx: { display: "flex", justifyContent: "center", alignItems: "center", height: "100vh" }, children: /* @__PURE__ */ jsx21(Typography10, { children: "Cargando dise\xF1o de la aplicaci\xF3n..." }) });
4073
4558
  }
4074
4559
  const appBarOffset = theme.mixins.toolbar;
4075
- return /* @__PURE__ */ jsxs15(Box15, { sx: { display: "flex", height: "100vh" }, children: [
4076
- /* @__PURE__ */ jsx20(CssBaseline, {}),
4077
- /* @__PURE__ */ jsx20(
4560
+ return /* @__PURE__ */ jsxs15(Box14, { sx: { display: "flex", height: "100vh" }, children: [
4561
+ /* @__PURE__ */ jsx21(CssBaseline, {}),
4562
+ /* @__PURE__ */ jsx21(
4078
4563
  AppBar,
4079
4564
  {
4080
4565
  position: "fixed",
@@ -4094,7 +4579,7 @@ var MainLayout = () => {
4094
4579
  }
4095
4580
  },
4096
4581
  children: /* @__PURE__ */ jsxs15(Toolbar, { children: [
4097
- /* @__PURE__ */ jsx20(
4582
+ /* @__PURE__ */ jsx21(
4098
4583
  IconButton4,
4099
4584
  {
4100
4585
  color: "inherit",
@@ -4104,10 +4589,10 @@ var MainLayout = () => {
4104
4589
  sx: {
4105
4590
  marginRight: 2
4106
4591
  },
4107
- children: isDrawerOpen ? /* @__PURE__ */ jsx20(ChevronLeftIcon, {}) : /* @__PURE__ */ jsx20(MenuIcon, {})
4592
+ children: isDrawerOpen ? /* @__PURE__ */ jsx21(ChevronLeftIcon, {}) : /* @__PURE__ */ jsx21(MenuIcon, {})
4108
4593
  }
4109
4594
  ),
4110
- !isDrawerOpen && /* @__PURE__ */ jsx20(
4595
+ !isDrawerOpen && /* @__PURE__ */ jsx21(
4111
4596
  "img",
4112
4597
  {
4113
4598
  src: `${envConfig.backendUrl}/img/logo-128.png`,
@@ -4115,14 +4600,14 @@ var MainLayout = () => {
4115
4600
  style: { height: "32px", marginRight: "12px", objectFit: "contain" }
4116
4601
  }
4117
4602
  ),
4118
- /* @__PURE__ */ jsx20(Typography11, { variant: "h6", noWrap: true, component: "div", sx: { flexGrow: 1 }, children: isDrawerOpen ? "" : clientContext.config.title }),
4119
- /* @__PURE__ */ jsx20(Typography11, { variant: "subtitle1", component: "div", sx: { mr: 2 }, children: clientContext.username }),
4120
- /* @__PURE__ */ jsx20(
4121
- Button7,
4603
+ /* @__PURE__ */ jsx21(Typography10, { variant: "h6", noWrap: true, component: "div", sx: { flexGrow: 1 }, children: isDrawerOpen ? "" : clientContext.config.title }),
4604
+ /* @__PURE__ */ jsx21(Typography10, { variant: "subtitle1", component: "div", sx: { mr: 2 }, children: clientContext.username }),
4605
+ /* @__PURE__ */ jsx21(
4606
+ Button6,
4122
4607
  {
4123
4608
  color: "inherit",
4124
4609
  onClick: logout,
4125
- startIcon: /* @__PURE__ */ jsx20(LogoutIcon, {}),
4610
+ startIcon: /* @__PURE__ */ jsx21(LogoutIcon, {}),
4126
4611
  children: "Salir"
4127
4612
  }
4128
4613
  )
@@ -4159,7 +4644,7 @@ var MainLayout = () => {
4159
4644
  gap: 1.5
4160
4645
  },
4161
4646
  children: [
4162
- /* @__PURE__ */ jsx20(
4647
+ /* @__PURE__ */ jsx21(
4163
4648
  "img",
4164
4649
  {
4165
4650
  src: `${envConfig.backendUrl}/img/logo-128.png`,
@@ -4167,16 +4652,16 @@ var MainLayout = () => {
4167
4652
  style: { height: "32px", objectFit: "contain" }
4168
4653
  }
4169
4654
  ),
4170
- /* @__PURE__ */ jsx20(Typography11, { variant: "h6", sx: { fontWeight: "bold" }, children: clientContext.config.title })
4655
+ /* @__PURE__ */ jsx21(Typography10, { variant: "h6", sx: { fontWeight: "bold" }, children: clientContext.config.title })
4171
4656
  ]
4172
4657
  }
4173
4658
  ),
4174
- /* @__PURE__ */ jsx20(SideMenu_default, { onMenuItemClick: handleDrawerCloseMobile })
4659
+ /* @__PURE__ */ jsx21(SideMenu_default, { onMenuItemClick: handleDrawerCloseMobile })
4175
4660
  ]
4176
4661
  }
4177
4662
  ),
4178
- /* @__PURE__ */ jsx20(
4179
- Box15,
4663
+ /* @__PURE__ */ jsx21(
4664
+ Box14,
4180
4665
  {
4181
4666
  component: "main",
4182
4667
  sx: {
@@ -4203,7 +4688,7 @@ var MainLayout = () => {
4203
4688
  flexDirection: "column",
4204
4689
  width: isDrawerOpen ? `calc(100% - ${drawerWidth}px)` : "100%"
4205
4690
  },
4206
- children: /* @__PURE__ */ jsx20(Outlet, {})
4691
+ children: /* @__PURE__ */ jsx21(Outlet, {})
4207
4692
  }
4208
4693
  )
4209
4694
  ] });
@@ -4211,8 +4696,8 @@ var MainLayout = () => {
4211
4696
  var MainLayout_default = MainLayout;
4212
4697
 
4213
4698
  // src/components/SessionExpiredMessage.tsx
4214
- import { Box as Box16, Typography as Typography12, Button as Button8, Modal } from "@mui/material";
4215
- import { jsx as jsx21, jsxs as jsxs16 } from "react/jsx-runtime";
4699
+ import { Box as Box15, Typography as Typography11, Button as Button7, Modal } from "@mui/material";
4700
+ import { jsx as jsx22, jsxs as jsxs16 } from "react/jsx-runtime";
4216
4701
  var style = {
4217
4702
  position: "absolute",
4218
4703
  top: "50%",
@@ -4231,7 +4716,7 @@ var SessionExpiredMessage = () => {
4231
4716
  const handleClose = () => {
4232
4717
  handleExpiredSessionRedirect();
4233
4718
  };
4234
- return /* @__PURE__ */ jsx21(
4719
+ return /* @__PURE__ */ jsx22(
4235
4720
  Modal,
4236
4721
  {
4237
4722
  open: showSessionExpiredMessage,
@@ -4251,10 +4736,10 @@ var SessionExpiredMessage = () => {
4251
4736
  }
4252
4737
  }
4253
4738
  },
4254
- children: /* @__PURE__ */ jsxs16(Box16, { sx: style, children: [
4255
- /* @__PURE__ */ jsx21(Typography12, { id: "session-expired-modal-title", variant: "h6", component: "h2", gutterBottom: true, children: "\xA1Sesi\xF3n Expirada!" }),
4256
- /* @__PURE__ */ jsx21(Typography12, { id: "session-expired-modal-description", sx: { mt: 2, mb: 3 }, children: "Tu sesi\xF3n ha expirado por inactividad o por seguridad. Por favor, inicia sesi\xF3n de nuevo." }),
4257
- /* @__PURE__ */ jsx21(Button8, { variant: "contained", color: "primary", onClick: handleClose, children: "Ir al Login" })
4739
+ children: /* @__PURE__ */ jsxs16(Box15, { sx: style, children: [
4740
+ /* @__PURE__ */ jsx22(Typography11, { id: "session-expired-modal-title", variant: "h6", component: "h2", gutterBottom: true, children: "\xA1Sesi\xF3n Expirada!" }),
4741
+ /* @__PURE__ */ jsx22(Typography11, { id: "session-expired-modal-description", sx: { mt: 2, mb: 3 }, children: "Tu sesi\xF3n ha expirado por inactividad o por seguridad. Por favor, inicia sesi\xF3n de nuevo." }),
4742
+ /* @__PURE__ */ jsx22(Button7, { variant: "contained", color: "primary", onClick: handleClose, children: "Ir al Login" })
4258
4743
  ] })
4259
4744
  }
4260
4745
  );
@@ -4262,27 +4747,27 @@ var SessionExpiredMessage = () => {
4262
4747
  var SessionExpiredMessage_default = SessionExpiredMessage;
4263
4748
 
4264
4749
  // src/pages/HomePage.tsx
4265
- import { Box as Box17, Typography as Typography13 } from "@mui/material";
4266
- import { jsx as jsx22, jsxs as jsxs17 } from "react/jsx-runtime";
4750
+ import { Box as Box16, Typography as Typography12 } from "@mui/material";
4751
+ import { jsx as jsx23, jsxs as jsxs17 } from "react/jsx-runtime";
4267
4752
  var HomePage = () => {
4268
4753
  const { clientContext } = useApp();
4269
- return /* @__PURE__ */ jsxs17(Box17, { sx: { p: 3 }, children: [
4270
- /* @__PURE__ */ jsx22(Typography13, { variant: "h4", component: "h1", gutterBottom: true, children: `Bienvenido/a ${clientContext?.username}` }),
4271
- /* @__PURE__ */ jsx22(Typography13, { variant: "body1", children: "Usa el men\xFA lateral para navegar por las diferentes secciones." })
4754
+ return /* @__PURE__ */ jsxs17(Box16, { sx: { p: 3 }, children: [
4755
+ /* @__PURE__ */ jsx23(Typography12, { variant: "h4", component: "h1", gutterBottom: true, children: `Bienvenido/a ${clientContext?.username}` }),
4756
+ /* @__PURE__ */ jsx23(Typography12, { variant: "body1", children: "Usa el men\xFA lateral para navegar por las diferentes secciones." })
4272
4757
  ] });
4273
4758
  };
4274
4759
  var HomePage_default = HomePage;
4275
4760
 
4276
4761
  // src/pages/LogoutPage.tsx
4277
- import { useEffect as useEffect7 } from "react";
4278
- import { Box as Box18, Typography as Typography14, CircularProgress as CircularProgress5 } from "@mui/material";
4279
- import { jsx as jsx23, jsxs as jsxs18 } from "react/jsx-runtime";
4762
+ import { useEffect as useEffect9 } from "react";
4763
+ import { Box as Box17, Typography as Typography13, CircularProgress as CircularProgress5 } from "@mui/material";
4764
+ import { jsx as jsx24, jsxs as jsxs18 } from "react/jsx-runtime";
4280
4765
  var LogoutPage = () => {
4281
4766
  const logout = useLogout_default();
4282
- useEffect7(() => {
4767
+ useEffect9(() => {
4283
4768
  logout();
4284
4769
  }, [logout]);
4285
- return /* @__PURE__ */ jsxs18(Box18, { sx: {
4770
+ return /* @__PURE__ */ jsxs18(Box17, { sx: {
4286
4771
  display: "flex",
4287
4772
  flexDirection: "column",
4288
4773
  justifyContent: "center",
@@ -4290,21 +4775,21 @@ var LogoutPage = () => {
4290
4775
  height: "100vh",
4291
4776
  textAlign: "center"
4292
4777
  }, children: [
4293
- /* @__PURE__ */ jsx23(CircularProgress5, { size: 60 }),
4294
- /* @__PURE__ */ jsx23(Typography14, { variant: "h6", sx: { mt: 2 }, children: "Cerrando sesi\xF3n..." })
4778
+ /* @__PURE__ */ jsx24(CircularProgress5, { size: 60 }),
4779
+ /* @__PURE__ */ jsx24(Typography13, { variant: "h6", sx: { mt: 2 }, children: "Cerrando sesi\xF3n..." })
4295
4780
  ] });
4296
4781
  };
4297
4782
  var LogoutPage_default = LogoutPage;
4298
4783
 
4299
4784
  // src/pages/LoginPage.tsx
4300
4785
  import { useState as useState14 } from "react";
4301
- import { Button as Button9, TextField as TextField2, Typography as Typography15, Alert as Alert3, AlertTitle, Box as Box19, CircularProgress as CircularProgress6 } from "@mui/material";
4786
+ import { Button as Button8, TextField as TextField2, Typography as Typography14, Alert as Alert3, AlertTitle, Box as Box18, CircularProgress as CircularProgress6 } from "@mui/material";
4302
4787
  import { useForm, Controller } from "react-hook-form";
4303
4788
  import { zodResolver } from "@hookform/resolvers/zod";
4304
4789
  import * as z from "zod";
4305
4790
  import { useNavigate as useNavigate4 } from "react-router-dom";
4306
4791
  import { useDispatch as useDispatch4 } from "react-redux";
4307
- import { Fragment as Fragment2, jsx as jsx24, jsxs as jsxs19 } from "react/jsx-runtime";
4792
+ import { Fragment as Fragment3, jsx as jsx25, jsxs as jsxs19 } from "react/jsx-runtime";
4308
4793
  var loginSchema = z.object({
4309
4794
  username: z.string().min(1, "El usuario es requerido"),
4310
4795
  // Añadir validación básica
@@ -4355,13 +4840,13 @@ var LoginPage = () => {
4355
4840
  } catch (error) {
4356
4841
  console.error("Error al iniciar sesi\xF3n:", error);
4357
4842
  setIsLoggedIn(false);
4358
- setLoginError(error.message || "Ocurri\xF3 un error al iniciar sesi\xF3n. Int\xE9ntalo de nuevo.");
4843
+ setLoginError(mensajeDeError(error, "Ocurri\xF3 un error al iniciar sesi\xF3n. Int\xE9ntalo de nuevo."));
4359
4844
  } finally {
4360
4845
  setIsSubmitting(false);
4361
4846
  }
4362
4847
  };
4363
- return /* @__PURE__ */ jsx24(
4364
- Box19,
4848
+ return /* @__PURE__ */ jsx25(
4849
+ Box18,
4365
4850
  {
4366
4851
  display: "flex",
4367
4852
  alignItems: "center",
@@ -4369,7 +4854,7 @@ var LoginPage = () => {
4369
4854
  minHeight: "100vh",
4370
4855
  bgcolor: "#f5f5f5",
4371
4856
  children: /* @__PURE__ */ jsxs19(
4372
- Box19,
4857
+ Box18,
4373
4858
  {
4374
4859
  width: "100%",
4375
4860
  maxWidth: "400px",
@@ -4378,24 +4863,24 @@ var LoginPage = () => {
4378
4863
  borderRadius: 8,
4379
4864
  boxShadow: 3,
4380
4865
  children: [
4381
- /* @__PURE__ */ jsx24(Box19, { sx: { display: "flex", justifyContent: "center", mb: 3 }, children: /* @__PURE__ */ jsx24(
4866
+ /* @__PURE__ */ jsx25(Box18, { sx: { display: "flex", justifyContent: "center", mb: 3 }, children: /* @__PURE__ */ jsx25(
4382
4867
  "img",
4383
4868
  {
4384
4869
  src: `${envConfig.backendUrl}/img/login-logo-icon.png`,
4385
4870
  alt: "Logo",
4386
- style: { height: "80px", maxWidth: "100%", objectFit: "contain" }
4871
+ style: { height: "192px", maxWidth: "100%", objectFit: "contain" }
4387
4872
  }
4388
4873
  ) }),
4389
- /* @__PURE__ */ jsx24(Typography15, { variant: "h5", align: "center", gutterBottom: true, sx: { fontWeight: "bold", color: "primary.main" }, children: "Iniciar Sesi\xF3n" }),
4874
+ /* @__PURE__ */ jsx25(Typography14, { variant: "h5", align: "center", gutterBottom: true, sx: { fontWeight: "bold", color: "primary.main" }, children: "Iniciar Sesi\xF3n" }),
4390
4875
  /* @__PURE__ */ jsxs19("form", { onSubmit: handleSubmit(onSubmit), className: "space-y-4", children: [
4391
4876
  /* @__PURE__ */ jsxs19("div", { children: [
4392
- /* @__PURE__ */ jsx24("label", { htmlFor: "username", children: /* @__PURE__ */ jsx24(Typography15, { variant: "subtitle1", component: "div", sx: { fontWeight: "medium" }, children: "Usuario" }) }),
4393
- /* @__PURE__ */ jsx24(
4877
+ /* @__PURE__ */ jsx25("label", { htmlFor: "username", children: /* @__PURE__ */ jsx25(Typography14, { variant: "subtitle1", component: "div", sx: { fontWeight: "medium" }, children: "Usuario" }) }),
4878
+ /* @__PURE__ */ jsx25(
4394
4879
  Controller,
4395
4880
  {
4396
4881
  name: "username",
4397
4882
  control,
4398
- render: ({ field }) => /* @__PURE__ */ jsx24(
4883
+ render: ({ field }) => /* @__PURE__ */ jsx25(
4399
4884
  TextField2,
4400
4885
  {
4401
4886
  ...field,
@@ -4412,13 +4897,13 @@ var LoginPage = () => {
4412
4897
  )
4413
4898
  ] }),
4414
4899
  /* @__PURE__ */ jsxs19("div", { children: [
4415
- /* @__PURE__ */ jsx24("label", { htmlFor: "password", children: /* @__PURE__ */ jsx24(Typography15, { variant: "subtitle1", component: "div", sx: { fontWeight: "medium" }, children: "Contrase\xF1a" }) }),
4416
- /* @__PURE__ */ jsx24(
4900
+ /* @__PURE__ */ jsx25("label", { htmlFor: "password", children: /* @__PURE__ */ jsx25(Typography14, { variant: "subtitle1", component: "div", sx: { fontWeight: "medium" }, children: "Contrase\xF1a" }) }),
4901
+ /* @__PURE__ */ jsx25(
4417
4902
  Controller,
4418
4903
  {
4419
4904
  name: "password",
4420
4905
  control,
4421
- render: ({ field }) => /* @__PURE__ */ jsx24(
4906
+ render: ({ field }) => /* @__PURE__ */ jsx25(
4422
4907
  TextField2,
4423
4908
  {
4424
4909
  ...field,
@@ -4434,14 +4919,14 @@ var LoginPage = () => {
4434
4919
  }
4435
4920
  )
4436
4921
  ] }),
4437
- /* @__PURE__ */ jsx24(Button9, { type: "submit", fullWidth: true, variant: "contained", color: "primary", disabled: isSubmitting, sx: { mt: 2 }, children: isSubmitting ? /* @__PURE__ */ jsxs19(Fragment2, { children: [
4438
- /* @__PURE__ */ jsx24(CircularProgress6, { size: 20, sx: { mr: 1 } }),
4922
+ /* @__PURE__ */ jsx25(Button8, { type: "submit", fullWidth: true, variant: "contained", color: "primary", disabled: isSubmitting, sx: { mt: 2 }, children: isSubmitting ? /* @__PURE__ */ jsxs19(Fragment3, { children: [
4923
+ /* @__PURE__ */ jsx25(CircularProgress6, { size: 20, sx: { mr: 1 } }),
4439
4924
  "Iniciando sesi\xF3n..."
4440
4925
  ] }) : "Iniciar Sesi\xF3n" })
4441
4926
  ] }),
4442
4927
  loginError && /* @__PURE__ */ jsxs19(Alert3, { severity: "error", sx: { mt: 2, maxHeight: "200px" }, children: [
4443
4928
  " ",
4444
- /* @__PURE__ */ jsx24(AlertTitle, { children: "Error" }),
4929
+ /* @__PURE__ */ jsx25(AlertTitle, { children: "Error" }),
4445
4930
  loginError
4446
4931
  ] })
4447
4932
  ]
@@ -4453,11 +4938,11 @@ var LoginPage = () => {
4453
4938
  var LoginPage_default = LoginPage;
4454
4939
 
4455
4940
  // src/components/ProcedureForm.tsx
4456
- import React16, { useState as useState15, useCallback as useCallback14, useMemo as useMemo10 } from "react";
4941
+ import React19, { useState as useState15, useCallback as useCallback14, useMemo as useMemo11 } from "react";
4457
4942
  import { useParams } from "react-router-dom";
4458
4943
  import {
4459
4944
  TextField as TextField3,
4460
- Button as Button10,
4945
+ Button as Button9,
4461
4946
  FormControl as FormControl3,
4462
4947
  InputLabel as InputLabel2,
4463
4948
  Select as Select2,
@@ -4465,8 +4950,8 @@ import {
4465
4950
  Checkbox as Checkbox3,
4466
4951
  FormControlLabel as FormControlLabel3,
4467
4952
  FormHelperText as FormHelperText2,
4468
- Typography as Typography17,
4469
- Box as Box21,
4953
+ Typography as Typography16,
4954
+ Box as Box20,
4470
4955
  CircularProgress as CircularProgress7,
4471
4956
  Alert as Alert4,
4472
4957
  Divider as Divider3,
@@ -4474,14 +4959,14 @@ import {
4474
4959
  } from "@mui/material";
4475
4960
 
4476
4961
  // src/pages/procedure-results/SuccessDisplay.tsx
4477
- import { Box as Box20, Typography as Typography16, Paper as Paper3 } from "@mui/material";
4478
- import { jsx as jsx25, jsxs as jsxs20 } from "react/jsx-runtime";
4962
+ import { Box as Box19, Typography as Typography15, Paper as Paper3 } from "@mui/material";
4963
+ import { jsx as jsx26, jsxs as jsxs20 } from "react/jsx-runtime";
4479
4964
  var SuccessDisplay = ({ data }) => {
4480
4965
  return /* @__PURE__ */ jsxs20(Paper3, { elevation: 2, sx: { p: 2, mt: 2, bgcolor: "success.light", color: "success.contrastText" }, children: [
4481
- /* @__PURE__ */ jsx25(Typography16, { variant: "h6", sx: { fontSize: "1rem", mb: 1 }, children: "\xA1Operaci\xF3n Exitosa!" }),
4482
- /* @__PURE__ */ jsx25(Typography16, { variant: "body2", sx: { fontSize: "0.85rem" }, children: "Detalles del resultado:" }),
4483
- /* @__PURE__ */ jsx25(Box20, { sx: { bgcolor: "success.dark", p: 1, borderRadius: 1, mt: 1, overflowX: "auto" }, children: /* @__PURE__ */ jsx25("pre", { style: { margin: 0, fontSize: "0.75rem", color: "white" }, children: JSON.stringify(data, null, 2) }) }),
4484
- /* @__PURE__ */ jsx25(Typography16, { variant: "body2", sx: { fontSize: "0.8rem", mt: 1 }, children: "Puedes revisar los detalles anteriores o cerrar este mensaje." })
4966
+ /* @__PURE__ */ jsx26(Typography15, { variant: "h6", sx: { fontSize: "1rem", mb: 1 }, children: "\xA1Operaci\xF3n Exitosa!" }),
4967
+ /* @__PURE__ */ jsx26(Typography15, { variant: "body2", sx: { fontSize: "0.85rem" }, children: "Detalles del resultado:" }),
4968
+ /* @__PURE__ */ jsx26(Box19, { sx: { bgcolor: "success.dark", p: 1, borderRadius: 1, mt: 1, overflowX: "auto" }, children: /* @__PURE__ */ jsx26("pre", { style: { margin: 0, fontSize: "0.75rem", color: "white" }, children: JSON.stringify(data, null, 2) }) }),
4969
+ /* @__PURE__ */ jsx26(Typography15, { variant: "body2", sx: { fontSize: "0.8rem", mt: 1 }, children: "Puedes revisar los detalles anteriores o cerrar este mensaje." })
4485
4970
  ] });
4486
4971
  };
4487
4972
  var SuccessDisplay_default = SuccessDisplay;
@@ -4495,7 +4980,7 @@ var extendResultsOk = (newComponents) => {
4495
4980
  };
4496
4981
 
4497
4982
  // src/components/ProcedureForm.tsx
4498
- import { jsx as jsx26, jsxs as jsxs21 } from "react/jsx-runtime";
4983
+ import { jsx as jsx27, jsxs as jsxs21 } from "react/jsx-runtime";
4499
4984
  var ProcedureForm = () => {
4500
4985
  const { procedureName } = useParams();
4501
4986
  const { clientContext } = useApp();
@@ -4504,7 +4989,7 @@ var ProcedureForm = () => {
4504
4989
  const [successMessage, setSuccessMessage] = useState15(null);
4505
4990
  const [executionLog, setExecutionLog] = useState15([]);
4506
4991
  const [procedureResultData, setProcedureResultData] = useState15(null);
4507
- const procedure = useMemo10(() => {
4992
+ const procedure = useMemo11(() => {
4508
4993
  if (procedureName && clientContext?.procedure) {
4509
4994
  return clientContext.procedure[procedureName];
4510
4995
  }
@@ -4535,7 +5020,7 @@ var ProcedureForm = () => {
4535
5020
  });
4536
5021
  return initialValues;
4537
5022
  });
4538
- React16.useEffect(() => {
5023
+ React19.useEffect(() => {
4539
5024
  if (procedure) {
4540
5025
  setValidationErrors({});
4541
5026
  setSuccessMessage(null);
@@ -4607,8 +5092,8 @@ var ProcedureForm = () => {
4607
5092
  if (value === "" || value === null) {
4608
5093
  processedValue = null;
4609
5094
  } else {
4610
- processedValue = parseFloat(value);
4611
- if (isNaN(processedValue)) {
5095
+ processedValue = parseFloat(String(value));
5096
+ if (typeof processedValue === "number" && isNaN(processedValue)) {
4612
5097
  paramError = `El valor para "${param.label || param.name}" no es un n\xFAmero v\xE1lido.`;
4613
5098
  }
4614
5099
  }
@@ -4618,8 +5103,8 @@ var ProcedureForm = () => {
4618
5103
  if (value === "" || value === null) {
4619
5104
  processedValue = null;
4620
5105
  } else {
4621
- processedValue = parseInt(value, 10);
4622
- if (isNaN(processedValue)) {
5106
+ processedValue = parseInt(String(value), 10);
5107
+ if (typeof processedValue === "number" && isNaN(processedValue)) {
4623
5108
  paramError = `El valor para "${param.label || param.name}" no es un entero v\xE1lido.`;
4624
5109
  }
4625
5110
  }
@@ -4633,9 +5118,9 @@ var ProcedureForm = () => {
4633
5118
  processedValue = null;
4634
5119
  } else {
4635
5120
  try {
4636
- processedValue = JSON.parse(value);
5121
+ processedValue = JSON.parse(String(value));
4637
5122
  } catch (jsonError) {
4638
- paramError = `Error en el formato JSON para "${param.label || param.name}": ${jsonError.message}`;
5123
+ paramError = `Error en el formato JSON para "${param.label || param.name}": ${mensajeDeError(jsonError)}`;
4639
5124
  }
4640
5125
  }
4641
5126
  break;
@@ -4686,7 +5171,7 @@ var ProcedureForm = () => {
4686
5171
  }
4687
5172
  } catch (err) {
4688
5173
  console.error("Error al ejecutar el procedimiento (capturado en ProcedureForm):", err);
4689
- addLogMessage(`Error en la ejecuci\xF3n: ${err.message || "Error desconocido."}`, true);
5174
+ addLogMessage(`Error en la ejecuci\xF3n: ${mensajeDeError(err, "Error desconocido.")}`, true);
4690
5175
  } finally {
4691
5176
  addLogMessage("Ejecuci\xF3n finalizada.");
4692
5177
  }
@@ -4711,7 +5196,7 @@ var ProcedureForm = () => {
4711
5196
  };
4712
5197
  if (param.options && param.options.length > 0) {
4713
5198
  return /* @__PURE__ */ jsxs21(FormControl3, { fullWidth: true, margin: "dense", size: "small", error: hasError, required: commonProps.required, children: [
4714
- /* @__PURE__ */ jsx26(InputLabel2, { id: `${param.name}-label`, sx: { fontSize: "0.8rem" }, children: param.label || param.name }),
5199
+ /* @__PURE__ */ jsx27(InputLabel2, { id: `${param.name}-label`, sx: { fontSize: "0.8rem" }, children: param.label || param.name }),
4715
5200
  /* @__PURE__ */ jsxs21(
4716
5201
  Select2,
4717
5202
  {
@@ -4723,14 +5208,14 @@ var ProcedureForm = () => {
4723
5208
  label: param.label || param.name,
4724
5209
  disabled: apiLoading,
4725
5210
  sx: { fontSize: "0.8rem" },
4726
- renderValue: (selected) => /* @__PURE__ */ jsx26(Typography17, { sx: { fontSize: "0.8rem" }, children: selected }),
5211
+ renderValue: (selected) => /* @__PURE__ */ jsx27(Typography16, { sx: { fontSize: "0.8rem" }, children: selected }),
4727
5212
  children: [
4728
- (!commonProps.required || formValues[param.name] === "") && /* @__PURE__ */ jsx26(MenuItem2, { value: "", sx: { fontSize: "0.8rem" }, children: /* @__PURE__ */ jsx26("em", { children: "Seleccione..." }) }),
4729
- param.options.map((option) => /* @__PURE__ */ jsx26(MenuItem2, { value: option, sx: { fontSize: "0.8rem" }, children: option }, option))
5213
+ (!commonProps.required || formValues[param.name] === "") && /* @__PURE__ */ jsx27(MenuItem2, { value: "", sx: { fontSize: "0.8rem" }, children: /* @__PURE__ */ jsx27("em", { children: "Seleccione..." }) }),
5214
+ param.options.map((option) => /* @__PURE__ */ jsx27(MenuItem2, { value: option, sx: { fontSize: "0.8rem" }, children: option }, option))
4730
5215
  ]
4731
5216
  }
4732
5217
  ),
4733
- (param.description || errorMessage) && /* @__PURE__ */ jsx26(FormHelperText2, { sx: { fontSize: "0.7rem" }, children: errorMessage || param.description })
5218
+ (param.description || errorMessage) && /* @__PURE__ */ jsx27(FormHelperText2, { sx: { fontSize: "0.7rem" }, children: errorMessage || param.description })
4734
5219
  ] });
4735
5220
  }
4736
5221
  switch (param.typeName) {
@@ -4739,18 +5224,18 @@ var ProcedureForm = () => {
4739
5224
  case "tsrange":
4740
5225
  case "time_range":
4741
5226
  case "daterange":
4742
- return /* @__PURE__ */ jsx26(TextField3, { type: "text", value: formValues[param.name] || "", ...commonProps });
5227
+ return /* @__PURE__ */ jsx27(TextField3, { type: "text", value: formValues[param.name] || "", ...commonProps });
4743
5228
  case "decimal":
4744
5229
  case "double":
4745
- return /* @__PURE__ */ jsx26(TextField3, { type: "number", inputProps: { step: "any", style: { fontSize: "0.8rem" } }, value: formValues[param.name] || "", ...commonProps });
5230
+ return /* @__PURE__ */ jsx27(TextField3, { type: "number", inputProps: { step: "any", style: { fontSize: "0.8rem" } }, value: formValues[param.name] || "", ...commonProps });
4746
5231
  case "integer":
4747
5232
  case "bigint":
4748
- return /* @__PURE__ */ jsx26(TextField3, { type: "number", inputProps: { step: "1", style: { fontSize: "0.8rem" } }, value: formValues[param.name] || "", ...commonProps });
5233
+ return /* @__PURE__ */ jsx27(TextField3, { type: "number", inputProps: { step: "1", style: { fontSize: "0.8rem" } }, value: formValues[param.name] || "", ...commonProps });
4749
5234
  case "boolean":
4750
- return /* @__PURE__ */ jsx26(
5235
+ return /* @__PURE__ */ jsx27(
4751
5236
  FormControlLabel3,
4752
5237
  {
4753
- control: /* @__PURE__ */ jsx26(
5238
+ control: /* @__PURE__ */ jsx27(
4754
5239
  Checkbox3,
4755
5240
  {
4756
5241
  checked: !!formValues[param.name],
@@ -4761,21 +5246,21 @@ var ProcedureForm = () => {
4761
5246
  size: "small"
4762
5247
  }
4763
5248
  ),
4764
- label: /* @__PURE__ */ jsx26(Typography17, { sx: { fontSize: "0.8rem", color: hasError ? "error.main" : "inherit" }, children: param.label || param.name }),
5249
+ label: /* @__PURE__ */ jsx27(Typography16, { sx: { fontSize: "0.8rem", color: hasError ? "error.main" : "inherit" }, children: param.label || param.name }),
4765
5250
  sx: { mt: 1, mb: 0 }
4766
5251
  }
4767
5252
  );
4768
5253
  case "date":
4769
5254
  case "timestamp":
4770
5255
  case "time":
4771
- return /* @__PURE__ */ jsx26(TextField3, { type: param.typeName === "date" ? "date" : param.typeName === "timestamp" ? "datetime-local" : "time", value: formValues[param.name] || "", ...commonProps, InputLabelProps: { shrink: true, sx: { fontSize: "0.8rem" } } });
5256
+ return /* @__PURE__ */ jsx27(TextField3, { type: param.typeName === "date" ? "date" : param.typeName === "timestamp" ? "datetime-local" : "time", value: formValues[param.name] || "", ...commonProps, InputLabelProps: { shrink: true, sx: { fontSize: "0.8rem" } } });
4772
5257
  case "jsonb":
4773
5258
  case "jsona":
4774
- return /* @__PURE__ */ jsx26(TextField3, { multiline: true, rows: 5, value: formValues[param.name] || "", ...commonProps, InputProps: { sx: { fontSize: "0.8rem" } } });
5259
+ return /* @__PURE__ */ jsx27(TextField3, { multiline: true, rows: 5, value: formValues[param.name] || "", ...commonProps, InputProps: { sx: { fontSize: "0.8rem" } } });
4775
5260
  case "bytea":
4776
5261
  return /* @__PURE__ */ jsxs21(FormControl3, { fullWidth: true, margin: "dense", error: hasError, required: commonProps.required, children: [
4777
- /* @__PURE__ */ jsx26(Typography17, { variant: "body2", color: "textSecondary", component: "label", htmlFor: param.name, sx: { fontSize: "0.8rem", color: hasError ? "error.main" : "text.secondary" }, children: param.label || param.name }),
4778
- /* @__PURE__ */ jsx26(
5262
+ /* @__PURE__ */ jsx27(Typography16, { variant: "body2", color: "textSecondary", component: "label", htmlFor: param.name, sx: { fontSize: "0.8rem", color: hasError ? "error.main" : "text.secondary" }, children: param.label || param.name }),
5263
+ /* @__PURE__ */ jsx27(
4779
5264
  "input",
4780
5265
  {
4781
5266
  type: "file",
@@ -4789,34 +5274,34 @@ var ProcedureForm = () => {
4789
5274
  style: { padding: "6px 0", fontSize: "0.8rem" }
4790
5275
  }
4791
5276
  ),
4792
- (param.description || errorMessage) && /* @__PURE__ */ jsx26(FormHelperText2, { sx: { fontSize: "0.7rem" }, children: errorMessage || param.description })
5277
+ (param.description || errorMessage) && /* @__PURE__ */ jsx27(FormHelperText2, { sx: { fontSize: "0.7rem" }, children: errorMessage || param.description })
4793
5278
  ] });
4794
5279
  default:
4795
- return /* @__PURE__ */ jsx26(TextField3, { type: "text", value: formValues[param.name] || "", ...commonProps });
5280
+ return /* @__PURE__ */ jsx27(TextField3, { type: "text", value: formValues[param.name] || "", ...commonProps });
4796
5281
  }
4797
5282
  }, [formValues, handleChange, apiLoading, validationErrors]);
4798
- const ResultDisplayContent = useMemo10(() => {
5283
+ const ResultDisplayContent = useMemo11(() => {
4799
5284
  if (!procedureResultData || !procedure?.resultOk) return null;
4800
5285
  const ComponentToRender = resultsOk[procedure.resultOk];
4801
5286
  if (ComponentToRender) {
4802
- return /* @__PURE__ */ jsx26(ComponentToRender, { data: procedureResultData });
5287
+ return /* @__PURE__ */ jsx27(ComponentToRender, { data: procedureResultData });
4803
5288
  } else {
4804
5289
  return /* @__PURE__ */ jsxs21(Paper4, { elevation: 2, sx: { p: 2, mt: 0, bgcolor: "warning.light" }, children: [
4805
- /* @__PURE__ */ jsxs21(Typography17, { variant: "h6", sx: { fontSize: "1rem", mb: 1 }, children: [
5290
+ /* @__PURE__ */ jsxs21(Typography16, { variant: "h6", sx: { fontSize: "1rem", mb: 1 }, children: [
4806
5291
  "el componente para resolver el resultOk: '",
4807
5292
  procedure.resultOk,
4808
5293
  "' definido en el procedure no existe o no est\xE1 mapeado."
4809
5294
  ] }),
4810
- /* @__PURE__ */ jsx26(Box21, { sx: {
5295
+ /* @__PURE__ */ jsx27(Box20, { sx: {
4811
5296
  bgcolor: "warning.dark",
4812
5297
  p: 1,
4813
5298
  borderRadius: 1
4814
- }, children: /* @__PURE__ */ jsx26("pre", { style: { margin: 0, fontSize: "0.75rem", color: "white" }, children: JSON.stringify(procedureResultData, null, 2) }) })
5299
+ }, children: /* @__PURE__ */ jsx27("pre", { style: { margin: 0, fontSize: "0.75rem", color: "white" }, children: JSON.stringify(procedureResultData, null, 2) }) })
4815
5300
  ] });
4816
5301
  }
4817
5302
  }, [procedureResultData, procedure]);
4818
5303
  if (!procedure) {
4819
- return /* @__PURE__ */ jsxs21(Box21, { sx: {
5304
+ return /* @__PURE__ */ jsxs21(Box20, { sx: {
4820
5305
  p: 2,
4821
5306
  width: "100%",
4822
5307
  boxSizing: "border-box",
@@ -4826,13 +5311,13 @@ var ProcedureForm = () => {
4826
5311
  boxShadow: 3,
4827
5312
  textAlign: "center"
4828
5313
  }, children: [
4829
- /* @__PURE__ */ jsx26(CircularProgress7, { sx: { mb: 2 } }),
4830
- /* @__PURE__ */ jsx26(Typography17, { variant: "h6", color: "text.secondary", children: "Cargando procedimiento o no encontrado..." })
5314
+ /* @__PURE__ */ jsx27(CircularProgress7, { sx: { mb: 2 } }),
5315
+ /* @__PURE__ */ jsx27(Typography16, { variant: "h6", color: "text.secondary", children: "Cargando procedimiento o no encontrado..." })
4831
5316
  ] });
4832
5317
  }
4833
5318
  return (
4834
5319
  // Esta es la Box más externa que ahora controlará el scroll
4835
- /* @__PURE__ */ jsxs21(Box21, { sx: {
5320
+ /* @__PURE__ */ jsxs21(Box20, { sx: {
4836
5321
  p: 2,
4837
5322
  ml: 1,
4838
5323
  mt: 2,
@@ -4849,17 +5334,17 @@ var ProcedureForm = () => {
4849
5334
  overflowX: "hidden"
4850
5335
  // Oculta el scroll horizontal si no es necesario para el contenedor principal
4851
5336
  }, children: [
4852
- /* @__PURE__ */ jsx26(Typography17, { variant: "h5", component: "h2", gutterBottom: true, align: "left", children: cambiarGuionesBajosPorEspacios(procedure.proceedLabel || procedure.action) }),
5337
+ /* @__PURE__ */ jsx27(Typography16, { variant: "h5", component: "h2", gutterBottom: true, align: "left", children: cambiarGuionesBajosPorEspacios(procedure.proceedLabel || procedure.action) }),
4853
5338
  Object.values(validationErrors).some((err) => err !== null) && /* @__PURE__ */ jsxs21(Alert4, { severity: "error", sx: { mb: 2, fontSize: "0.8rem" }, children: [
4854
5339
  "Por favor, corrige los errores en el formulario antes de enviar.",
4855
- /* @__PURE__ */ jsx26("ul", { children: Object.values(validationErrors).map((err, idx) => err && /* @__PURE__ */ jsx26("li", { children: err }, idx)) })
5340
+ /* @__PURE__ */ jsx27("ul", { children: Object.values(validationErrors).map((err, idx) => err && /* @__PURE__ */ jsx27("li", { children: err }, idx)) })
4856
5341
  ] }),
4857
- !Object.values(validationErrors).some((err) => err !== null) && apiError && /* @__PURE__ */ jsx26(Alert4, { severity: "error", sx: { mb: 2, fontSize: "0.8rem" }, children: apiError.message }),
4858
- !Object.values(validationErrors).some((err) => err !== null) && !apiError && successMessage && /* @__PURE__ */ jsx26(Alert4, { severity: "success", sx: { mb: 2, fontSize: "0.8rem" }, children: successMessage }),
5342
+ !Object.values(validationErrors).some((err) => err !== null) && apiError && /* @__PURE__ */ jsx27(Alert4, { severity: "error", sx: { mb: 2, fontSize: "0.8rem" }, children: apiError.message }),
5343
+ !Object.values(validationErrors).some((err) => err !== null) && !apiError && successMessage && /* @__PURE__ */ jsx27(Alert4, { severity: "success", sx: { mb: 2, fontSize: "0.8rem" }, children: successMessage }),
4859
5344
  /* @__PURE__ */ jsxs21("form", { onSubmit: handleSubmit, children: [
4860
- procedure.parameters.map((param) => /* @__PURE__ */ jsx26("div", { children: renderInputField(param) }, param.name)),
4861
- /* @__PURE__ */ jsx26(
4862
- Button10,
5345
+ procedure.parameters.map((param) => /* @__PURE__ */ jsx27("div", { children: renderInputField(param) }, param.name)),
5346
+ /* @__PURE__ */ jsx27(
5347
+ Button9,
4863
5348
  {
4864
5349
  type: "submit",
4865
5350
  variant: "contained",
@@ -4867,20 +5352,20 @@ var ProcedureForm = () => {
4867
5352
  disabled: apiLoading || Object.values(validationErrors).some((err) => err !== null),
4868
5353
  sx: { mt: 2 },
4869
5354
  size: "medium",
4870
- startIcon: apiLoading ? /* @__PURE__ */ jsx26(CircularProgress7, { size: 20, color: "inherit" }) : null,
5355
+ startIcon: apiLoading ? /* @__PURE__ */ jsx27(CircularProgress7, { size: 20, color: "inherit" }) : null,
4871
5356
  children: apiLoading ? "Ejecutando..." : procedure.proceedLabel || "Ejecutar"
4872
5357
  }
4873
5358
  )
4874
5359
  ] }),
4875
- ResultDisplayContent && /* @__PURE__ */ jsxs21(Box21, { sx: { mt: 2 }, children: [
5360
+ ResultDisplayContent && /* @__PURE__ */ jsxs21(Box20, { sx: { mt: 2 }, children: [
4876
5361
  " ",
4877
5362
  ResultDisplayContent
4878
5363
  ] }),
4879
- executionLog.length > 0 && /* @__PURE__ */ jsxs21(Box21, { sx: { mt: 3 }, children: [
4880
- /* @__PURE__ */ jsx26(Divider3, { sx: { mb: 2 } }),
4881
- /* @__PURE__ */ jsx26(Typography17, { variant: "h6", gutterBottom: true, sx: { fontSize: "0.9rem" }, children: "Registro de Ejecuci\xF3n" }),
4882
- /* @__PURE__ */ jsx26(
4883
- Box21,
5364
+ executionLog.length > 0 && /* @__PURE__ */ jsxs21(Box20, { sx: { mt: 3 }, children: [
5365
+ /* @__PURE__ */ jsx27(Divider3, { sx: { mb: 2 } }),
5366
+ /* @__PURE__ */ jsx27(Typography16, { variant: "h6", gutterBottom: true, sx: { fontSize: "0.9rem" }, children: "Registro de Ejecuci\xF3n" }),
5367
+ /* @__PURE__ */ jsx27(
5368
+ Box20,
4884
5369
  {
4885
5370
  sx: {
4886
5371
  bgcolor: "grey.100",
@@ -4893,8 +5378,8 @@ var ProcedureForm = () => {
4893
5378
  fontSize: "0.75rem",
4894
5379
  whiteSpace: "pre-wrap"
4895
5380
  },
4896
- children: executionLog.map((log, index) => /* @__PURE__ */ jsx26(
4897
- Typography17,
5381
+ children: executionLog.map((log, index) => /* @__PURE__ */ jsx27(
5382
+ Typography16,
4898
5383
  {
4899
5384
  component: "pre",
4900
5385
  sx: {
@@ -4919,9 +5404,9 @@ import { Provider } from "react-redux";
4919
5404
  import { PersistGate } from "redux-persist/integration/react";
4920
5405
 
4921
5406
  // src/components/PrivateRoute.tsx
4922
- import { useEffect as useEffect8 } from "react";
5407
+ import { useEffect as useEffect10 } from "react";
4923
5408
  import { Navigate, useLocation as useLocation3 } from "react-router-dom";
4924
- import { Fragment as Fragment3, jsx as jsx27 } from "react/jsx-runtime";
5409
+ import { Fragment as Fragment4, jsx as jsx28 } from "react/jsx-runtime";
4925
5410
  var PrivateRoute = ({ children }) => {
4926
5411
  const location = useLocation3();
4927
5412
  const dispatch = useAppDispatch();
@@ -4929,7 +5414,7 @@ var PrivateRoute = ({ children }) => {
4929
5414
  const isAuthenticated = clientContextStatus === "succeeded";
4930
5415
  const isLoadingAuth = clientContextStatus === "loading";
4931
5416
  console.log(`[PrivateRoute] Render: Path=${location.pathname}, AuthStatus=${clientContextStatus}, IsAuthenticated=${isAuthenticated}, IsLoadingAuth=${isLoadingAuth}`);
4932
- useEffect8(() => {
5417
+ useEffect10(() => {
4933
5418
  console.log(`[PrivateRoute] Effect: Path=${location.pathname}, AuthStatus=${clientContextStatus}, IsAuthenticated=${isAuthenticated}, IsLoadingAuth=${isLoadingAuth}`);
4934
5419
  if (!isAuthenticated && !isLoadingAuth && location.pathname !== "/login") {
4935
5420
  const path = location.pathname + location.search;
@@ -4945,19 +5430,19 @@ var PrivateRoute = ({ children }) => {
4945
5430
  }, [isAuthenticated, isLoadingAuth, location, dispatch, clientContextStatus]);
4946
5431
  if (isLoadingAuth) {
4947
5432
  console.log(`[PrivateRoute] Returning loading state...`);
4948
- return /* @__PURE__ */ jsx27("p", { children: "Verificando autenticaci\xF3n..." });
5433
+ return /* @__PURE__ */ jsx28("p", { children: "Verificando autenticaci\xF3n..." });
4949
5434
  }
4950
5435
  if (!isAuthenticated) {
4951
5436
  console.log(`[PrivateRoute] User not authenticated, navigating to /login`);
4952
- return /* @__PURE__ */ jsx27(Navigate, { to: "/login", replace: true });
5437
+ return /* @__PURE__ */ jsx28(Navigate, { to: "/login", replace: true });
4953
5438
  }
4954
5439
  console.log(`[PrivateRoute] User authenticated, rendering children.`);
4955
- return /* @__PURE__ */ jsx27(Fragment3, { children });
5440
+ return /* @__PURE__ */ jsx28(Fragment4, { children });
4956
5441
  };
4957
5442
  var PrivateRoute_default = PrivateRoute;
4958
5443
 
4959
5444
  // src/components/InitialRedirectHandler.tsx
4960
- import { useEffect as useEffect9 } from "react";
5445
+ import { useEffect as useEffect11, useRef as useRef8 } from "react";
4961
5446
  import { useLocation as useLocation4, useNavigate as useNavigate5 } from "react-router-dom";
4962
5447
  var InitialRedirectHandler = () => {
4963
5448
  const location = useLocation4();
@@ -4965,16 +5450,21 @@ var InitialRedirectHandler = () => {
4965
5450
  const dispatch = useAppDispatch();
4966
5451
  const redirectPath = useRedirectPath();
4967
5452
  const clientContextStatus = useClientContextStatus();
4968
- useEffect9(() => {
5453
+ useEffect11(() => {
4969
5454
  dispatch(setCurrentPath(location.pathname + location.search));
4970
5455
  }, [location, dispatch]);
4971
- useEffect9(() => {
5456
+ const navegandoRef = useRef8(false);
5457
+ useEffect11(() => {
5458
+ navegandoRef.current = false;
5459
+ }, [location.pathname]);
5460
+ useEffect11(() => {
4972
5461
  if (clientContextStatus === "succeeded") {
4973
5462
  if (redirectPath && redirectPath !== "/login") {
4974
5463
  console.log("Redirigiendo a la ruta guardada:", redirectPath);
5464
+ navegandoRef.current = true;
4975
5465
  navigate(redirectPath);
4976
5466
  dispatch(setRedirectPath(null));
4977
- } else if (location.pathname === "/login" || location.pathname === "/") {
5467
+ } else if (!navegandoRef.current && (location.pathname === "/login" || location.pathname === "/")) {
4978
5468
  console.log("Usuario autenticado, redirigiendo a /home por defecto.");
4979
5469
  navigate("/home");
4980
5470
  }
@@ -4985,11 +5475,11 @@ var InitialRedirectHandler = () => {
4985
5475
  var InitialRedirectHandler_default = InitialRedirectHandler;
4986
5476
 
4987
5477
  // src/pages/GenericDataGridPage.tsx
4988
- import React19, { useState as useState16, useCallback as useCallback15 } from "react";
5478
+ import React22, { useState as useState16, useCallback as useCallback15 } from "react";
4989
5479
  import { useParams as useParams2, useLocation as useLocation5 } from "react-router-dom";
4990
- import { Box as Box22, Alert as Alert5, Typography as Typography18, Tabs, Tab, IconButton as IconButton5 } from "@mui/material";
5480
+ import { Box as Box21, Alert as Alert5, Typography as Typography17, Tabs, Tab, IconButton as IconButton5 } from "@mui/material";
4991
5481
  import CloseIcon2 from "@mui/icons-material/Close";
4992
- import { jsx as jsx28, jsxs as jsxs22 } from "react/jsx-runtime";
5482
+ import { jsx as jsx29, jsxs as jsxs22 } from "react/jsx-runtime";
4993
5483
  var GenericDataGridPage = ({
4994
5484
  initialTableName,
4995
5485
  initialFixedFields = []
@@ -5000,7 +5490,7 @@ var GenericDataGridPage = ({
5000
5490
  const [activeTabIdx, setActiveTabIdx] = useState16(0);
5001
5491
  const ffKey = JSON.stringify(initialFixedFields);
5002
5492
  const location = useLocation5();
5003
- React19.useEffect(() => {
5493
+ React22.useEffect(() => {
5004
5494
  if (effectiveTableName) {
5005
5495
  setTabs([{
5006
5496
  id: `main-${effectiveTableName}-${ffKey}`,
@@ -5035,26 +5525,26 @@ var GenericDataGridPage = ({
5035
5525
  else if (activeTabIdx === index) setActiveTabIdx(index - 1);
5036
5526
  };
5037
5527
  if (!effectiveTableName) {
5038
- return /* @__PURE__ */ jsx28(Box22, { p: 3, children: /* @__PURE__ */ jsx28(Alert5, { severity: "error", children: "No se especific\xF3 una tabla." }) });
5528
+ return /* @__PURE__ */ jsx29(Box21, { p: 3, children: /* @__PURE__ */ jsx29(Alert5, { severity: "error", children: "No se especific\xF3 una tabla." }) });
5039
5529
  }
5040
- return /* @__PURE__ */ jsxs22(Box22, { sx: { width: "100%", height: "calc(100vh - 64px)", display: "flex", flexDirection: "column" }, children: [
5041
- /* @__PURE__ */ jsx28(Box22, { sx: { borderBottom: 1, borderColor: "divider", bgcolor: "background.paper" }, children: /* @__PURE__ */ jsx28(Tabs, { value: activeTabIdx, onChange: (_, v) => setActiveTabIdx(v), variant: "scrollable", children: tabs.map((tab, index) => /* @__PURE__ */ jsx28(
5530
+ return /* @__PURE__ */ jsxs22(Box21, { sx: { width: "100%", height: "calc(100vh - 64px)", display: "flex", flexDirection: "column" }, children: [
5531
+ /* @__PURE__ */ jsx29(Box21, { sx: { borderBottom: 1, borderColor: "divider", bgcolor: "background.paper" }, children: /* @__PURE__ */ jsx29(Tabs, { value: activeTabIdx, onChange: (_, v) => setActiveTabIdx(v), variant: "scrollable", children: tabs.map((tab, index) => /* @__PURE__ */ jsx29(
5042
5532
  Tab,
5043
5533
  {
5044
- label: /* @__PURE__ */ jsxs22(Box22, { sx: { display: "flex", alignItems: "center", gap: 1 }, children: [
5045
- /* @__PURE__ */ jsx28(Typography18, { variant: "caption", sx: { fontWeight: "bold" }, children: tab.label }),
5046
- index !== 0 && /* @__PURE__ */ jsx28(IconButton5, { size: "small", onClick: (e) => handleCloseTab(index, e), children: /* @__PURE__ */ jsx28(CloseIcon2, { fontSize: "inherit" }) })
5534
+ label: /* @__PURE__ */ jsxs22(Box21, { sx: { display: "flex", alignItems: "center", gap: 1 }, children: [
5535
+ /* @__PURE__ */ jsx29(Typography17, { variant: "caption", sx: { fontWeight: "bold" }, children: tab.label }),
5536
+ index !== 0 && /* @__PURE__ */ jsx29(IconButton5, { size: "small", onClick: (e) => handleCloseTab(index, e), children: /* @__PURE__ */ jsx29(CloseIcon2, { fontSize: "inherit" }) })
5047
5537
  ] })
5048
5538
  },
5049
5539
  tab.id
5050
5540
  )) }) }),
5051
- tabs.map((tab, index) => /* @__PURE__ */ jsx28(
5052
- Box22,
5541
+ tabs.map((tab, index) => /* @__PURE__ */ jsx29(
5542
+ Box21,
5053
5543
  {
5054
5544
  role: "tabpanel",
5055
5545
  hidden: activeTabIdx !== index,
5056
5546
  sx: { flexGrow: 1, display: activeTabIdx === index ? "flex" : "none", flexDirection: "column", overflow: "hidden" },
5057
- children: /* @__PURE__ */ jsx28(
5547
+ children: /* @__PURE__ */ jsx29(
5058
5548
  GenericDataGrid_default,
5059
5549
  {
5060
5550
  tableName: tab.tableName,
@@ -5070,11 +5560,30 @@ var GenericDataGridPage = ({
5070
5560
  };
5071
5561
  var GenericDataGridPage_default = GenericDataGridPage;
5072
5562
 
5563
+ // src/pages/PantallaDeRuta.tsx
5564
+ import { useMemo as useMemo12 } from "react";
5565
+ import { useSearchParams } from "react-router-dom";
5566
+ import { Box as Box22 } from "@mui/material";
5567
+ import { jsx as jsx30 } from "react/jsx-runtime";
5568
+ var PantallaDeRuta = ({ screenName }) => {
5569
+ const [busqueda] = useSearchParams();
5570
+ const params = useMemo12(() => Object.fromEntries(busqueda.entries()), [busqueda]);
5571
+ const Pantalla = wScreens[screenName];
5572
+ return /* @__PURE__ */ jsx30(Box22, { sx: { pt: 3, pl: 4 }, children: Pantalla ? /* @__PURE__ */ jsx30(Pantalla, { screenName, params }) : /* @__PURE__ */ jsx30(FallbackWScreen, { screenName }) });
5573
+ };
5574
+
5073
5575
  // src/pages/MenuTablePage.tsx
5074
- import { useMemo as useMemo11 } from "react";
5576
+ import { useMemo as useMemo13 } from "react";
5075
5577
  import { useParams as useParams3 } from "react-router-dom";
5076
- import { Box as Box23, Alert as Alert6, Typography as Typography19 } from "@mui/material";
5077
- import { jsx as jsx29, jsxs as jsxs23 } from "react/jsx-runtime";
5578
+ import { Box as Box23, Alert as Alert6, Typography as Typography18 } from "@mui/material";
5579
+ import { jsx as jsx31, jsxs as jsxs23 } from "react/jsx-runtime";
5580
+ function fixedFieldsDeMenu(ff) {
5581
+ if (!ff) return [];
5582
+ if (Array.isArray(ff)) {
5583
+ return ff.map(({ fieldName, value }) => ({ fieldName, value }));
5584
+ }
5585
+ return Object.entries(ff).map(([fieldName, value]) => ({ fieldName, value }));
5586
+ }
5078
5587
  var MenuTablePage = () => {
5079
5588
  const { menuName } = useParams3();
5080
5589
  const { clientContext } = useApp();
@@ -5090,22 +5599,14 @@ var MenuTablePage = () => {
5090
5599
  }
5091
5600
  return void 0;
5092
5601
  };
5093
- const { currentTableName, currentFixedFields } = useMemo11(() => {
5602
+ const { currentTableName, currentFixedFields } = useMemo13(() => {
5094
5603
  let tableName = void 0;
5095
5604
  let fixedFields = [];
5096
5605
  if (menuName && clientContext && clientContext.menu) {
5097
5606
  const menuItem = findMenuItem(clientContext.menu, menuName);
5098
5607
  if (menuItem) {
5099
5608
  tableName = menuItem.table || menuItem.name;
5100
- if (menuItem.ff) {
5101
- Object.keys(menuItem.ff || []).forEach((fixedFieldKey) => {
5102
- fixedFields.push({
5103
- fieldName: fixedFieldKey,
5104
- //@ts-ignore
5105
- value: menuItem.ff[fixedFieldKey]
5106
- });
5107
- });
5108
- }
5609
+ fixedFields = fixedFieldsDeMenu(menuItem.ff);
5109
5610
  } else {
5110
5611
  console.warn(`[${menuName}] \xCDtem de men\xFA '${menuName}' no encontrado o no es de tipo 'table' en clientContext.menu.`);
5111
5612
  }
@@ -5116,12 +5617,12 @@ var MenuTablePage = () => {
5116
5617
  };
5117
5618
  }, [menuName, clientContext]);
5118
5619
  if (!currentTableName) {
5119
- return /* @__PURE__ */ jsx29(Box23, { display: "flex", justifyContent: "center", alignItems: "center", minHeight: "200px", children: /* @__PURE__ */ jsxs23(Alert6, { severity: "error", children: [
5120
- /* @__PURE__ */ jsx29(Typography19, { variant: "h6", children: "Error: No se pudo cargar la informaci\xF3n de la tabla." }),
5121
- /* @__PURE__ */ jsx29(Typography19, { variant: "body1", children: "Verifique la configuraci\xF3n del men\xFA o el nombre de la tabla en la URL." })
5620
+ return /* @__PURE__ */ jsx31(Box23, { display: "flex", justifyContent: "center", alignItems: "center", minHeight: "200px", children: /* @__PURE__ */ jsxs23(Alert6, { severity: "error", children: [
5621
+ /* @__PURE__ */ jsx31(Typography18, { variant: "h6", children: "Error: No se pudo cargar la informaci\xF3n de la tabla." }),
5622
+ /* @__PURE__ */ jsx31(Typography18, { variant: "body1", children: "Verifique la configuraci\xF3n del men\xFA o el nombre de la tabla en la URL." })
5122
5623
  ] }) });
5123
5624
  }
5124
- return /* @__PURE__ */ jsx29(
5625
+ return /* @__PURE__ */ jsx31(
5125
5626
  GenericDataGridPage_default,
5126
5627
  {
5127
5628
  initialTableName: currentTableName,
@@ -5133,84 +5634,60 @@ var MenuTablePage_default = MenuTablePage;
5133
5634
 
5134
5635
  // src/App.tsx
5135
5636
  import { Box as Box24 } from "@mui/material";
5136
- import typeStore7 from "type-store";
5137
-
5138
- // src/utils/routeUtils.ts
5139
- import { Children, isValidElement } from "react";
5140
- var extractPathsFromRoutes = (node) => {
5141
- const paths = [];
5142
- Children.forEach(node, (child) => {
5143
- if (!isValidElement(child)) return;
5144
- if (child.props.path) {
5145
- paths.push(child.props.path);
5146
- }
5147
- if (child.props.children) {
5148
- paths.push(...extractPathsFromRoutes(child.props.children));
5149
- }
5150
- });
5151
- return paths;
5152
- };
5153
-
5154
- // src/App.tsx
5155
- import { jsx as jsx30, jsxs as jsxs24 } from "react/jsx-runtime";
5637
+ import typeStore6 from "type-store";
5638
+ import { Fragment as Fragment5, jsx as jsx32, jsxs as jsxs24 } from "react/jsx-runtime";
5156
5639
  var LocationTracker = () => {
5157
5640
  const location = useLocation6();
5158
5641
  const dispatch = useAppDispatch();
5159
- useEffect11(() => {
5642
+ useEffect13(() => {
5160
5643
  dispatch(setCurrentPath(location.pathname + location.search));
5161
5644
  }, [location, dispatch]);
5162
5645
  return null;
5163
5646
  };
5164
5647
  function FrontendPlusReactRoutes({ myRoutes, myUnloggedRoutes, layout: Layout = MainLayout_default, unloggedLayout: UnloggedLayout }) {
5165
- return /* @__PURE__ */ jsxs24(Routes, { children: [
5166
- /* @__PURE__ */ jsxs24(Route, { element: UnloggedLayout ? /* @__PURE__ */ jsx30(UnloggedLayout, {}) : /* @__PURE__ */ jsx30(Outlet2, {}), children: [
5167
- /* @__PURE__ */ jsx30(Route, { path: "/login", element: /* @__PURE__ */ jsx30(LoginPage_default, {}) }),
5168
- /* @__PURE__ */ jsx30(Route, { path: "/logout", element: /* @__PURE__ */ jsx30(LogoutPage_default, {}) }),
5169
- myUnloggedRoutes
5170
- ] }),
5171
- /* @__PURE__ */ jsxs24(Route, { element: /* @__PURE__ */ jsxs24(PrivateRoute_default, { children: [
5172
- /* @__PURE__ */ jsx30(InitialRedirectHandler_default, {}),
5173
- /* @__PURE__ */ jsx30(Layout, {})
5174
- ] }), children: [
5175
- /* @__PURE__ */ jsx30(Route, { path: "/", element: /* @__PURE__ */ jsx30(HomePage_default, {}) }),
5176
- /* @__PURE__ */ jsx30(Route, { path: "/home", element: /* @__PURE__ */ jsx30(HomePage_default, {}) }),
5177
- /* @__PURE__ */ jsx30(Route, { path: "/table/:tableName", element: /* @__PURE__ */ jsx30(GenericDataGridPage_default, {}) }),
5178
- /* @__PURE__ */ jsx30(Route, { path: "/menu/:menuName", element: /* @__PURE__ */ jsx30(MenuTablePage_default, {}) }),
5179
- /* @__PURE__ */ jsx30(Route, { path: "/procedures/:procedureName", element: /* @__PURE__ */ jsx30(ProcedureForm_default, {}) }),
5180
- Object.keys(wScreens).map((screenName) => /* @__PURE__ */ jsx30(
5181
- Route,
5182
- {
5183
- path: `/wScreens/${screenName}`,
5184
- element: React22.createElement(
5185
- Box24,
5186
- {
5187
- sx: { pt: 3, pl: 4 }
5188
- },
5189
- React22.createElement(wScreens[screenName], { screenName })
5190
- )
5191
- },
5192
- screenName
5193
- )),
5194
- /* @__PURE__ */ jsx30(
5195
- Route,
5196
- {
5197
- path: "/wScreens-fallback/:screenName",
5198
- element: /* @__PURE__ */ jsx30(Box24, { sx: { p: 3 }, children: /* @__PURE__ */ jsx30(FallbackWScreen, { screenName: ":screenName" }) })
5199
- }
5200
- ),
5201
- myRoutes,
5202
- /* @__PURE__ */ jsx30(Route, { path: "*", element: /* @__PURE__ */ jsx30("div", { style: { marginTop: "20px", marginLeft: "10px" }, children: "404 - Recurso No Encontrado" }) })
5203
- ] }),
5204
- /* @__PURE__ */ jsx30(Route, { path: "*", element: /* @__PURE__ */ jsx30(Navigate2, { to: "/", replace: true }) })
5648
+ return /* @__PURE__ */ jsxs24(Fragment5, { children: [
5649
+ /* @__PURE__ */ jsx32(InitialRedirectHandler_default, {}),
5650
+ /* @__PURE__ */ jsxs24(Routes, { children: [
5651
+ /* @__PURE__ */ jsxs24(Route, { element: UnloggedLayout ? /* @__PURE__ */ jsx32(UnloggedLayout, {}) : /* @__PURE__ */ jsx32(Outlet2, {}), children: [
5652
+ /* @__PURE__ */ jsx32(Route, { path: "/login", element: /* @__PURE__ */ jsx32(LoginPage_default, {}) }),
5653
+ /* @__PURE__ */ jsx32(Route, { path: "/logout", element: /* @__PURE__ */ jsx32(LogoutPage_default, {}) }),
5654
+ myUnloggedRoutes
5655
+ ] }),
5656
+ /* @__PURE__ */ jsxs24(Route, { element: /* @__PURE__ */ jsx32(PrivateRoute_default, { children: /* @__PURE__ */ jsx32(Layout, {}) }), children: [
5657
+ /* @__PURE__ */ jsx32(Route, { path: "/", element: /* @__PURE__ */ jsx32(HomePage_default, {}) }),
5658
+ /* @__PURE__ */ jsx32(Route, { path: "/home", element: /* @__PURE__ */ jsx32(HomePage_default, {}) }),
5659
+ /* @__PURE__ */ jsx32(Route, { path: "/table/:tableName", element: /* @__PURE__ */ jsx32(GenericDataGridPage_default, {}) }),
5660
+ /* @__PURE__ */ jsx32(Route, { path: "/menu/:menuName", element: /* @__PURE__ */ jsx32(MenuTablePage_default, {}) }),
5661
+ /* @__PURE__ */ jsx32(Route, { path: "/procedures/:procedureName", element: /* @__PURE__ */ jsx32(ProcedureForm_default, {}) }),
5662
+ Object.keys(wScreens).map((screenName) => /* @__PURE__ */ jsx32(
5663
+ Route,
5664
+ {
5665
+ path: `/wScreens/${screenName}`,
5666
+ element: /* @__PURE__ */ jsx32(PantallaDeRuta, { screenName })
5667
+ },
5668
+ screenName
5669
+ )),
5670
+ /* @__PURE__ */ jsx32(
5671
+ Route,
5672
+ {
5673
+ path: "/wScreens-fallback/:screenName",
5674
+ element: /* @__PURE__ */ jsx32(Box24, { sx: { p: 3 }, children: /* @__PURE__ */ jsx32(FallbackWScreen, { screenName: ":screenName" }) })
5675
+ }
5676
+ ),
5677
+ myRoutes,
5678
+ /* @__PURE__ */ jsx32(Route, { path: "*", element: /* @__PURE__ */ jsx32("div", { style: { marginTop: "20px", marginLeft: "10px" }, children: "404 - Recurso No Encontrado" }) })
5679
+ ] }),
5680
+ /* @__PURE__ */ jsx32(Route, { path: "*", element: /* @__PURE__ */ jsx32(Navigate2, { to: "/", replace: true }) })
5681
+ ] })
5205
5682
  ] });
5206
5683
  }
5207
5684
  var FrontendPlusProviders = ({ children, publicPaths }) => {
5208
- return /* @__PURE__ */ jsx30(Provider, { store, children: /* @__PURE__ */ jsx30(PersistGate, { loading: null, persistor, children: /* @__PURE__ */ jsxs24(BrowserRouter, { children: [
5209
- /* @__PURE__ */ jsx30(LocationTracker, {}),
5685
+ return /* @__PURE__ */ jsx32(Provider, { store, children: /* @__PURE__ */ jsx32(PersistGate, { loading: null, persistor, children: /* @__PURE__ */ jsxs24(BrowserRouter, { children: [
5686
+ /* @__PURE__ */ jsx32(LocationTracker, {}),
5210
5687
  " ",
5211
- /* @__PURE__ */ jsx30(AppProvider, { publicPaths, children: /* @__PURE__ */ jsxs24(SnackbarProvider, { children: [
5688
+ /* @__PURE__ */ jsx32(AppProvider, { publicPaths, children: /* @__PURE__ */ jsxs24(SnackbarProvider, { children: [
5212
5689
  children,
5213
- /* @__PURE__ */ jsx30(SessionExpiredMessage_default, {})
5690
+ /* @__PURE__ */ jsx32(SessionExpiredMessage_default, {})
5214
5691
  ] }) })
5215
5692
  ] }) }) });
5216
5693
  };
@@ -5220,11 +5697,10 @@ var App = ({
5220
5697
  unloggedLayout,
5221
5698
  myWScreens,
5222
5699
  myClientSides,
5223
- myResultsOk
5700
+ myResultsOk,
5701
+ myConditions
5224
5702
  }) => {
5225
- useEffect11(() => {
5226
- typeStore7.messages = typeStore7.i18n.messages.es;
5227
- typeStore7.locale = typeStore7.i18n.locale.es;
5703
+ useMemo14(() => {
5228
5704
  if (myClientSides) {
5229
5705
  extendClientSides(myClientSides);
5230
5706
  }
@@ -5234,17 +5710,24 @@ var App = ({
5234
5710
  if (myWScreens) {
5235
5711
  extendWScreens(myWScreens);
5236
5712
  }
5713
+ if (myConditions) {
5714
+ extendConditions(myConditions);
5715
+ }
5716
+ }, [myClientSides, myResultsOk, myWScreens, myConditions]);
5717
+ useEffect13(() => {
5718
+ typeStore6.messages = typeStore6.i18n.messages.es;
5719
+ typeStore6.locale = typeStore6.i18n.locale.es;
5237
5720
  const link = document.querySelector("link[rel*='icon']") || document.createElement("link");
5238
5721
  link.type = "image/png";
5239
5722
  link.rel = "shortcut icon";
5240
5723
  link.href = `${envConfig.backendUrl}/img/logo-128.png`;
5241
5724
  document.getElementsByTagName("head")[0].appendChild(link);
5242
- }, [myClientSides, myResultsOk, myWScreens]);
5243
- const safePaths = React22.useMemo(() => {
5725
+ }, []);
5726
+ const safePaths = React25.useMemo(() => {
5244
5727
  const extracted = extractPathsFromRoutes(myUnloggedRoutes);
5245
5728
  return ["/login", "/logout", ...extracted];
5246
5729
  }, [myUnloggedRoutes]);
5247
- return /* @__PURE__ */ jsx30(FrontendPlusProviders, { publicPaths: safePaths, children: /* @__PURE__ */ jsx30(
5730
+ return /* @__PURE__ */ jsx32(FrontendPlusProviders, { publicPaths: safePaths, children: /* @__PURE__ */ jsx32(
5248
5731
  FrontendPlusReactRoutes,
5249
5732
  {
5250
5733
  myRoutes,
@@ -5258,6 +5741,7 @@ export {
5258
5741
  App_default as App,
5259
5742
  AppProvider,
5260
5743
  ConfirmDialog,
5744
+ DOM_TEMP_ID,
5261
5745
  FrontendPlusProviders,
5262
5746
  FrontendPlusReactRoutes,
5263
5747
  GenericDataGrid_default as GenericDataGrid,
@@ -5266,6 +5750,7 @@ export {
5266
5750
  cambiarGuionesBajosPorEspacios,
5267
5751
  clientSides,
5268
5752
  extendClientSides,
5753
+ extendConditions,
5269
5754
  extendResultsOk,
5270
5755
  extendWScreens,
5271
5756
  extractPathsFromRoutes,