frontend-plus-react 0.6.0 → 0.8.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.cjs CHANGED
@@ -378,7 +378,7 @@ var useApiCallWithoutSnackbar = () => {
378
378
  };
379
379
 
380
380
  // src/components/grid/GenericDataGrid.tsx
381
- var import_material18 = require("@mui/material");
381
+ var import_material19 = require("@mui/material");
382
382
 
383
383
  // src/store/index.ts
384
384
  var import_toolkit4 = require("@reduxjs/toolkit");
@@ -456,8 +456,9 @@ var import_toolkit2 = require("@reduxjs/toolkit");
456
456
  var initialState2 = {
457
457
  currentPath: "/",
458
458
  previousPath: null,
459
- redirectPath: null
459
+ redirectPath: null,
460
460
  // <--- Inicializamos en null
461
+ redirectUsername: null
461
462
  };
462
463
  var routerSlice = (0, import_toolkit2.createSlice)({
463
464
  name: "router",
@@ -469,15 +470,20 @@ var routerSlice = (0, import_toolkit2.createSlice)({
469
470
  },
470
471
  setRedirectPath: (state, action) => {
471
472
  state.redirectPath = action.payload;
473
+ if (action.payload === null) state.redirectUsername = null;
474
+ },
475
+ setRedirectUsername: (state, action) => {
476
+ state.redirectUsername = action.payload;
472
477
  },
473
478
  resetRouterState: (state) => {
474
479
  state.currentPath = "/";
475
480
  state.previousPath = null;
476
481
  state.redirectPath = null;
482
+ state.redirectUsername = null;
477
483
  }
478
484
  }
479
485
  });
480
- var { setCurrentPath, setRedirectPath, resetRouterState } = routerSlice.actions;
486
+ var { setCurrentPath, setRedirectPath, setRedirectUsername, resetRouterState } = routerSlice.actions;
481
487
  var routerSlice_default = routerSlice.reducer;
482
488
 
483
489
  // src/store/menuUiSlice.ts
@@ -502,13 +508,23 @@ var menuUiSlice = (0, import_toolkit3.createSlice)({
502
508
  toggleSubMenu: (state, action) => {
503
509
  state.subMenuOpenStates[action.payload] = !state.subMenuOpenStates[action.payload];
504
510
  },
505
- // --- NUEVO REDUCER: Establecer el estado de todos los submenús ---
506
- setAllSubMenusOpen: (state, action) => {
507
- for (const menuName in state.subMenuOpenStates) {
508
- if (Object.prototype.hasOwnProperty.call(state.subMenuOpenStates, menuName)) {
509
- state.subMenuOpenStates[menuName] = action.payload;
511
+ /** Acordeón: abre un grupo y cierra a sus hermanos (con todo lo que tienen adentro). */
512
+ abrirGrupo: (state, action) => {
513
+ for (const clave of Object.keys(state.subMenuOpenStates)) {
514
+ if (action.payload.hermanos.some((hermano) => clave === hermano || clave.startsWith(hermano + "/"))) {
515
+ state.subMenuOpenStates[clave] = false;
510
516
  }
511
517
  }
518
+ state.subMenuOpenStates[action.payload.clave] = true;
519
+ },
520
+ /** Deja abiertos solo los grupos de este camino (el del ítem que se está mostrando). */
521
+ abrirCamino: (state, action) => {
522
+ for (const clave of Object.keys(state.subMenuOpenStates)) {
523
+ state.subMenuOpenStates[clave] = action.payload.includes(clave);
524
+ }
525
+ for (const clave of action.payload) {
526
+ state.subMenuOpenStates[clave] = true;
527
+ }
512
528
  },
513
529
  resetMenuUiState: (state) => {
514
530
  Object.assign(state, initialState3);
@@ -520,8 +536,8 @@ var {
520
536
  toggleDrawer,
521
537
  setSubMenuOpen,
522
538
  toggleSubMenu,
523
- setAllSubMenusOpen,
524
- // ¡Exportamos la nueva acción!
539
+ abrirGrupo,
540
+ abrirCamino,
525
541
  resetMenuUiState
526
542
  } = menuUiSlice.actions;
527
543
  var menuUiSlice_default = menuUiSlice.reducer;
@@ -1420,7 +1436,7 @@ function BotonDetalle({ row, rowId, detailTable, deshabilitado }) {
1420
1436
  const { abiertos, alternarDetalle } = useDetallesGrilla();
1421
1437
  if (!cumpleCondicion(detailTable.condition, row)) return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "fpr-boton-detalle" });
1422
1438
  const abierto = abiertos.has(claveDetalle(rowId, detailTable));
1423
- const titulo = deshabilitado ? "Grab\xE1 la fila para ver sus detalles" : `${detailTable.label || detailTable.abr}${abierto ? " (replegar)" : ""} \u2014 Ctrl+click: en otra pesta\xF1a`;
1439
+ const titulo = deshabilitado ? "Grab\xE1 la fila para ver sus detalles" : "";
1424
1440
  return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_material3.Tooltip, { title: titulo, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "fpr-boton-detalle", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1425
1441
  import_material3.IconButton,
1426
1442
  {
@@ -1856,7 +1872,8 @@ var useGridMenu = ({
1856
1872
  callApi,
1857
1873
  resetSorting,
1858
1874
  triggerImport,
1859
- triggerExport
1875
+ triggerExport,
1876
+ abrirColumnas
1860
1877
  }) => {
1861
1878
  const { showSuccess, showError, showWarning } = useSnackbar();
1862
1879
  const menuOptions = (0, import_react10.useMemo)(() => {
@@ -1892,7 +1909,7 @@ var useGridMenu = ({
1892
1909
  label: "ocultar o mostrar columnas",
1893
1910
  icon: import_react10.default.createElement(import_VisibilityOff.default),
1894
1911
  handler: async () => {
1895
- console.log("Ocultar/mostrar columnas");
1912
+ abrirColumnas?.();
1896
1913
  },
1897
1914
  visible: true
1898
1915
  });
@@ -1941,7 +1958,7 @@ var useGridMenu = ({
1941
1958
  visible: true
1942
1959
  });
1943
1960
  return options;
1944
- }, [tableDefinition, tableName, fixedFields, setTableData, callApi, resetSorting, triggerImport, triggerExport, showSuccess, showError, showWarning]);
1961
+ }, [tableDefinition, tableName, fixedFields, setTableData, callApi, resetSorting, triggerImport, triggerExport, abrirColumnas, showSuccess, showError, showWarning]);
1945
1962
  return { menuOptions };
1946
1963
  };
1947
1964
 
@@ -2012,7 +2029,7 @@ var useVistaGrilla = () => (0, import_react11.useContext)(VistaGrillaContext);
2012
2029
 
2013
2030
  // src/components/grid/renderers/headerCellRenderers.tsx
2014
2031
  var import_jsx_runtime6 = require("react/jsx-runtime");
2015
- var defaultColumnHeaderCellRenderer = (props, fieldDef) => {
2032
+ var defaultColumnHeaderCellRenderer = (props, fieldDef, ocultarColumna) => {
2016
2033
  const { column, sortDirection, priority } = props;
2017
2034
  const isPrimaryKey = fieldDef.isPk;
2018
2035
  const sorted = sortDirection !== void 0;
@@ -2027,6 +2044,11 @@ var defaultColumnHeaderCellRenderer = (props, fieldDef) => {
2027
2044
  return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
2028
2045
  import_material4.Box,
2029
2046
  {
2047
+ onClickCapture: (e) => {
2048
+ if (!e.altKey || !ocultarColumna) return;
2049
+ e.stopPropagation();
2050
+ ocultarColumna(fieldDef.name);
2051
+ },
2030
2052
  sx: {
2031
2053
  display: "flex",
2032
2054
  alignItems: "center",
@@ -2042,9 +2064,10 @@ var defaultColumnHeaderCellRenderer = (props, fieldDef) => {
2042
2064
  {
2043
2065
  variant: "body2",
2044
2066
  sx: {
2045
- fontWeight: "bold",
2067
+ fontWeight: 500,
2068
+ color: "#37474f",
2046
2069
  textDecoration: isPrimaryKey ? "underline" : "none",
2047
- fontSize: "0.930rem",
2070
+ fontSize: "0.85rem",
2048
2071
  textAlign: "left",
2049
2072
  flexGrow: 1,
2050
2073
  overflow: "hidden",
@@ -2070,22 +2093,20 @@ var ActionsColumnHeaderCell = ({
2070
2093
  allowInsert && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2071
2094
  import_material4.IconButton,
2072
2095
  {
2073
- color: "inherit",
2074
2096
  onClick: () => handleAddRow(),
2075
2097
  size: "small",
2076
2098
  title: "A\xF1adir registro",
2077
- sx: { p: 0.25 },
2078
- children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_Add.default, { sx: { fontSize: 18, color: "success.main" } })
2099
+ sx: { p: 0.25, color: "grey.800", "&:hover": { color: "success.main" } },
2100
+ children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_Add.default, { sx: { fontSize: 18 } })
2079
2101
  }
2080
2102
  ),
2081
2103
  /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2082
2104
  import_material4.IconButton,
2083
2105
  {
2084
- color: "inherit",
2085
2106
  onClick: toggleFilterVisibility,
2086
2107
  size: "small",
2087
2108
  title: isFilterRowVisible ? "Ocultar filtros" : "Mostrar filtros",
2088
- sx: { p: 0.25 },
2109
+ sx: { p: 0.25, color: "grey.800" },
2089
2110
  children: isFilterRowVisible ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_SearchOff.default, { sx: { fontSize: 18 } }) : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_Search.default, { sx: { fontSize: 18 } })
2090
2111
  }
2091
2112
  ),
@@ -2095,7 +2116,7 @@ var ActionsColumnHeaderCell = ({
2095
2116
  onClick: (event) => handleDataGridOptions(event),
2096
2117
  size: "small",
2097
2118
  title: "Opciones de esta tabla",
2098
- sx: { p: 0.25 },
2119
+ sx: { p: 0.25, color: "grey.800" },
2099
2120
  children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_MoreVert.default, { sx: { fontSize: 20, variant: "filled", size: "small" } })
2100
2121
  }
2101
2122
  )
@@ -2576,9 +2597,12 @@ var TypedField = ({ fieldDef, value, onChange, onCommit, disabled, isFilterMode
2576
2597
  "& .MuiOutlinedInput-root": {
2577
2598
  backgroundColor: "background.paper",
2578
2599
  height: FILTER_ROW_HEIGHT - 5,
2579
- minWidth: 50,
2600
+ minWidth: 30,
2580
2601
  fontSize: "0.8rem",
2581
2602
  padding: "0px"
2603
+ },
2604
+ "& .MuiOutlinedInput-input": {
2605
+ padding: "0 4px"
2582
2606
  }
2583
2607
  } : {
2584
2608
  "& .MuiOutlinedInput-root": {
@@ -2602,7 +2626,10 @@ var TypedField = ({ fieldDef, value, onChange, onCommit, disabled, isFilterMode
2602
2626
  };
2603
2627
 
2604
2628
  // src/components/grid/FilterInputRender.tsx
2605
- var import_jsx_runtime12 = require("react/jsx-runtime");
2629
+ var import_jsx_runtime12 = (
2630
+ // como en backend-plus, el operador es un símbolo chico y el campo se queda con el resto del ancho
2631
+ require("react/jsx-runtime")
2632
+ );
2606
2633
  function FilterInputRenderer({
2607
2634
  columnKey,
2608
2635
  currentFilter,
@@ -2625,7 +2652,7 @@ function FilterInputRenderer({
2625
2652
  [columnKey]: { operator: newOp, value: formattedVal }
2626
2653
  }));
2627
2654
  };
2628
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_material9.Box, { sx: { mt: 0, display: "flex", alignItems: "center", gap: 0.5, pr: 1 }, children: [
2655
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_material9.Box, { sx: { mt: 0, display: "flex", alignItems: "center", gap: "2px", width: "100%" }, children: [
2629
2656
  /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
2630
2657
  "select",
2631
2658
  {
@@ -2633,13 +2660,16 @@ function FilterInputRenderer({
2633
2660
  onChange: (e) => handleFilterChange(e.target.value, val),
2634
2661
  style: {
2635
2662
  height: FILTER_ROW_HEIGHT - 5,
2636
- minWidth: 40,
2637
- backgroundColor: "white",
2638
- border: "1px solid #ccc",
2663
+ width: 22,
2664
+ flexShrink: 0,
2665
+ appearance: "none",
2666
+ backgroundColor: "#CEF",
2667
+ border: "none",
2639
2668
  borderRadius: "4px",
2640
2669
  fontSize: "0.8rem",
2641
- padding: "0 2px",
2670
+ padding: 0,
2642
2671
  textAlign: "center",
2672
+ textAlignLast: "center",
2643
2673
  cursor: "pointer"
2644
2674
  },
2645
2675
  children: filterOperators.map((op) => /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("option", { value: op.value, children: op.label }, op.value))
@@ -2690,7 +2720,7 @@ var defaultColumnSummaryCellRenderer = (props, fixedFields) => {
2690
2720
  const { filters, setFilters } = row;
2691
2721
  if (valorFijoDe(fixedFields, column.key)) return null;
2692
2722
  const fieldDef = esColumnaPropia(column) && column.customType === "default" ? column.fieldDef : void 0;
2693
- return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_material10.Box, { sx: { width: "100%", height: "100%", display: "flex", alignItems: "center" }, children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2723
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_material10.Box, { sx: { position: "absolute", inset: 0, display: "flex", alignItems: "center", px: "2px" }, children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2694
2724
  FilterInputRender_default,
2695
2725
  {
2696
2726
  columnKey: column.key,
@@ -2917,14 +2947,12 @@ var allColumnsCellRenderer = (props) => {
2917
2947
  }
2918
2948
  ];
2919
2949
  return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_material13.Box, { sx: { display: "flex", justifyContent: "center", alignItems: "center", height: "100%", gap: 0.5 }, children: gridActionButtons.map((actionDef) => tableDefinition.allow[actionDef.action] ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
2920
- import_material13.Button,
2950
+ import_material13.IconButton,
2921
2951
  {
2922
- variant: "outlined",
2923
- color: actionDef.color,
2924
2952
  size: "small",
2925
2953
  onClick: () => actionDef.handler(row),
2926
2954
  title: actionDef.title,
2927
- sx: { width: 22, minWidth: 22, height: 22, "& .MuiButton-startIcon": { m: 0 } },
2955
+ sx: { width: 22, height: 22, p: 0, color: "grey.800", "&:hover": { color: `${actionDef.color}.main` } },
2928
2956
  children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(actionDef.icon, { sx: { fontSize: 18 } })
2929
2957
  },
2930
2958
  actionDef.action
@@ -3324,22 +3352,46 @@ var allColumnsEditCellRenderer = (props, allColumns) => {
3324
3352
  }
3325
3353
  };
3326
3354
 
3355
+ // src/utils/columnasOcultas.ts
3356
+ function columnasOcultasIniciales(tableDefinition) {
3357
+ return Array.from(new Set(tableDefinition.hiddenColumns ?? []));
3358
+ }
3359
+ function campoDibujable(field) {
3360
+ return field.visible !== false;
3361
+ }
3362
+
3327
3363
  // src/hooks/grid/useGridColumns.ts
3328
3364
  var estimateTextWidth = (text) => text.length * 8 + 16;
3329
- var calcularAnchosDeColumnas = (tableDefinition, filas) => {
3365
+ var contextoDeMedida;
3366
+ var anchoDeTitulo = (texto) => {
3367
+ if (contextoDeMedida === void 0) {
3368
+ try {
3369
+ contextoDeMedida = document.createElement("canvas").getContext("2d");
3370
+ } catch {
3371
+ contextoDeMedida = null;
3372
+ }
3373
+ }
3374
+ if (!contextoDeMedida) return texto.length * 9;
3375
+ contextoDeMedida.font = "bold 14.9px Roboto, Helvetica, Arial, sans-serif";
3376
+ return Math.ceil(contextoDeMedida.measureText(texto).width);
3377
+ };
3378
+ var EXTRA_TITULO = 8 + 20 + 4;
3379
+ var calcularAnchosDeColumnas = (tableDefinition, filas, anchoDisponible = Infinity) => {
3330
3380
  const anchos = /* @__PURE__ */ new Map();
3381
+ const anchosConTituloCompleto = /* @__PURE__ */ new Map();
3331
3382
  const muestra = filas.slice(0, 50);
3332
3383
  tableDefinition.fields.forEach((fieldDef) => {
3333
3384
  if (typeof fieldDef.width === "number" && fieldDef.width > 0) {
3334
3385
  anchos.set(fieldDef.name, fieldDef.width);
3386
+ anchosConTituloCompleto.set(fieldDef.name, fieldDef.width);
3335
3387
  return;
3336
3388
  }
3337
3389
  const headerLabel = fieldDef.label || fieldDef.name;
3338
3390
  const type = fieldDef.typeName?.toLowerCase() || "";
3339
- let typeMinWidth = 60;
3340
- if (type.includes("boolean") || type.includes("checkbox")) typeMinWidth = 60;
3341
- else if (type.includes("date") || type.includes("timestamp")) typeMinWidth = 110;
3342
- else if (type.includes("integer") || type.includes("numeric")) typeMinWidth = 80;
3391
+ let typeMinWidth = 80;
3392
+ if (type.includes("boolean") || type.includes("checkbox")) typeMinWidth = 80;
3393
+ else if (type.includes("date") || type.includes("timestamp")) typeMinWidth = 120;
3394
+ else if (type.includes("integer") || type.includes("numeric")) typeMinWidth = 90;
3343
3395
  const headerWidth = estimateTextWidth(headerLabel) + 20;
3344
3396
  const typer = typerFrom(fieldDef);
3345
3397
  const maxDataWidth = muestra.reduce((maxW, row) => {
@@ -3353,14 +3405,19 @@ var calcularAnchosDeColumnas = (tableDefinition, filas) => {
3353
3405
  }
3354
3406
  return Math.max(maxW, estimateTextWidth(texto));
3355
3407
  }, 0);
3356
- anchos.set(fieldDef.name, Math.min(Math.max(headerWidth, maxDataWidth, typeMinWidth), 500));
3408
+ const compacto = Math.min(Math.max(headerWidth, maxDataWidth, typeMinWidth), 500);
3409
+ anchos.set(fieldDef.name, compacto);
3410
+ anchosConTituloCompleto.set(fieldDef.name, Math.max(compacto, Math.min(anchoDeTitulo(cambiarGuionesBajosPorEspacios(headerLabel)) + EXTRA_TITULO, 500)));
3357
3411
  });
3358
- return anchos;
3412
+ const sumaCompleta = [...anchos.keys()].reduce((total, nombre) => total + (anchosConTituloCompleto.get(nombre) ?? 0), 0);
3413
+ return sumaCompleta <= anchoDisponible ? anchosConTituloCompleto : anchos;
3359
3414
  };
3360
3415
  var useGridColumns = ({
3361
3416
  tableDefinition,
3362
3417
  anchosCalculados,
3363
3418
  fixedFields,
3419
+ columnasOcultas,
3420
+ ocultarColumna,
3364
3421
  primaryKey,
3365
3422
  setTableData,
3366
3423
  handleKeyPressInEditor,
@@ -3374,7 +3431,7 @@ var useGridColumns = ({
3374
3431
  const columns = (0, import_react22.useMemo)(() => {
3375
3432
  if (!tableDefinition) return [];
3376
3433
  const fieldsToShow = tableDefinition.fields.filter((field) => {
3377
- return !columnaOcultaPorFixedField(fixedFields, field.name) && field.visible !== false;
3434
+ return campoDibujable(field) && !columnaOcultaPorFixedField(fixedFields, field.name) && !columnasOcultas.has(field.name);
3378
3435
  });
3379
3436
  const defaultColumns = fieldsToShow.map((fieldDef) => {
3380
3437
  const isFixedField = valorFijoDe(fixedFields, fieldDef.name) !== void 0;
@@ -3399,7 +3456,7 @@ var useGridColumns = ({
3399
3456
  registrarEditor,
3400
3457
  width: colWidth,
3401
3458
  minWidth: 40,
3402
- renderHeaderCell: (props) => defaultColumnHeaderCellRenderer(props, fieldDef),
3459
+ renderHeaderCell: (props) => defaultColumnHeaderCellRenderer(props, fieldDef, ocultarColumna),
3403
3460
  renderSummaryCell: (props) => defaultColumnSummaryCellRenderer(props, fixedFields)
3404
3461
  };
3405
3462
  return column;
@@ -3462,7 +3519,7 @@ var useGridColumns = ({
3462
3519
  renderEditCell: (props) => allColumnsEditCellRenderer(props, allColumns),
3463
3520
  renderCell: (props) => allColumnsCellRenderer(props)
3464
3521
  }));
3465
- }, [tableDefinition, anchosCalculados, fixedFields, primaryKey, setTableData, handleKeyPressInEditor, registrarEditor, handleDeleteRow, handleAddRow, handleVerticalEditRow, toggleFilterVisibility, abrirOpcionesDeGrilla]);
3522
+ }, [tableDefinition, anchosCalculados, fixedFields, columnasOcultas, ocultarColumna, primaryKey, setTableData, handleKeyPressInEditor, registrarEditor, handleDeleteRow, handleAddRow, handleVerticalEditRow, toggleFilterVisibility, abrirOpcionesDeGrilla]);
3466
3523
  return { columns };
3467
3524
  };
3468
3525
 
@@ -3610,6 +3667,7 @@ var ExportDialog = ({
3610
3667
  open,
3611
3668
  onClose,
3612
3669
  tableDefinition,
3670
+ columnasOcultas,
3613
3671
  tableData,
3614
3672
  filteredRows,
3615
3673
  username = "anonymous"
@@ -3640,8 +3698,7 @@ var ExportDialog = ({
3640
3698
  };
3641
3699
  const executeExport = async () => {
3642
3700
  const fieldsDef2Export = tableDefinition.fields.filter((fieldDef) => {
3643
- const isVisible = fieldDef.visible !== false;
3644
- return (fieldDef.inTable !== false || options.fromOtherTables) && isVisible && (fieldDef.editable !== false || options.readOnly || tableDefinition.primaryKey?.includes(fieldDef.name)) && (isVisible || options.hiddens);
3701
+ return (fieldDef.inTable !== false || options.fromOtherTables) && campoDibujable(fieldDef) && (fieldDef.editable !== false || options.readOnly || tableDefinition.primaryKey?.includes(fieldDef.name)) && (!columnasOcultas.has(fieldDef.name) || options.hiddens);
3645
3702
  });
3646
3703
  if (format === "xlsx") {
3647
3704
  await excelExport(fieldsDef2Export);
@@ -3805,16 +3862,36 @@ var ExportDialog = ({
3805
3862
  ] });
3806
3863
  };
3807
3864
 
3865
+ // src/components/grid/DialogoDeColumnas.tsx
3866
+ var import_material17 = require("@mui/material");
3867
+ var import_jsx_runtime21 = require("react/jsx-runtime");
3868
+ var DialogoDeColumnas = ({ open, onClose, columnas, ocultas, alternarColumna }) => {
3869
+ const lista = (titulo, nombres, idDeLista) => /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(import_material17.Box, { sx: { flex: 1, minWidth: 0 }, children: [
3870
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_material17.Typography, { variant: "subtitle2", sx: { mb: 1 }, children: titulo }),
3871
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_material17.List, { dense: true, "data-testid": idDeLista, sx: { maxHeight: 360, overflow: "auto", border: 1, borderColor: "divider", borderRadius: 1 }, children: nombres.map((nombre) => /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_material17.ListItemButton, { onClick: () => alternarColumna(nombre), children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_material17.ListItemText, { primary: nombre }) }, nombre)) })
3872
+ ] });
3873
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(import_material17.Dialog, { open, onClose, maxWidth: "sm", fullWidth: true, children: [
3874
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_material17.DialogTitle, { children: "Ocultar o mostrar columnas" }),
3875
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_material17.DialogContent, { children: /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(import_material17.Box, { sx: { display: "flex", gap: 2, pt: 1 }, children: [
3876
+ lista("Columnas mostradas", columnas.filter((nombre) => !ocultas.has(nombre)), "columnas-mostradas"),
3877
+ lista("Columnas ocultas", columnas.filter((nombre) => ocultas.has(nombre)), "columnas-ocultas")
3878
+ ] }) }),
3879
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_material17.DialogActions, { children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_material17.Button, { onClick: onClose, children: "Cerrar" }) })
3880
+ ] });
3881
+ };
3882
+
3808
3883
  // src/pages/VerticalEditorPage.tsx
3809
3884
  var import_react25 = require("react");
3810
- var import_material17 = require("@mui/material");
3885
+ var import_material18 = require("@mui/material");
3811
3886
  var import_Close = __toESM(require("@mui/icons-material/Close"), 1);
3812
- var import_jsx_runtime21 = require("react/jsx-runtime");
3887
+ var import_jsx_runtime22 = require("react/jsx-runtime");
3888
+ var SIN_OCULTAS = /* @__PURE__ */ new Set();
3813
3889
  var VerticalEditorPage = ({
3814
3890
  tableName,
3815
3891
  tableDefinition,
3816
3892
  initialData,
3817
3893
  fixedFields,
3894
+ columnasOcultas = SIN_OCULTAS,
3818
3895
  isNewRow = false,
3819
3896
  onSaveSuccess,
3820
3897
  onClose
@@ -3936,21 +4013,21 @@ var VerticalEditorPage = ({
3936
4013
  tableDefinition,
3937
4014
  onSaveSuccess
3938
4015
  ]);
3939
- return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(import_material17.Box, { sx: { p: 2, display: "flex", flexDirection: "column", height: "100%" }, children: [
3940
- /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(import_material17.DialogTitle, { sx: { px: 0, pt: 0, display: "flex", justifyContent: "space-between", alignItems: "center" }, children: [
3941
- /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(import_material17.Typography, { component: "div", variant: "h6", children: [
4016
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(import_material18.Box, { sx: { p: 2, display: "flex", flexDirection: "column", height: "100%" }, children: [
4017
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(import_material18.DialogTitle, { sx: { px: 0, pt: 0, display: "flex", justifyContent: "space-between", alignItems: "center" }, children: [
4018
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(import_material18.Typography, { component: "div", variant: "h6", children: [
3942
4019
  isNewRow ? "Nuevo Registro" : "Editar Registro",
3943
4020
  " - ",
3944
4021
  tableDefinition.title || tableName
3945
4022
  ] }),
3946
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_material17.IconButton, { onClick: onClose, size: "small", edge: "end", children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_Close.default, {}) })
4023
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_material18.IconButton, { onClick: onClose, size: "small", edge: "end", children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_Close.default, {}) })
3947
4024
  ] }),
3948
- /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(import_material17.DialogContent, { dividers: true, sx: { px: 2, flexGrow: 1, py: 1 }, children: [
3949
- globalError && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_material17.Alert, { severity: "error", sx: { mb: 2 }, children: globalError }),
3950
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_material17.Box, { sx: { display: "flex", flexDirection: "column", gap: 0.5 }, children: tableDefinition.fields.map((field) => {
4025
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(import_material18.DialogContent, { dividers: true, sx: { px: 2, flexGrow: 1, py: 1 }, children: [
4026
+ globalError && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_material18.Alert, { severity: "error", sx: { mb: 2 }, children: globalError }),
4027
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_material18.Box, { sx: { display: "flex", flexDirection: "column", gap: 0.5 }, children: tableDefinition.fields.filter((field) => campoDibujable(field) && !columnasOcultas.has(field.name)).map((field) => {
3951
4028
  const isFixed = fixedFields?.some((ff) => ff.fieldName === field.name);
3952
4029
  const isMandatory = field.nullable === false || tableDefinition.primaryKey.includes(field.name);
3953
- return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_material17.Box, { sx: { width: "100%", maxWidth: "100%" }, children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
4030
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_material18.Box, { sx: { width: "100%", maxWidth: "100%" }, children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
3954
4031
  TypedField,
3955
4032
  {
3956
4033
  fieldDef: field,
@@ -3964,12 +4041,12 @@ var VerticalEditorPage = ({
3964
4041
  ) }, field.name);
3965
4042
  }) })
3966
4043
  ] }),
3967
- /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(import_material17.DialogActions, { sx: { px: 0, pb: 0, pt: 2, justifyContent: "space-between", alignItems: "center" }, children: [
3968
- /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(import_material17.Box, { children: [
3969
- isSaving && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_material17.CircularProgress, { size: 20, sx: { ml: 2 } }),
3970
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("span", { style: { marginLeft: 10, fontSize: "0.8rem", color: "#666" }, children: isSaving ? "Guardando..." : "Cambios auto-guardados" })
4044
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(import_material18.DialogActions, { sx: { px: 0, pb: 0, pt: 2, justifyContent: "space-between", alignItems: "center" }, children: [
4045
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(import_material18.Box, { children: [
4046
+ isSaving && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_material18.CircularProgress, { size: 20, sx: { ml: 2 } }),
4047
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("span", { style: { marginLeft: 10, fontSize: "0.8rem", color: "#666" }, children: isSaving ? "Guardando..." : "Cambios auto-guardados" })
3971
4048
  ] }),
3972
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_material17.Button, { variant: "outlined", onClick: onClose, children: "Cerrar" })
4049
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_material18.Button, { variant: "outlined", onClick: onClose, children: "Cerrar" })
3973
4050
  ] })
3974
4051
  ] });
3975
4052
  };
@@ -4047,7 +4124,7 @@ var baseDelBundler = import_meta2.env?.BASE_URL ?? "/";
4047
4124
  var rutaBase = baseDelBundler.replace(/\/+$/, "");
4048
4125
 
4049
4126
  // src/components/grid/GenericDataGrid.tsx
4050
- var import_jsx_runtime22 = require("react/jsx-runtime");
4127
+ var import_jsx_runtime23 = require("react/jsx-runtime");
4051
4128
  var SUMMARY_ROW_HEIGHT = 35;
4052
4129
  var FILTER_ROW_HEIGHT = 35;
4053
4130
  var HEADER_ROW_HEIGHT = 30;
@@ -4058,6 +4135,7 @@ var ALTO_TITULO_ANIDADA = 26;
4058
4135
  var ALTO_MINIMO_CUERPO_ANIDADA = 120;
4059
4136
  var HOLGURA_ANIDADA = 24;
4060
4137
  var ANCHO_MINIMO_ANIDADA = 240;
4138
+ var ANCHO_RESERVADO_PANTALLA = 320;
4061
4139
  var SANGRIA_DETALLE = 28 + 8 + 3;
4062
4140
  var MARGEN_INFERIOR_PAGINA = 24;
4063
4141
  var PRIMERAS_FILAS_ANIDADA = 20;
@@ -4066,7 +4144,7 @@ var esColumnaPropia = (columna) => "customType" in columna;
4066
4144
  var SIN_ANCESTROS = [];
4067
4145
  var cargasEnCurso = /* @__PURE__ */ new Map();
4068
4146
  var StaticAncestorGrid = ({ ancestor, index, fieldsToHide }) => {
4069
- const theme = (0, import_material18.useTheme)();
4147
+ const theme = (0, import_material19.useTheme)();
4070
4148
  const { tableDefinition, row } = ancestor;
4071
4149
  const columns = (0, import_react26.useMemo)(() => {
4072
4150
  const filteredFields = tableDefinition.fields.filter(
@@ -4079,8 +4157,8 @@ var StaticAncestorGrid = ({ ancestor, index, fieldsToHide }) => {
4079
4157
  name: field.label || cambiarGuionesBajosPorEspacios(field.name),
4080
4158
  width: 150,
4081
4159
  editable: false,
4082
- renderHeaderCell: () => /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_material18.Box, { sx: { p: 0.5, height: "100%", display: "flex", alignItems: "center" }, children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
4083
- import_material18.Typography,
4160
+ renderHeaderCell: () => /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_material19.Box, { sx: { p: 0.5, height: "100%", display: "flex", alignItems: "center" }, children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
4161
+ import_material19.Typography,
4084
4162
  {
4085
4163
  variant: "caption",
4086
4164
  sx: {
@@ -4091,11 +4169,11 @@ var StaticAncestorGrid = ({ ancestor, index, fieldsToHide }) => {
4091
4169
  children: field.label || cambiarGuionesBajosPorEspacios(field.name)
4092
4170
  }
4093
4171
  ) }),
4094
- renderCell: (props) => /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_material18.Box, { sx: { px: 1, height: "100%", display: "flex", alignItems: "center" }, children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_material18.Typography, { variant: "body2", sx: { fontSize: "0.875rem" }, noWrap: true, children: String(props.row[field.name] ?? "") }) })
4172
+ renderCell: (props) => /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_material19.Box, { sx: { px: 1, height: "100%", display: "flex", alignItems: "center" }, children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_material19.Typography, { variant: "body2", sx: { fontSize: "0.875rem" }, noWrap: true, children: String(props.row[field.name] ?? "") }) })
4095
4173
  };
4096
4174
  });
4097
4175
  }, [tableDefinition, fieldsToHide]);
4098
- return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(import_material18.Box, { sx: {
4176
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(import_material19.Box, { sx: {
4099
4177
  mb: 1.5,
4100
4178
  ml: index * 4,
4101
4179
  // El primer ancestro (index 0) no tiene margen, los siguientes sí
@@ -4106,7 +4184,7 @@ var StaticAncestorGrid = ({ ancestor, index, fieldsToHide }) => {
4106
4184
  boxShadow: theme.shadows[1],
4107
4185
  bgcolor: "background.paper"
4108
4186
  }, children: [
4109
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_material18.Box, { sx: {
4187
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_material19.Box, { sx: {
4110
4188
  bgcolor: "primary.main",
4111
4189
  color: "primary.contrastText",
4112
4190
  px: 1.5,
@@ -4117,8 +4195,8 @@ var StaticAncestorGrid = ({ ancestor, index, fieldsToHide }) => {
4117
4195
  alignItems: "center",
4118
4196
  fontWeight: "bold",
4119
4197
  gap: 1
4120
- }, children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_material18.Typography, { variant: "subtitle2", component: "div", children: cambiarGuionesBajosPorEspacios(ancestor.tableName) }) }),
4121
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
4198
+ }, children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_material19.Typography, { variant: "subtitle2", component: "div", children: cambiarGuionesBajosPorEspacios(ancestor.tableName) }) }),
4199
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
4122
4200
  import_react_data_grid.DataGrid,
4123
4201
  {
4124
4202
  className: "rdg-light",
@@ -4168,13 +4246,19 @@ var GenericDataGrid = ({
4168
4246
  const [cargandoInicial, setCargandoInicial] = (0, import_react26.useState)(!guardada);
4169
4247
  const [errorDeCarga, setErrorDeCarga] = (0, import_react26.useState)(null);
4170
4248
  const [anchosCalculados, setAnchosCalculados] = (0, import_react26.useState)(() => guardada?.anchosCalculados ?? /* @__PURE__ */ new Map());
4249
+ const [columnasOcultas, setColumnasOcultas] = (0, import_react26.useState)(() => guardada?.columnasOcultas ?? []);
4250
+ const [openDialogoDeColumnas, setOpenDialogoDeColumnas] = (0, import_react26.useState)(false);
4251
+ const conjuntoDeOcultas = (0, import_react26.useMemo)(() => new Set(columnasOcultas), [columnasOcultas]);
4252
+ const ocultarColumna = (0, import_react26.useCallback)((columna) => setColumnasOcultas((anteriores) => anteriores.includes(columna) ? anteriores : [...anteriores, columna]), []);
4253
+ const alternarColumna = (0, import_react26.useCallback)((columna) => setColumnasOcultas((anteriores) => anteriores.includes(columna) ? anteriores.filter((oculta) => oculta !== columna) : [...anteriores, columna]), []);
4254
+ const abrirDialogoDeColumnas = (0, import_react26.useCallback)(() => setOpenDialogoDeColumnas(true), []);
4171
4255
  const [detallesAbiertos, setDetallesAbiertos] = (0, import_react26.useState)(guardada?.detallesAbiertos ?? []);
4172
4256
  const [altosDetalle, setAltosDetalle] = (0, import_react26.useState)(() => guardada?.altosDetalle ?? /* @__PURE__ */ new Map());
4173
4257
  const [anchosDetalle, setAnchosDetalle] = (0, import_react26.useState)(() => /* @__PURE__ */ new Map());
4174
4258
  const [selectedRows, setSelectedRows] = (0, import_react26.useState)(() => /* @__PURE__ */ new Set());
4175
4259
  const [, setSelectedCell] = (0, import_react26.useState)(void 0);
4176
4260
  const [estadoGrilla] = (0, import_react26.useState)(crearEstadoGrilla);
4177
- const theme = (0, import_material18.useTheme)();
4261
+ const theme = (0, import_material19.useTheme)();
4178
4262
  const [openDataGridOptions, setOpenDataGridOptions] = (0, import_react26.useState)(false);
4179
4263
  const [dataGridOptionsAnchorEl, setDataGridOptionsAnchorEl] = (0, import_react26.useState)(null);
4180
4264
  const [exitingRowIds, setExitingRowIds] = (0, import_react26.useState)(/* @__PURE__ */ new Set());
@@ -4267,7 +4351,7 @@ var GenericDataGrid = ({
4267
4351
  const firstDisplayCount = tableDefinition?.firstDisplayCount ?? PRIMERAS_FILAS_ANIDADA;
4268
4352
  const firstDisplayOverLimit = tableDefinition?.firstDisplayOverLimit ?? LIMITE_PRIMERAS_FILAS_ANIDADA;
4269
4353
  const filasVisiblesMax = anidada ? filteredRows.length <= firstDisplayOverLimit ? filteredRows.length : firstDisplayCount : void 0;
4270
- const conPie = !anidada || !!tableDefinition?.fields.some((field) => field.aggregate);
4354
+ const conPie = !!tableDefinition?.fields.some((field) => field.aggregate);
4271
4355
  const { gridHeight, bottomSummaryRow, summaryRows, filterHeight } = useGridLayout({
4272
4356
  filteredRows,
4273
4357
  isFilterRowVisible,
@@ -4361,7 +4445,8 @@ var GenericDataGrid = ({
4361
4445
  const definition = parametros.tableDef ? fusionar(definicionDelServidor, parametros.tableDef) : definicionDelServidor;
4362
4446
  setTableDefinition(definition);
4363
4447
  setSortColumns(getInitialSortColumns(definition));
4364
- setAnchosCalculados(calcularAnchosDeColumnas(definition, data));
4448
+ setAnchosCalculados(calcularAnchosDeColumnas(definition, data, window.innerWidth - ANCHO_RESERVADO_PANTALLA));
4449
+ setColumnasOcultas(columnasOcultasIniciales(definition));
4365
4450
  setTableData(data);
4366
4451
  const filasDeFiltros = parametros.filterColumns ?? aFiltrosIniciales(definition.filterColumns);
4367
4452
  if (filasDeFiltros.length > 1) console.warn(`'${tableName}': varias filas de filtros (alternativas) todav\xEDa no est\xE1n soportadas; se aplica la primera`);
@@ -4384,8 +4469,8 @@ var GenericDataGrid = ({
4384
4469
  }, [tableName, claveFixedFields, fixedFields, claveParametros, parametros, showError, callApi, getInitialSortColumns, setSortColumns, aplicarFiltrosIniciales, guardada]);
4385
4470
  (0, import_react26.useEffect)(() => {
4386
4471
  if (!claveCache || !tableDefinition || cargandoInicial) return;
4387
- cache.set(claveCache, { tableDefinition, tableData, anchosCalculados, sortColumns, detallesAbiertos, altosDetalle });
4388
- }, [cache, claveCache, tableDefinition, tableData, anchosCalculados, sortColumns, detallesAbiertos, altosDetalle, cargandoInicial]);
4472
+ cache.set(claveCache, { tableDefinition, tableData, anchosCalculados, columnasOcultas, sortColumns, detallesAbiertos, altosDetalle });
4473
+ }, [cache, claveCache, tableDefinition, tableData, anchosCalculados, columnasOcultas, sortColumns, detallesAbiertos, altosDetalle, cargandoInicial]);
4389
4474
  (0, import_react26.useEffect)(() => {
4390
4475
  let timer = null;
4391
4476
  const desuscribir = estadoGrilla.suscribir(() => {
@@ -4424,7 +4509,8 @@ var GenericDataGrid = ({
4424
4509
  callApi,
4425
4510
  resetSorting: tableDefinition ? resetSortingDeLaTabla : void 0,
4426
4511
  triggerImport: abrirImportacion,
4427
- triggerExport: abrirExportacion
4512
+ triggerExport: abrirExportacion,
4513
+ abrirColumnas: abrirDialogoDeColumnas
4428
4514
  });
4429
4515
  const abrirOpcionesDeGrilla = (0, import_react26.useCallback)((anchorEl) => {
4430
4516
  setDataGridOptionsAnchorEl(anchorEl);
@@ -4438,6 +4524,8 @@ var GenericDataGrid = ({
4438
4524
  tableDefinition,
4439
4525
  anchosCalculados,
4440
4526
  fixedFields,
4527
+ columnasOcultas: conjuntoDeOcultas,
4528
+ ocultarColumna,
4441
4529
  primaryKey,
4442
4530
  setTableData,
4443
4531
  handleKeyPressInEditor,
@@ -4511,13 +4599,13 @@ var GenericDataGrid = ({
4511
4599
  }, [altoMaximoDetalleEfectivo]);
4512
4600
  const renderDetalle = (0, import_react26.useCallback)((fila) => {
4513
4601
  const { detailTable } = fila;
4514
- return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
4602
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
4515
4603
  "div",
4516
4604
  {
4517
4605
  className: "fpr-detalle",
4518
4606
  style: { maxWidth: anchoVisible ? anchoVisible - 2 : void 0 },
4519
4607
  onKeyDown: (e) => e.stopPropagation(),
4520
- children: detailTable.table ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
4608
+ children: detailTable.table ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
4521
4609
  GenericDataGrid,
4522
4610
  {
4523
4611
  tableName: detailTable.table,
@@ -4530,7 +4618,7 @@ var GenericDataGrid = ({
4530
4618
  onOpenDetail,
4531
4619
  ancestors: tableDefinition ? [...ancestors, { tableName: tableDefinition.name, row: fila.filaPadre, tableDefinition, fixedFields: fila.fixedFields }] : ancestors
4532
4620
  }
4533
- ) : detailTable.wScreen ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
4621
+ ) : detailTable.wScreen ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
4534
4622
  DetalleWScreen,
4535
4623
  {
4536
4624
  fila,
@@ -4538,7 +4626,7 @@ var GenericDataGrid = ({
4538
4626
  onAlto: (alto) => cambiarAltoDetalle(fila.clave, alto),
4539
4627
  onAncho: (ancho) => cambiarAnchoDetalle(fila.clave, ancho)
4540
4628
  }
4541
- ) : /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(import_material18.Alert, { severity: "warning", children: [
4629
+ ) : /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(import_material19.Alert, { severity: "warning", children: [
4542
4630
  "El detalle '",
4543
4631
  detailTable.abr,
4544
4632
  "' no tiene ni tabla ni wScreen."
@@ -4558,7 +4646,7 @@ var GenericDataGrid = ({
4558
4646
  [exitingRowIds, primaryKey]
4559
4647
  );
4560
4648
  const anchoContenido = (0, import_react26.useMemo)(() => {
4561
- if (!anidada || columns.length === 0) return void 0;
4649
+ if (columns.length === 0) return void 0;
4562
4650
  const sumaColumnas = columns.reduce((total, col) => {
4563
4651
  const medido = columnWidths.get(col.key)?.width;
4564
4652
  return total + (typeof medido === "number" ? medido : typeof col.width === "number" ? col.width : 100);
@@ -4568,8 +4656,9 @@ var GenericDataGrid = ({
4568
4656
  return Math.max(ANCHO_MINIMO_ANIDADA, propio, anchoDetalleMax > 0 ? anchoDetalleMax + SANGRIA_DETALLE + (medidas?.barra ?? 0) + 2 : 0);
4569
4657
  }, [anidada, columns, columnWidths, medidas?.barra, detallesAbiertos, anchosDetalle]);
4570
4658
  (0, import_react26.useEffect)(() => {
4571
- if (anchoContenido !== void 0) onAnchoDeseado?.(anchoContenido);
4572
- }, [onAnchoDeseado, anchoContenido]);
4659
+ if (anidada && anchoContenido !== void 0) onAnchoDeseado?.(anchoContenido);
4660
+ }, [onAnchoDeseado, anidada, anchoContenido]);
4661
+ const anchoExterior = anchoContenido === void 0 ? void 0 : anidada ? anchoContenido : anchoContenido - 2 + 32 + ancestors.length * 32;
4573
4662
  const estiloGrilla = (0, import_react26.useMemo)(() => ({ height: "100%", width: "100%", boxSizing: "border-box", ...gridStyles }), [gridStyles]);
4574
4663
  const bottomSummaryRows = (0, import_react26.useMemo)(() => conPie ? [bottomSummaryRow] : [], [conPie, bottomSummaryRow]);
4575
4664
  const vistaGrilla = (0, import_react26.useMemo)(() => ({ isFilterRowVisible }), [isFilterRowVisible]);
@@ -4584,19 +4673,19 @@ var GenericDataGrid = ({
4584
4673
  };
4585
4674
  const fallBackMessage = getFallBackMessage();
4586
4675
  if (cargandoInicial) {
4587
- return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(import_material18.Box, { display: "flex", justifyContent: "center", alignItems: "center", minHeight: "200px", children: [
4588
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_material18.CircularProgress, {}),
4589
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_material18.Typography, { variant: "h6", sx: { ml: 2 }, children: "Cargando tabla..." })
4676
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(import_material19.Box, { display: "flex", justifyContent: "center", alignItems: "center", minHeight: "200px", children: [
4677
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_material19.CircularProgress, {}),
4678
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_material19.Typography, { variant: "h6", sx: { ml: 2 }, children: "Cargando tabla..." })
4590
4679
  ] });
4591
4680
  }
4592
4681
  if (errorDeCarga) {
4593
- return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_material18.Box, { display: "flex", justifyContent: "center", alignItems: "center", minHeight: "200px", children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_material18.Alert, { severity: "error", children: errorDeCarga }) });
4682
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_material19.Box, { display: "flex", justifyContent: "center", alignItems: "center", minHeight: "200px", children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_material19.Alert, { severity: "error", children: errorDeCarga }) });
4594
4683
  }
4595
4684
  if (!tableDefinition) {
4596
- return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_material18.Box, { display: "flex", justifyContent: "center", alignItems: "center", minHeight: "200px", children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_material18.Alert, { severity: "warning", children: "No se pudo cargar la definici\xF3n de la tabla." }) });
4685
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_material19.Box, { display: "flex", justifyContent: "center", alignItems: "center", minHeight: "200px", children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_material19.Alert, { severity: "warning", children: "No se pudo cargar la definici\xF3n de la tabla." }) });
4597
4686
  }
4598
- return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(CacheGrillasContext.Provider, { value: cache, children: /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(import_material18.Box, { sx: { pt: anidada ? 0 : 2, display: "flex", flexDirection: "column", height: "100%", boxSizing: "border-box", width: anchoContenido ?? void 0, maxWidth: "100%" }, children: [
4599
- !anidada && ancestors.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_material18.Box, { sx: { px: 2, pt: 0, pb: 1, display: "flex", flexDirection: "column" }, children: ancestors.map((ancestor, index) => /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
4687
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(CacheGrillasContext.Provider, { value: cache, children: /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(import_material19.Box, { sx: { pt: anidada ? 0 : 2, display: "flex", flexDirection: "column", height: "100%", boxSizing: "border-box", width: anchoExterior, maxWidth: "100%" }, children: [
4688
+ !anidada && ancestors.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_material19.Box, { sx: { px: 2, pt: 0, pb: 1, display: "flex", flexDirection: "column" }, children: ancestors.map((ancestor, index) => /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
4600
4689
  StaticAncestorGrid,
4601
4690
  {
4602
4691
  ancestor,
@@ -4605,8 +4694,8 @@ var GenericDataGrid = ({
4605
4694
  },
4606
4695
  index
4607
4696
  )) }),
4608
- /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
4609
- import_material18.Box,
4697
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
4698
+ import_material19.Box,
4610
4699
  {
4611
4700
  sx: {
4612
4701
  backgroundColor: theme.palette.primary.main,
@@ -4628,17 +4717,17 @@ var GenericDataGrid = ({
4628
4717
  gap: 1
4629
4718
  },
4630
4719
  children: [
4631
- /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(import_material18.Typography, { variant: "subtitle2", component: "div", children: [
4720
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(import_material19.Typography, { variant: "subtitle2", component: "div", children: [
4632
4721
  titulo ?? cambiarGuionesBajosPorEspacios(tableDefinition.title || tableDefinition.name),
4633
4722
  " - ",
4634
4723
  filteredRows.length === tableData.length ? `${tableData.length} registros` : `${filteredRows.length} (F)`
4635
4724
  ] }),
4636
- loading && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_material18.CircularProgress, { size: 14, color: "inherit" })
4725
+ loading && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_material19.CircularProgress, { size: 14, color: "inherit" })
4637
4726
  ]
4638
4727
  }
4639
4728
  ),
4640
- /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
4641
- import_material18.Box,
4729
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
4730
+ import_material19.Box,
4642
4731
  {
4643
4732
  sx: {
4644
4733
  // Una grilla anidada se acota con px (el alto que le dio la de arriba, o el de una wScreen): una wScreen
@@ -4656,7 +4745,7 @@ var GenericDataGrid = ({
4656
4745
  pb: anidada ? 0 : 3
4657
4746
  },
4658
4747
  children: [
4659
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(EstadoGrillaContext.Provider, { value: estadoGrilla, children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(VistaGrillaContext.Provider, { value: vistaGrilla, children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(DetallesGrillaContext.Provider, { value: detallesGrilla, children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
4748
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(EstadoGrillaContext.Provider, { value: estadoGrilla, children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(VistaGrillaContext.Provider, { value: vistaGrilla, children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(DetallesGrillaContext.Provider, { value: detallesGrilla, children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
4660
4749
  import_react_data_grid.DataGrid,
4661
4750
  {
4662
4751
  className: "rdg-light",
@@ -4686,13 +4775,13 @@ var GenericDataGrid = ({
4686
4775
  onCellKeyDown: handleCellKeyDown
4687
4776
  }
4688
4777
  ) }) }) }),
4689
- fallBackMessage && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
4690
- import_material18.Box,
4778
+ fallBackMessage && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
4779
+ import_material19.Box,
4691
4780
  {
4692
4781
  sx: {
4693
4782
  position: "absolute",
4694
4783
  top: filterHeight + HEADER_ROW_HEIGHT + 1,
4695
- bottom: anidada ? (conPie ? SUMMARY_ROW_HEIGHT : 0) + 4 : 102,
4784
+ bottom: anidada ? (conPie ? SUMMARY_ROW_HEIGHT : 0) + 4 : conPie ? 102 : 102 - SUMMARY_ROW_HEIGHT,
4696
4785
  left: 18,
4697
4786
  right: 0,
4698
4787
  display: "flex",
@@ -4703,24 +4792,35 @@ var GenericDataGrid = ({
4703
4792
  zIndex: tableData.length === 0 ? 10 : 1
4704
4793
  // Mantenemos el zIndex superior para el estado vacío total
4705
4794
  },
4706
- children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_material18.Typography, { variant: "body2", color: "textSecondary", children: fallBackMessage })
4795
+ children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_material19.Typography, { variant: "body2", color: "textSecondary", children: fallBackMessage })
4707
4796
  }
4708
4797
  )
4709
4798
  ]
4710
4799
  }
4711
4800
  ),
4712
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
4801
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
4713
4802
  ExportDialog,
4714
4803
  {
4715
4804
  open: openExportDialog,
4716
4805
  onClose: () => setOpenExportDialog(false),
4717
4806
  tableDefinition,
4807
+ columnasOcultas: conjuntoDeOcultas,
4718
4808
  tableData,
4719
4809
  filteredRows,
4720
4810
  username: usuario || "anonymous"
4721
4811
  }
4722
4812
  ),
4723
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
4813
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
4814
+ DialogoDeColumnas,
4815
+ {
4816
+ open: openDialogoDeColumnas,
4817
+ onClose: () => setOpenDialogoDeColumnas(false),
4818
+ columnas: (tableDefinition?.fields ?? []).filter(campoDibujable).map((field) => field.name).filter((nombre) => !columnaOcultaPorFixedField(fixedFields, nombre)),
4819
+ ocultas: conjuntoDeOcultas,
4820
+ alternarColumna
4821
+ }
4822
+ ),
4823
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
4724
4824
  ConfirmDialog,
4725
4825
  {
4726
4826
  open: openConfirmDialog,
@@ -4729,7 +4829,7 @@ var GenericDataGrid = ({
4729
4829
  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."
4730
4830
  }
4731
4831
  ),
4732
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
4832
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
4733
4833
  DataGridOptionsDialog,
4734
4834
  {
4735
4835
  open: openDataGridOptions,
@@ -4738,7 +4838,7 @@ var GenericDataGrid = ({
4738
4838
  anchorEl: dataGridOptionsAnchorEl
4739
4839
  }
4740
4840
  ),
4741
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
4841
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
4742
4842
  ImportDialog,
4743
4843
  {
4744
4844
  open: openImportDialog,
@@ -4747,20 +4847,21 @@ var GenericDataGrid = ({
4747
4847
  loading
4748
4848
  }
4749
4849
  ),
4750
- /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
4751
- import_material18.Dialog,
4850
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
4851
+ import_material19.Dialog,
4752
4852
  {
4753
4853
  open: openVerticalEditDialog,
4754
4854
  onClose: () => setOpenVerticalEditDialog(false),
4755
4855
  maxWidth: "sm",
4756
4856
  fullWidth: true,
4757
- children: rowToEditVertical && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
4857
+ children: rowToEditVertical && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
4758
4858
  VerticalEditorPage,
4759
4859
  {
4760
4860
  tableName,
4761
4861
  tableDefinition,
4762
4862
  initialData: rowToEditVertical,
4763
4863
  fixedFields,
4864
+ columnasOcultas: conjuntoDeOcultas,
4764
4865
  isNewRow: !!rowToEditVertical[NEW_ROW_INDICATOR],
4765
4866
  onSaveSuccess: (savedRow, isNewItem) => {
4766
4867
  setRowToEditVertical(savedRow);
@@ -4799,25 +4900,34 @@ var GenericDataGrid = ({
4799
4900
  )
4800
4901
  }
4801
4902
  ),
4802
- contenidoDeCelda && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(VentanaDeTexto, { anclaje: contenidoDeCelda.anclaje, texto: contenidoDeCelda.texto, editable: false, onAceptar: cerrarContenidoDeCelda, onCerrar: cerrarContenidoDeCelda })
4903
+ contenidoDeCelda && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(VentanaDeTexto, { anclaje: contenidoDeCelda.anclaje, texto: contenidoDeCelda.texto, editable: false, onAceptar: cerrarContenidoDeCelda, onCerrar: cerrarContenidoDeCelda })
4803
4904
  ] }) });
4804
4905
  };
4805
4906
  var GenericDataGrid_default = GenericDataGrid;
4806
4907
 
4807
4908
  // src/App.tsx
4808
- var import_react43 = __toESM(require("react"), 1);
4809
- var import_react_router_dom15 = require("react-router-dom");
4909
+ var import_react44 = __toESM(require("react"), 1);
4910
+ var import_react_router_dom18 = require("react-router-dom");
4810
4911
 
4811
4912
  // src/components/MainLayout.tsx
4812
4913
  var import_react30 = require("react");
4813
4914
  var import_react_router_dom4 = require("react-router-dom");
4814
- var import_material20 = require("@mui/material");
4915
+ var import_material21 = require("@mui/material");
4815
4916
 
4816
4917
  // src/contexts/AppContext.tsx
4817
4918
  var import_react27 = require("react");
4818
4919
  var import_react_router_dom = require("react-router-dom");
4819
4920
  var import_react_redux2 = require("react-redux");
4820
- var import_jsx_runtime23 = require("react/jsx-runtime");
4921
+
4922
+ // src/utils/cierreVoluntario.ts
4923
+ var cierreVoluntario = false;
4924
+ var marcarCierreVoluntario = (activo) => {
4925
+ cierreVoluntario = activo;
4926
+ };
4927
+ var huboCierreVoluntario = () => cierreVoluntario;
4928
+
4929
+ // src/contexts/AppContext.tsx
4930
+ var import_jsx_runtime24 = require("react/jsx-runtime");
4821
4931
  var AuthContext = (0, import_react27.createContext)(void 0);
4822
4932
  var useApp = () => {
4823
4933
  const context = (0, import_react27.useContext)(AuthContext);
@@ -4833,9 +4943,10 @@ var AppProvider = ({ children, publicPaths = [] }) => {
4833
4943
  const [showSessionExpiredMessage, setShowSessionExpiredMessage] = (0, import_react27.useState)(false);
4834
4944
  const isRedirectingRef = (0, import_react27.useRef)(false);
4835
4945
  const huboSesionRef = (0, import_react27.useRef)(false);
4946
+ const cierreVoluntarioRef = (0, import_react27.useRef)(false);
4836
4947
  const dispatch = (0, import_react_redux2.useDispatch)();
4837
4948
  const clientContext = (0, import_react_redux2.useSelector)((state) => state.clientContext);
4838
- if (clientContext.status === "succeeded") huboSesionRef.current = true;
4949
+ if (clientContext.status === "succeeded" && !cierreVoluntarioRef.current) huboSesionRef.current = true;
4839
4950
  const navigate = (0, import_react_router_dom.useNavigate)();
4840
4951
  const handleExpiredSessionRedirect = (0, import_react27.useCallback)(() => {
4841
4952
  isRedirectingRef.current = true;
@@ -4846,6 +4957,17 @@ var AppProvider = ({ children, publicPaths = [] }) => {
4846
4957
  isRedirectingRef.current = false;
4847
4958
  }, 2e3);
4848
4959
  }, [navigate]);
4960
+ const avisarCierreVoluntario = (0, import_react27.useCallback)((activo) => {
4961
+ cierreVoluntarioRef.current = activo;
4962
+ marcarCierreVoluntario(activo);
4963
+ if (activo) huboSesionRef.current = false;
4964
+ }, []);
4965
+ const limpiarContextoPorSesionPerdida = (0, import_react27.useCallback)(() => {
4966
+ if (clientContext.status === "succeeded" && clientContext.username !== "" && !cierreVoluntarioRef.current) {
4967
+ dispatch(setRedirectUsername(clientContext.username));
4968
+ }
4969
+ dispatch(clearClientContext());
4970
+ }, [dispatch, clientContext.status, clientContext.username]);
4849
4971
  const location = (0, import_react_router_dom.useLocation)();
4850
4972
  const isCurrentPathPublic = (0, import_react27.useCallback)(() => {
4851
4973
  const current = location.pathname;
@@ -4871,8 +4993,8 @@ var AppProvider = ({ children, publicPaths = [] }) => {
4871
4993
  }
4872
4994
  } else {
4873
4995
  setIsLoggedIn(false);
4874
- dispatch(clearClientContext());
4875
- if (!showSessionExpiredMessage && !isCurrentPathPublic() && huboSesionRef.current) {
4996
+ limpiarContextoPorSesionPerdida();
4997
+ if (!showSessionExpiredMessage && !isCurrentPathPublic() && huboSesionRef.current && !cierreVoluntarioRef.current) {
4876
4998
  console.warn("Sesi\xF3n inv\xE1lida en ruta protegida. Mostrando modal.");
4877
4999
  setShowSessionExpiredMessage(true);
4878
5000
  } else {
@@ -4882,13 +5004,13 @@ var AppProvider = ({ children, publicPaths = [] }) => {
4882
5004
  } catch (error) {
4883
5005
  console.error("Error checking session:", error);
4884
5006
  setIsLoggedIn(false);
4885
- dispatch(clearClientContext());
5007
+ limpiarContextoPorSesionPerdida();
4886
5008
  const isPublic = publicPaths.some((p) => location.pathname === p || location.pathname.startsWith(p + "/"));
4887
- if (!showSessionExpiredMessage && !isCurrentPathPublic() && huboSesionRef.current) {
5009
+ if (!showSessionExpiredMessage && !isCurrentPathPublic() && huboSesionRef.current && !cierreVoluntarioRef.current) {
4888
5010
  setShowSessionExpiredMessage(true);
4889
5011
  }
4890
5012
  }
4891
- }, [dispatch, clientContext.status, showSessionExpiredMessage, isCurrentPathPublic]);
5013
+ }, [dispatch, clientContext.status, showSessionExpiredMessage, isCurrentPathPublic, limpiarContextoPorSesionPerdida]);
4892
5014
  (0, import_react27.useEffect)(() => {
4893
5015
  checkSession();
4894
5016
  const intervalId = setInterval(checkSession, 15 * 1e3);
@@ -4902,26 +5024,30 @@ var AppProvider = ({ children, publicPaths = [] }) => {
4902
5024
  checkSession,
4903
5025
  showSessionExpiredMessage,
4904
5026
  setShowSessionExpiredMessage,
4905
- handleExpiredSessionRedirect
5027
+ handleExpiredSessionRedirect,
5028
+ avisarCierreVoluntario
4906
5029
  }), [
4907
5030
  isLoggedIn,
4908
5031
  setIsLoggedIn,
4909
5032
  checkSession,
4910
5033
  showSessionExpiredMessage,
4911
5034
  setShowSessionExpiredMessage,
4912
- handleExpiredSessionRedirect
5035
+ handleExpiredSessionRedirect,
5036
+ avisarCierreVoluntario
4913
5037
  ]);
4914
- return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(AuthContext.Provider, { value: authContextValue, children });
5038
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(AuthContext.Provider, { value: authContextValue, children });
4915
5039
  };
4916
5040
 
4917
5041
  // src/components/MainLayout.tsx
5042
+ var import_react_router_dom5 = require("react-router-dom");
4918
5043
  var import_Logout = __toESM(require("@mui/icons-material/Logout"), 1);
5044
+ var import_VpnKey = __toESM(require("@mui/icons-material/VpnKey"), 1);
4919
5045
  var import_Menu = __toESM(require("@mui/icons-material/Menu"), 1);
4920
5046
  var import_ChevronLeft = __toESM(require("@mui/icons-material/ChevronLeft"), 1);
4921
5047
 
4922
5048
  // src/components/SideMenu.tsx
4923
5049
  var import_react28 = __toESM(require("react"), 1);
4924
- var import_material19 = require("@mui/material");
5050
+ var import_material20 = require("@mui/material");
4925
5051
  var import_ExpandLess = __toESM(require("@mui/icons-material/ExpandLess"), 1);
4926
5052
  var import_ExpandMore = __toESM(require("@mui/icons-material/ExpandMore"), 1);
4927
5053
  var import_TableChart = __toESM(require("@mui/icons-material/TableChart"), 1);
@@ -4929,18 +5055,56 @@ var import_Folder = __toESM(require("@mui/icons-material/Folder"), 1);
4929
5055
  var import_Dns = __toESM(require("@mui/icons-material/Dns"), 1);
4930
5056
  var import_WarningAmber3 = __toESM(require("@mui/icons-material/WarningAmber"), 1);
4931
5057
  var import_DesktopWindows = __toESM(require("@mui/icons-material/DesktopWindows"), 1);
4932
- var import_UnfoldMore = __toESM(require("@mui/icons-material/UnfoldMore"), 1);
4933
- var import_UnfoldLess = __toESM(require("@mui/icons-material/UnfoldLess"), 1);
5058
+ var import_Search3 = __toESM(require("@mui/icons-material/Search"), 1);
5059
+ var import_Clear = __toESM(require("@mui/icons-material/Clear"), 1);
4934
5060
  var import_react_router_dom2 = require("react-router-dom");
4935
5061
  var import_colors = require("@mui/material/colors");
4936
5062
 
5063
+ // src/puente/habilitacion.ts
5064
+ var habilitado = false;
5065
+ var habilitarPuenteBP = () => {
5066
+ habilitado = true;
5067
+ };
5068
+ var puenteBPHabilitado = () => habilitado;
5069
+
4937
5070
  // src/utils/menuInicial.ts
4938
- function rutaDeItemDeMenu(item) {
5071
+ function rutaDeTablaDeMenu(camino) {
5072
+ return `/menu/${camino.map(encodeURIComponent).join("/")}`;
5073
+ }
5074
+ function gruposDeItem(menu, item) {
5075
+ for (const candidato of menu) {
5076
+ if (candidato === item) return [];
5077
+ if (candidato.menuType === "menu") {
5078
+ const grupos = gruposDeItem(candidato.menuContent, item);
5079
+ if (grupos) return [candidato.name, ...grupos];
5080
+ }
5081
+ }
5082
+ return void 0;
5083
+ }
5084
+ function itemDeCamino(menu, camino) {
5085
+ const [nombre, ...resto] = camino;
5086
+ const item = menu.find((candidato) => candidato.name === nombre && candidato.menuType === (resto.length ? "menu" : "table"));
5087
+ return item && resto.length ? itemDeCamino(item.menuContent, resto) : item;
5088
+ }
5089
+ function primeraTablaConNombre(menu, nombre) {
5090
+ for (const item of menu) {
5091
+ if (item.menuType === "table" && item.name === nombre) return item;
5092
+ const encontrado = item.menuType === "menu" ? primeraTablaConNombre(item.menuContent, nombre) : void 0;
5093
+ if (encontrado) return encontrado;
5094
+ }
5095
+ return void 0;
5096
+ }
5097
+ function itemDeRuta(menu, camino) {
5098
+ if (camino.length === 0) return void 0;
5099
+ const item = itemDeCamino(menu, camino) ?? primeraTablaConNombre(menu, camino[camino.length - 1]);
5100
+ return item;
5101
+ }
5102
+ function rutaDeItemDeMenu(item, grupos = []) {
4939
5103
  if (item.menuType === "table") {
4940
5104
  const consulta = new URLSearchParams();
4941
5105
  if (item.td) consulta.append("td", JSON.stringify(item.td));
4942
5106
  if (item.fc) consulta.append("fc", JSON.stringify(item.fc));
4943
- return `/menu/${item.name}${consulta.size ? `?${consulta.toString()}` : ""}`;
5107
+ return `${rutaDeTablaDeMenu([...grupos, item.name])}${consulta.size ? `?${consulta.toString()}` : ""}`;
4944
5108
  }
4945
5109
  if (item.menuType === "proc") return `/procedures/${item.name}`;
4946
5110
  if (wScreens[item.menuType] !== void 0) return `/wScreens/${item.menuType}`;
@@ -4953,140 +5117,266 @@ function itemInicial(menu) {
4953
5117
  return elegido.menuType === "menu" ? itemInicial(elegido.menuContent) : elegido;
4954
5118
  }
4955
5119
 
5120
+ // src/utils/busquedaDeMenu.ts
5121
+ function etiquetaDeItem(item) {
5122
+ return item.label || item.name;
5123
+ }
5124
+ function claveDeMenu(camino) {
5125
+ return camino.join("/");
5126
+ }
5127
+ function hojasDeMenu(menu, grupos = [], etiquetasDeGrupos = []) {
5128
+ return menu.flatMap(
5129
+ (item) => item.menuType === "menu" ? hojasDeMenu(item.menuContent, [...grupos, item.name], [...etiquetasDeGrupos, etiquetaDeItem(item)]) : [{ item, grupos, etiquetasDeGrupos, clave: claveDeMenu([...grupos, item.name]) }]
5130
+ );
5131
+ }
5132
+ function normalizarParaBuscar(texto) {
5133
+ return texto.normalize("NFD").replace(/[̀-ͯ]/g, "").replace(/_/g, " ").toLowerCase();
5134
+ }
5135
+ function buscarEnMenu(hojas, consulta) {
5136
+ const palabras = normalizarParaBuscar(consulta).split(/\s+/).filter((palabra) => palabra !== "");
5137
+ if (palabras.length === 0) return [];
5138
+ const propias = [];
5139
+ const porGrupo = [];
5140
+ for (const hoja of hojas) {
5141
+ const propia = normalizarParaBuscar(`${etiquetaDeItem(hoja.item)} ${hoja.item.name}`);
5142
+ const completa = `${hoja.etiquetasDeGrupos.map(normalizarParaBuscar).join(" ")} ${propia}`;
5143
+ if (!palabras.every((palabra) => completa.includes(palabra))) continue;
5144
+ (palabras.every((palabra) => propia.includes(palabra)) ? propias : porGrupo).push(hoja);
5145
+ }
5146
+ return [...propias, ...porGrupo];
5147
+ }
5148
+
4956
5149
  // src/components/SideMenu.tsx
4957
- var import_jsx_runtime24 = require("react/jsx-runtime");
4958
- var MenuListItem = ({ item, level, onMenuItemClick }) => {
5150
+ var import_jsx_runtime25 = require("react/jsx-runtime");
5151
+ var CLAVE_RECIENTES = "fpr.menu.recientes";
5152
+ var MAXIMO_RECIENTES = 4;
5153
+ var getIcon = (item, destacado = false) => {
5154
+ switch (item.menuType) {
5155
+ case "table":
5156
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_TableChart.default, { sx: destacado ? { color: import_colors.blue[700] } : void 0 });
5157
+ case "proc":
5158
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_Dns.default, { sx: destacado ? { color: import_colors.teal[700] } : void 0 });
5159
+ case "menu":
5160
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_Folder.default, { sx: destacado ? { color: import_colors.orange[800] } : void 0 });
5161
+ default:
5162
+ if (wScreens[item.menuType] !== void 0 || puenteBPHabilitado()) {
5163
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_DesktopWindows.default, { sx: destacado ? { color: import_colors.indigo[500] } : void 0 });
5164
+ }
5165
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_WarningAmber3.default, { sx: destacado ? { color: import_colors.red[500] } : void 0 });
5166
+ }
5167
+ };
5168
+ var estaSeleccionado = (item, grupos, currentPath, hash = "") => {
5169
+ const pathParts = currentPath.split("/");
5170
+ const urlTableName = pathParts[1] === "table" ? pathParts[2] : null;
5171
+ if (item.menuType === "table") {
5172
+ return currentPath === rutaDeTablaDeMenu([...grupos, item.name]) || urlTableName === (item.table || item.name);
5173
+ } else if (item.menuType === "proc") {
5174
+ return currentPath === `/procedures/${item.name}`;
5175
+ } else if (item.menuType !== "menu") {
5176
+ return currentPath.startsWith(`/wScreens/${item.menuType}`) || currentPath.startsWith(`/wScreens-fallback/${item.menuType}`) || currentPath === "/bp/menu" && new URLSearchParams(hash.replace(/^[#?]/, "")).get("w") === item.menuType;
5177
+ }
5178
+ return false;
5179
+ };
5180
+ var leerRecientes = () => {
5181
+ try {
5182
+ const guardado = JSON.parse(localStorage.getItem(CLAVE_RECIENTES) ?? "[]");
5183
+ return Array.isArray(guardado) ? guardado.filter((clave) => typeof clave === "string") : [];
5184
+ } catch {
5185
+ return [];
5186
+ }
5187
+ };
5188
+ var guardarRecientes = (recientes) => {
5189
+ try {
5190
+ localStorage.setItem(CLAVE_RECIENTES, JSON.stringify(recientes));
5191
+ } catch {
5192
+ }
5193
+ };
5194
+ var MenuListItem = ({ item, level, grupos = [], hermanos = [], onMenuItemClick }) => {
4959
5195
  const navigate = (0, import_react_router_dom2.useNavigate)();
4960
5196
  const location = (0, import_react_router_dom2.useLocation)();
4961
- const open = useSubMenuOpenState(item.name);
5197
+ const clave = claveDeMenu([...grupos, item.name]);
5198
+ const open = useSubMenuOpenState(clave);
4962
5199
  const dispatch = useAppDispatch();
4963
5200
  const handleClick = () => {
4964
5201
  if (item.menuType === "menu") {
4965
- dispatch(toggleSubMenu(item.name));
5202
+ if (open) {
5203
+ dispatch(setSubMenuOpen({ menuName: clave, isOpen: false }));
5204
+ } else {
5205
+ dispatch(abrirGrupo({ clave, hermanos }));
5206
+ }
4966
5207
  } else {
4967
- navigate(rutaDeItemDeMenu(item));
5208
+ navigate(rutaDeItemDeMenu(item, grupos));
4968
5209
  if (onMenuItemClick) {
4969
5210
  onMenuItemClick();
4970
5211
  }
4971
5212
  }
4972
5213
  };
4973
- const getIcon = (item2) => {
4974
- switch (item2.menuType) {
4975
- case "table":
4976
- return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_TableChart.default, { sx: { color: import_colors.blue[700] } });
4977
- case "proc":
4978
- return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_Dns.default, { sx: { color: import_colors.teal[700] } });
4979
- case "menu":
4980
- return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_Folder.default, { sx: { color: import_colors.orange[800] } });
4981
- default:
4982
- const WScreenComponent = wScreens[item2.menuType];
4983
- if (WScreenComponent !== void 0) {
4984
- return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_DesktopWindows.default, { sx: { color: import_colors.grey[700] } });
4985
- }
4986
- return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_WarningAmber3.default, { sx: { color: import_colors.red[500] } });
4987
- }
4988
- };
4989
- const currentPath = location.pathname;
4990
- let isSelected = false;
4991
- const pathParts = currentPath.split("/");
4992
- const urlTableName = pathParts[1] === "table" ? pathParts[2] : null;
4993
- if (item.menuType === "table") {
4994
- isSelected = currentPath === `/menu/${item.name}` || urlTableName === (item.table || item.name);
4995
- } else if (item.menuType === "proc") {
4996
- isSelected = currentPath === `/procedures/${item.name}`;
4997
- } else if (item.menuType !== "menu") {
4998
- isSelected = currentPath.startsWith(`/wScreens/${item.menuType}`) || currentPath.startsWith(`/wScreens-fallback/${item.menuType}`);
4999
- }
5214
+ const isSelected = estaSeleccionado(item, grupos, location.pathname, location.hash);
5000
5215
  const itemRef = import_react28.default.useRef(null);
5001
5216
  (0, import_react28.useEffect)(() => {
5002
5217
  if (isSelected && itemRef.current) {
5003
5218
  itemRef.current.scrollIntoView({ behavior: "smooth", block: "nearest" });
5004
5219
  }
5005
5220
  }, [isSelected]);
5006
- return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { ref: itemRef, children: [
5007
- /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(
5008
- import_material19.ListItemButton,
5221
+ const contenido = item.menuType === "menu" ? item.menuContent : [];
5222
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { ref: itemRef, children: [
5223
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
5224
+ import_material20.ListItemButton,
5009
5225
  {
5010
5226
  onClick: handleClick,
5011
5227
  sx: { pl: level * 2 },
5012
5228
  selected: isSelected,
5013
5229
  children: [
5014
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_material19.ListItemIcon, { sx: { minWidth: "38px" }, children: getIcon(item) }),
5015
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_material19.ListItemText, { primary: item.label || item.name }),
5016
- item.menuType === "menu" ? open ? /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_ExpandLess.default, {}) : /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_ExpandMore.default, {}) : null
5230
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_material20.ListItemIcon, { sx: { minWidth: "38px" }, children: getIcon(item, isSelected || open) }),
5231
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_material20.ListItemText, { primary: etiquetaDeItem(item) }),
5232
+ item.menuType === "menu" ? open ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_ExpandLess.default, {}) : /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_ExpandMore.default, {}) : null
5017
5233
  ]
5018
5234
  }
5019
5235
  ),
5020
- item.menuType === "menu" && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_material19.Collapse, { in: open, timeout: "auto", unmountOnExit: true, children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_material19.List, { component: "div", disablePadding: true, children: item.menuContent.map((subItem) => /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
5236
+ item.menuType === "menu" && /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_material20.Collapse, { in: open, timeout: "auto", unmountOnExit: true, children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_material20.List, { component: "div", disablePadding: true, children: contenido.map((subItem) => /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
5021
5237
  MenuListItem,
5022
5238
  {
5023
5239
  item: subItem,
5024
5240
  level: level + 1,
5241
+ grupos: [...grupos, item.name],
5242
+ hermanos: contenido.filter((otro) => otro !== subItem).map((otro) => claveDeMenu([...grupos, item.name, otro.name])),
5025
5243
  onMenuItemClick
5026
5244
  },
5027
5245
  subItem.name
5028
5246
  )) }) })
5029
5247
  ] });
5030
5248
  };
5249
+ var ItemPlano = ({ hoja, seleccionado, traerALaVista = false, onElegir }) => {
5250
+ const boton = (0, import_react28.useRef)(null);
5251
+ (0, import_react28.useEffect)(() => {
5252
+ if (traerALaVista && seleccionado) boton.current?.scrollIntoView({ block: "nearest" });
5253
+ }, [traerALaVista, seleccionado]);
5254
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(import_material20.ListItemButton, { dense: true, selected: seleccionado, onClick: () => onElegir(hoja), ref: boton, children: [
5255
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_material20.ListItemIcon, { sx: { minWidth: "38px" }, children: getIcon(hoja.item, seleccionado) }),
5256
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
5257
+ import_material20.ListItemText,
5258
+ {
5259
+ primary: etiquetaDeItem(hoja.item),
5260
+ secondary: hoja.etiquetasDeGrupos.join(" \u203A ") || void 0,
5261
+ secondaryTypographyProps: { noWrap: true }
5262
+ }
5263
+ )
5264
+ ] });
5265
+ };
5031
5266
  var SideMenu = ({ onMenuItemClick }) => {
5032
5267
  const { clientContext } = useApp();
5033
5268
  const navigate = (0, import_react_router_dom2.useNavigate)();
5034
5269
  const location = (0, import_react_router_dom2.useLocation)();
5035
5270
  const dispatch = useAppDispatch();
5036
- const subMenuOpenStates = useAppSelector((state) => state.menuUi.subMenuOpenStates);
5037
- const allSubMenusKeys = Object.keys(subMenuOpenStates);
5038
- const openSubMenusCount = allSubMenusKeys.filter((key) => subMenuOpenStates[key]).length;
5039
- const isMostlyOpen = allSubMenusKeys.length > 0 && openSubMenusCount / allSubMenusKeys.length > 0.5;
5040
- const handleToggleAllSubMenus = () => {
5041
- dispatch(setAllSubMenusOpen(!isMostlyOpen));
5042
- };
5043
- if (!clientContext || !clientContext.menu) {
5044
- return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_material19.Box, { sx: { p: 2, textAlign: "center" }, children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_material19.Typography, { variant: "body2", color: "text.secondary", children: "Cargando men\xFA..." }) });
5045
- }
5271
+ const [consulta, setConsulta] = (0, import_react28.useState)("");
5272
+ const [indice, setIndice] = (0, import_react28.useState)(0);
5273
+ const [recientes, setRecientes] = (0, import_react28.useState)(leerRecientes);
5274
+ const campoDeBusqueda = (0, import_react28.useRef)(null);
5275
+ const menu = clientContext?.menu;
5276
+ const hojas = (0, import_react28.useMemo)(() => hojasDeMenu(menu ?? []), [menu]);
5277
+ const resultados = (0, import_react28.useMemo)(() => buscarEnMenu(hojas, consulta), [hojas, consulta]);
5046
5278
  (0, import_react28.useEffect)(() => {
5047
- if (!clientContext?.menu) return;
5048
- const expandParents = (items, targetPath, parentNames = []) => {
5049
- const pathParts = targetPath.split("/");
5050
- const urlTableName = pathParts[1] === "table" ? pathParts[2] : null;
5051
- for (const item of items) {
5052
- let matches = false;
5053
- if (item.menuType === "table") {
5054
- matches = targetPath === `/menu/${item.name}` || urlTableName === (item.table || item.name);
5055
- } else if (item.menuType === "proc") {
5056
- matches = targetPath === `/procedures/${item.name}`;
5057
- } else if (item.menuType !== "menu") {
5058
- matches = targetPath.startsWith(`/wScreens/${item.menuType}`) || targetPath.startsWith(`/wScreens-fallback/${item.menuType}`);
5059
- }
5060
- if (matches) {
5061
- parentNames.forEach((name) => {
5062
- dispatch(setSubMenuOpen({ menuName: name, isOpen: true }));
5063
- });
5064
- return true;
5065
- }
5066
- if (item.menuType === "menu") {
5067
- const found = expandParents(item.menuContent, targetPath, [...parentNames, item.name]);
5068
- if (found) return true;
5069
- }
5279
+ const alApretar = (evento) => {
5280
+ if ((evento.ctrlKey || evento.metaKey) && !evento.altKey && !evento.shiftKey && evento.key.toLowerCase() === "k") {
5281
+ evento.preventDefault();
5282
+ dispatch(setDrawerOpen(true));
5283
+ setTimeout(() => {
5284
+ campoDeBusqueda.current?.focus();
5285
+ campoDeBusqueda.current?.select();
5286
+ }, 50);
5070
5287
  }
5071
- return false;
5072
5288
  };
5073
- expandParents(clientContext.menu, location.pathname);
5074
- }, [location.pathname, clientContext, dispatch]);
5075
- return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(import_material19.Box, { sx: { width: "100%", flexShrink: 0 }, children: [
5076
- clientContext.menu.some((item) => item.menuType === "menu") && /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_material19.ListItem, { disablePadding: true, children: /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)(import_material19.ListItemButton, { onClick: handleToggleAllSubMenus, children: [
5077
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_material19.ListItemIcon, { sx: { minWidth: "38px" }, children: isMostlyOpen ? /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_UnfoldLess.default, {}) : /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_UnfoldMore.default, {}) }),
5078
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_material19.ListItemText, { primary: isMostlyOpen ? "colapsar " : "expandir" })
5079
- ] }) }),
5080
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_material19.Divider, {}),
5081
- /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_material19.List, { children: clientContext.menu.map((menuItem) => /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
5082
- MenuListItem,
5289
+ window.addEventListener("keydown", alApretar);
5290
+ return () => window.removeEventListener("keydown", alApretar);
5291
+ }, [dispatch]);
5292
+ (0, import_react28.useEffect)(() => {
5293
+ const actual = hojas.find((hoja) => estaSeleccionado(hoja.item, hoja.grupos, location.pathname, location.hash));
5294
+ if (!actual) return;
5295
+ dispatch(abrirCamino(actual.grupos.map((_, i) => claveDeMenu(actual.grupos.slice(0, i + 1)))));
5296
+ setRecientes((anteriores) => {
5297
+ if (anteriores.includes(actual.clave)) return anteriores;
5298
+ const nuevos = [actual.clave, ...anteriores].slice(0, MAXIMO_RECIENTES);
5299
+ guardarRecientes(nuevos);
5300
+ return nuevos;
5301
+ });
5302
+ }, [location.pathname, location.hash, hojas, dispatch]);
5303
+ if (!menu) {
5304
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_material20.Box, { sx: { p: 2, textAlign: "center" }, children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_material20.Typography, { variant: "body2", color: "text.secondary", children: "Cargando men\xFA..." }) });
5305
+ }
5306
+ const elegir = (hoja) => {
5307
+ navigate(rutaDeItemDeMenu(hoja.item, hoja.grupos));
5308
+ setConsulta("");
5309
+ setIndice(0);
5310
+ if (onMenuItemClick) {
5311
+ onMenuItemClick();
5312
+ }
5313
+ };
5314
+ const alApretarEnBusqueda = (evento) => {
5315
+ if (evento.key === "ArrowDown" || evento.key === "ArrowUp") {
5316
+ evento.preventDefault();
5317
+ if (resultados.length === 0) return;
5318
+ setIndice((actual) => (actual + (evento.key === "ArrowDown" ? 1 : -1) + resultados.length) % resultados.length);
5319
+ } else if (evento.key === "Enter") {
5320
+ evento.preventDefault();
5321
+ const hoja = resultados[indice];
5322
+ if (hoja) elegir(hoja);
5323
+ } else if (evento.key === "Escape" && consulta !== "") {
5324
+ evento.stopPropagation();
5325
+ setConsulta("");
5326
+ }
5327
+ };
5328
+ const hojasRecientes = recientes.map((clave) => hojas.find((hoja) => hoja.clave === clave)).filter((hoja) => hoja !== void 0);
5329
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(import_material20.Box, { sx: { width: "100%", flex: 1, minHeight: 0, display: "flex", flexDirection: "column" }, children: [
5330
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_material20.Box, { sx: { px: 1.5, py: 1, flexShrink: 0 }, children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
5331
+ import_material20.TextField,
5083
5332
  {
5084
- item: menuItem,
5085
- level: 1,
5086
- onMenuItemClick
5087
- },
5088
- menuItem.name
5089
- )) })
5333
+ inputRef: campoDeBusqueda,
5334
+ value: consulta,
5335
+ onChange: (evento) => {
5336
+ setConsulta(evento.target.value);
5337
+ setIndice(0);
5338
+ },
5339
+ onKeyDown: alApretarEnBusqueda,
5340
+ placeholder: "Buscar (Ctrl+K)",
5341
+ size: "small",
5342
+ fullWidth: true,
5343
+ autoComplete: "off",
5344
+ sx: { "& .MuiInputBase-input": { fontSize: "0.8rem" } },
5345
+ InputProps: {
5346
+ startAdornment: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_material20.InputAdornment, { position: "start", children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_Search3.default, { fontSize: "small" }) }),
5347
+ endAdornment: consulta !== "" ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_material20.InputAdornment, { position: "end", children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_material20.IconButton, { size: "small", "aria-label": "borrar b\xFAsqueda", edge: "end", onClick: () => {
5348
+ setConsulta("");
5349
+ campoDeBusqueda.current?.focus();
5350
+ }, children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_Clear.default, { fontSize: "small" }) }) }) : void 0
5351
+ }
5352
+ }
5353
+ ) }),
5354
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_material20.Divider, {}),
5355
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_material20.Box, { sx: { flex: 1, minHeight: 0, overflowY: "auto" }, children: consulta.trim() !== "" ? resultados.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_material20.Box, { sx: { p: 2, textAlign: "center" }, children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_material20.Typography, { variant: "body2", color: "text.secondary", children: "Sin resultados" }) }) : /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_material20.List, { children: resultados.map((hoja, i) => /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(ItemPlano, { hoja, seleccionado: i === indice, traerALaVista: true, onElegir: elegir }, hoja.clave)) }) : /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(import_jsx_runtime25.Fragment, { children: [
5356
+ hojasRecientes.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(import_jsx_runtime25.Fragment, { children: [
5357
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_material20.Typography, { variant: "overline", color: "text.secondary", sx: { display: "block", px: 2, pt: 1, lineHeight: 2 }, children: "Recientes" }),
5358
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_material20.List, { disablePadding: true, children: hojasRecientes.map((hoja) => /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
5359
+ ItemPlano,
5360
+ {
5361
+ hoja,
5362
+ seleccionado: estaSeleccionado(hoja.item, hoja.grupos, location.pathname, location.hash),
5363
+ onElegir: elegir
5364
+ },
5365
+ hoja.clave
5366
+ )) }),
5367
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_material20.Divider, {})
5368
+ ] }),
5369
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_material20.List, { children: menu.map((menuItem) => /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
5370
+ MenuListItem,
5371
+ {
5372
+ item: menuItem,
5373
+ level: 1,
5374
+ hermanos: menu.filter((otro) => otro !== menuItem).map((otro) => claveDeMenu([otro.name])),
5375
+ onMenuItemClick
5376
+ },
5377
+ menuItem.name
5378
+ )) })
5379
+ ] }) })
5090
5380
  ] });
5091
5381
  };
5092
5382
  var SideMenu_default = SideMenu;
@@ -5096,10 +5386,11 @@ var import_react29 = require("react");
5096
5386
  var import_react_router_dom3 = require("react-router-dom");
5097
5387
  var import_react_redux3 = require("react-redux");
5098
5388
  var useLogout = () => {
5099
- const { setIsLoggedIn } = useApp();
5389
+ const { setIsLoggedIn, avisarCierreVoluntario } = useApp();
5100
5390
  const dispatch = (0, import_react_redux3.useDispatch)();
5101
5391
  const navigate = (0, import_react_router_dom3.useNavigate)();
5102
5392
  const logout = (0, import_react29.useCallback)(async () => {
5393
+ avisarCierreVoluntario(true);
5103
5394
  try {
5104
5395
  const response = await fetchApi("/logout", { method: "GET" });
5105
5396
  if (response.status === 401 || response.ok) {
@@ -5112,23 +5403,25 @@ var useLogout = () => {
5112
5403
  } finally {
5113
5404
  setIsLoggedIn(false);
5114
5405
  dispatch(clearClientContext());
5406
+ dispatch(setRedirectPath(null));
5115
5407
  navigate("/login", { replace: true });
5116
5408
  }
5117
- }, [setIsLoggedIn, dispatch, navigate]);
5409
+ }, [setIsLoggedIn, avisarCierreVoluntario, dispatch, navigate]);
5118
5410
  return logout;
5119
5411
  };
5120
5412
  var useLogout_default = useLogout;
5121
5413
 
5122
5414
  // src/components/MainLayout.tsx
5123
- var import_jsx_runtime25 = require("react/jsx-runtime");
5415
+ var import_jsx_runtime26 = require("react/jsx-runtime");
5124
5416
  var drawerWidth = 240;
5125
5417
  var MainLayout = () => {
5126
5418
  const { clientContext } = useApp();
5127
5419
  const logout = useLogout_default();
5420
+ const navigate = (0, import_react_router_dom5.useNavigate)();
5128
5421
  const isDrawerOpen = useIsDrawerOpen();
5129
5422
  const dispatch = useAppDispatch();
5130
- const theme = (0, import_material20.useTheme)();
5131
- const isMobile = (0, import_material20.useMediaQuery)(theme.breakpoints.down("sm"));
5423
+ const theme = (0, import_material21.useTheme)();
5424
+ const isMobile = (0, import_material21.useMediaQuery)(theme.breakpoints.down("sm"));
5132
5425
  (0, import_react30.useEffect)(() => {
5133
5426
  if (isMobile && isDrawerOpen) {
5134
5427
  dispatch(setDrawerOpen(false));
@@ -5143,12 +5436,12 @@ var MainLayout = () => {
5143
5436
  }
5144
5437
  };
5145
5438
  if (!clientContext) {
5146
- return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_material20.Box, { sx: { display: "flex", justifyContent: "center", alignItems: "center", height: "100vh" }, children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_material20.Typography, { children: "Cargando dise\xF1o de la aplicaci\xF3n..." }) });
5439
+ return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(import_material21.Box, { sx: { display: "flex", justifyContent: "center", alignItems: "center", height: "100vh" }, children: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(import_material21.Typography, { children: "Cargando dise\xF1o de la aplicaci\xF3n..." }) });
5147
5440
  }
5148
- return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(import_material20.Box, { sx: { display: "flex", height: "100vh" }, children: [
5149
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_material20.CssBaseline, {}),
5150
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
5151
- import_material20.AppBar,
5441
+ return /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(import_material21.Box, { sx: { display: "flex", height: "100vh" }, children: [
5442
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(import_material21.CssBaseline, {}),
5443
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
5444
+ import_material21.AppBar,
5152
5445
  {
5153
5446
  position: "fixed",
5154
5447
  sx: {
@@ -5166,9 +5459,9 @@ var MainLayout = () => {
5166
5459
  })
5167
5460
  }
5168
5461
  },
5169
- children: /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(import_material20.Toolbar, { children: [
5170
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
5171
- import_material20.IconButton,
5462
+ children: /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(import_material21.Toolbar, { children: [
5463
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
5464
+ import_material21.IconButton,
5172
5465
  {
5173
5466
  color: "inherit",
5174
5467
  "aria-label": "open drawer",
@@ -5177,10 +5470,10 @@ var MainLayout = () => {
5177
5470
  sx: {
5178
5471
  marginRight: 2
5179
5472
  },
5180
- children: isDrawerOpen ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_ChevronLeft.default, {}) : /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_Menu.default, {})
5473
+ children: isDrawerOpen ? /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(import_ChevronLeft.default, {}) : /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(import_Menu.default, {})
5181
5474
  }
5182
5475
  ),
5183
- !isDrawerOpen && /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
5476
+ !isDrawerOpen && /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
5184
5477
  "img",
5185
5478
  {
5186
5479
  src: `${envConfig.backendUrl}/img/logo-128.png`,
@@ -5188,22 +5481,23 @@ var MainLayout = () => {
5188
5481
  style: { height: "32px", marginRight: "12px", objectFit: "contain" }
5189
5482
  }
5190
5483
  ),
5191
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_material20.Typography, { variant: "h6", noWrap: true, component: "div", sx: { flexGrow: 1 }, children: isDrawerOpen ? "" : clientContext.config.title }),
5192
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_material20.Typography, { variant: "subtitle1", component: "div", sx: { mr: 2 }, children: clientContext.username }),
5193
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
5194
- import_material20.Button,
5484
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(import_material21.Typography, { variant: "h6", noWrap: true, component: "div", sx: { flexGrow: 1 }, children: isDrawerOpen ? "" : clientContext.config.title }),
5485
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(import_material21.Typography, { variant: "subtitle1", component: "div", sx: { mr: 2 }, children: clientContext.username }),
5486
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(import_material21.IconButton, { color: "inherit", title: "Cambiar contrase\xF1a", "aria-label": "cambiar contrase\xF1a", onClick: () => navigate("/chpass"), sx: { mr: 1 }, children: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(import_VpnKey.default, {}) }),
5487
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
5488
+ import_material21.Button,
5195
5489
  {
5196
5490
  color: "inherit",
5197
5491
  onClick: logout,
5198
- startIcon: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_Logout.default, {}),
5492
+ startIcon: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(import_Logout.default, {}),
5199
5493
  children: "Salir"
5200
5494
  }
5201
5495
  )
5202
5496
  ] })
5203
5497
  }
5204
5498
  ),
5205
- /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
5206
- import_material20.Drawer,
5499
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(
5500
+ import_material21.Drawer,
5207
5501
  {
5208
5502
  variant: "persistent",
5209
5503
  anchor: "left",
@@ -5214,25 +5508,28 @@ var MainLayout = () => {
5214
5508
  "& .MuiDrawer-paper": {
5215
5509
  width: drawerWidth,
5216
5510
  boxSizing: "border-box",
5217
- overflowX: "hidden",
5218
- overflowY: "auto"
5511
+ overflow: "hidden",
5512
+ display: "flex",
5513
+ flexDirection: "column"
5219
5514
  }
5220
5515
  },
5221
5516
  children: [
5222
- /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
5223
- import_material20.Toolbar,
5517
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(
5518
+ import_material21.Toolbar,
5224
5519
  {
5225
5520
  sx: {
5226
5521
  display: "flex",
5227
5522
  alignItems: "center",
5228
5523
  justifyContent: "flex-start",
5229
5524
  px: 1,
5525
+ flexShrink: 0,
5526
+ // el logo queda fijo: solo scrollea la lista del menú
5230
5527
  fontSize: "1.3rem",
5231
5528
  minHeight: theme.mixins.toolbar.minHeight,
5232
5529
  gap: 1.5
5233
5530
  },
5234
5531
  children: [
5235
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
5532
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
5236
5533
  "img",
5237
5534
  {
5238
5535
  src: `${envConfig.backendUrl}/img/logo-128.png`,
@@ -5240,16 +5537,16 @@ var MainLayout = () => {
5240
5537
  style: { height: "32px", objectFit: "contain" }
5241
5538
  }
5242
5539
  ),
5243
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_material20.Typography, { variant: "h6", sx: { fontWeight: "bold" }, children: clientContext.config.title })
5540
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(import_material21.Typography, { variant: "h6", sx: { fontWeight: "bold" }, children: clientContext.config.title })
5244
5541
  ]
5245
5542
  }
5246
5543
  ),
5247
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(SideMenu_default, { onMenuItemClick: handleDrawerCloseMobile })
5544
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(SideMenu_default, { onMenuItemClick: handleDrawerCloseMobile })
5248
5545
  ]
5249
5546
  }
5250
5547
  ),
5251
- /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
5252
- import_material20.Box,
5548
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(
5549
+ import_material21.Box,
5253
5550
  {
5254
5551
  component: "main",
5255
5552
  sx: {
@@ -5275,8 +5572,8 @@ var MainLayout = () => {
5275
5572
  width: isDrawerOpen ? `calc(100% - ${drawerWidth}px)` : "100%"
5276
5573
  },
5277
5574
  children: [
5278
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_material20.Toolbar, {}),
5279
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_material20.Box, { sx: { flex: 1, minHeight: 0, overflowY: "auto", display: "flex", flexDirection: "column" }, children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_react_router_dom4.Outlet, {}) })
5575
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(import_material21.Toolbar, {}),
5576
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(import_material21.Box, { sx: { flex: 1, minHeight: 0, overflowY: "auto", display: "flex", flexDirection: "column" }, children: /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(import_react_router_dom4.Outlet, {}) })
5280
5577
  ]
5281
5578
  }
5282
5579
  )
@@ -5285,8 +5582,8 @@ var MainLayout = () => {
5285
5582
  var MainLayout_default = MainLayout;
5286
5583
 
5287
5584
  // src/components/SessionExpiredMessage.tsx
5288
- var import_material21 = require("@mui/material");
5289
- var import_jsx_runtime26 = require("react/jsx-runtime");
5585
+ var import_material22 = require("@mui/material");
5586
+ var import_jsx_runtime27 = require("react/jsx-runtime");
5290
5587
  var style = {
5291
5588
  position: "absolute",
5292
5589
  top: "50%",
@@ -5305,8 +5602,8 @@ var SessionExpiredMessage = () => {
5305
5602
  const handleClose = () => {
5306
5603
  handleExpiredSessionRedirect();
5307
5604
  };
5308
- return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
5309
- import_material21.Modal,
5605
+ return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
5606
+ import_material22.Modal,
5310
5607
  {
5311
5608
  open: showSessionExpiredMessage,
5312
5609
  onClose: () => {
@@ -5325,10 +5622,10 @@ var SessionExpiredMessage = () => {
5325
5622
  }
5326
5623
  }
5327
5624
  },
5328
- children: /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(import_material21.Box, { sx: style, children: [
5329
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(import_material21.Typography, { id: "session-expired-modal-title", variant: "h6", component: "h2", gutterBottom: true, children: "\xA1Sesi\xF3n Expirada!" }),
5330
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(import_material21.Typography, { 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." }),
5331
- /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(import_material21.Button, { variant: "contained", color: "primary", onClick: handleClose, children: "Ir al Login" })
5625
+ children: /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(import_material22.Box, { sx: style, children: [
5626
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_material22.Typography, { id: "session-expired-modal-title", variant: "h6", component: "h2", gutterBottom: true, children: "\xA1Sesi\xF3n Expirada!" }),
5627
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_material22.Typography, { 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." }),
5628
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_material22.Button, { variant: "contained", color: "primary", onClick: handleClose, children: "Ir al Login" })
5332
5629
  ] })
5333
5630
  }
5334
5631
  );
@@ -5336,25 +5633,25 @@ var SessionExpiredMessage = () => {
5336
5633
  var SessionExpiredMessage_default = SessionExpiredMessage;
5337
5634
 
5338
5635
  // src/pages/PantallaInicial.tsx
5339
- var import_react_router_dom5 = require("react-router-dom");
5340
- var import_jsx_runtime27 = require("react/jsx-runtime");
5636
+ var import_react_router_dom6 = require("react-router-dom");
5637
+ var import_jsx_runtime28 = require("react/jsx-runtime");
5341
5638
  var PantallaInicial = () => {
5342
5639
  const { clientContext } = useApp();
5343
5640
  const item = clientContext.menu ? itemInicial(clientContext.menu) : void 0;
5344
- return item ? /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_react_router_dom5.Navigate, { to: rutaDeItemDeMenu(item), replace: true }) : null;
5641
+ return item && clientContext.menu ? /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_react_router_dom6.Navigate, { to: rutaDeItemDeMenu(item, gruposDeItem(clientContext.menu, item)), replace: true }) : null;
5345
5642
  };
5346
5643
  var PantallaInicial_default = PantallaInicial;
5347
5644
 
5348
5645
  // src/pages/LogoutPage.tsx
5349
5646
  var import_react31 = require("react");
5350
- var import_material22 = require("@mui/material");
5351
- var import_jsx_runtime28 = require("react/jsx-runtime");
5647
+ var import_material23 = require("@mui/material");
5648
+ var import_jsx_runtime29 = require("react/jsx-runtime");
5352
5649
  var LogoutPage = () => {
5353
5650
  const logout = useLogout_default();
5354
5651
  (0, import_react31.useEffect)(() => {
5355
5652
  logout();
5356
5653
  }, [logout]);
5357
- return /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(import_material22.Box, { sx: {
5654
+ return /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(import_material23.Box, { sx: {
5358
5655
  display: "flex",
5359
5656
  flexDirection: "column",
5360
5657
  justifyContent: "center",
@@ -5362,20 +5659,31 @@ var LogoutPage = () => {
5362
5659
  height: "100vh",
5363
5660
  textAlign: "center"
5364
5661
  }, children: [
5365
- /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_material22.CircularProgress, { size: 60 }),
5366
- /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_material22.Typography, { variant: "h6", sx: { mt: 2 }, children: "Cerrando sesi\xF3n..." })
5662
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(import_material23.CircularProgress, { size: 60 }),
5663
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(import_material23.Typography, { variant: "h6", sx: { mt: 2 }, children: "Cerrando sesi\xF3n..." })
5367
5664
  ] });
5368
5665
  };
5369
5666
  var LogoutPage_default = LogoutPage;
5370
5667
 
5371
5668
  // src/pages/LoginPage.tsx
5372
5669
  var import_react32 = require("react");
5373
- var import_material23 = require("@mui/material");
5670
+ var import_material24 = require("@mui/material");
5671
+ var import_react_router_dom7 = require("react-router-dom");
5672
+
5673
+ // src/pages/configuracionLogin.ts
5674
+ var RUTA_POR_OMISION = "/new-pass";
5675
+ var rutaDeRecuperarClave = null;
5676
+ var configurarRecuperarClave = (recuperarClave) => {
5677
+ rutaDeRecuperarClave = recuperarClave === true ? RUTA_POR_OMISION : typeof recuperarClave === "string" && recuperarClave !== "" ? recuperarClave : null;
5678
+ };
5679
+ var rutaParaRecuperarClave = () => rutaDeRecuperarClave;
5680
+
5681
+ // src/pages/LoginPage.tsx
5374
5682
  var import_react_hook_form = require("react-hook-form");
5375
5683
  var import_zod = require("@hookform/resolvers/zod");
5376
5684
  var z = __toESM(require("zod"), 1);
5377
5685
  var import_react_redux4 = require("react-redux");
5378
- var import_jsx_runtime29 = require("react/jsx-runtime");
5686
+ var import_jsx_runtime30 = require("react/jsx-runtime");
5379
5687
  var loginSchema = z.object({
5380
5688
  username: z.string().min(1, "El usuario es requerido"),
5381
5689
  // Añadir validación básica
@@ -5385,7 +5693,10 @@ var loginSchema = z.object({
5385
5693
  var LoginPage = () => {
5386
5694
  const [loginError, setLoginError] = (0, import_react32.useState)(null);
5387
5695
  const [isSubmitting, setIsSubmitting] = (0, import_react32.useState)(false);
5388
- const { setIsLoggedIn, checkSession } = useApp();
5696
+ const estadoDeLaRuta = (0, import_react_router_dom7.useLocation)().state;
5697
+ const claveCambiada = typeof estadoDeLaRuta === "object" && estadoDeLaRuta !== null && "claveCambiada" in estadoDeLaRuta && estadoDeLaRuta.claveCambiada === true;
5698
+ const rutaDeRecuperarClave2 = rutaParaRecuperarClave();
5699
+ const { setIsLoggedIn, checkSession, avisarCierreVoluntario } = useApp();
5389
5700
  const dispatch = (0, import_react_redux4.useDispatch)();
5390
5701
  const {
5391
5702
  control,
@@ -5417,6 +5728,7 @@ var LoginPage = () => {
5417
5728
  const errorText = "Credenciales incorrectas o error al iniciar sesi\xF3n";
5418
5729
  throw new Error(errorText);
5419
5730
  }
5731
+ avisarCierreVoluntario(false);
5420
5732
  setIsLoggedIn(true);
5421
5733
  await dispatch(fetchClientContext()).unwrap();
5422
5734
  console.log("Login exitoso y clientContext cargado.");
@@ -5429,16 +5741,16 @@ var LoginPage = () => {
5429
5741
  setIsSubmitting(false);
5430
5742
  }
5431
5743
  };
5432
- return /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
5433
- import_material23.Box,
5744
+ return /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
5745
+ import_material24.Box,
5434
5746
  {
5435
5747
  display: "flex",
5436
5748
  alignItems: "center",
5437
5749
  justifyContent: "center",
5438
5750
  minHeight: "100vh",
5439
5751
  bgcolor: "#f5f5f5",
5440
- children: /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(
5441
- import_material23.Box,
5752
+ children: /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)(
5753
+ import_material24.Box,
5442
5754
  {
5443
5755
  width: "100%",
5444
5756
  maxWidth: "400px",
@@ -5447,7 +5759,7 @@ var LoginPage = () => {
5447
5759
  borderRadius: 8,
5448
5760
  boxShadow: 3,
5449
5761
  children: [
5450
- /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(import_material23.Box, { sx: { display: "flex", justifyContent: "center", mb: 3 }, children: /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
5762
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(import_material24.Box, { sx: { display: "flex", justifyContent: "center", mb: 3 }, children: /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
5451
5763
  "img",
5452
5764
  {
5453
5765
  src: `${envConfig.backendUrl}/img/login-logo-icon.png`,
@@ -5455,62 +5767,81 @@ var LoginPage = () => {
5455
5767
  style: { height: "192px", maxWidth: "100%", objectFit: "contain" }
5456
5768
  }
5457
5769
  ) }),
5458
- /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(import_material23.Typography, { variant: "h5", align: "center", gutterBottom: true, sx: { fontWeight: "bold", color: "primary.main" }, children: "Iniciar Sesi\xF3n" }),
5459
- /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("form", { onSubmit: handleSubmit(onSubmit), className: "space-y-4", children: [
5460
- /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("div", { children: [
5461
- /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("label", { htmlFor: "username", children: /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(import_material23.Typography, { variant: "subtitle1", component: "div", sx: { fontWeight: "medium" }, children: "Usuario" }) }),
5462
- /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
5463
- import_react_hook_form.Controller,
5464
- {
5465
- name: "username",
5466
- control,
5467
- render: ({ field }) => /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
5468
- import_material23.TextField,
5770
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(import_material24.Typography, { variant: "h5", align: "center", gutterBottom: true, sx: { fontWeight: "bold", color: "primary.main" }, children: "Iniciar Sesi\xF3n" }),
5771
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)(
5772
+ "form",
5773
+ {
5774
+ onSubmit: handleSubmit(onSubmit),
5775
+ className: "space-y-4",
5776
+ onKeyDown: (evento) => {
5777
+ if (evento.key !== "Enter" || evento.shiftKey || evento.ctrlKey || evento.altKey || evento.metaKey) return;
5778
+ if (!(evento.target instanceof HTMLInputElement)) return;
5779
+ evento.preventDefault();
5780
+ if (!isSubmitting) void handleSubmit(onSubmit)();
5781
+ },
5782
+ children: [
5783
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("div", { children: [
5784
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("label", { htmlFor: "username", children: /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(import_material24.Typography, { variant: "subtitle1", component: "div", sx: { fontWeight: "medium" }, children: "Usuario" }) }),
5785
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
5786
+ import_react_hook_form.Controller,
5469
5787
  {
5470
- ...field,
5471
- type: "text",
5472
- placeholder: "Ingresa tu usuario",
5473
- fullWidth: true,
5474
- margin: "normal",
5475
- error: !!errors.username,
5476
- helperText: errors.username?.message,
5477
- disabled: isSubmitting
5788
+ name: "username",
5789
+ control,
5790
+ render: ({ field }) => /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
5791
+ import_material24.TextField,
5792
+ {
5793
+ ...field,
5794
+ type: "text",
5795
+ id: "username",
5796
+ autoComplete: "username",
5797
+ placeholder: "Ingresa tu usuario",
5798
+ fullWidth: true,
5799
+ margin: "normal",
5800
+ error: !!errors.username,
5801
+ helperText: errors.username?.message,
5802
+ disabled: isSubmitting
5803
+ }
5804
+ )
5478
5805
  }
5479
5806
  )
5480
- }
5481
- )
5482
- ] }),
5483
- /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("div", { children: [
5484
- /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("label", { htmlFor: "password", children: /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(import_material23.Typography, { variant: "subtitle1", component: "div", sx: { fontWeight: "medium" }, children: "Contrase\xF1a" }) }),
5485
- /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
5486
- import_react_hook_form.Controller,
5487
- {
5488
- name: "password",
5489
- control,
5490
- render: ({ field }) => /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
5491
- import_material23.TextField,
5807
+ ] }),
5808
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)("div", { children: [
5809
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("label", { htmlFor: "password", children: /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(import_material24.Typography, { variant: "subtitle1", component: "div", sx: { fontWeight: "medium" }, children: "Contrase\xF1a" }) }),
5810
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
5811
+ import_react_hook_form.Controller,
5492
5812
  {
5493
- ...field,
5494
- type: "password",
5495
- placeholder: "Ingresa tu contrase\xF1a",
5496
- fullWidth: true,
5497
- margin: "normal",
5498
- error: !!errors.password,
5499
- helperText: errors.password?.message,
5500
- disabled: isSubmitting
5813
+ name: "password",
5814
+ control,
5815
+ render: ({ field }) => /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
5816
+ import_material24.TextField,
5817
+ {
5818
+ ...field,
5819
+ type: "password",
5820
+ id: "password",
5821
+ autoComplete: "current-password",
5822
+ placeholder: "Ingresa tu contrase\xF1a",
5823
+ fullWidth: true,
5824
+ margin: "normal",
5825
+ error: !!errors.password,
5826
+ helperText: errors.password?.message,
5827
+ disabled: isSubmitting
5828
+ }
5829
+ )
5501
5830
  }
5502
5831
  )
5503
- }
5504
- )
5505
- ] }),
5506
- /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(import_material23.Button, { type: "submit", fullWidth: true, variant: "contained", color: "primary", disabled: isSubmitting, sx: { mt: 2 }, children: isSubmitting ? /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(import_jsx_runtime29.Fragment, { children: [
5507
- /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(import_material23.CircularProgress, { size: 20, sx: { mr: 1 } }),
5508
- "Iniciando sesi\xF3n..."
5509
- ] }) : "Iniciar Sesi\xF3n" })
5510
- ] }),
5511
- loginError && /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(import_material23.Alert, { severity: "error", sx: { mt: 2, maxHeight: "200px" }, children: [
5832
+ ] }),
5833
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(import_material24.Button, { type: "submit", fullWidth: true, variant: "contained", color: "primary", disabled: isSubmitting, sx: { mt: 2 }, children: isSubmitting ? /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)(import_jsx_runtime30.Fragment, { children: [
5834
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(import_material24.CircularProgress, { size: 20, sx: { mr: 1 } }),
5835
+ "Iniciando sesi\xF3n..."
5836
+ ] }) : "Iniciar Sesi\xF3n" })
5837
+ ]
5838
+ }
5839
+ ),
5840
+ rutaDeRecuperarClave2 && /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(import_material24.Box, { sx: { mt: 2, textAlign: "center" }, children: /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(import_material24.Link, { href: `${envConfig.backendUrl}${rutaDeRecuperarClave2}`, variant: "body2", underline: "hover", children: "Me olvid\xE9 la clave / es mi primer ingreso" }) }),
5841
+ claveCambiada && !loginError && /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(import_material24.Alert, { severity: "success", sx: { mt: 2 }, children: "La contrase\xF1a se cambi\xF3. Ingres\xE1 con la clave nueva." }),
5842
+ loginError && /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)(import_material24.Alert, { severity: "error", sx: { mt: 2, maxHeight: "200px" }, children: [
5512
5843
  " ",
5513
- /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(import_material23.AlertTitle, { children: "Error" }),
5844
+ /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(import_material24.AlertTitle, { children: "Error" }),
5514
5845
  loginError
5515
5846
  ] })
5516
5847
  ]
@@ -5523,18 +5854,18 @@ var LoginPage_default = LoginPage;
5523
5854
 
5524
5855
  // src/components/ProcedureForm.tsx
5525
5856
  var import_react33 = __toESM(require("react"), 1);
5526
- var import_react_router_dom6 = require("react-router-dom");
5527
- var import_material25 = require("@mui/material");
5857
+ var import_react_router_dom8 = require("react-router-dom");
5858
+ var import_material26 = require("@mui/material");
5528
5859
 
5529
5860
  // src/pages/procedure-results/SuccessDisplay.tsx
5530
- var import_material24 = require("@mui/material");
5531
- var import_jsx_runtime30 = require("react/jsx-runtime");
5861
+ var import_material25 = require("@mui/material");
5862
+ var import_jsx_runtime31 = require("react/jsx-runtime");
5532
5863
  var SuccessDisplay = ({ data }) => {
5533
- return /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)(import_material24.Paper, { elevation: 2, sx: { p: 2, mt: 2, bgcolor: "success.light", color: "success.contrastText" }, children: [
5534
- /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(import_material24.Typography, { variant: "h6", sx: { fontSize: "1rem", mb: 1 }, children: "\xA1Operaci\xF3n Exitosa!" }),
5535
- /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(import_material24.Typography, { variant: "body2", sx: { fontSize: "0.85rem" }, children: "Detalles del resultado:" }),
5536
- /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(import_material24.Box, { sx: { bgcolor: "success.dark", p: 1, borderRadius: 1, mt: 1, overflowX: "auto" }, children: /* @__PURE__ */ (0, import_jsx_runtime30.jsx)("pre", { style: { margin: 0, fontSize: "0.75rem", color: "white" }, children: JSON.stringify(data, null, 2) }) }),
5537
- /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(import_material24.Typography, { variant: "body2", sx: { fontSize: "0.8rem", mt: 1 }, children: "Puedes revisar los detalles anteriores o cerrar este mensaje." })
5864
+ return /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)(import_material25.Paper, { elevation: 2, sx: { p: 2, mt: 2, bgcolor: "success.light", color: "success.contrastText" }, children: [
5865
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(import_material25.Typography, { variant: "h6", sx: { fontSize: "1rem", mb: 1 }, children: "\xA1Operaci\xF3n Exitosa!" }),
5866
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(import_material25.Typography, { variant: "body2", sx: { fontSize: "0.85rem" }, children: "Detalles del resultado:" }),
5867
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(import_material25.Box, { sx: { bgcolor: "success.dark", p: 1, borderRadius: 1, mt: 1, overflowX: "auto" }, children: /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("pre", { style: { margin: 0, fontSize: "0.75rem", color: "white" }, children: JSON.stringify(data, null, 2) }) }),
5868
+ /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(import_material25.Typography, { variant: "body2", sx: { fontSize: "0.8rem", mt: 1 }, children: "Puedes revisar los detalles anteriores o cerrar este mensaje." })
5538
5869
  ] });
5539
5870
  };
5540
5871
  var SuccessDisplay_default = SuccessDisplay;
@@ -5548,9 +5879,9 @@ var extendResultsOk = (newComponents) => {
5548
5879
  };
5549
5880
 
5550
5881
  // src/components/ProcedureForm.tsx
5551
- var import_jsx_runtime31 = require("react/jsx-runtime");
5882
+ var import_jsx_runtime32 = require("react/jsx-runtime");
5552
5883
  var ProcedureForm = () => {
5553
- const { procedureName } = (0, import_react_router_dom6.useParams)();
5884
+ const { procedureName } = (0, import_react_router_dom8.useParams)();
5554
5885
  const { clientContext } = useApp();
5555
5886
  const { callApi, loading: apiLoading, error: apiError } = useApiCall();
5556
5887
  const [validationErrors, setValidationErrors] = (0, import_react33.useState)({});
@@ -5763,10 +6094,10 @@ var ProcedureForm = () => {
5763
6094
  sx: { fontSize: "0.8rem" }
5764
6095
  };
5765
6096
  if (param.options && param.options.length > 0) {
5766
- return /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)(import_material25.FormControl, { fullWidth: true, margin: "dense", size: "small", error: hasError, required: commonProps.required, children: [
5767
- /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(import_material25.InputLabel, { id: `${param.name}-label`, sx: { fontSize: "0.8rem" }, children: param.label || param.name }),
5768
- /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)(
5769
- import_material25.Select,
6097
+ return /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(import_material26.FormControl, { fullWidth: true, margin: "dense", size: "small", error: hasError, required: commonProps.required, children: [
6098
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(import_material26.InputLabel, { id: `${param.name}-label`, sx: { fontSize: "0.8rem" }, children: param.label || param.name }),
6099
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(
6100
+ import_material26.Select,
5770
6101
  {
5771
6102
  labelId: `${param.name}-label`,
5772
6103
  value: formValues[param.name] === void 0 ? "" : formValues[param.name],
@@ -5776,14 +6107,14 @@ var ProcedureForm = () => {
5776
6107
  label: param.label || param.name,
5777
6108
  disabled: apiLoading,
5778
6109
  sx: { fontSize: "0.8rem" },
5779
- renderValue: (selected) => /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(import_material25.Typography, { sx: { fontSize: "0.8rem" }, children: selected }),
6110
+ renderValue: (selected) => /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(import_material26.Typography, { sx: { fontSize: "0.8rem" }, children: selected }),
5780
6111
  children: [
5781
- (!commonProps.required || formValues[param.name] === "") && /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(import_material25.MenuItem, { value: "", sx: { fontSize: "0.8rem" }, children: /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("em", { children: "Seleccione..." }) }),
5782
- param.options.map((option) => /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(import_material25.MenuItem, { value: option, sx: { fontSize: "0.8rem" }, children: option }, option))
6112
+ (!commonProps.required || formValues[param.name] === "") && /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(import_material26.MenuItem, { value: "", sx: { fontSize: "0.8rem" }, children: /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("em", { children: "Seleccione..." }) }),
6113
+ param.options.map((option) => /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(import_material26.MenuItem, { value: option, sx: { fontSize: "0.8rem" }, children: option }, option))
5783
6114
  ]
5784
6115
  }
5785
6116
  ),
5786
- (param.description || errorMessage) && /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(import_material25.FormHelperText, { sx: { fontSize: "0.7rem" }, children: errorMessage || param.description })
6117
+ (param.description || errorMessage) && /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(import_material26.FormHelperText, { sx: { fontSize: "0.7rem" }, children: errorMessage || param.description })
5787
6118
  ] });
5788
6119
  }
5789
6120
  switch (param.typeName) {
@@ -5792,19 +6123,19 @@ var ProcedureForm = () => {
5792
6123
  case "tsrange":
5793
6124
  case "time_range":
5794
6125
  case "daterange":
5795
- return /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(import_material25.TextField, { type: "text", value: formValues[param.name] || "", ...commonProps });
6126
+ return /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(import_material26.TextField, { type: "text", value: formValues[param.name] || "", ...commonProps });
5796
6127
  case "decimal":
5797
6128
  case "double":
5798
- return /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(import_material25.TextField, { type: "number", inputProps: { step: "any", style: { fontSize: "0.8rem" } }, value: formValues[param.name] || "", ...commonProps });
6129
+ return /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(import_material26.TextField, { type: "number", inputProps: { step: "any", style: { fontSize: "0.8rem" } }, value: formValues[param.name] || "", ...commonProps });
5799
6130
  case "integer":
5800
6131
  case "bigint":
5801
- return /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(import_material25.TextField, { type: "number", inputProps: { step: "1", style: { fontSize: "0.8rem" } }, value: formValues[param.name] || "", ...commonProps });
6132
+ return /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(import_material26.TextField, { type: "number", inputProps: { step: "1", style: { fontSize: "0.8rem" } }, value: formValues[param.name] || "", ...commonProps });
5802
6133
  case "boolean":
5803
- return /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
5804
- import_material25.FormControlLabel,
6134
+ return /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
6135
+ import_material26.FormControlLabel,
5805
6136
  {
5806
- control: /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
5807
- import_material25.Checkbox,
6137
+ control: /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
6138
+ import_material26.Checkbox,
5808
6139
  {
5809
6140
  checked: !!formValues[param.name],
5810
6141
  onChange: handleChange,
@@ -5814,21 +6145,21 @@ var ProcedureForm = () => {
5814
6145
  size: "small"
5815
6146
  }
5816
6147
  ),
5817
- label: /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(import_material25.Typography, { sx: { fontSize: "0.8rem", color: hasError ? "error.main" : "inherit" }, children: param.label || param.name }),
6148
+ label: /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(import_material26.Typography, { sx: { fontSize: "0.8rem", color: hasError ? "error.main" : "inherit" }, children: param.label || param.name }),
5818
6149
  sx: { mt: 1, mb: 0 }
5819
6150
  }
5820
6151
  );
5821
6152
  case "date":
5822
6153
  case "timestamp":
5823
6154
  case "time":
5824
- return /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(import_material25.TextField, { type: param.typeName === "date" ? "date" : param.typeName === "timestamp" ? "datetime-local" : "time", value: formValues[param.name] || "", ...commonProps, InputLabelProps: { shrink: true, sx: { fontSize: "0.8rem" } } });
6155
+ return /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(import_material26.TextField, { type: param.typeName === "date" ? "date" : param.typeName === "timestamp" ? "datetime-local" : "time", value: formValues[param.name] || "", ...commonProps, InputLabelProps: { shrink: true, sx: { fontSize: "0.8rem" } } });
5825
6156
  case "jsonb":
5826
6157
  case "jsona":
5827
- return /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(import_material25.TextField, { multiline: true, rows: 5, value: formValues[param.name] || "", ...commonProps, InputProps: { sx: { fontSize: "0.8rem" } } });
6158
+ return /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(import_material26.TextField, { multiline: true, rows: 5, value: formValues[param.name] || "", ...commonProps, InputProps: { sx: { fontSize: "0.8rem" } } });
5828
6159
  case "bytea":
5829
- return /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)(import_material25.FormControl, { fullWidth: true, margin: "dense", error: hasError, required: commonProps.required, children: [
5830
- /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(import_material25.Typography, { variant: "body2", color: "textSecondary", component: "label", htmlFor: param.name, sx: { fontSize: "0.8rem", color: hasError ? "error.main" : "text.secondary" }, children: param.label || param.name }),
5831
- /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
6160
+ return /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(import_material26.FormControl, { fullWidth: true, margin: "dense", error: hasError, required: commonProps.required, children: [
6161
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(import_material26.Typography, { variant: "body2", color: "textSecondary", component: "label", htmlFor: param.name, sx: { fontSize: "0.8rem", color: hasError ? "error.main" : "text.secondary" }, children: param.label || param.name }),
6162
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
5832
6163
  "input",
5833
6164
  {
5834
6165
  type: "file",
@@ -5842,34 +6173,34 @@ var ProcedureForm = () => {
5842
6173
  style: { padding: "6px 0", fontSize: "0.8rem" }
5843
6174
  }
5844
6175
  ),
5845
- (param.description || errorMessage) && /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(import_material25.FormHelperText, { sx: { fontSize: "0.7rem" }, children: errorMessage || param.description })
6176
+ (param.description || errorMessage) && /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(import_material26.FormHelperText, { sx: { fontSize: "0.7rem" }, children: errorMessage || param.description })
5846
6177
  ] });
5847
6178
  default:
5848
- return /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(import_material25.TextField, { type: "text", value: formValues[param.name] || "", ...commonProps });
6179
+ return /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(import_material26.TextField, { type: "text", value: formValues[param.name] || "", ...commonProps });
5849
6180
  }
5850
6181
  }, [formValues, handleChange, apiLoading, validationErrors]);
5851
6182
  const ResultDisplayContent = (0, import_react33.useMemo)(() => {
5852
6183
  if (!procedureResultData || !procedure?.resultOk) return null;
5853
6184
  const ComponentToRender = resultsOk[procedure.resultOk];
5854
6185
  if (ComponentToRender) {
5855
- return /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(ComponentToRender, { data: procedureResultData });
6186
+ return /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(ComponentToRender, { data: procedureResultData });
5856
6187
  } else {
5857
- return /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)(import_material25.Paper, { elevation: 2, sx: { p: 2, mt: 0, bgcolor: "warning.light" }, children: [
5858
- /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)(import_material25.Typography, { variant: "h6", sx: { fontSize: "1rem", mb: 1 }, children: [
6188
+ return /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(import_material26.Paper, { elevation: 2, sx: { p: 2, mt: 0, bgcolor: "warning.light" }, children: [
6189
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(import_material26.Typography, { variant: "h6", sx: { fontSize: "1rem", mb: 1 }, children: [
5859
6190
  "el componente para resolver el resultOk: '",
5860
6191
  procedure.resultOk,
5861
6192
  "' definido en el procedure no existe o no est\xE1 mapeado."
5862
6193
  ] }),
5863
- /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(import_material25.Box, { sx: {
6194
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(import_material26.Box, { sx: {
5864
6195
  bgcolor: "warning.dark",
5865
6196
  p: 1,
5866
6197
  borderRadius: 1
5867
- }, children: /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("pre", { style: { margin: 0, fontSize: "0.75rem", color: "white" }, children: JSON.stringify(procedureResultData, null, 2) }) })
6198
+ }, children: /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("pre", { style: { margin: 0, fontSize: "0.75rem", color: "white" }, children: JSON.stringify(procedureResultData, null, 2) }) })
5868
6199
  ] });
5869
6200
  }
5870
6201
  }, [procedureResultData, procedure]);
5871
6202
  if (!procedure) {
5872
- return /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)(import_material25.Box, { sx: {
6203
+ return /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(import_material26.Box, { sx: {
5873
6204
  p: 2,
5874
6205
  width: "100%",
5875
6206
  boxSizing: "border-box",
@@ -5879,13 +6210,13 @@ var ProcedureForm = () => {
5879
6210
  boxShadow: 3,
5880
6211
  textAlign: "center"
5881
6212
  }, children: [
5882
- /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(import_material25.CircularProgress, { sx: { mb: 2 } }),
5883
- /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(import_material25.Typography, { variant: "h6", color: "text.secondary", children: "Cargando procedimiento o no encontrado..." })
6213
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(import_material26.CircularProgress, { sx: { mb: 2 } }),
6214
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(import_material26.Typography, { variant: "h6", color: "text.secondary", children: "Cargando procedimiento o no encontrado..." })
5884
6215
  ] });
5885
6216
  }
5886
6217
  return (
5887
6218
  // Esta es la Box más externa que ahora controlará el scroll
5888
- /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)(import_material25.Box, { sx: {
6219
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(import_material26.Box, { sx: {
5889
6220
  p: 2,
5890
6221
  ml: 1,
5891
6222
  mt: 2,
@@ -5902,17 +6233,17 @@ var ProcedureForm = () => {
5902
6233
  overflowX: "hidden"
5903
6234
  // Oculta el scroll horizontal si no es necesario para el contenedor principal
5904
6235
  }, children: [
5905
- /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(import_material25.Typography, { variant: "h5", component: "h2", gutterBottom: true, align: "left", children: cambiarGuionesBajosPorEspacios(procedure.proceedLabel || procedure.action) }),
5906
- Object.values(validationErrors).some((err) => err !== null) && /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)(import_material25.Alert, { severity: "error", sx: { mb: 2, fontSize: "0.8rem" }, children: [
6236
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(import_material26.Typography, { variant: "h5", component: "h2", gutterBottom: true, align: "left", children: cambiarGuionesBajosPorEspacios(procedure.proceedLabel || procedure.action) }),
6237
+ Object.values(validationErrors).some((err) => err !== null) && /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(import_material26.Alert, { severity: "error", sx: { mb: 2, fontSize: "0.8rem" }, children: [
5907
6238
  "Por favor, corrige los errores en el formulario antes de enviar.",
5908
- /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("ul", { children: Object.values(validationErrors).map((err, idx) => err && /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("li", { children: err }, idx)) })
6239
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("ul", { children: Object.values(validationErrors).map((err, idx) => err && /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("li", { children: err }, idx)) })
5909
6240
  ] }),
5910
- !Object.values(validationErrors).some((err) => err !== null) && apiError && /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(import_material25.Alert, { severity: "error", sx: { mb: 2, fontSize: "0.8rem" }, children: apiError.message }),
5911
- !Object.values(validationErrors).some((err) => err !== null) && !apiError && successMessage && /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(import_material25.Alert, { severity: "success", sx: { mb: 2, fontSize: "0.8rem" }, children: successMessage }),
5912
- /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)("form", { onSubmit: handleSubmit, children: [
5913
- procedure.parameters.map((param) => /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("div", { children: renderInputField(param) }, param.name)),
5914
- /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
5915
- import_material25.Button,
6241
+ !Object.values(validationErrors).some((err) => err !== null) && apiError && /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(import_material26.Alert, { severity: "error", sx: { mb: 2, fontSize: "0.8rem" }, children: apiError.message }),
6242
+ !Object.values(validationErrors).some((err) => err !== null) && !apiError && successMessage && /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(import_material26.Alert, { severity: "success", sx: { mb: 2, fontSize: "0.8rem" }, children: successMessage }),
6243
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("form", { onSubmit: handleSubmit, children: [
6244
+ procedure.parameters.map((param) => /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("div", { children: renderInputField(param) }, param.name)),
6245
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
6246
+ import_material26.Button,
5916
6247
  {
5917
6248
  type: "submit",
5918
6249
  variant: "contained",
@@ -5920,20 +6251,20 @@ var ProcedureForm = () => {
5920
6251
  disabled: apiLoading || Object.values(validationErrors).some((err) => err !== null),
5921
6252
  sx: { mt: 2 },
5922
6253
  size: "medium",
5923
- startIcon: apiLoading ? /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(import_material25.CircularProgress, { size: 20, color: "inherit" }) : null,
6254
+ startIcon: apiLoading ? /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(import_material26.CircularProgress, { size: 20, color: "inherit" }) : null,
5924
6255
  children: apiLoading ? "Ejecutando..." : procedure.proceedLabel || "Ejecutar"
5925
6256
  }
5926
6257
  )
5927
6258
  ] }),
5928
- ResultDisplayContent && /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)(import_material25.Box, { sx: { mt: 2 }, children: [
6259
+ ResultDisplayContent && /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(import_material26.Box, { sx: { mt: 2 }, children: [
5929
6260
  " ",
5930
6261
  ResultDisplayContent
5931
6262
  ] }),
5932
- executionLog.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)(import_material25.Box, { sx: { mt: 3 }, children: [
5933
- /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(import_material25.Divider, { sx: { mb: 2 } }),
5934
- /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(import_material25.Typography, { variant: "h6", gutterBottom: true, sx: { fontSize: "0.9rem" }, children: "Registro de Ejecuci\xF3n" }),
5935
- /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
5936
- import_material25.Box,
6263
+ executionLog.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(import_material26.Box, { sx: { mt: 3 }, children: [
6264
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(import_material26.Divider, { sx: { mb: 2 } }),
6265
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(import_material26.Typography, { variant: "h6", gutterBottom: true, sx: { fontSize: "0.9rem" }, children: "Registro de Ejecuci\xF3n" }),
6266
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
6267
+ import_material26.Box,
5937
6268
  {
5938
6269
  sx: {
5939
6270
  bgcolor: "grey.100",
@@ -5946,8 +6277,8 @@ var ProcedureForm = () => {
5946
6277
  fontSize: "0.75rem",
5947
6278
  whiteSpace: "pre-wrap"
5948
6279
  },
5949
- children: executionLog.map((log, index) => /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
5950
- import_material25.Typography,
6280
+ children: executionLog.map((log, index) => /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
6281
+ import_material26.Typography,
5951
6282
  {
5952
6283
  component: "pre",
5953
6284
  sx: {
@@ -5968,15 +6299,15 @@ var ProcedureForm = () => {
5968
6299
  var ProcedureForm_default = ProcedureForm;
5969
6300
 
5970
6301
  // src/App.tsx
5971
- var import_react_redux5 = require("react-redux");
5972
- var import_react44 = require("redux-persist/integration/react");
6302
+ var import_react_redux6 = require("react-redux");
6303
+ var import_react45 = require("redux-persist/integration/react");
5973
6304
 
5974
6305
  // src/components/PrivateRoute.tsx
5975
6306
  var import_react34 = require("react");
5976
- var import_react_router_dom7 = require("react-router-dom");
5977
- var import_jsx_runtime32 = require("react/jsx-runtime");
6307
+ var import_react_router_dom9 = require("react-router-dom");
6308
+ var import_jsx_runtime33 = require("react/jsx-runtime");
5978
6309
  var PrivateRoute = ({ children }) => {
5979
- const location = (0, import_react_router_dom7.useLocation)();
6310
+ const location = (0, import_react_router_dom9.useLocation)();
5980
6311
  const dispatch = useAppDispatch();
5981
6312
  const clientContextStatus = useClientContextStatus();
5982
6313
  const isAuthenticated = clientContextStatus === "succeeded";
@@ -5984,7 +6315,7 @@ var PrivateRoute = ({ children }) => {
5984
6315
  console.log(`[PrivateRoute] Render: Path=${location.pathname}, AuthStatus=${clientContextStatus}, IsAuthenticated=${isAuthenticated}, IsLoadingAuth=${isLoadingAuth}`);
5985
6316
  (0, import_react34.useEffect)(() => {
5986
6317
  console.log(`[PrivateRoute] Effect: Path=${location.pathname}, AuthStatus=${clientContextStatus}, IsAuthenticated=${isAuthenticated}, IsLoadingAuth=${isLoadingAuth}`);
5987
- if (!isAuthenticated && !isLoadingAuth && location.pathname !== "/login") {
6318
+ if (!isAuthenticated && !isLoadingAuth && location.pathname !== "/login" && !huboCierreVoluntario()) {
5988
6319
  const path = location.pathname + location.search + location.hash;
5989
6320
  console.log(`[PrivateRoute] ACTION: Dispatching setRedirectPath(${path})`);
5990
6321
  dispatch(setRedirectPath(path));
@@ -5998,26 +6329,28 @@ var PrivateRoute = ({ children }) => {
5998
6329
  }, [isAuthenticated, isLoadingAuth, location, dispatch, clientContextStatus]);
5999
6330
  if (isLoadingAuth) {
6000
6331
  console.log(`[PrivateRoute] Returning loading state...`);
6001
- return /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("p", { children: "Verificando autenticaci\xF3n..." });
6332
+ return /* @__PURE__ */ (0, import_jsx_runtime33.jsx)("p", { children: "Verificando autenticaci\xF3n..." });
6002
6333
  }
6003
6334
  if (!isAuthenticated) {
6004
6335
  console.log(`[PrivateRoute] User not authenticated, navigating to /login`);
6005
- return /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(import_react_router_dom7.Navigate, { to: "/login", replace: true });
6336
+ return /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(import_react_router_dom9.Navigate, { to: "/login", replace: true });
6006
6337
  }
6007
6338
  console.log(`[PrivateRoute] User authenticated, rendering children.`);
6008
- return /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(import_jsx_runtime32.Fragment, { children });
6339
+ return /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(import_jsx_runtime33.Fragment, { children });
6009
6340
  };
6010
6341
  var PrivateRoute_default = PrivateRoute;
6011
6342
 
6012
6343
  // src/components/InitialRedirectHandler.tsx
6013
6344
  var import_react35 = require("react");
6014
- var import_react_router_dom8 = require("react-router-dom");
6345
+ var import_react_router_dom10 = require("react-router-dom");
6015
6346
  var InitialRedirectHandler = () => {
6016
- const location = (0, import_react_router_dom8.useLocation)();
6017
- const navigate = (0, import_react_router_dom8.useNavigate)();
6347
+ const location = (0, import_react_router_dom10.useLocation)();
6348
+ const navigate = (0, import_react_router_dom10.useNavigate)();
6018
6349
  const dispatch = useAppDispatch();
6019
6350
  const redirectPath = useRedirectPath();
6020
6351
  const clientContextStatus = useClientContextStatus();
6352
+ const username = useAppSelector((state) => state.clientContext.username);
6353
+ const redirectUsername = useAppSelector((state) => state.router.redirectUsername);
6021
6354
  (0, import_react35.useEffect)(() => {
6022
6355
  dispatch(setCurrentPath(location.pathname + location.search));
6023
6356
  }, [location, dispatch]);
@@ -6027,7 +6360,9 @@ var InitialRedirectHandler = () => {
6027
6360
  }, [location.pathname]);
6028
6361
  (0, import_react35.useEffect)(() => {
6029
6362
  if (clientContextStatus === "succeeded") {
6030
- if (redirectPath && redirectPath !== "/login") {
6363
+ if (redirectPath && redirectPath !== "/login" && redirectUsername && redirectUsername !== username) {
6364
+ dispatch(setRedirectPath(null));
6365
+ } else if (redirectPath && redirectPath !== "/login") {
6031
6366
  console.log("Redirigiendo a la ruta guardada:", redirectPath);
6032
6367
  navegandoRef.current = true;
6033
6368
  navigate(redirectPath);
@@ -6037,28 +6372,28 @@ var InitialRedirectHandler = () => {
6037
6372
  navigate("/");
6038
6373
  }
6039
6374
  }
6040
- }, [clientContextStatus, redirectPath, location.pathname, navigate, dispatch]);
6375
+ }, [clientContextStatus, redirectPath, redirectUsername, username, location.pathname, navigate, dispatch]);
6041
6376
  return null;
6042
6377
  };
6043
6378
  var InitialRedirectHandler_default = InitialRedirectHandler;
6044
6379
 
6045
6380
  // src/pages/GenericDataGridPage.tsx
6046
6381
  var import_react36 = __toESM(require("react"), 1);
6047
- var import_react_router_dom9 = require("react-router-dom");
6048
- var import_material26 = require("@mui/material");
6382
+ var import_react_router_dom11 = require("react-router-dom");
6383
+ var import_material27 = require("@mui/material");
6049
6384
  var import_Close2 = __toESM(require("@mui/icons-material/Close"), 1);
6050
- var import_jsx_runtime33 = require("react/jsx-runtime");
6385
+ var import_jsx_runtime34 = require("react/jsx-runtime");
6051
6386
  var GenericDataGridPage = ({
6052
6387
  initialTableName,
6053
6388
  initialFixedFields = [],
6054
6389
  parametros: parametrosRecibidos
6055
6390
  }) => {
6056
- const { tableName: urlTableName } = (0, import_react_router_dom9.useParams)();
6391
+ const { tableName: urlTableName } = (0, import_react_router_dom11.useParams)();
6057
6392
  const effectiveTableName = initialTableName || urlTableName;
6058
6393
  const [tabs, setTabs] = (0, import_react36.useState)([]);
6059
6394
  const [activeTabIdx, setActiveTabIdx] = (0, import_react36.useState)(0);
6060
6395
  const ffKey = JSON.stringify(initialFixedFields);
6061
- const location = (0, import_react_router_dom9.useLocation)();
6396
+ const location = (0, import_react_router_dom11.useLocation)();
6062
6397
  const parametros = (0, import_react36.useMemo)(() => parametrosRecibidos ?? parametrosDeTabla(void 0, location.search), [parametrosRecibidos, location.search]);
6063
6398
  const fixedFieldsIniciales = initialFixedFields.length > 0 ? initialFixedFields : parametros.fixedFields ?? [];
6064
6399
  const parametrosKey = JSON.stringify(parametros);
@@ -6098,26 +6433,26 @@ var GenericDataGridPage = ({
6098
6433
  else if (activeTabIdx === index) setActiveTabIdx(index - 1);
6099
6434
  };
6100
6435
  if (!effectiveTableName) {
6101
- return /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(import_material26.Box, { p: 3, children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(import_material26.Alert, { severity: "error", children: "No se especific\xF3 una tabla." }) });
6436
+ return /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(import_material27.Box, { p: 3, children: /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(import_material27.Alert, { severity: "error", children: "No se especific\xF3 una tabla." }) });
6102
6437
  }
6103
- return /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(import_material26.Box, { sx: { width: "100%", height: "calc(100vh - 64px)", display: "flex", flexDirection: "column" }, children: [
6104
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(import_material26.Box, { sx: { borderBottom: 1, borderColor: "divider", bgcolor: "background.paper" }, children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(import_material26.Tabs, { value: activeTabIdx, onChange: (_, v) => setActiveTabIdx(v), variant: "scrollable", children: tabs.map((tab, index) => /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
6105
- import_material26.Tab,
6438
+ return /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)(import_material27.Box, { sx: { width: "100%", height: "calc(100vh - 64px)", display: "flex", flexDirection: "column" }, children: [
6439
+ /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(import_material27.Box, { sx: { borderBottom: 1, borderColor: "divider", bgcolor: "background.paper" }, children: /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(import_material27.Tabs, { value: activeTabIdx, onChange: (_, v) => setActiveTabIdx(v), variant: "scrollable", children: tabs.map((tab, index) => /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
6440
+ import_material27.Tab,
6106
6441
  {
6107
- label: /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(import_material26.Box, { sx: { display: "flex", alignItems: "center", gap: 1 }, children: [
6108
- /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(import_material26.Typography, { variant: "caption", sx: { fontWeight: "bold" }, children: tab.label }),
6109
- index !== 0 && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(import_material26.IconButton, { size: "small", onClick: (e) => handleCloseTab(index, e), children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(import_Close2.default, { fontSize: "inherit" }) })
6442
+ label: /* @__PURE__ */ (0, import_jsx_runtime34.jsxs)(import_material27.Box, { sx: { display: "flex", alignItems: "center", gap: 1 }, children: [
6443
+ /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(import_material27.Typography, { variant: "caption", sx: { fontWeight: "bold" }, children: tab.label }),
6444
+ index !== 0 && /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(import_material27.IconButton, { size: "small", onClick: (e) => handleCloseTab(index, e), children: /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(import_Close2.default, { fontSize: "inherit" }) })
6110
6445
  ] })
6111
6446
  },
6112
6447
  tab.id
6113
6448
  )) }) }),
6114
- tabs.map((tab, index) => /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
6115
- import_material26.Box,
6449
+ tabs.map((tab, index) => /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
6450
+ import_material27.Box,
6116
6451
  {
6117
6452
  role: "tabpanel",
6118
6453
  hidden: activeTabIdx !== index,
6119
6454
  sx: { flexGrow: 1, display: activeTabIdx === index ? "flex" : "none", flexDirection: "column", overflow: "hidden" },
6120
- children: /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
6455
+ children: /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
6121
6456
  GenericDataGrid_default,
6122
6457
  {
6123
6458
  tableName: tab.tableName,
@@ -6139,43 +6474,31 @@ var GenericDataGridPage_default = GenericDataGridPage;
6139
6474
 
6140
6475
  // src/pages/PantallaDeRuta.tsx
6141
6476
  var import_react37 = require("react");
6142
- var import_react_router_dom10 = require("react-router-dom");
6143
- var import_material27 = require("@mui/material");
6144
- var import_jsx_runtime34 = require("react/jsx-runtime");
6477
+ var import_react_router_dom12 = require("react-router-dom");
6478
+ var import_material28 = require("@mui/material");
6479
+ var import_jsx_runtime35 = require("react/jsx-runtime");
6145
6480
  var PantallaDeRuta = ({ screenName }) => {
6146
- const [busqueda] = (0, import_react_router_dom10.useSearchParams)();
6481
+ const [busqueda] = (0, import_react_router_dom12.useSearchParams)();
6147
6482
  const params = (0, import_react37.useMemo)(() => Object.fromEntries(busqueda.entries()), [busqueda]);
6148
6483
  const Pantalla = wScreens[screenName];
6149
- return /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(import_material27.Box, { sx: { pt: 3, pl: 4 }, children: Pantalla ? /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(Pantalla, { screenName, params }) : /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(FallbackWScreen, { screenName }) });
6484
+ return /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(import_material28.Box, { sx: { pt: 3, pl: 4 }, children: Pantalla ? /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(Pantalla, { screenName, params }) : /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(FallbackWScreen, { screenName }) });
6150
6485
  };
6151
6486
 
6152
6487
  // src/pages/MenuTablePage.tsx
6153
6488
  var import_react38 = require("react");
6154
- var import_react_router_dom11 = require("react-router-dom");
6155
- var import_material28 = require("@mui/material");
6156
- var import_jsx_runtime35 = require("react/jsx-runtime");
6489
+ var import_react_router_dom13 = require("react-router-dom");
6490
+ var import_material29 = require("@mui/material");
6491
+ var import_jsx_runtime36 = require("react/jsx-runtime");
6157
6492
  var MenuTablePage = () => {
6158
- const { menuName } = (0, import_react_router_dom11.useParams)();
6493
+ const { "*": menuName } = (0, import_react_router_dom13.useParams)();
6159
6494
  const { clientContext } = useApp();
6160
- const { search } = (0, import_react_router_dom11.useLocation)();
6161
- const findMenuItem = (items, nameToFind) => {
6162
- for (const item of items) {
6163
- if (item.name === nameToFind && item.menuType === "table") {
6164
- return item;
6165
- }
6166
- if (item.menuType === "menu" && item.menuContent) {
6167
- const found = findMenuItem(item.menuContent, nameToFind);
6168
- if (found) return found;
6169
- }
6170
- }
6171
- return void 0;
6172
- };
6495
+ const { search } = (0, import_react_router_dom13.useLocation)();
6173
6496
  const { currentTableName, currentFixedFields, parametros } = (0, import_react38.useMemo)(() => {
6174
6497
  let tableName = void 0;
6175
6498
  let fixedFields = [];
6176
6499
  let parametros2 = {};
6177
6500
  if (menuName && clientContext && clientContext.menu) {
6178
- const menuItem = findMenuItem(clientContext.menu, menuName);
6501
+ const menuItem = itemDeRuta(clientContext.menu, menuName.split("/").filter((tramo) => tramo !== ""));
6179
6502
  if (menuItem) {
6180
6503
  tableName = menuItem.table || menuItem.name;
6181
6504
  parametros2 = parametrosDeTabla(menuItem, search);
@@ -6191,12 +6514,12 @@ var MenuTablePage = () => {
6191
6514
  };
6192
6515
  }, [menuName, clientContext, search]);
6193
6516
  if (!currentTableName) {
6194
- return /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(import_material28.Box, { display: "flex", justifyContent: "center", alignItems: "center", minHeight: "200px", children: /* @__PURE__ */ (0, import_jsx_runtime35.jsxs)(import_material28.Alert, { severity: "error", children: [
6195
- /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(import_material28.Typography, { variant: "h6", children: "Error: No se pudo cargar la informaci\xF3n de la tabla." }),
6196
- /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(import_material28.Typography, { variant: "body1", children: "Verifique la configuraci\xF3n del men\xFA o el nombre de la tabla en la URL." })
6517
+ return /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(import_material29.Box, { display: "flex", justifyContent: "center", alignItems: "center", minHeight: "200px", children: /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)(import_material29.Alert, { severity: "error", children: [
6518
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(import_material29.Typography, { variant: "h6", children: "Error: No se pudo cargar la informaci\xF3n de la tabla." }),
6519
+ /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(import_material29.Typography, { variant: "body1", children: "Verifique la configuraci\xF3n del men\xFA o el nombre de la tabla en la URL." })
6197
6520
  ] }) });
6198
6521
  }
6199
- return /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
6522
+ return /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
6200
6523
  GenericDataGridPage_default,
6201
6524
  {
6202
6525
  initialTableName: currentTableName,
@@ -6209,8 +6532,8 @@ var MenuTablePage_default = MenuTablePage;
6209
6532
 
6210
6533
  // src/puente/PantallaBP.tsx
6211
6534
  var import_react40 = require("react");
6212
- var import_react_router_dom12 = require("react-router-dom");
6213
- var import_material30 = require("@mui/material");
6535
+ var import_react_router_dom14 = require("react-router-dom");
6536
+ var import_material31 = require("@mui/material");
6214
6537
 
6215
6538
  // src/puente/clienteBP.ts
6216
6539
  function extraerRecursos(html) {
@@ -6300,8 +6623,8 @@ async function cargarSinMemoria(urlBackend) {
6300
6623
 
6301
6624
  // src/puente/ConsolaBP.tsx
6302
6625
  var import_react39 = require("react");
6303
- var import_material29 = require("@mui/material");
6304
- var import_jsx_runtime36 = require("react/jsx-runtime");
6626
+ var import_material30 = require("@mui/material");
6627
+ var import_jsx_runtime37 = require("react/jsx-runtime");
6305
6628
  var MARGEN_DE_REPETIDO_MS = 1e3;
6306
6629
  function descartarRepetidos(consola, agregados, ahora) {
6307
6630
  for (const nodo of agregados) {
@@ -6323,8 +6646,8 @@ var ConsolaBP = () => {
6323
6646
  observador.observe(consola, { childList: true });
6324
6647
  return () => observador.disconnect();
6325
6648
  }, []);
6326
- return /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
6327
- import_material29.Box,
6649
+ return /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
6650
+ import_material30.Box,
6328
6651
  {
6329
6652
  id: "mini-console",
6330
6653
  sx: (tema) => ({
@@ -6412,15 +6735,8 @@ function resolverPantallaBP(myOwn, nombre, contenedor) {
6412
6735
  return null;
6413
6736
  }
6414
6737
 
6415
- // src/puente/habilitacion.ts
6416
- var habilitado = false;
6417
- var habilitarPuenteBP = () => {
6418
- habilitado = true;
6419
- };
6420
- var puenteBPHabilitado = () => habilitado;
6421
-
6422
6738
  // src/puente/PantallaBP.tsx
6423
- var import_jsx_runtime37 = require("react/jsx-runtime");
6739
+ var import_jsx_runtime38 = require("react/jsx-runtime");
6424
6740
  function buscarItemDeMenu(items, tipo) {
6425
6741
  for (const item of items) {
6426
6742
  if (item.menuType === tipo) return item;
@@ -6469,43 +6785,43 @@ var PantallaBP = ({ nombre, direccion }) => {
6469
6785
  elemento.replaceChildren();
6470
6786
  };
6471
6787
  }, [nombre, direccion, menu]);
6472
- if (noExiste) return /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(FallbackWScreen, { screenName: nombre });
6788
+ if (noExiste) return /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(FallbackWScreen, { screenName: nombre });
6473
6789
  return (
6474
6790
  // el indicador de carga flota: si ocupara lugar, el contenido de backend-plus empezaría más abajo mientras carga y subiría al terminar
6475
- /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)(import_material30.Box, { sx: { position: "relative" }, children: [
6476
- cargando && /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(import_material30.CircularProgress, { size: 24, sx: { position: "absolute", top: 16, left: 16 } }),
6477
- error && /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(import_material30.Alert, { severity: "error", sx: { m: 2 }, children: error }),
6478
- /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("div", { id: "main_layout", ref: contenedor }),
6479
- /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(ConsolaBP, {})
6791
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)(import_material31.Box, { sx: { position: "relative" }, children: [
6792
+ cargando && /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(import_material31.CircularProgress, { size: 24, sx: { position: "absolute", top: 16, left: 16 } }),
6793
+ error && /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(import_material31.Alert, { severity: "error", sx: { m: 2 }, children: error }),
6794
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("div", { id: "main_layout", ref: contenedor }),
6795
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(ConsolaBP, {})
6480
6796
  ] })
6481
6797
  );
6482
6798
  };
6483
6799
  var PantallaDeRespaldo = () => {
6484
- const { screenName = "" } = (0, import_react_router_dom12.useParams)();
6485
- const { search } = (0, import_react_router_dom12.useLocation)();
6800
+ const { screenName = "" } = (0, import_react_router_dom14.useParams)();
6801
+ const { search } = (0, import_react_router_dom14.useLocation)();
6486
6802
  if (!puenteBPHabilitado()) {
6487
- return /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(import_material30.Box, { sx: { p: 3 }, children: /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(FallbackWScreen, { screenName }) });
6803
+ return /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(import_material31.Box, { sx: { p: 3 }, children: /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(FallbackWScreen, { screenName }) });
6488
6804
  }
6489
- return /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(import_react_router_dom12.Navigate, { to: rutaDePantallaBP(screenName, search), replace: true });
6805
+ return /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(import_react_router_dom14.Navigate, { to: rutaDePantallaBP(screenName, search), replace: true });
6490
6806
  };
6491
6807
  var PaginaBP = () => {
6492
- const { hash, search } = (0, import_react_router_dom12.useLocation)();
6808
+ const { hash, search } = (0, import_react_router_dom14.useLocation)();
6493
6809
  const direccion = hash || search;
6494
6810
  const nombre = new URLSearchParams(direccion.replace(/^[#?]/, "")).get("w");
6495
- if (!puenteBPHabilitado()) return /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(import_react_router_dom12.Navigate, { to: "/", replace: true });
6496
- if (!nombre) return /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(import_material30.Box, { sx: { p: 3 }, children: /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)(import_material30.Alert, { severity: "warning", children: [
6811
+ if (!puenteBPHabilitado()) return /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(import_react_router_dom14.Navigate, { to: "/", replace: true });
6812
+ if (!nombre) return /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(import_material31.Box, { sx: { p: 3 }, children: /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)(import_material31.Alert, { severity: "warning", children: [
6497
6813
  "Falta la pantalla de backend-plus (",
6498
- /* @__PURE__ */ (0, import_jsx_runtime37.jsx)("code", { children: "#w=..." }),
6814
+ /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("code", { children: "#w=..." }),
6499
6815
  ")."
6500
6816
  ] }) });
6501
- return /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(PantallaBP, { nombre, direccion }, nombre);
6817
+ return /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(PantallaBP, { nombre, direccion }, nombre);
6502
6818
  };
6503
6819
 
6504
6820
  // src/puente/GrillaBP.tsx
6505
6821
  var import_react41 = require("react");
6506
- var import_react_router_dom13 = require("react-router-dom");
6507
- var import_material31 = require("@mui/material");
6508
- var import_jsx_runtime38 = (
6822
+ var import_react_router_dom15 = require("react-router-dom");
6823
+ var import_material32 = require("@mui/material");
6824
+ var import_jsx_runtime39 = (
6509
6825
  // el indicador de carga flota: si ocupara lugar, el contenido de backend-plus empezaría más abajo mientras carga y subiría al terminar
6510
6826
  require("react/jsx-runtime")
6511
6827
  );
@@ -6535,21 +6851,21 @@ var GrillaBP = ({ tabla, fixedFields }) => {
6535
6851
  elemento.replaceChildren();
6536
6852
  };
6537
6853
  }, [tabla, clave]);
6538
- return /* @__PURE__ */ (0, import_jsx_runtime38.jsxs)(import_material31.Box, { sx: { position: "relative" }, children: [
6539
- cargando && /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(import_material31.CircularProgress, { size: 24, sx: { position: "absolute", top: 16, left: 16 } }),
6540
- error && /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(import_material31.Alert, { severity: "error", sx: { m: 2 }, children: error }),
6541
- /* @__PURE__ */ (0, import_jsx_runtime38.jsx)("div", { ref: contenedor }),
6542
- /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(ConsolaBP, {})
6854
+ return /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)(import_material32.Box, { sx: { position: "relative" }, children: [
6855
+ cargando && /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(import_material32.CircularProgress, { size: 24, sx: { position: "absolute", top: 16, left: 16 } }),
6856
+ error && /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(import_material32.Alert, { severity: "error", sx: { m: 2 }, children: error }),
6857
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("div", { ref: contenedor }),
6858
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(ConsolaBP, {})
6543
6859
  ] });
6544
6860
  };
6545
6861
  var PaginaGrillaBP = () => {
6546
- const { tableName = "" } = (0, import_react_router_dom13.useParams)();
6547
- return /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(GrillaBP, { tabla: tableName }, tableName);
6862
+ const { tableName = "" } = (0, import_react_router_dom15.useParams)();
6863
+ return /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(GrillaBP, { tabla: tableName }, tableName);
6548
6864
  };
6549
6865
 
6550
6866
  // src/puente/CapturaBP.tsx
6551
6867
  var import_react42 = require("react");
6552
- var import_react_router_dom14 = require("react-router-dom");
6868
+ var import_react_router_dom16 = require("react-router-dom");
6553
6869
 
6554
6870
  // src/puente/capturaDeNavegacion.ts
6555
6871
  function apiDeNavegacion() {
@@ -6594,62 +6910,175 @@ function capturarNavegacionBP(urlBackend, navegar) {
6594
6910
 
6595
6911
  // src/puente/CapturaBP.tsx
6596
6912
  var CapturaBP = () => {
6597
- const navigate = (0, import_react_router_dom14.useNavigate)();
6913
+ const navigate = (0, import_react_router_dom16.useNavigate)();
6598
6914
  (0, import_react42.useEffect)(() => capturarNavegacionBP(envConfig.backendUrl, navigate), [navigate]);
6599
6915
  return null;
6600
6916
  };
6601
6917
 
6918
+ // src/pages/CambiarClavePage.tsx
6919
+ var import_react43 = require("react");
6920
+ var import_material33 = require("@mui/material");
6921
+ var import_react_router_dom17 = require("react-router-dom");
6922
+ var import_react_redux5 = require("react-redux");
6923
+
6924
+ // src/utils/cambiarClave.ts
6925
+ var MENSAJE_POR_OMISION = "No se pudo cambiar la contrase\xF1a";
6926
+ function resultadoDeCambioDeClave(urlFinal, html) {
6927
+ if (/\/login\/?(\?.*)?$/.test(urlFinal)) return { ok: true };
6928
+ const mensajes = Array.from(new DOMParser().parseFromString(html, "text/html").querySelectorAll(".error-message")).map((elemento) => (elemento.textContent ?? "").trim()).filter((mensaje) => mensaje !== "");
6929
+ return { ok: false, mensaje: mensajes.join("\n") || MENSAJE_POR_OMISION };
6930
+ }
6931
+
6932
+ // src/pages/CambiarClavePage.tsx
6933
+ var import_jsx_runtime40 = require("react/jsx-runtime");
6934
+ var CambiarClavePage = () => {
6935
+ const { clientContext, setIsLoggedIn, avisarCierreVoluntario } = useApp();
6936
+ const dispatch = (0, import_react_redux5.useDispatch)();
6937
+ const navigate = (0, import_react_router_dom17.useNavigate)();
6938
+ const [claveActual, setClaveActual] = (0, import_react43.useState)("");
6939
+ const [claveNueva, setClaveNueva] = (0, import_react43.useState)("");
6940
+ const [claveRepetida, setClaveRepetida] = (0, import_react43.useState)("");
6941
+ const [error, setError] = (0, import_react43.useState)(null);
6942
+ const [enviando, setEnviando] = (0, import_react43.useState)(false);
6943
+ const enviar = async (evento) => {
6944
+ evento.preventDefault();
6945
+ setError(null);
6946
+ if (claveNueva !== claveRepetida) {
6947
+ setError("La clave nueva y su repetici\xF3n no coinciden");
6948
+ return;
6949
+ }
6950
+ setEnviando(true);
6951
+ avisarCierreVoluntario(true);
6952
+ try {
6953
+ const respuesta = await fetchApi("/chpass", {
6954
+ method: "POST",
6955
+ body: new URLSearchParams({ oldPassword: claveActual, newPassword: claveNueva, repPassword: claveRepetida })
6956
+ });
6957
+ const resultado = resultadoDeCambioDeClave(respuesta.url, await respuesta.text());
6958
+ if (!resultado.ok) {
6959
+ avisarCierreVoluntario(false);
6960
+ setError(resultado.mensaje);
6961
+ return;
6962
+ }
6963
+ setIsLoggedIn(false);
6964
+ dispatch(clearClientContext());
6965
+ dispatch(setRedirectPath(null));
6966
+ navigate("/login", { replace: true, state: { claveCambiada: true } });
6967
+ } catch (err) {
6968
+ avisarCierreVoluntario(false);
6969
+ setError(mensajeDeError(err, "No se pudo cambiar la contrase\xF1a"));
6970
+ } finally {
6971
+ setEnviando(false);
6972
+ }
6973
+ };
6974
+ return /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(import_material33.Box, { sx: { p: 3, display: "flex", justifyContent: "center" }, children: /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)(import_material33.Box, { component: "form", onSubmit: enviar, sx: { width: "100%", maxWidth: 420 }, children: [
6975
+ /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(import_material33.Typography, { variant: "h5", gutterBottom: true, children: "Cambiar contrase\xF1a" }),
6976
+ /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(import_material33.TextField, { label: "Usuario", value: clientContext?.username ?? "", fullWidth: true, margin: "normal", disabled: true, autoComplete: "username" }),
6977
+ /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
6978
+ import_material33.TextField,
6979
+ {
6980
+ label: "Contrase\xF1a actual",
6981
+ type: "password",
6982
+ value: claveActual,
6983
+ onChange: (e) => setClaveActual(e.target.value),
6984
+ fullWidth: true,
6985
+ margin: "normal",
6986
+ autoFocus: true,
6987
+ required: true,
6988
+ autoComplete: "current-password",
6989
+ disabled: enviando
6990
+ }
6991
+ ),
6992
+ /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
6993
+ import_material33.TextField,
6994
+ {
6995
+ label: "Contrase\xF1a nueva",
6996
+ type: "password",
6997
+ value: claveNueva,
6998
+ onChange: (e) => setClaveNueva(e.target.value),
6999
+ fullWidth: true,
7000
+ margin: "normal",
7001
+ required: true,
7002
+ autoComplete: "new-password",
7003
+ disabled: enviando
7004
+ }
7005
+ ),
7006
+ /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
7007
+ import_material33.TextField,
7008
+ {
7009
+ label: "Repetir contrase\xF1a nueva",
7010
+ type: "password",
7011
+ value: claveRepetida,
7012
+ onChange: (e) => setClaveRepetida(e.target.value),
7013
+ fullWidth: true,
7014
+ margin: "normal",
7015
+ required: true,
7016
+ autoComplete: "new-password",
7017
+ disabled: enviando
7018
+ }
7019
+ ),
7020
+ error && /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(import_material33.Alert, { severity: "error", sx: { mt: 1, whiteSpace: "pre-line" }, children: error }),
7021
+ /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)(import_material33.Box, { sx: { display: "flex", gap: 1, justifyContent: "flex-end", mt: 2 }, children: [
7022
+ /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(import_material33.Button, { onClick: () => navigate(-1), disabled: enviando, children: "Cancelar" }),
7023
+ /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(import_material33.Button, { type: "submit", variant: "contained", disabled: enviando, children: enviando ? /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(import_material33.CircularProgress, { size: 20 }) : "Cambiar contrase\xF1a" })
7024
+ ] }),
7025
+ /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(import_material33.Typography, { variant: "caption", color: "text.secondary", sx: { display: "block", mt: 2 }, children: "Al cambiarla se cierra la sesi\xF3n: hay que ingresar de nuevo con la clave nueva." })
7026
+ ] }) });
7027
+ };
7028
+ var CambiarClavePage_default = CambiarClavePage;
7029
+
6602
7030
  // src/App.tsx
6603
7031
  var import_type_store6 = __toESM(require("type-store"), 1);
6604
- var import_jsx_runtime39 = require("react/jsx-runtime");
7032
+ var import_jsx_runtime41 = require("react/jsx-runtime");
6605
7033
  var LocationTracker = () => {
6606
- const location = (0, import_react_router_dom15.useLocation)();
7034
+ const location = (0, import_react_router_dom18.useLocation)();
6607
7035
  const dispatch = useAppDispatch();
6608
- (0, import_react43.useEffect)(() => {
7036
+ (0, import_react44.useEffect)(() => {
6609
7037
  dispatch(setCurrentPath(location.pathname + location.search));
6610
7038
  }, [location, dispatch]);
6611
7039
  return null;
6612
7040
  };
6613
7041
  function FrontendPlusReactRoutes({ myRoutes, myUnloggedRoutes, layout: Layout = MainLayout_default, unloggedLayout: UnloggedLayout }) {
6614
- return /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)(import_jsx_runtime39.Fragment, { children: [
6615
- /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(InitialRedirectHandler_default, {}),
6616
- puenteBPHabilitado() && /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(CapturaBP, {}),
6617
- /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)(import_react_router_dom15.Routes, { children: [
6618
- /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)(import_react_router_dom15.Route, { element: UnloggedLayout ? /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(UnloggedLayout, {}) : /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(import_react_router_dom15.Outlet, {}), children: [
6619
- /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(import_react_router_dom15.Route, { path: "/login", element: /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(LoginPage_default, {}) }),
6620
- /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(import_react_router_dom15.Route, { path: "/logout", element: /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(LogoutPage_default, {}) }),
7042
+ return /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)(import_jsx_runtime41.Fragment, { children: [
7043
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(InitialRedirectHandler_default, {}),
7044
+ puenteBPHabilitado() && /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(CapturaBP, {}),
7045
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)(import_react_router_dom18.Routes, { children: [
7046
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)(import_react_router_dom18.Route, { element: UnloggedLayout ? /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(UnloggedLayout, {}) : /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(import_react_router_dom18.Outlet, {}), children: [
7047
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(import_react_router_dom18.Route, { path: "/login", element: /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(LoginPage_default, {}) }),
7048
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(import_react_router_dom18.Route, { path: "/logout", element: /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(LogoutPage_default, {}) }),
6621
7049
  myUnloggedRoutes
6622
7050
  ] }),
6623
- /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)(import_react_router_dom15.Route, { element: /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(PrivateRoute_default, { children: /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(Layout, {}) }), children: [
6624
- /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(import_react_router_dom15.Route, { path: "/", element: /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(PantallaInicial_default, {}) }),
6625
- /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(import_react_router_dom15.Route, { path: "/table/:tableName", element: /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(GenericDataGridPage_default, {}) }),
6626
- /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(import_react_router_dom15.Route, { path: "/menu/:menuName", element: /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(MenuTablePage_default, {}) }),
6627
- /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(import_react_router_dom15.Route, { path: "/procedures/:procedureName", element: /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(ProcedureForm_default, {}) }),
6628
- Object.keys(wScreens).map((screenName) => /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
6629
- import_react_router_dom15.Route,
7051
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)(import_react_router_dom18.Route, { element: /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(PrivateRoute_default, { children: /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(Layout, {}) }), children: [
7052
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(import_react_router_dom18.Route, { path: "/", element: /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(PantallaInicial_default, {}) }),
7053
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(import_react_router_dom18.Route, { path: "/table/:tableName", element: /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(GenericDataGridPage_default, {}) }),
7054
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(import_react_router_dom18.Route, { path: "/menu/*", element: /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(MenuTablePage_default, {}) }),
7055
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(import_react_router_dom18.Route, { path: "/procedures/:procedureName", element: /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(ProcedureForm_default, {}) }),
7056
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(import_react_router_dom18.Route, { path: "/chpass", element: /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(CambiarClavePage_default, {}) }),
7057
+ Object.keys(wScreens).map((screenName) => /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
7058
+ import_react_router_dom18.Route,
6630
7059
  {
6631
7060
  path: `/wScreens/${screenName}`,
6632
- element: /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(PantallaDeRuta, { screenName })
7061
+ element: /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(PantallaDeRuta, { screenName })
6633
7062
  },
6634
7063
  screenName
6635
7064
  )),
6636
- /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(import_react_router_dom15.Route, { path: "/wScreens-fallback/:screenName", element: /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(PantallaDeRespaldo, {}) }),
6637
- puenteBPHabilitado() && /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(import_react_router_dom15.Route, { path: "/bp/menu", element: /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(PaginaBP, {}) }),
6638
- puenteBPHabilitado() && /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(import_react_router_dom15.Route, { path: "/bp/table/:tableName", element: /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(PaginaGrillaBP, {}) }),
7065
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(import_react_router_dom18.Route, { path: "/wScreens-fallback/:screenName", element: /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(PantallaDeRespaldo, {}) }),
7066
+ puenteBPHabilitado() && /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(import_react_router_dom18.Route, { path: "/bp/menu", element: /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(PaginaBP, {}) }),
7067
+ puenteBPHabilitado() && /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(import_react_router_dom18.Route, { path: "/bp/table/:tableName", element: /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(PaginaGrillaBP, {}) }),
6639
7068
  myRoutes,
6640
- /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(import_react_router_dom15.Route, { path: "*", element: /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("div", { style: { marginTop: "20px", marginLeft: "10px" }, children: "404 - Recurso No Encontrado" }) })
7069
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(import_react_router_dom18.Route, { path: "*", element: /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("div", { style: { marginTop: "20px", marginLeft: "10px" }, children: "404 - Recurso No Encontrado" }) })
6641
7070
  ] }),
6642
- /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(import_react_router_dom15.Route, { path: "*", element: /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(import_react_router_dom15.Navigate, { to: "/", replace: true }) })
7071
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(import_react_router_dom18.Route, { path: "*", element: /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(import_react_router_dom18.Navigate, { to: "/", replace: true }) })
6643
7072
  ] })
6644
7073
  ] });
6645
7074
  }
6646
7075
  var FrontendPlusProviders = ({ children, publicPaths }) => {
6647
- return /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(import_react_redux5.Provider, { store, children: /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(import_react44.PersistGate, { loading: null, persistor, children: /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)(import_react_router_dom15.BrowserRouter, { basename: rutaBase, children: [
6648
- /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(LocationTracker, {}),
7076
+ return /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(import_react_redux6.Provider, { store, children: /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(import_react45.PersistGate, { loading: null, persistor, children: /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)(import_react_router_dom18.BrowserRouter, { basename: rutaBase, children: [
7077
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(LocationTracker, {}),
6649
7078
  " ",
6650
- /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(AppProvider, { publicPaths, children: /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)(SnackbarProvider, { children: [
7079
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(AppProvider, { publicPaths, children: /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)(SnackbarProvider, { children: [
6651
7080
  children,
6652
- /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(SessionExpiredMessage_default, {})
7081
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(SessionExpiredMessage_default, {})
6653
7082
  ] }) })
6654
7083
  ] }) }) });
6655
7084
  };
@@ -6661,9 +7090,10 @@ var App = ({
6661
7090
  myClientSides,
6662
7091
  myResultsOk,
6663
7092
  myConditions,
6664
- puenteBP
7093
+ puenteBP,
7094
+ recuperarClave
6665
7095
  }) => {
6666
- (0, import_react43.useMemo)(() => {
7096
+ (0, import_react44.useMemo)(() => {
6667
7097
  if (myClientSides) {
6668
7098
  extendClientSides(myClientSides);
6669
7099
  }
@@ -6679,8 +7109,9 @@ var App = ({
6679
7109
  if (puenteBP) {
6680
7110
  habilitarPuenteBP();
6681
7111
  }
6682
- }, [myClientSides, myResultsOk, myWScreens, myConditions, puenteBP]);
6683
- (0, import_react43.useEffect)(() => {
7112
+ configurarRecuperarClave(recuperarClave);
7113
+ }, [myClientSides, myResultsOk, myWScreens, myConditions, puenteBP, recuperarClave]);
7114
+ (0, import_react44.useEffect)(() => {
6684
7115
  import_type_store6.default.messages = import_type_store6.default.i18n.messages.es;
6685
7116
  import_type_store6.default.locale = import_type_store6.default.i18n.locale.es;
6686
7117
  const link = document.querySelector("link[rel*='icon']") || document.createElement("link");
@@ -6689,11 +7120,11 @@ var App = ({
6689
7120
  link.href = `${envConfig.backendUrl}/img/logo-128.png`;
6690
7121
  document.getElementsByTagName("head")[0].appendChild(link);
6691
7122
  }, []);
6692
- const safePaths = import_react43.default.useMemo(() => {
7123
+ const safePaths = import_react44.default.useMemo(() => {
6693
7124
  const extracted = extractPathsFromRoutes(myUnloggedRoutes);
6694
7125
  return ["/login", "/logout", ...extracted];
6695
7126
  }, [myUnloggedRoutes]);
6696
- return /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(FrontendPlusProviders, { publicPaths: safePaths, children: /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
7127
+ return /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(FrontendPlusProviders, { publicPaths: safePaths, children: /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
6697
7128
  FrontendPlusReactRoutes,
6698
7129
  {
6699
7130
  myRoutes,