frontend-plus-react 0.1.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/LICENSE +21 -0
- package/README.md +2 -0
- package/dist/index.cjs +3393 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.css +79 -0
- package/dist/index.css.map +1 -0
- package/dist/index.d.cts +200 -0
- package/dist/index.d.ts +200 -0
- package/dist/index.js +3393 -0
- package/dist/index.js.map +1 -0
- package/package.json +79 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,3393 @@
|
|
|
1
|
+
var __create = Object.create;
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
6
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
+
var __commonJS = (cb, mod) => function __require() {
|
|
8
|
+
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
19
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
20
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
21
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
22
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
23
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
24
|
+
mod
|
|
25
|
+
));
|
|
26
|
+
|
|
27
|
+
// node_modules/json4all/json4all.js
|
|
28
|
+
var require_json4all = __commonJS({
|
|
29
|
+
"node_modules/json4all/json4all.js"(exports, module) {
|
|
30
|
+
"use strict";
|
|
31
|
+
(function codenautasModuleDefinition(root, name, factory) {
|
|
32
|
+
if (typeof root.globalModuleName !== "string") {
|
|
33
|
+
root.globalModuleName = name;
|
|
34
|
+
}
|
|
35
|
+
if (typeof exports === "object" && typeof module === "object") {
|
|
36
|
+
module.exports = factory();
|
|
37
|
+
} else if (typeof define === "function" && define.amd) {
|
|
38
|
+
define(factory);
|
|
39
|
+
} else if (typeof exports === "object") {
|
|
40
|
+
exports[root.globalModuleName] = factory();
|
|
41
|
+
} else {
|
|
42
|
+
root[root.globalModuleName] = factory();
|
|
43
|
+
}
|
|
44
|
+
root.globalModuleName = null;
|
|
45
|
+
})(
|
|
46
|
+
/*jshint -W040 */
|
|
47
|
+
exports,
|
|
48
|
+
"json4all",
|
|
49
|
+
function() {
|
|
50
|
+
var json4all = {};
|
|
51
|
+
json4all.PretendedClass = Symbol("Pretended Class");
|
|
52
|
+
function functionName(fun) {
|
|
53
|
+
if ("name" in fun) {
|
|
54
|
+
return fun.name;
|
|
55
|
+
} else {
|
|
56
|
+
return fun.toString().replace(/^\s*function\s*([^(]*)\((.|\s)*$/i, "$1");
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
function constructorName(obj) {
|
|
60
|
+
return functionName(obj[json4all.PretendedClass] || obj.constructor);
|
|
61
|
+
}
|
|
62
|
+
var root;
|
|
63
|
+
if (typeof window !== "undefined") {
|
|
64
|
+
root = window;
|
|
65
|
+
} else {
|
|
66
|
+
root = global;
|
|
67
|
+
}
|
|
68
|
+
root.json4allRegisteredTypes = root.json4allRegisteredTypes || {};
|
|
69
|
+
var types = root.json4allRegisteredTypes;
|
|
70
|
+
var thisPlatformSkipsUndefinedInArrays = true;
|
|
71
|
+
JSON.stringify([void 0], function(key, value) {
|
|
72
|
+
if (key === "0" || key === 0) {
|
|
73
|
+
thisPlatformSkipsUndefinedInArrays = false;
|
|
74
|
+
}
|
|
75
|
+
return value;
|
|
76
|
+
});
|
|
77
|
+
var thisPlatformHasReplacerBug = false;
|
|
78
|
+
JSON.parse('{"3":"33"}', function(key, value) {
|
|
79
|
+
if (value === void 0) {
|
|
80
|
+
thisPlatformHasReplacerBug = true;
|
|
81
|
+
}
|
|
82
|
+
return value;
|
|
83
|
+
});
|
|
84
|
+
function InternalValueForUndefined() {
|
|
85
|
+
throw new Error("this is not a function");
|
|
86
|
+
}
|
|
87
|
+
function InternalValueForUnset() {
|
|
88
|
+
throw new Error("this is not a function");
|
|
89
|
+
}
|
|
90
|
+
json4all.directTypes = {
|
|
91
|
+
"Object": true,
|
|
92
|
+
"Array": true,
|
|
93
|
+
"anonymous": true,
|
|
94
|
+
"": true
|
|
95
|
+
};
|
|
96
|
+
json4all.anonymizate = function(classedObject) {
|
|
97
|
+
var plainObject = {};
|
|
98
|
+
for (var attr in classedObject) {
|
|
99
|
+
plainObject[attr] = classedObject[attr];
|
|
100
|
+
}
|
|
101
|
+
return plainObject;
|
|
102
|
+
};
|
|
103
|
+
json4all.nonymizate = function(plainValue, Constructor) {
|
|
104
|
+
var typedValue = new Constructor();
|
|
105
|
+
for (var attr in plainValue) {
|
|
106
|
+
typedValue[attr] = plainValue[attr];
|
|
107
|
+
}
|
|
108
|
+
return typedValue;
|
|
109
|
+
};
|
|
110
|
+
json4all.replacer = function replacer(key, value) {
|
|
111
|
+
var realValue = this[key];
|
|
112
|
+
if (realValue === InternalValueForUndefined) {
|
|
113
|
+
this[key] = void 0;
|
|
114
|
+
return { $special: "undefined" };
|
|
115
|
+
}
|
|
116
|
+
if (key !== "" && (!(key in this) || realValue !== null && realValue instanceof Function)) {
|
|
117
|
+
return { $special: "unset" };
|
|
118
|
+
}
|
|
119
|
+
if (realValue === void 0 || typeof realValue === "undefined" || realValue !== null && realValue instanceof Function) {
|
|
120
|
+
return { $special: "undefined" };
|
|
121
|
+
}
|
|
122
|
+
if (realValue === null || typeof realValue !== "object" || key === "$escape") {
|
|
123
|
+
return value;
|
|
124
|
+
}
|
|
125
|
+
if ("$special" in realValue || "$escape" in realValue) {
|
|
126
|
+
return { $escape: realValue };
|
|
127
|
+
}
|
|
128
|
+
if (thisPlatformSkipsUndefinedInArrays && realValue instanceof Array) {
|
|
129
|
+
for (var i = 0; i < realValue.length; i++) {
|
|
130
|
+
if (typeof realValue[i] === "undefined") {
|
|
131
|
+
realValue[i] = InternalValueForUndefined;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
return realValue;
|
|
135
|
+
}
|
|
136
|
+
var typeName = constructorName(realValue);
|
|
137
|
+
if (json4all.directTypes[typeName]) {
|
|
138
|
+
return value;
|
|
139
|
+
} else {
|
|
140
|
+
var typeDef = types[typeName];
|
|
141
|
+
if (typeDef) {
|
|
142
|
+
var replaced = { $special: typeDef.specialTag(realValue), $value: typeDef.deconstruct(realValue) };
|
|
143
|
+
var ref = realValue[RefKey];
|
|
144
|
+
if (ref !== void 0) {
|
|
145
|
+
replaced.$ref = ref;
|
|
146
|
+
if (json4all.$RefStoreSpace == null) {
|
|
147
|
+
delete replaced.$value;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
return replaced;
|
|
151
|
+
} else {
|
|
152
|
+
console.log("JSON4all.stringify unregistered object type", typeName);
|
|
153
|
+
throw new Error("JSON4all.stringify unregistered object type");
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
};
|
|
157
|
+
json4all.reviver = function reviver(key, plainValue) {
|
|
158
|
+
var log = false;
|
|
159
|
+
var result;
|
|
160
|
+
if (key === "$escape") {
|
|
161
|
+
return plainValue;
|
|
162
|
+
} else if (plainValue !== null && plainValue.$ref && json4all.$RefStoreSpace) {
|
|
163
|
+
var collection = json4all.$RefStoreSpace[plainValue.$ref[0][0]];
|
|
164
|
+
if (!collection) {
|
|
165
|
+
throw new Error("json4all ref collection invalid");
|
|
166
|
+
}
|
|
167
|
+
var object2 = collection[plainValue.$ref[1]];
|
|
168
|
+
if (!object2) {
|
|
169
|
+
throw new Error("json4all ref key invalid");
|
|
170
|
+
}
|
|
171
|
+
return object2;
|
|
172
|
+
} else if (plainValue !== null && plainValue.$special) {
|
|
173
|
+
if (plainValue.$special === "undefined") {
|
|
174
|
+
if (key === "") {
|
|
175
|
+
return void 0;
|
|
176
|
+
}
|
|
177
|
+
return InternalValueForUndefined;
|
|
178
|
+
} else if (plainValue.$special === "unset") {
|
|
179
|
+
return void 0;
|
|
180
|
+
} else {
|
|
181
|
+
var typeDef = types[plainValue.$special];
|
|
182
|
+
if (typeDef) {
|
|
183
|
+
result = new typeDef.construct(plainValue.$value, typeDef.constructor);
|
|
184
|
+
} else {
|
|
185
|
+
console.log("JSON4all.parse invalid $special", plainValue.$special);
|
|
186
|
+
throw new Error("JSON4all.parse invalid $special");
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
} else if (plainValue !== null && plainValue.$escape) {
|
|
190
|
+
return plainValue.$escape;
|
|
191
|
+
} else {
|
|
192
|
+
result = plainValue;
|
|
193
|
+
if (plainValue instanceof Object) {
|
|
194
|
+
for (var k in plainValue) {
|
|
195
|
+
if (plainValue[k] === InternalValueForUndefined) {
|
|
196
|
+
plainValue[k] = void 0;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
if (plainValue != null && plainValue.$ref) {
|
|
202
|
+
result[RefKey] = plainValue.$ref;
|
|
203
|
+
}
|
|
204
|
+
return result;
|
|
205
|
+
};
|
|
206
|
+
var directRegExp = /^((null|true|false)$|[-\]\[{}".0-9])/;
|
|
207
|
+
var directStringRegExp = /^[a-zA-ZÑñáéíóúüÁÉÍÓÚÜ_@-][0-9a-zA-ZÑñáéíóúüÁÉÍÓÚÜ_@-]{0,32}$/;
|
|
208
|
+
var AttributeNameRegExp = /^[a-zA-ZÑñáéíóúüÁÉÍÓÚÜ_@-][0-9a-zA-ZÑñáéíóúüÁÉÍÓÚÜ_@-]*($|,)/;
|
|
209
|
+
json4all.stringifyAnyPlace = function stringifyAnyPlace(value) {
|
|
210
|
+
return JSON.stringify(value, json4all.replacer);
|
|
211
|
+
};
|
|
212
|
+
var CHANNEL = {
|
|
213
|
+
object: { separator: ",", pairSeparator: ":", empty: function() {
|
|
214
|
+
return {};
|
|
215
|
+
} },
|
|
216
|
+
array: { separator: ";", pairSeparator: null, empty: function() {
|
|
217
|
+
return [];
|
|
218
|
+
} }
|
|
219
|
+
};
|
|
220
|
+
var SEPARATOR = { ",": "object", ";": "array" };
|
|
221
|
+
function maxConsumer() {
|
|
222
|
+
var fun = function(node) {
|
|
223
|
+
for (var channel2 in CHANNEL) {
|
|
224
|
+
if (node[channel2] > fun[channel2]) fun[channel2] = node[channel2];
|
|
225
|
+
}
|
|
226
|
+
return node.value;
|
|
227
|
+
};
|
|
228
|
+
for (var channel in CHANNEL) {
|
|
229
|
+
fun[channel] = null;
|
|
230
|
+
}
|
|
231
|
+
return fun;
|
|
232
|
+
}
|
|
233
|
+
function simpleValue(value) {
|
|
234
|
+
return { value, object: 0, array: 0 };
|
|
235
|
+
}
|
|
236
|
+
json4all.maxConsumer = maxConsumer;
|
|
237
|
+
json4all.mesureString = function mesureString(value) {
|
|
238
|
+
var currentSeparator = null;
|
|
239
|
+
var currentLength = 0;
|
|
240
|
+
var result = simpleValue(value);
|
|
241
|
+
for (var char of value) {
|
|
242
|
+
var channel = SEPARATOR[char];
|
|
243
|
+
if (channel) {
|
|
244
|
+
if (currentSeparator != char) {
|
|
245
|
+
currentLength = 0;
|
|
246
|
+
currentSeparator = char;
|
|
247
|
+
}
|
|
248
|
+
currentLength++;
|
|
249
|
+
if (currentLength > result[channel]) result[channel] = currentLength;
|
|
250
|
+
} else {
|
|
251
|
+
currentSeparator = null;
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
return result;
|
|
255
|
+
};
|
|
256
|
+
json4all.quoteString = function quoteString(text, escapeColon) {
|
|
257
|
+
var value = directStringRegExp.test(text) && !directRegExp.test(text) ? text : JSON.stringify(text);
|
|
258
|
+
if (escapeColon) value = value.replace(/:/g, "\\u003a");
|
|
259
|
+
return json4all.mesureString(value);
|
|
260
|
+
};
|
|
261
|
+
var STAR = "*";
|
|
262
|
+
var BANG = "!";
|
|
263
|
+
json4all.toUrl = function toUrl(value) {
|
|
264
|
+
return json4all.toUrlConstruct(value).value;
|
|
265
|
+
};
|
|
266
|
+
json4all.toUrlLines = function toUrlLines(value, eol) {
|
|
267
|
+
return json4all.toUrlConstruct(value, eol ? eol : "\n").value;
|
|
268
|
+
};
|
|
269
|
+
var repeat = (str, count) => Array.prototype.concat(new Array(count + 1)).join(str);
|
|
270
|
+
json4all.toUrlConstruct = function toUrlConstruct(value, addEol) {
|
|
271
|
+
if (value === null) return simpleValue("null");
|
|
272
|
+
if (value === void 0) return simpleValue("!undefined");
|
|
273
|
+
if (value instanceof Function) return simpleValue("!unset");
|
|
274
|
+
var typeName = constructorName(value);
|
|
275
|
+
if (typeof value === "string") {
|
|
276
|
+
return json4all.quoteString(value);
|
|
277
|
+
} else if (value && typeof value === "object" && !value[RefKey]) {
|
|
278
|
+
if (!json4all.directTypes[typeName]) {
|
|
279
|
+
var typeDef = types[typeName];
|
|
280
|
+
if (typeDef) {
|
|
281
|
+
var serializedValue = typeDef.serialize(value);
|
|
282
|
+
if (typeof serializedValue === "string") return json4all.mesureString(serializedValue);
|
|
283
|
+
return serializedValue;
|
|
284
|
+
} else {
|
|
285
|
+
console.log("JSON4all.stringify unregistered object type", typeName);
|
|
286
|
+
throw new Error("JSON4all.stringify unregistered object type");
|
|
287
|
+
}
|
|
288
|
+
} else {
|
|
289
|
+
var thisChannel = value instanceof Array ? "array" : "object";
|
|
290
|
+
var parts = [];
|
|
291
|
+
var result = simpleValue(null);
|
|
292
|
+
var cantSimplify = false;
|
|
293
|
+
var max = maxConsumer();
|
|
294
|
+
if (thisChannel == "array") {
|
|
295
|
+
for (var i = 0; i < value.length; i++) {
|
|
296
|
+
var pair = [max(json4all.toUrlConstruct(value[i]))];
|
|
297
|
+
parts.push(pair);
|
|
298
|
+
}
|
|
299
|
+
} else {
|
|
300
|
+
for (var attr in value) {
|
|
301
|
+
var pair = [max(json4all.quoteString(attr, true)), max(json4all.toUrlConstruct(value[attr]))];
|
|
302
|
+
parts.push(pair);
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
for (var channel in CHANNEL) {
|
|
306
|
+
result[channel] = (max[channel] || 0) + (channel == thisChannel ? 1 : 0);
|
|
307
|
+
}
|
|
308
|
+
var PairSep = ":";
|
|
309
|
+
var lengthSep = result[thisChannel];
|
|
310
|
+
var ListSep = addEol ? addEol : repeat(CHANNEL[thisChannel].separator, lengthSep);
|
|
311
|
+
result.value = (addEol ? "!json4all" + CHANNEL[thisChannel].separator : "") + ListSep + parts.map((pair2) => pair2.join(PairSep)).join(ListSep);
|
|
312
|
+
if (!cantSimplify && parts.length) {
|
|
313
|
+
return result;
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
return json4all.mesureString(JSON.stringify(value, json4all.replacer));
|
|
318
|
+
};
|
|
319
|
+
json4all.stringify = json4all.stringifyAnyPlace;
|
|
320
|
+
json4all.convertPlain2$special = function convertPlain2$special(o, internally) {
|
|
321
|
+
if (o != null && o instanceof Object) {
|
|
322
|
+
for (var key in o) {
|
|
323
|
+
var realKey = o[key] === void 0 && !isNaN(key) ? Number(key) : key;
|
|
324
|
+
json4all.convertPlain2$special(o[key], true);
|
|
325
|
+
var newValue = json4all.reviver(key, o[key]);
|
|
326
|
+
if (newValue === void 0 && !(o instanceof Array)) {
|
|
327
|
+
delete o[key];
|
|
328
|
+
} else {
|
|
329
|
+
o[key] = newValue;
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
if (!internally) {
|
|
334
|
+
return json4all.reviver("", o);
|
|
335
|
+
}
|
|
336
|
+
};
|
|
337
|
+
json4all.isTesting = true;
|
|
338
|
+
json4all.getPlainObject = function getPlainObject(payload, separator, initial, PairSep) {
|
|
339
|
+
var i = 0;
|
|
340
|
+
if (separator instanceof RegExp) {
|
|
341
|
+
var ListSep = separator;
|
|
342
|
+
} else {
|
|
343
|
+
var ListSep = "";
|
|
344
|
+
while (i < payload.length && payload[i] === separator) {
|
|
345
|
+
i++;
|
|
346
|
+
ListSep += separator;
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
var result = initial;
|
|
350
|
+
var parts = payload.split(ListSep).slice(1);
|
|
351
|
+
var index = -1;
|
|
352
|
+
for (var part of parts) {
|
|
353
|
+
if (PairSep) {
|
|
354
|
+
var pos = part.indexOf(PairSep);
|
|
355
|
+
if (pos < 0) {
|
|
356
|
+
throw new Error('JSON4all.parse error. Lack of colon "' + PairSep + '" in object');
|
|
357
|
+
}
|
|
358
|
+
var value = part.substr(pos + PairSep.length);
|
|
359
|
+
var index = json4all.parse(part.substr(0, pos));
|
|
360
|
+
} else {
|
|
361
|
+
var value = part;
|
|
362
|
+
index++;
|
|
363
|
+
}
|
|
364
|
+
var value = json4all.parse(value, true);
|
|
365
|
+
if (value !== InternalValueForUnset) {
|
|
366
|
+
result[index] = value;
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
return result;
|
|
370
|
+
};
|
|
371
|
+
json4all.parse = function parse2(text, inner) {
|
|
372
|
+
var payload = text[0] === STAR ? text.substr(1) : text;
|
|
373
|
+
if (payload[0] === BANG) {
|
|
374
|
+
payload = payload.substr(1);
|
|
375
|
+
if (payload === "undefined") return void 0;
|
|
376
|
+
if (payload === "unset") {
|
|
377
|
+
return inner ? InternalValueForUnset : void 0;
|
|
378
|
+
}
|
|
379
|
+
if (payload[0] == "@") {
|
|
380
|
+
var commaPosition = payload.indexOf(",");
|
|
381
|
+
var className = payload.substr(1, commaPosition - 1);
|
|
382
|
+
var typeDef = types[className];
|
|
383
|
+
if (!typeDef) {
|
|
384
|
+
throw new Error("JSON4all.parse unrecognize className " + className);
|
|
385
|
+
}
|
|
386
|
+
return typeDef.deserialize(payload).value;
|
|
387
|
+
}
|
|
388
|
+
if (payload[0] == "/") {
|
|
389
|
+
var typeDef = types.RegExp;
|
|
390
|
+
return typeDef.deserialize(payload).value;
|
|
391
|
+
}
|
|
392
|
+
if (payload.substr(0, 8) == "json4all") {
|
|
393
|
+
var iSeparator = SEPARATOR[payload[8]];
|
|
394
|
+
if (iSeparator) {
|
|
395
|
+
var channel = CHANNEL[iSeparator];
|
|
396
|
+
if (channel) {
|
|
397
|
+
var eol = payload[9] == "\r" && payload[10] == "\n" ? "\r\n" : payload[9] == "\n" ? "\n" : null;
|
|
398
|
+
if (eol) {
|
|
399
|
+
return json4all.getPlainObject(payload.substr(8 + eol.length), /\r?\n/, channel.empty(), channel.pairSeparator);
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
throw new Error("JSON4all.parse unrecognize ! token");
|
|
405
|
+
}
|
|
406
|
+
if (SEPARATOR[payload[0]]) {
|
|
407
|
+
var channel = CHANNEL[SEPARATOR[payload[0]]];
|
|
408
|
+
return json4all.getPlainObject(payload, channel.separator, channel.empty(), channel.pairSeparator);
|
|
409
|
+
}
|
|
410
|
+
for (var typeName in types) {
|
|
411
|
+
var typeDef = types[typeName];
|
|
412
|
+
var okDetected = null;
|
|
413
|
+
if (!typeDef.deserialize) {
|
|
414
|
+
throw new Error("JSON4all.parse type without deserialize: " + typeName);
|
|
415
|
+
}
|
|
416
|
+
var valueOk = null;
|
|
417
|
+
var { ok, value } = typeDef.deserialize(payload);
|
|
418
|
+
if (ok) {
|
|
419
|
+
valueOk = value;
|
|
420
|
+
if (json4all.isTesting) {
|
|
421
|
+
if (okDetected) {
|
|
422
|
+
console.log("More than one way", typeName, okDetected, text, value, valueOk);
|
|
423
|
+
throw Error("");
|
|
424
|
+
}
|
|
425
|
+
okDetected = typeName;
|
|
426
|
+
}
|
|
427
|
+
break;
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
if (okDetected) return valueOk;
|
|
431
|
+
if (typeof text === "string" && !directRegExp.test(text)) {
|
|
432
|
+
return text;
|
|
433
|
+
}
|
|
434
|
+
if (thisPlatformHasReplacerBug) {
|
|
435
|
+
var parsed = JSON.parse(text);
|
|
436
|
+
return json4all.convertPlain2$special(parsed);
|
|
437
|
+
} else {
|
|
438
|
+
return JSON.parse(text, json4all.reviver);
|
|
439
|
+
}
|
|
440
|
+
};
|
|
441
|
+
json4all.addType = function addType(typeConstructor, functions, skipIfExists) {
|
|
442
|
+
functions = functions || {};
|
|
443
|
+
var constructorName2 = typeof typeConstructor === "string" ? typeConstructor : functionName(typeConstructor);
|
|
444
|
+
if (skipIfExists && types[constructorName2]) {
|
|
445
|
+
return;
|
|
446
|
+
}
|
|
447
|
+
var prefix = "@" + constructorName2;
|
|
448
|
+
types[constructorName2] = {
|
|
449
|
+
construct: functions.construct || function construct(plainValue, constructor2) {
|
|
450
|
+
return typeConstructor.JSON4reviver(plainValue, constructor2);
|
|
451
|
+
},
|
|
452
|
+
deconstruct: functions.deconstruct || function deconstruct(o) {
|
|
453
|
+
return o.JSON4replacer();
|
|
454
|
+
},
|
|
455
|
+
specialTag: functions.specialTag || function specialTag(value) {
|
|
456
|
+
return constructorName2;
|
|
457
|
+
},
|
|
458
|
+
serialize: functions.serialize || function serialize(o) {
|
|
459
|
+
var plainObject = "JSON4replacer" in typeConstructor.prototype ? o.JSON4replacer() : functions.deconstruct(o);
|
|
460
|
+
var result = json4all.toUrlConstruct(plainObject);
|
|
461
|
+
result.value = BANG + prefix + result.value;
|
|
462
|
+
return result;
|
|
463
|
+
},
|
|
464
|
+
deserialize: functions.deserialize || function deserialize(plainValue) {
|
|
465
|
+
if (plainValue.startsWith(prefix + ",")) {
|
|
466
|
+
var plainObject = json4all.parse(STAR + plainValue.substr(prefix.length), constructor);
|
|
467
|
+
return {
|
|
468
|
+
ok: true,
|
|
469
|
+
value: "JSON4replacer" in typeConstructor.prototype ? typeConstructor.JSON4reviver(plainObject, typeConstructor) : functions.construct(plainObject, typeConstructor)
|
|
470
|
+
};
|
|
471
|
+
}
|
|
472
|
+
return { ok: false };
|
|
473
|
+
},
|
|
474
|
+
valueLike: functions.valueLike || typeConstructor.JSON4valueLike
|
|
475
|
+
};
|
|
476
|
+
if (typeof typeConstructor === "function") {
|
|
477
|
+
types[constructorName2].constructor = typeConstructor;
|
|
478
|
+
}
|
|
479
|
+
};
|
|
480
|
+
var NativeDateRegExp = /^\d\d\d\d-\d\d-\d\dT\d\d:\d\d:\d\d(\.\d*)?Z$/;
|
|
481
|
+
json4all.DateFunctions = {
|
|
482
|
+
construct: function construct(plainValue) {
|
|
483
|
+
return new Date(plainValue);
|
|
484
|
+
},
|
|
485
|
+
deconstruct: function deconstruct(o) {
|
|
486
|
+
return o.getTime();
|
|
487
|
+
},
|
|
488
|
+
serialize: function serialize(o) {
|
|
489
|
+
return o.toISOString();
|
|
490
|
+
},
|
|
491
|
+
deserialize: function deserialize(plainValue) {
|
|
492
|
+
var ok = NativeDateRegExp.test(plainValue);
|
|
493
|
+
var value = ok && new Date(plainValue) || null;
|
|
494
|
+
return { ok, value };
|
|
495
|
+
},
|
|
496
|
+
valueLike: true
|
|
497
|
+
};
|
|
498
|
+
json4all.addType(Date, json4all.DateFunctions, true);
|
|
499
|
+
json4all.addType(RegExp, {
|
|
500
|
+
construct: function construct(plainValue) {
|
|
501
|
+
return new RegExp(plainValue.source, plainValue.flags);
|
|
502
|
+
},
|
|
503
|
+
deconstruct: function deconstruct(o) {
|
|
504
|
+
return { source: o.source, flags: o.toString().substr(o.toString().lastIndexOf("/") + 1) };
|
|
505
|
+
},
|
|
506
|
+
serialize: function serialize(o) {
|
|
507
|
+
return BANG + "/" + o.source + "/" + o.flags;
|
|
508
|
+
},
|
|
509
|
+
deserialize: function deserialize(plainValue) {
|
|
510
|
+
var ok = false;
|
|
511
|
+
var value = null;
|
|
512
|
+
plainValue.replace(/^\/(.+)\/(\w*)$/, function(_, pattern, flags) {
|
|
513
|
+
value = new RegExp(pattern, flags);
|
|
514
|
+
ok = true;
|
|
515
|
+
});
|
|
516
|
+
return { ok, value };
|
|
517
|
+
},
|
|
518
|
+
valueLike: true
|
|
519
|
+
});
|
|
520
|
+
json4all._types = types;
|
|
521
|
+
const RefKey = Symbol("RefKey for RefMap");
|
|
522
|
+
json4all.RefKey = RefKey;
|
|
523
|
+
json4all.RefStoreSpace = (myCollection) => {
|
|
524
|
+
json4all.$RefStoreSpace = myCollection;
|
|
525
|
+
};
|
|
526
|
+
json4all.RefStore = (path) => {
|
|
527
|
+
var myCollection = json4all.$RefStoreSpace;
|
|
528
|
+
var o = {};
|
|
529
|
+
var p = new Proxy(o, {
|
|
530
|
+
/*
|
|
531
|
+
get:function(target, prop, _receiver) {
|
|
532
|
+
return target[prop];
|
|
533
|
+
},
|
|
534
|
+
*/
|
|
535
|
+
/** @param {Partial<{[key in K]:V}>} target */
|
|
536
|
+
/** @param {K} prop */
|
|
537
|
+
/** @param {V} value */
|
|
538
|
+
set: function(target, prop, value) {
|
|
539
|
+
if (
|
|
540
|
+
// @ts-expect-error RefKey no está en el tipo original
|
|
541
|
+
value[RefKey] == null
|
|
542
|
+
) {
|
|
543
|
+
value[RefKey] = [path, prop];
|
|
544
|
+
} else if (
|
|
545
|
+
// @ts-expect-error RefKey no está en el tipo original
|
|
546
|
+
value[RefKey][1] != prop
|
|
547
|
+
) {
|
|
548
|
+
console.log("This value was stored in another place", path, prop);
|
|
549
|
+
throw new Error("This value was stored in another place");
|
|
550
|
+
}
|
|
551
|
+
return Reflect.set(target, prop, value);
|
|
552
|
+
}
|
|
553
|
+
});
|
|
554
|
+
myCollection[path[0]] = p;
|
|
555
|
+
return p;
|
|
556
|
+
};
|
|
557
|
+
json4all.$props2serialize = Symbol("props2serialize");
|
|
558
|
+
json4all.addProperty = function(constructorPosition) {
|
|
559
|
+
var innerFunction = (classPrototype, prop, index) => {
|
|
560
|
+
if (!(json4all.$props2serialize in classPrototype)) {
|
|
561
|
+
classPrototype[json4all.$props2serialize] = [];
|
|
562
|
+
}
|
|
563
|
+
var info = { name: prop };
|
|
564
|
+
if (typeof constructorPosition === "number") info.construct = constructorPosition;
|
|
565
|
+
classPrototype[json4all.$props2serialize].push(info);
|
|
566
|
+
};
|
|
567
|
+
if (typeof constructorPosition === "number") {
|
|
568
|
+
return innerFunction;
|
|
569
|
+
} else {
|
|
570
|
+
return innerFunction.apply(null, arguments);
|
|
571
|
+
}
|
|
572
|
+
};
|
|
573
|
+
json4all.pretendClass = function(object2, Constructor) {
|
|
574
|
+
object2[json4all.PretendedClass] = Constructor;
|
|
575
|
+
object2.JSON4replacer = Constructor.prototype.JSON4replacer;
|
|
576
|
+
};
|
|
577
|
+
json4all.addClass = (constructor2) => {
|
|
578
|
+
if (!(json4all.$props2serialize in constructor2.prototype)) {
|
|
579
|
+
throw new Error("must add parameters or properties");
|
|
580
|
+
}
|
|
581
|
+
var propList = constructor2.prototype[json4all.$props2serialize];
|
|
582
|
+
constructor2.prototype.JSON4replacer = function() {
|
|
583
|
+
var o = {};
|
|
584
|
+
for (var prop of propList) {
|
|
585
|
+
o[prop.name] = this[prop.name];
|
|
586
|
+
}
|
|
587
|
+
return o;
|
|
588
|
+
};
|
|
589
|
+
constructor2.JSON4reviver = function(value, constructor3) {
|
|
590
|
+
var constructParams = propList.filter((p2) => p2.construct != null).map((p2) => value[p2.name]);
|
|
591
|
+
var o = new constructor3(...constructParams);
|
|
592
|
+
for (var p of propList) {
|
|
593
|
+
if (!p.construct) {
|
|
594
|
+
o[p.name] = value[p.name];
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
return o;
|
|
598
|
+
};
|
|
599
|
+
json4all.addType(constructor2);
|
|
600
|
+
};
|
|
601
|
+
return json4all;
|
|
602
|
+
}
|
|
603
|
+
);
|
|
604
|
+
}
|
|
605
|
+
});
|
|
606
|
+
|
|
607
|
+
// src/components/grid/GenericDataGrid.tsx
|
|
608
|
+
import { useState as useState4, useEffect, useCallback as useCallback4, useMemo as useMemo2, useRef } from "react";
|
|
609
|
+
import { DataGrid } from "react-data-grid";
|
|
610
|
+
import "react-data-grid/lib/styles.css";
|
|
611
|
+
|
|
612
|
+
// src/hooks/useApiCall.ts
|
|
613
|
+
import { useState as useState2, useCallback as useCallback2 } from "react";
|
|
614
|
+
|
|
615
|
+
// src/contexts/SnackbarContext.tsx
|
|
616
|
+
import React, { createContext, useContext, useState, useCallback } from "react";
|
|
617
|
+
import MuiAlert from "@mui/material/Alert";
|
|
618
|
+
import Snackbar from "@mui/material/Snackbar";
|
|
619
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
620
|
+
var SnackbarAlert = React.forwardRef(function SnackbarAlert2(props, ref) {
|
|
621
|
+
return /* @__PURE__ */ jsx(MuiAlert, { elevation: 6, ref, variant: "filled", ...props });
|
|
622
|
+
});
|
|
623
|
+
var SnackbarContext = createContext(void 0);
|
|
624
|
+
var DEFAULT_SUCCESS_DURATION = 3e3;
|
|
625
|
+
var DEFAULT_ERROR_DURATION = 5e3;
|
|
626
|
+
var SnackbarProvider = ({ children }) => {
|
|
627
|
+
const [snackbar, setSnackbar] = useState({
|
|
628
|
+
open: false,
|
|
629
|
+
message: "",
|
|
630
|
+
severity: "info",
|
|
631
|
+
duration: DEFAULT_SUCCESS_DURATION
|
|
632
|
+
// Valor inicial
|
|
633
|
+
});
|
|
634
|
+
const showSnackbar = useCallback((message, severity, duration) => {
|
|
635
|
+
const finalDuration = duration !== void 0 && duration !== null ? duration : severity === "error" ? DEFAULT_ERROR_DURATION : DEFAULT_SUCCESS_DURATION;
|
|
636
|
+
setSnackbar({
|
|
637
|
+
open: true,
|
|
638
|
+
message,
|
|
639
|
+
severity,
|
|
640
|
+
duration: finalDuration
|
|
641
|
+
});
|
|
642
|
+
}, []);
|
|
643
|
+
const showSuccess = useCallback((message, duration) => showSnackbar(message, "success", duration), [showSnackbar]);
|
|
644
|
+
const showError = useCallback((message, duration) => showSnackbar(message, "error", duration), [showSnackbar]);
|
|
645
|
+
const showWarning = useCallback((message, duration) => showSnackbar(message, "warning", duration), [showSnackbar]);
|
|
646
|
+
const showInfo = useCallback((message, duration) => showSnackbar(message, "info", duration), [showSnackbar]);
|
|
647
|
+
const handleCloseSnackbar = (event, reason) => {
|
|
648
|
+
if (reason === "clickaway") {
|
|
649
|
+
return;
|
|
650
|
+
}
|
|
651
|
+
setSnackbar((prev) => ({ ...prev, open: false }));
|
|
652
|
+
};
|
|
653
|
+
return /* @__PURE__ */ jsxs(SnackbarContext.Provider, { value: { showSnackbar, showSuccess, showError, showWarning, showInfo }, children: [
|
|
654
|
+
children,
|
|
655
|
+
/* @__PURE__ */ jsx(
|
|
656
|
+
Snackbar,
|
|
657
|
+
{
|
|
658
|
+
open: snackbar.open,
|
|
659
|
+
autoHideDuration: snackbar.duration,
|
|
660
|
+
onClose: handleCloseSnackbar,
|
|
661
|
+
anchorOrigin: { vertical: "top", horizontal: "center" },
|
|
662
|
+
children: /* @__PURE__ */ jsx(SnackbarAlert, { onClose: handleCloseSnackbar, severity: snackbar.severity, children: snackbar.message })
|
|
663
|
+
}
|
|
664
|
+
)
|
|
665
|
+
] });
|
|
666
|
+
};
|
|
667
|
+
var useSnackbar = () => {
|
|
668
|
+
const context = useContext(SnackbarContext);
|
|
669
|
+
if (context === void 0) {
|
|
670
|
+
throw new Error("useSnackbar must be used within a SnackbarProvider");
|
|
671
|
+
}
|
|
672
|
+
return context;
|
|
673
|
+
};
|
|
674
|
+
|
|
675
|
+
// src/env.ts
|
|
676
|
+
var getEnvVar = (key) => {
|
|
677
|
+
if (typeof import.meta !== "undefined" && import.meta.env) {
|
|
678
|
+
const viteKey = `VITE_${key}`;
|
|
679
|
+
if (import.meta.env[viteKey]) {
|
|
680
|
+
return import.meta.env[viteKey];
|
|
681
|
+
}
|
|
682
|
+
}
|
|
683
|
+
if (typeof process !== "undefined" && process.env) {
|
|
684
|
+
const craKey = `REACT_APP_${key}`;
|
|
685
|
+
if (process.env[craKey]) {
|
|
686
|
+
return process.env[craKey];
|
|
687
|
+
}
|
|
688
|
+
if (process.env[key]) {
|
|
689
|
+
return process.env[key];
|
|
690
|
+
}
|
|
691
|
+
}
|
|
692
|
+
console.warn(`Variable de entorno "${key}" no encontrada. Aseg\xFArate de definirla con el prefijo correcto (VITE_ o REACT_APP_).`);
|
|
693
|
+
return "";
|
|
694
|
+
};
|
|
695
|
+
var envConfig = {
|
|
696
|
+
backendUrl: getEnvVar("BACKEND_URL")
|
|
697
|
+
// Agrega aquí las demás variables siguiendo el mismo patrón
|
|
698
|
+
};
|
|
699
|
+
|
|
700
|
+
// src/utils/fetchApi.ts
|
|
701
|
+
async function fetchApi(endPoint, options) {
|
|
702
|
+
const BACKEND_URL = envConfig.backendUrl;
|
|
703
|
+
const defaultHeaders = {
|
|
704
|
+
"Content-Type": "application/x-www-form-urlencoded"
|
|
705
|
+
};
|
|
706
|
+
const config = {
|
|
707
|
+
...options,
|
|
708
|
+
headers: {
|
|
709
|
+
...defaultHeaders,
|
|
710
|
+
...options?.headers
|
|
711
|
+
},
|
|
712
|
+
credentials: "include"
|
|
713
|
+
};
|
|
714
|
+
if (config.method === "GET" || config.method === "HEAD") {
|
|
715
|
+
delete config.body;
|
|
716
|
+
}
|
|
717
|
+
return await fetch(BACKEND_URL + endPoint, config);
|
|
718
|
+
}
|
|
719
|
+
var executeBackendProcedure = async (procedureName, params) => {
|
|
720
|
+
function stringifyObjectsAndArraysInParams(params2) {
|
|
721
|
+
const newParams = {};
|
|
722
|
+
for (const key in params2) {
|
|
723
|
+
if (Object.prototype.hasOwnProperty.call(params2, key)) {
|
|
724
|
+
const value = params2[key];
|
|
725
|
+
if (typeof value === "object" && value !== null) {
|
|
726
|
+
try {
|
|
727
|
+
newParams[key] = JSON.stringify(value);
|
|
728
|
+
} catch (e) {
|
|
729
|
+
console.warn(`Warning: Could not stringify value for key '${key}'. Keeping original value. Error:`, e);
|
|
730
|
+
newParams[key] = value;
|
|
731
|
+
}
|
|
732
|
+
} else {
|
|
733
|
+
newParams[key] = value;
|
|
734
|
+
}
|
|
735
|
+
}
|
|
736
|
+
}
|
|
737
|
+
return newParams;
|
|
738
|
+
}
|
|
739
|
+
const body = new URLSearchParams(stringifyObjectsAndArraysInParams(params));
|
|
740
|
+
const response = await fetchApi(`/${procedureName}`, { body, method: "POST" });
|
|
741
|
+
if (response.ok) {
|
|
742
|
+
const rawResponseTextDefinition = await response.text();
|
|
743
|
+
const result = JSON.parse(rawResponseTextDefinition.replace(/^--\n/, ""));
|
|
744
|
+
if (result.error) {
|
|
745
|
+
throw new Error(result.error.message);
|
|
746
|
+
} else {
|
|
747
|
+
return result;
|
|
748
|
+
}
|
|
749
|
+
} else {
|
|
750
|
+
const errorTextDefinition = await response.text();
|
|
751
|
+
throw new Error(`Error al ejecutar procedure '${procedureName}': ${response.status} - ${errorTextDefinition}`);
|
|
752
|
+
}
|
|
753
|
+
};
|
|
754
|
+
|
|
755
|
+
// src/hooks/useApiCall.ts
|
|
756
|
+
var useApiCall = () => {
|
|
757
|
+
const { showSnackbar } = useSnackbar();
|
|
758
|
+
const [loading, setLoading] = useState2(false);
|
|
759
|
+
const [error, setError] = useState2(null);
|
|
760
|
+
const callApi = useCallback2(async (procedureName, params) => {
|
|
761
|
+
setLoading(true);
|
|
762
|
+
setError(null);
|
|
763
|
+
try {
|
|
764
|
+
const result = await executeBackendProcedure(procedureName, params);
|
|
765
|
+
return result === null ? void 0 : result;
|
|
766
|
+
} catch (err) {
|
|
767
|
+
setError(err);
|
|
768
|
+
let snackbarMessage = `Error inesperado al ejecutar '${procedureName}'.`;
|
|
769
|
+
if (err instanceof TypeError) {
|
|
770
|
+
snackbarMessage = `Problema de conexi\xF3n: ${err.message}. Por favor, revisa tu internet o intenta de nuevo.`;
|
|
771
|
+
} else if (err instanceof Error) {
|
|
772
|
+
snackbarMessage = err.message;
|
|
773
|
+
}
|
|
774
|
+
showSnackbar(snackbarMessage, "error");
|
|
775
|
+
throw err;
|
|
776
|
+
} finally {
|
|
777
|
+
setLoading(false);
|
|
778
|
+
}
|
|
779
|
+
}, [showSnackbar]);
|
|
780
|
+
return { callApi, loading, error };
|
|
781
|
+
};
|
|
782
|
+
|
|
783
|
+
// src/components/grid/GenericDataGrid.tsx
|
|
784
|
+
import {
|
|
785
|
+
CircularProgress,
|
|
786
|
+
Typography as Typography5,
|
|
787
|
+
Box as Box4,
|
|
788
|
+
Alert,
|
|
789
|
+
useTheme,
|
|
790
|
+
Button as Button2,
|
|
791
|
+
IconButton
|
|
792
|
+
} from "@mui/material";
|
|
793
|
+
|
|
794
|
+
// src/utils/functions.tsx
|
|
795
|
+
var JSON4all = __toESM(require_json4all(), 1);
|
|
796
|
+
|
|
797
|
+
// src/store/index.ts
|
|
798
|
+
import { configureStore, combineReducers } from "@reduxjs/toolkit";
|
|
799
|
+
import {
|
|
800
|
+
persistStore,
|
|
801
|
+
persistReducer,
|
|
802
|
+
FLUSH,
|
|
803
|
+
REHYDRATE,
|
|
804
|
+
PAUSE,
|
|
805
|
+
PERSIST,
|
|
806
|
+
PURGE,
|
|
807
|
+
REGISTER
|
|
808
|
+
} from "redux-persist";
|
|
809
|
+
import storage from "redux-persist/lib/storage";
|
|
810
|
+
|
|
811
|
+
// src/store/clientContextSlice.ts
|
|
812
|
+
import { createSlice, createAsyncThunk } from "@reduxjs/toolkit";
|
|
813
|
+
var initialState = {
|
|
814
|
+
menu: [],
|
|
815
|
+
procedure: {},
|
|
816
|
+
procedures: [],
|
|
817
|
+
config: {},
|
|
818
|
+
// Inicializa con un objeto vacío o valores por defecto adecuados
|
|
819
|
+
useragent: {},
|
|
820
|
+
// Igual aquí
|
|
821
|
+
username: "",
|
|
822
|
+
status: "idle",
|
|
823
|
+
// Por defecto, sin carga
|
|
824
|
+
error: null
|
|
825
|
+
// Sin error
|
|
826
|
+
};
|
|
827
|
+
var fetchClientContext = createAsyncThunk(
|
|
828
|
+
"clientContext/fetchClientContext",
|
|
829
|
+
async (_, { rejectWithValue }) => {
|
|
830
|
+
try {
|
|
831
|
+
const setupResponse = await fetchApi("/client-setup", { method: "GET" });
|
|
832
|
+
if (!setupResponse.ok) {
|
|
833
|
+
const errorData = await setupResponse.text();
|
|
834
|
+
throw new Error(errorData || "Error al obtener configuraci\xF3n del cliente");
|
|
835
|
+
}
|
|
836
|
+
const clientSetup = await setupResponse.json();
|
|
837
|
+
return clientSetup;
|
|
838
|
+
} catch (error) {
|
|
839
|
+
return rejectWithValue(error.message || "Error desconocido al cargar el contexto");
|
|
840
|
+
}
|
|
841
|
+
}
|
|
842
|
+
);
|
|
843
|
+
var clientContextSlice = createSlice({
|
|
844
|
+
name: "clientContext",
|
|
845
|
+
initialState,
|
|
846
|
+
reducers: {
|
|
847
|
+
// Un reducer para limpiar el contexto del cliente (ej. al cerrar sesión)
|
|
848
|
+
clearClientContext: (state) => {
|
|
849
|
+
Object.assign(state, initialState);
|
|
850
|
+
}
|
|
851
|
+
// Puedes añadir otros reducers aquí si necesitas modificar partes del clientContext directamente
|
|
852
|
+
// pero el thunk es la forma preferida para la carga inicial.
|
|
853
|
+
},
|
|
854
|
+
// **extraReducers maneja las acciones del thunk asíncrono**
|
|
855
|
+
extraReducers: (builder) => {
|
|
856
|
+
builder.addCase(fetchClientContext.pending, (state) => {
|
|
857
|
+
state.status = "loading";
|
|
858
|
+
state.error = null;
|
|
859
|
+
}).addCase(fetchClientContext.fulfilled, (state, action) => {
|
|
860
|
+
state.status = "succeeded";
|
|
861
|
+
state.menu = action.payload.menu;
|
|
862
|
+
state.procedure = action.payload.procedure;
|
|
863
|
+
state.procedures = action.payload.procedures;
|
|
864
|
+
state.config = action.payload.config;
|
|
865
|
+
state.useragent = action.payload.useragent;
|
|
866
|
+
state.username = action.payload.username;
|
|
867
|
+
state.error = null;
|
|
868
|
+
}).addCase(fetchClientContext.rejected, (state, action) => {
|
|
869
|
+
state.status = "failed";
|
|
870
|
+
state.error = action.payload || "Fallo al cargar el contexto del cliente";
|
|
871
|
+
});
|
|
872
|
+
}
|
|
873
|
+
});
|
|
874
|
+
var { clearClientContext } = clientContextSlice.actions;
|
|
875
|
+
var clientContextSlice_default = clientContextSlice.reducer;
|
|
876
|
+
|
|
877
|
+
// src/store/routerSlice.ts
|
|
878
|
+
import { createSlice as createSlice2 } from "@reduxjs/toolkit";
|
|
879
|
+
var initialState2 = {
|
|
880
|
+
currentPath: "/",
|
|
881
|
+
previousPath: null,
|
|
882
|
+
redirectPath: null
|
|
883
|
+
// <--- Inicializamos en null
|
|
884
|
+
};
|
|
885
|
+
var routerSlice = createSlice2({
|
|
886
|
+
name: "router",
|
|
887
|
+
initialState: initialState2,
|
|
888
|
+
reducers: {
|
|
889
|
+
setCurrentPath: (state, action) => {
|
|
890
|
+
state.previousPath = state.currentPath;
|
|
891
|
+
state.currentPath = action.payload;
|
|
892
|
+
},
|
|
893
|
+
setRedirectPath: (state, action) => {
|
|
894
|
+
state.redirectPath = action.payload;
|
|
895
|
+
},
|
|
896
|
+
resetRouterState: (state) => {
|
|
897
|
+
state.currentPath = "/";
|
|
898
|
+
state.previousPath = null;
|
|
899
|
+
state.redirectPath = null;
|
|
900
|
+
}
|
|
901
|
+
}
|
|
902
|
+
});
|
|
903
|
+
var { setCurrentPath, setRedirectPath, resetRouterState } = routerSlice.actions;
|
|
904
|
+
var routerSlice_default = routerSlice.reducer;
|
|
905
|
+
|
|
906
|
+
// src/store/menuUiSlice.ts
|
|
907
|
+
import { createSlice as createSlice3 } from "@reduxjs/toolkit";
|
|
908
|
+
var initialState3 = {
|
|
909
|
+
isDrawerOpen: false,
|
|
910
|
+
subMenuOpenStates: {}
|
|
911
|
+
};
|
|
912
|
+
var menuUiSlice = createSlice3({
|
|
913
|
+
name: "menuUi",
|
|
914
|
+
initialState: initialState3,
|
|
915
|
+
reducers: {
|
|
916
|
+
setDrawerOpen: (state, action) => {
|
|
917
|
+
state.isDrawerOpen = action.payload;
|
|
918
|
+
},
|
|
919
|
+
toggleDrawer: (state) => {
|
|
920
|
+
state.isDrawerOpen = !state.isDrawerOpen;
|
|
921
|
+
},
|
|
922
|
+
setSubMenuOpen: (state, action) => {
|
|
923
|
+
state.subMenuOpenStates[action.payload.menuName] = action.payload.isOpen;
|
|
924
|
+
},
|
|
925
|
+
toggleSubMenu: (state, action) => {
|
|
926
|
+
state.subMenuOpenStates[action.payload] = !state.subMenuOpenStates[action.payload];
|
|
927
|
+
},
|
|
928
|
+
// --- NUEVO REDUCER: Establecer el estado de todos los submenús ---
|
|
929
|
+
setAllSubMenusOpen: (state, action) => {
|
|
930
|
+
for (const menuName in state.subMenuOpenStates) {
|
|
931
|
+
if (Object.prototype.hasOwnProperty.call(state.subMenuOpenStates, menuName)) {
|
|
932
|
+
state.subMenuOpenStates[menuName] = action.payload;
|
|
933
|
+
}
|
|
934
|
+
}
|
|
935
|
+
},
|
|
936
|
+
resetMenuUiState: (state) => {
|
|
937
|
+
Object.assign(state, initialState3);
|
|
938
|
+
}
|
|
939
|
+
}
|
|
940
|
+
});
|
|
941
|
+
var {
|
|
942
|
+
setDrawerOpen,
|
|
943
|
+
toggleDrawer,
|
|
944
|
+
setSubMenuOpen,
|
|
945
|
+
toggleSubMenu,
|
|
946
|
+
setAllSubMenusOpen,
|
|
947
|
+
// ¡Exportamos la nueva acción!
|
|
948
|
+
resetMenuUiState
|
|
949
|
+
} = menuUiSlice.actions;
|
|
950
|
+
var menuUiSlice_default = menuUiSlice.reducer;
|
|
951
|
+
|
|
952
|
+
// src/store/index.ts
|
|
953
|
+
import { useDispatch, useSelector } from "react-redux";
|
|
954
|
+
var rootReducer = combineReducers({
|
|
955
|
+
clientContext: clientContextSlice_default,
|
|
956
|
+
router: routerSlice_default,
|
|
957
|
+
menuUi: menuUiSlice_default
|
|
958
|
+
// ...otros slices
|
|
959
|
+
});
|
|
960
|
+
var persistConfig = {
|
|
961
|
+
key: "root",
|
|
962
|
+
storage,
|
|
963
|
+
whitelist: ["clientContext", "router", "menuUi"]
|
|
964
|
+
};
|
|
965
|
+
var persistedReducer = persistReducer(persistConfig, rootReducer);
|
|
966
|
+
var store = configureStore({
|
|
967
|
+
reducer: persistedReducer,
|
|
968
|
+
middleware: (getDefaultMiddleware) => getDefaultMiddleware({
|
|
969
|
+
serializableCheck: {
|
|
970
|
+
ignoredActions: [FLUSH, REHYDRATE, PAUSE, PERSIST, PURGE, REGISTER]
|
|
971
|
+
}
|
|
972
|
+
})
|
|
973
|
+
});
|
|
974
|
+
var persistor = persistStore(store);
|
|
975
|
+
var useAppDispatch = useDispatch;
|
|
976
|
+
var useAppSelector = useSelector;
|
|
977
|
+
var useClientContextStatus = () => {
|
|
978
|
+
return useAppSelector((state) => state.clientContext.status);
|
|
979
|
+
};
|
|
980
|
+
var useIsDrawerOpen = () => {
|
|
981
|
+
return useAppSelector((state) => state.menuUi.isDrawerOpen);
|
|
982
|
+
};
|
|
983
|
+
var useSubMenuOpenState = (menuName) => {
|
|
984
|
+
return useAppSelector((state) => state.menuUi.subMenuOpenStates[menuName] || false);
|
|
985
|
+
};
|
|
986
|
+
var useRedirectPath = () => {
|
|
987
|
+
return useAppSelector((state) => state.router.redirectPath);
|
|
988
|
+
};
|
|
989
|
+
|
|
990
|
+
// src/utils/functions.tsx
|
|
991
|
+
var cambiarGuionesBajosPorEspacios = (texto) => texto.replace(/_/g, " ");
|
|
992
|
+
|
|
993
|
+
// src/components/grid/GenericDataGrid.tsx
|
|
994
|
+
import SearchIcon from "@mui/icons-material/Search";
|
|
995
|
+
import SearchOffIcon from "@mui/icons-material/SearchOff";
|
|
996
|
+
import AddIcon from "@mui/icons-material/Add";
|
|
997
|
+
import DeleteIcon from "@mui/icons-material/Delete";
|
|
998
|
+
|
|
999
|
+
// src/components/grid/PkHeaderRenderer.tsx
|
|
1000
|
+
import { Box, Typography } from "@mui/material";
|
|
1001
|
+
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
1002
|
+
function PkHeaderRenderer(props) {
|
|
1003
|
+
const { column } = props;
|
|
1004
|
+
const isPrimaryKey = column.isPK;
|
|
1005
|
+
return /* @__PURE__ */ jsx2(
|
|
1006
|
+
Box,
|
|
1007
|
+
{
|
|
1008
|
+
sx: {
|
|
1009
|
+
display: "flex",
|
|
1010
|
+
flexDirection: "column",
|
|
1011
|
+
justifyContent: "center",
|
|
1012
|
+
alignItems: "flex-start",
|
|
1013
|
+
padding: "4px",
|
|
1014
|
+
boxSizing: "border-box",
|
|
1015
|
+
height: "100%"
|
|
1016
|
+
},
|
|
1017
|
+
children: /* @__PURE__ */ jsx2(
|
|
1018
|
+
Typography,
|
|
1019
|
+
{
|
|
1020
|
+
variant: "body2",
|
|
1021
|
+
sx: {
|
|
1022
|
+
fontWeight: "bold",
|
|
1023
|
+
textDecoration: isPrimaryKey ? "underline" : "none",
|
|
1024
|
+
fontSize: "0.875rem"
|
|
1025
|
+
// Puedes ajustar el tamaño si es necesario
|
|
1026
|
+
},
|
|
1027
|
+
children: column.name
|
|
1028
|
+
}
|
|
1029
|
+
)
|
|
1030
|
+
}
|
|
1031
|
+
);
|
|
1032
|
+
}
|
|
1033
|
+
var PkHeaderRenderer_default = PkHeaderRenderer;
|
|
1034
|
+
|
|
1035
|
+
// src/components/grid/PkCellRenderer.tsx
|
|
1036
|
+
import { Typography as Typography2 } from "@mui/material";
|
|
1037
|
+
import { jsx as jsx3 } from "react/jsx-runtime";
|
|
1038
|
+
function PkCellRenderer(props) {
|
|
1039
|
+
const { column, row } = props;
|
|
1040
|
+
const isPrimaryKey = column.isPK;
|
|
1041
|
+
const rowAsRecord = row;
|
|
1042
|
+
const value = rowAsRecord[column.key];
|
|
1043
|
+
return /* @__PURE__ */ jsx3(
|
|
1044
|
+
Typography2,
|
|
1045
|
+
{
|
|
1046
|
+
variant: "body2",
|
|
1047
|
+
sx: {
|
|
1048
|
+
//fontWeight: isPrimaryKey ? 'bold' : 'normal',
|
|
1049
|
+
fontSize: "0.875rem",
|
|
1050
|
+
// Ajusta el tamaño si es necesario
|
|
1051
|
+
whiteSpace: "nowrap",
|
|
1052
|
+
overflow: "hidden",
|
|
1053
|
+
textOverflow: "ellipsis",
|
|
1054
|
+
width: "100%"
|
|
1055
|
+
},
|
|
1056
|
+
children: value === null || value === void 0 ? "" : String(value)
|
|
1057
|
+
}
|
|
1058
|
+
);
|
|
1059
|
+
}
|
|
1060
|
+
var PkCellRenderer_default = PkCellRenderer;
|
|
1061
|
+
|
|
1062
|
+
// src/components/ConfirmDialog.tsx
|
|
1063
|
+
import Dialog from "@mui/material/Dialog";
|
|
1064
|
+
import DialogTitle from "@mui/material/DialogTitle";
|
|
1065
|
+
import DialogContent from "@mui/material/DialogContent";
|
|
1066
|
+
import DialogContentText from "@mui/material/DialogContentText";
|
|
1067
|
+
import DialogActions from "@mui/material/DialogActions";
|
|
1068
|
+
import Button from "@mui/material/Button";
|
|
1069
|
+
import { jsx as jsx4, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
1070
|
+
var ConfirmDialog = ({ open, onClose, title, message }) => {
|
|
1071
|
+
return /* @__PURE__ */ jsxs2(
|
|
1072
|
+
Dialog,
|
|
1073
|
+
{
|
|
1074
|
+
open,
|
|
1075
|
+
onClose: () => onClose(false),
|
|
1076
|
+
"aria-labelledby": "confirm-dialog-title",
|
|
1077
|
+
"aria-describedby": "confirm-dialog-description",
|
|
1078
|
+
children: [
|
|
1079
|
+
/* @__PURE__ */ jsx4(DialogTitle, { id: "confirm-dialog-title", children: title }),
|
|
1080
|
+
/* @__PURE__ */ jsx4(DialogContent, { children: /* @__PURE__ */ jsx4(DialogContentText, { id: "confirm-dialog-description", children: message }) }),
|
|
1081
|
+
/* @__PURE__ */ jsxs2(DialogActions, { children: [
|
|
1082
|
+
/* @__PURE__ */ jsx4(Button, { onClick: () => onClose(false), color: "primary", children: "Cancelar" }),
|
|
1083
|
+
/* @__PURE__ */ jsx4(Button, { onClick: () => onClose(true), color: "error", autoFocus: true, children: "Confirmar" })
|
|
1084
|
+
] })
|
|
1085
|
+
]
|
|
1086
|
+
}
|
|
1087
|
+
);
|
|
1088
|
+
};
|
|
1089
|
+
|
|
1090
|
+
// src/components/grid/FilterInputRender.tsx
|
|
1091
|
+
import { InputBase } from "@mui/material";
|
|
1092
|
+
import { jsx as jsx5 } from "react/jsx-runtime";
|
|
1093
|
+
function FilterInputRenderer({
|
|
1094
|
+
column,
|
|
1095
|
+
filters,
|
|
1096
|
+
setFilters
|
|
1097
|
+
}) {
|
|
1098
|
+
return /* @__PURE__ */ jsx5(
|
|
1099
|
+
InputBase,
|
|
1100
|
+
{
|
|
1101
|
+
value: filters[column.key] || "",
|
|
1102
|
+
onChange: (e) => setFilters({
|
|
1103
|
+
...filters,
|
|
1104
|
+
[column.key]: e.target.value
|
|
1105
|
+
}),
|
|
1106
|
+
sx: {
|
|
1107
|
+
width: "100%",
|
|
1108
|
+
margin: "0",
|
|
1109
|
+
border: "1px solid #ccc",
|
|
1110
|
+
borderRadius: "4px",
|
|
1111
|
+
padding: "2px 4px",
|
|
1112
|
+
fontSize: "0.8rem",
|
|
1113
|
+
boxSizing: "border-box"
|
|
1114
|
+
},
|
|
1115
|
+
onClick: (e) => e.stopPropagation()
|
|
1116
|
+
}
|
|
1117
|
+
);
|
|
1118
|
+
}
|
|
1119
|
+
var FilterInputRender_default = FilterInputRenderer;
|
|
1120
|
+
|
|
1121
|
+
// src/components/grid/InputRendered.tsx
|
|
1122
|
+
import { useCallback as useCallback3, useMemo, useState as useState3 } from "react";
|
|
1123
|
+
import InputBase2 from "@mui/material/InputBase";
|
|
1124
|
+
import { jsx as jsx6 } from "react/jsx-runtime";
|
|
1125
|
+
function InputRenderer({
|
|
1126
|
+
column,
|
|
1127
|
+
row,
|
|
1128
|
+
rowIdx,
|
|
1129
|
+
tableDefinition,
|
|
1130
|
+
onRowChange,
|
|
1131
|
+
onClose,
|
|
1132
|
+
setCellFeedback,
|
|
1133
|
+
onEnterPress,
|
|
1134
|
+
setTableData,
|
|
1135
|
+
setLocalCellChanges,
|
|
1136
|
+
localCellChanges,
|
|
1137
|
+
primaryKey
|
|
1138
|
+
}) {
|
|
1139
|
+
const tableName = tableDefinition.tableName;
|
|
1140
|
+
const [editingValue, setEditingValue] = useState3(row[column.key]);
|
|
1141
|
+
const { showSuccess, showError } = useSnackbar();
|
|
1142
|
+
const initialRowId = useMemo(() => getPrimaryKeyValues(row, primaryKey), [row, primaryKey]);
|
|
1143
|
+
const { callApi, loading, error } = useApiCall();
|
|
1144
|
+
const handleCommit = useCallback3(async (currentValue, closeEditor, focusNextCell) => {
|
|
1145
|
+
const processedNewValue = typeof currentValue === "string" ? currentValue.trim() === "" ? null : currentValue.trim() : currentValue;
|
|
1146
|
+
const potentialUpdatedRow = { ...row, [column.key]: processedNewValue };
|
|
1147
|
+
const arePKValuesFilled = tableDefinition.primaryKey.every(
|
|
1148
|
+
(key) => potentialUpdatedRow[key] !== void 0 && potentialUpdatedRow[key] !== null && String(potentialUpdatedRow[key]).trim() !== ""
|
|
1149
|
+
);
|
|
1150
|
+
const isNewRow = !arePKValuesFilled || potentialUpdatedRow[NEW_ROW_INDICATOR];
|
|
1151
|
+
const isMandatoryField = tableDefinition.primaryKey.includes(column.key) || tableDefinition.fields.find((f) => f.name === column.key)?.nullable === false;
|
|
1152
|
+
const isMandatoryFieldEmpty = isNewRow && isMandatoryField && (processedNewValue === null || processedNewValue === void 0 || String(processedNewValue).trim() === "");
|
|
1153
|
+
if (processedNewValue === row[column.key] && !isNewRow && !isMandatoryFieldEmpty) {
|
|
1154
|
+
console.log("No se guard\xF3: el valor no cambi\xF3 (y no es una nueva fila o campo obligatorio vac\xEDo que se est\xE1 iniciando).");
|
|
1155
|
+
onClose(false, focusNextCell);
|
|
1156
|
+
setLocalCellChanges((prev) => {
|
|
1157
|
+
const newMap = new Map(prev);
|
|
1158
|
+
const columnKeys = newMap.get(initialRowId);
|
|
1159
|
+
if (columnKeys) {
|
|
1160
|
+
columnKeys.delete(column.key);
|
|
1161
|
+
if (columnKeys.size === 0) {
|
|
1162
|
+
newMap.delete(initialRowId);
|
|
1163
|
+
} else {
|
|
1164
|
+
newMap.set(initialRowId, columnKeys);
|
|
1165
|
+
}
|
|
1166
|
+
}
|
|
1167
|
+
return newMap;
|
|
1168
|
+
});
|
|
1169
|
+
return;
|
|
1170
|
+
}
|
|
1171
|
+
const oldRowData = { ...row };
|
|
1172
|
+
const primaryKeyValuesForBackend = tableDefinition.primaryKey.map((key) => potentialUpdatedRow[key]);
|
|
1173
|
+
const currentRowIdBeforeUpdate = getPrimaryKeyValues(oldRowData, tableDefinition.primaryKey);
|
|
1174
|
+
onRowChange({ ...row, [column.key]: processedNewValue }, true);
|
|
1175
|
+
onClose(true, focusNextCell);
|
|
1176
|
+
if (isNewRow) {
|
|
1177
|
+
const areAllMandatoryFieldsFilled = tableDefinition.fields.every((fieldDef) => {
|
|
1178
|
+
const isMandatory = fieldDef.nullable === false || fieldDef.isPk;
|
|
1179
|
+
const fieldValue = potentialUpdatedRow[fieldDef.name];
|
|
1180
|
+
return !isMandatory || fieldValue !== null && fieldValue !== void 0 && String(fieldValue).trim() !== "";
|
|
1181
|
+
});
|
|
1182
|
+
if (!areAllMandatoryFieldsFilled) {
|
|
1183
|
+
console.log("Nueva fila: Faltan campos obligatorios. No se guarda en el backend todav\xEDa.");
|
|
1184
|
+
setLocalCellChanges((prev) => {
|
|
1185
|
+
const newMap = new Map(prev);
|
|
1186
|
+
const currentColumnsInRow = newMap.get(initialRowId) || /* @__PURE__ */ new Set();
|
|
1187
|
+
tableDefinition.fields.forEach((fieldDef) => {
|
|
1188
|
+
const isMandatory = fieldDef.nullable === false || fieldDef.isPk;
|
|
1189
|
+
const isEditable = fieldDef.editable !== false;
|
|
1190
|
+
const fieldValue = potentialUpdatedRow[fieldDef.name];
|
|
1191
|
+
if (isMandatory && isEditable && (fieldValue === null || fieldValue === void 0 || String(fieldValue).trim() === "")) {
|
|
1192
|
+
currentColumnsInRow.add(fieldDef.name);
|
|
1193
|
+
} else {
|
|
1194
|
+
currentColumnsInRow.delete(fieldDef.name);
|
|
1195
|
+
}
|
|
1196
|
+
});
|
|
1197
|
+
newMap.set(initialRowId, currentColumnsInRow);
|
|
1198
|
+
return newMap;
|
|
1199
|
+
});
|
|
1200
|
+
return;
|
|
1201
|
+
} else {
|
|
1202
|
+
console.log("Nueva fila: Todos los campos obligatorios est\xE1n llenos. Procediendo a guardar.");
|
|
1203
|
+
setLocalCellChanges((prev) => {
|
|
1204
|
+
const newMap = new Map(prev);
|
|
1205
|
+
newMap.delete(initialRowId);
|
|
1206
|
+
return newMap;
|
|
1207
|
+
});
|
|
1208
|
+
}
|
|
1209
|
+
}
|
|
1210
|
+
const status = isNewRow ? "new" : "update";
|
|
1211
|
+
let rowToSend = {};
|
|
1212
|
+
if (isNewRow) {
|
|
1213
|
+
tableDefinition.fields.forEach((fieldDef) => {
|
|
1214
|
+
const fieldValue = potentialUpdatedRow[fieldDef.name];
|
|
1215
|
+
if (fieldValue !== void 0 && fieldValue !== null && String(fieldValue).trim() !== "") {
|
|
1216
|
+
rowToSend[fieldDef.name] = fieldValue;
|
|
1217
|
+
} else if (tableDefinition.primaryKey.includes(fieldDef.name) && (fieldValue === null || fieldValue === void 0 || String(fieldValue).trim() === "")) {
|
|
1218
|
+
rowToSend[fieldDef.name] = fieldValue;
|
|
1219
|
+
}
|
|
1220
|
+
});
|
|
1221
|
+
if (localCellChanges.has(initialRowId)) {
|
|
1222
|
+
localCellChanges.get(initialRowId)?.forEach((colKey) => {
|
|
1223
|
+
if (!rowToSend.hasOwnProperty(colKey)) {
|
|
1224
|
+
rowToSend[colKey] = potentialUpdatedRow[colKey];
|
|
1225
|
+
}
|
|
1226
|
+
});
|
|
1227
|
+
}
|
|
1228
|
+
delete rowToSend[NEW_ROW_INDICATOR];
|
|
1229
|
+
} else {
|
|
1230
|
+
rowToSend[column.key] = processedNewValue;
|
|
1231
|
+
tableDefinition.primaryKey.forEach((pkField) => {
|
|
1232
|
+
rowToSend[pkField] = potentialUpdatedRow[pkField];
|
|
1233
|
+
});
|
|
1234
|
+
}
|
|
1235
|
+
try {
|
|
1236
|
+
const response = await callApi("table_record_save", {
|
|
1237
|
+
table: tableName,
|
|
1238
|
+
primaryKeyValues: primaryKeyValuesForBackend,
|
|
1239
|
+
newRow: rowToSend,
|
|
1240
|
+
oldRow: oldRowData,
|
|
1241
|
+
status
|
|
1242
|
+
});
|
|
1243
|
+
setLocalCellChanges((prev) => {
|
|
1244
|
+
const newMap = new Map(prev);
|
|
1245
|
+
const columnKeys = newMap.get(initialRowId);
|
|
1246
|
+
if (columnKeys) {
|
|
1247
|
+
columnKeys.delete(column.key);
|
|
1248
|
+
if (columnKeys.size === 0) {
|
|
1249
|
+
newMap.delete(initialRowId);
|
|
1250
|
+
} else {
|
|
1251
|
+
newMap.set(initialRowId, columnKeys);
|
|
1252
|
+
}
|
|
1253
|
+
}
|
|
1254
|
+
return newMap;
|
|
1255
|
+
});
|
|
1256
|
+
showSuccess("Registro guardado exitosamente!");
|
|
1257
|
+
let finalRowIdForFeedback;
|
|
1258
|
+
let persistedRowData;
|
|
1259
|
+
if (response.row && isNewRow) {
|
|
1260
|
+
persistedRowData = { ...response.row };
|
|
1261
|
+
setTableData((prevData) => {
|
|
1262
|
+
const newData = [...prevData];
|
|
1263
|
+
const originalRowId = getPrimaryKeyValues(oldRowData, tableDefinition.primaryKey);
|
|
1264
|
+
const rowIndex = newData.findIndex((r) => getPrimaryKeyValues(r, tableDefinition.primaryKey) === originalRowId);
|
|
1265
|
+
if (rowIndex !== -1) {
|
|
1266
|
+
newData[rowIndex] = persistedRowData;
|
|
1267
|
+
} else {
|
|
1268
|
+
console.warn("Fila no encontrada para actualizar despu\xE9s de la inserci\xF3n. Podr\xEDa haber un problema de sincronizaci\xF3n.");
|
|
1269
|
+
const newPrimaryKeyId = getPrimaryKeyValues(persistedRowData, tableDefinition.primaryKey);
|
|
1270
|
+
const newRowIndex = newData.findIndex((r) => getPrimaryKeyValues(r, tableDefinition.primaryKey) === newPrimaryKeyId);
|
|
1271
|
+
if (newRowIndex !== -1) {
|
|
1272
|
+
newData[newRowIndex] = persistedRowData;
|
|
1273
|
+
}
|
|
1274
|
+
}
|
|
1275
|
+
return newData;
|
|
1276
|
+
});
|
|
1277
|
+
finalRowIdForFeedback = getPrimaryKeyValues(persistedRowData, tableDefinition.primaryKey);
|
|
1278
|
+
} else {
|
|
1279
|
+
persistedRowData = potentialUpdatedRow;
|
|
1280
|
+
const isPrimaryKeyColumn = tableDefinition.primaryKey.includes(column.key);
|
|
1281
|
+
finalRowIdForFeedback = isPrimaryKeyColumn ? getPrimaryKeyValues(potentialUpdatedRow, tableDefinition.primaryKey) : currentRowIdBeforeUpdate;
|
|
1282
|
+
}
|
|
1283
|
+
setCellFeedback({ rowId: finalRowIdForFeedback, columnKey: column.key, type: "success" });
|
|
1284
|
+
} catch (err) {
|
|
1285
|
+
console.error("Error al guardar el registro:", err);
|
|
1286
|
+
setCellFeedback({ rowId: currentRowIdBeforeUpdate, columnKey: column.key, type: "error" });
|
|
1287
|
+
onRowChange(oldRowData, true);
|
|
1288
|
+
}
|
|
1289
|
+
}, [
|
|
1290
|
+
column,
|
|
1291
|
+
row,
|
|
1292
|
+
onRowChange,
|
|
1293
|
+
tableName,
|
|
1294
|
+
tableDefinition.primaryKey,
|
|
1295
|
+
tableDefinition.fields,
|
|
1296
|
+
showSuccess,
|
|
1297
|
+
showError,
|
|
1298
|
+
setCellFeedback,
|
|
1299
|
+
onClose,
|
|
1300
|
+
setTableData,
|
|
1301
|
+
setLocalCellChanges,
|
|
1302
|
+
localCellChanges,
|
|
1303
|
+
initialRowId
|
|
1304
|
+
]);
|
|
1305
|
+
const handleKeyDown = useCallback3((event) => {
|
|
1306
|
+
if (event.key === "Enter") {
|
|
1307
|
+
handleCommit(editingValue, true, true);
|
|
1308
|
+
event.preventDefault();
|
|
1309
|
+
if (onEnterPress) {
|
|
1310
|
+
onEnterPress(rowIdx, column.key);
|
|
1311
|
+
}
|
|
1312
|
+
} else if (event.key === "Tab") {
|
|
1313
|
+
handleCommit(editingValue, true, true);
|
|
1314
|
+
}
|
|
1315
|
+
}, [handleCommit, editingValue, column.key, rowIdx, onEnterPress]);
|
|
1316
|
+
const handleBlur = useCallback3(() => {
|
|
1317
|
+
handleCommit(editingValue, true, false);
|
|
1318
|
+
}, [handleCommit, editingValue]);
|
|
1319
|
+
const fieldDefinition = tableDefinition.fields.find((f) => f.name === column.key);
|
|
1320
|
+
const isFieldEditable = fieldDefinition?.editable !== false;
|
|
1321
|
+
return /* @__PURE__ */ jsx6(
|
|
1322
|
+
InputBase2,
|
|
1323
|
+
{
|
|
1324
|
+
value: editingValue === null ? "" : editingValue,
|
|
1325
|
+
onChange: (e) => setEditingValue(e.target.value),
|
|
1326
|
+
onKeyDown: handleKeyDown,
|
|
1327
|
+
onBlur: handleBlur,
|
|
1328
|
+
placeholder: "",
|
|
1329
|
+
sx: {
|
|
1330
|
+
width: "100%",
|
|
1331
|
+
margin: "0",
|
|
1332
|
+
border: "1px solid #ccc",
|
|
1333
|
+
borderRadius: "4px",
|
|
1334
|
+
padding: "2px 4px",
|
|
1335
|
+
fontSize: "0.8rem",
|
|
1336
|
+
boxSizing: "border-box"
|
|
1337
|
+
},
|
|
1338
|
+
onClick: (e) => e.stopPropagation(),
|
|
1339
|
+
autoFocus: true,
|
|
1340
|
+
disabled: !isFieldEditable
|
|
1341
|
+
}
|
|
1342
|
+
);
|
|
1343
|
+
}
|
|
1344
|
+
var InputRendered_default = InputRenderer;
|
|
1345
|
+
|
|
1346
|
+
// src/components/grid/ExampleClientSideComponent.tsx
|
|
1347
|
+
import { Box as Box2, Typography as Typography3 } from "@mui/material";
|
|
1348
|
+
import { jsx as jsx7 } from "react/jsx-runtime";
|
|
1349
|
+
var ExampleClientSideComponent = ({ row, column, fieldDefinition }) => {
|
|
1350
|
+
const value = row[column.key];
|
|
1351
|
+
return /* @__PURE__ */ jsx7(Box2, { sx: {
|
|
1352
|
+
padding: 0.5,
|
|
1353
|
+
width: "100%",
|
|
1354
|
+
height: "100%",
|
|
1355
|
+
display: "flex",
|
|
1356
|
+
alignItems: "center",
|
|
1357
|
+
backgroundColor: value === "Special" ? "lightblue" : "transparent"
|
|
1358
|
+
}, children: /* @__PURE__ */ jsx7(Typography3, { variant: "body2", sx: { fontWeight: "bold" }, children: value ? `CS: ${value}` : "N/A" }) });
|
|
1359
|
+
};
|
|
1360
|
+
var ExampleClientSideComponent_default = ExampleClientSideComponent;
|
|
1361
|
+
|
|
1362
|
+
// src/components/grid/FallbackClientSideRenderer.tsx
|
|
1363
|
+
import { Box as Box3, Typography as Typography4, Tooltip } from "@mui/material";
|
|
1364
|
+
import WarningAmberIcon from "@mui/icons-material/WarningAmber";
|
|
1365
|
+
import { jsx as jsx8, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
1366
|
+
var FallbackClientSideRenderer = ({ column, row, fieldDefinition }) => {
|
|
1367
|
+
const value = row[column.key];
|
|
1368
|
+
const clientSideName = fieldDefinition?.clientSide || "Desconocido";
|
|
1369
|
+
return /* @__PURE__ */ jsx8(Tooltip, { title: `Componente clientSide '${clientSideName}' no implementado. Mostrando valor por defecto.`, children: /* @__PURE__ */ jsxs3(
|
|
1370
|
+
Box3,
|
|
1371
|
+
{
|
|
1372
|
+
sx: {
|
|
1373
|
+
display: "flex",
|
|
1374
|
+
alignItems: "center",
|
|
1375
|
+
justifyContent: "space-between",
|
|
1376
|
+
// Para espaciar el valor y el icono
|
|
1377
|
+
gap: 1,
|
|
1378
|
+
// Espacio entre elementos
|
|
1379
|
+
width: "100%",
|
|
1380
|
+
height: "100%",
|
|
1381
|
+
paddingLeft: "8px",
|
|
1382
|
+
backgroundColor: "rgba(255, 193, 7, 0.1)",
|
|
1383
|
+
// Amarillo claro para advertencia
|
|
1384
|
+
border: "1px dashed rgba(255, 193, 7, 0.5)",
|
|
1385
|
+
boxSizing: "border-box",
|
|
1386
|
+
overflow: "hidden"
|
|
1387
|
+
// Evita que el contenido se desborde
|
|
1388
|
+
},
|
|
1389
|
+
children: [
|
|
1390
|
+
/* @__PURE__ */ jsx8(Typography4, { variant: "body2", noWrap: true, sx: { flexGrow: 1 }, children: value !== null && value !== void 0 ? String(value) : "*Vac\xEDo*" }),
|
|
1391
|
+
/* @__PURE__ */ jsx8(
|
|
1392
|
+
WarningAmberIcon,
|
|
1393
|
+
{
|
|
1394
|
+
sx: {
|
|
1395
|
+
fontSize: 18,
|
|
1396
|
+
color: "warning.main",
|
|
1397
|
+
marginRight: "4px"
|
|
1398
|
+
// Pequeño margen a la derecha del icono
|
|
1399
|
+
}
|
|
1400
|
+
}
|
|
1401
|
+
)
|
|
1402
|
+
]
|
|
1403
|
+
}
|
|
1404
|
+
) });
|
|
1405
|
+
};
|
|
1406
|
+
var FallbackClientSideRenderer_default = FallbackClientSideRenderer;
|
|
1407
|
+
|
|
1408
|
+
// src/components/grid/clientSides.ts
|
|
1409
|
+
var clientSides = {
|
|
1410
|
+
"ExampleClientSideComponent": ExampleClientSideComponent_default,
|
|
1411
|
+
// Aseguramos el tipo aquí también
|
|
1412
|
+
"FallbackClientSideRenderer": FallbackClientSideRenderer_default
|
|
1413
|
+
// Y aquí
|
|
1414
|
+
};
|
|
1415
|
+
var extendClientSides = (newRenderers) => {
|
|
1416
|
+
clientSides = { ...clientSides, ...newRenderers };
|
|
1417
|
+
console.log("clientSides extendidos:", clientSides);
|
|
1418
|
+
};
|
|
1419
|
+
|
|
1420
|
+
// src/components/grid/GenericDataGrid.tsx
|
|
1421
|
+
import { Fragment, jsx as jsx9, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
1422
|
+
var getPrimaryKeyValues = (row, primaryKey) => {
|
|
1423
|
+
return primaryKey.map((key) => {
|
|
1424
|
+
return row[key] !== void 0 && row[key] !== null ? String(row[key]) : "NULL_OR_UNDEFINED";
|
|
1425
|
+
}).join("|");
|
|
1426
|
+
};
|
|
1427
|
+
var NEW_ROW_INDICATOR = ".$new";
|
|
1428
|
+
var GenericDataGrid = ({
|
|
1429
|
+
tableName,
|
|
1430
|
+
fixedFields
|
|
1431
|
+
}) => {
|
|
1432
|
+
const [tableDefinition, setTableDefinition] = useState4(null);
|
|
1433
|
+
const [tableData, setTableData] = useState4([]);
|
|
1434
|
+
const [isFilterRowVisible, setIsFilterRowVisible] = useState4(false);
|
|
1435
|
+
const [filters, setFilters] = useState4({});
|
|
1436
|
+
const [selectedRows, setSelectedRows] = useState4(() => /* @__PURE__ */ new Set());
|
|
1437
|
+
const [cellFeedback, setCellFeedback] = useState4(null);
|
|
1438
|
+
const [localCellChanges, setLocalCellChanges] = useState4(/* @__PURE__ */ new Map());
|
|
1439
|
+
const theme = useTheme();
|
|
1440
|
+
const [openConfirmDialog, setOpenConfirmDialog] = useState4(false);
|
|
1441
|
+
const [rowToDelete, setRowToDelete] = useState4(null);
|
|
1442
|
+
const [exitingRowIds, setExitingRowIds] = useState4(/* @__PURE__ */ new Set());
|
|
1443
|
+
const { showSuccess, showError, showWarning, showInfo } = useSnackbar();
|
|
1444
|
+
const feedbackTimerRef = useRef(null);
|
|
1445
|
+
const dataGridRef = useRef(null);
|
|
1446
|
+
const { callApi, loading, error } = useApiCall();
|
|
1447
|
+
useEffect(() => {
|
|
1448
|
+
setFilters({});
|
|
1449
|
+
setIsFilterRowVisible(false);
|
|
1450
|
+
setSelectedRows(/* @__PURE__ */ new Set());
|
|
1451
|
+
setTableDefinition(null);
|
|
1452
|
+
setTableData([]);
|
|
1453
|
+
setCellFeedback(null);
|
|
1454
|
+
setLocalCellChanges(/* @__PURE__ */ new Map());
|
|
1455
|
+
setOpenConfirmDialog(false);
|
|
1456
|
+
setRowToDelete(null);
|
|
1457
|
+
setExitingRowIds(/* @__PURE__ */ new Set());
|
|
1458
|
+
if (feedbackTimerRef.current) {
|
|
1459
|
+
clearTimeout(feedbackTimerRef.current);
|
|
1460
|
+
}
|
|
1461
|
+
}, [tableName]);
|
|
1462
|
+
useEffect(() => {
|
|
1463
|
+
const fetchDataAndDefinition = async () => {
|
|
1464
|
+
try {
|
|
1465
|
+
const definition = await callApi("table_structure", { table: tableName });
|
|
1466
|
+
setTableDefinition(definition);
|
|
1467
|
+
const data = await callApi("table_data", {
|
|
1468
|
+
table: tableName,
|
|
1469
|
+
fixedFields
|
|
1470
|
+
// Envía el array fixedFields directamente a la API
|
|
1471
|
+
});
|
|
1472
|
+
setTableData(data);
|
|
1473
|
+
} catch (err) {
|
|
1474
|
+
setTableDefinition(null);
|
|
1475
|
+
setTableData([]);
|
|
1476
|
+
showError(`Error al cargar datos para la tabla '${tableName}': ${err.message || "Error desconocido"}`);
|
|
1477
|
+
} finally {
|
|
1478
|
+
}
|
|
1479
|
+
};
|
|
1480
|
+
fetchDataAndDefinition();
|
|
1481
|
+
}, [tableName, fixedFields, showError]);
|
|
1482
|
+
useEffect(() => {
|
|
1483
|
+
if (cellFeedback) {
|
|
1484
|
+
if (feedbackTimerRef.current) {
|
|
1485
|
+
clearTimeout(feedbackTimerRef.current);
|
|
1486
|
+
}
|
|
1487
|
+
const timerDuration = cellFeedback.type === "success" ? 4e3 : 3e3;
|
|
1488
|
+
feedbackTimerRef.current = setTimeout(() => {
|
|
1489
|
+
setCellFeedback(null);
|
|
1490
|
+
}, timerDuration);
|
|
1491
|
+
}
|
|
1492
|
+
return () => {
|
|
1493
|
+
if (feedbackTimerRef.current) {
|
|
1494
|
+
clearTimeout(feedbackTimerRef.current);
|
|
1495
|
+
}
|
|
1496
|
+
};
|
|
1497
|
+
}, [cellFeedback]);
|
|
1498
|
+
const primaryKey = useMemo2(() => {
|
|
1499
|
+
if (!tableDefinition) return ["id"];
|
|
1500
|
+
return tableDefinition.primaryKey && tableDefinition.primaryKey.length > 0 ? tableDefinition.primaryKey : ["id"];
|
|
1501
|
+
}, [tableDefinition]);
|
|
1502
|
+
const toggleFilterVisibility = useCallback4(() => {
|
|
1503
|
+
setIsFilterRowVisible((prev) => {
|
|
1504
|
+
if (prev) {
|
|
1505
|
+
setFilters({});
|
|
1506
|
+
}
|
|
1507
|
+
return !prev;
|
|
1508
|
+
});
|
|
1509
|
+
}, []);
|
|
1510
|
+
const handleAddRow = useCallback4(() => {
|
|
1511
|
+
if (!tableDefinition) {
|
|
1512
|
+
showWarning("No se puede agregar una fila sin la definici\xF3n de la tabla.");
|
|
1513
|
+
return;
|
|
1514
|
+
}
|
|
1515
|
+
const newRow = {};
|
|
1516
|
+
tableDefinition.fields.forEach((field) => {
|
|
1517
|
+
newRow[field.name] = null;
|
|
1518
|
+
});
|
|
1519
|
+
newRow[NEW_ROW_INDICATOR] = true;
|
|
1520
|
+
if (fixedFields) {
|
|
1521
|
+
fixedFields.forEach((fixedField) => {
|
|
1522
|
+
newRow[fixedField.fieldName] = fixedField.value;
|
|
1523
|
+
});
|
|
1524
|
+
}
|
|
1525
|
+
setTableData((prevData) => [newRow, ...prevData]);
|
|
1526
|
+
setSelectedRows(/* @__PURE__ */ new Set());
|
|
1527
|
+
const tempRowId = getPrimaryKeyValues(newRow, primaryKey);
|
|
1528
|
+
setLocalCellChanges((prev) => {
|
|
1529
|
+
const newMap = new Map(prev);
|
|
1530
|
+
const mandatoryEditableColumns = /* @__PURE__ */ new Set();
|
|
1531
|
+
tableDefinition.fields.forEach((field) => {
|
|
1532
|
+
const isMandatory = field.nullable === false || field.isPk;
|
|
1533
|
+
const isEditable = field.editable !== false;
|
|
1534
|
+
if (isMandatory && isEditable) {
|
|
1535
|
+
mandatoryEditableColumns.add(field.name);
|
|
1536
|
+
}
|
|
1537
|
+
});
|
|
1538
|
+
newMap.set(tempRowId, mandatoryEditableColumns);
|
|
1539
|
+
return newMap;
|
|
1540
|
+
});
|
|
1541
|
+
}, [tableDefinition, showWarning, primaryKey, fixedFields]);
|
|
1542
|
+
const handleDeleteRow = useCallback4(async (row) => {
|
|
1543
|
+
setRowToDelete(row);
|
|
1544
|
+
setOpenConfirmDialog(true);
|
|
1545
|
+
}, []);
|
|
1546
|
+
const handleConfirmDelete = useCallback4(async (confirm) => {
|
|
1547
|
+
setOpenConfirmDialog(false);
|
|
1548
|
+
if (!confirm || !rowToDelete) {
|
|
1549
|
+
showWarning("Eliminaci\xF3n cancelada por el usuario.");
|
|
1550
|
+
setRowToDelete(null);
|
|
1551
|
+
return;
|
|
1552
|
+
}
|
|
1553
|
+
if (!tableDefinition || !tableName) {
|
|
1554
|
+
showError("No se puede eliminar la fila sin la definici\xF3n de la tabla o el nombre de la tabla.");
|
|
1555
|
+
setRowToDelete(null);
|
|
1556
|
+
return;
|
|
1557
|
+
}
|
|
1558
|
+
const rowId = getPrimaryKeyValues(rowToDelete, primaryKey);
|
|
1559
|
+
setExitingRowIds((prev) => new Set(prev).add(rowId));
|
|
1560
|
+
setTimeout(async () => {
|
|
1561
|
+
if (rowToDelete[NEW_ROW_INDICATOR]) {
|
|
1562
|
+
setTimeout(() => {
|
|
1563
|
+
setTableData((prevData) => prevData.filter((row) => getPrimaryKeyValues(row, primaryKey) !== rowId));
|
|
1564
|
+
setLocalCellChanges((prev) => {
|
|
1565
|
+
const newMap = new Map(prev);
|
|
1566
|
+
newMap.delete(rowId);
|
|
1567
|
+
return newMap;
|
|
1568
|
+
});
|
|
1569
|
+
setSelectedRows((prev) => {
|
|
1570
|
+
const newSet = new Set(prev);
|
|
1571
|
+
newSet.delete(rowId);
|
|
1572
|
+
return newSet;
|
|
1573
|
+
});
|
|
1574
|
+
setExitingRowIds((prev) => {
|
|
1575
|
+
const newSet = new Set(prev);
|
|
1576
|
+
newSet.delete(rowId);
|
|
1577
|
+
return newSet;
|
|
1578
|
+
});
|
|
1579
|
+
showInfo(`Fila no guardada '${rowId}' eliminada localmente.`);
|
|
1580
|
+
setRowToDelete(null);
|
|
1581
|
+
}, 500);
|
|
1582
|
+
return;
|
|
1583
|
+
}
|
|
1584
|
+
try {
|
|
1585
|
+
const primaryKeyValues = tableDefinition.primaryKey.map((key) => rowToDelete[key]);
|
|
1586
|
+
await callApi("table_record_delete", {
|
|
1587
|
+
table: tableName,
|
|
1588
|
+
primaryKeyValues
|
|
1589
|
+
});
|
|
1590
|
+
console.log(`Fila con ID ${rowId} eliminada exitosamente del backend.`);
|
|
1591
|
+
setTimeout(() => {
|
|
1592
|
+
setTableData((prevData) => prevData.filter((row) => getPrimaryKeyValues(row, primaryKey) !== rowId));
|
|
1593
|
+
setLocalCellChanges((prev) => {
|
|
1594
|
+
const newMap = new Map(prev);
|
|
1595
|
+
newMap.delete(rowId);
|
|
1596
|
+
return newMap;
|
|
1597
|
+
});
|
|
1598
|
+
setSelectedRows((prev) => {
|
|
1599
|
+
const newSet = new Set(prev);
|
|
1600
|
+
newSet.delete(rowId);
|
|
1601
|
+
return newSet;
|
|
1602
|
+
});
|
|
1603
|
+
setExitingRowIds((prev) => {
|
|
1604
|
+
const newSet = new Set(prev);
|
|
1605
|
+
newSet.delete(rowId);
|
|
1606
|
+
return newSet;
|
|
1607
|
+
});
|
|
1608
|
+
showSuccess(`Fila '${rowId}' eliminada exitosamente.`);
|
|
1609
|
+
setRowToDelete(null);
|
|
1610
|
+
}, 500);
|
|
1611
|
+
} catch (err) {
|
|
1612
|
+
console.error(`Error al eliminar la fila '${rowId}':`, err);
|
|
1613
|
+
showError(`Error al eliminar la fila '${rowId}': ${err.message || "Error desconocido"}`);
|
|
1614
|
+
setExitingRowIds((prev) => {
|
|
1615
|
+
const newSet = new Set(prev);
|
|
1616
|
+
newSet.delete(rowId);
|
|
1617
|
+
return newSet;
|
|
1618
|
+
});
|
|
1619
|
+
setRowToDelete(null);
|
|
1620
|
+
}
|
|
1621
|
+
}, 10);
|
|
1622
|
+
}, [rowToDelete, tableDefinition, tableName, primaryKey, showInfo, showSuccess, showError, showWarning, setTableData, setLocalCellChanges, setSelectedRows]);
|
|
1623
|
+
const filteredRows = useMemo2(() => {
|
|
1624
|
+
let rows = tableData;
|
|
1625
|
+
if (isFilterRowVisible) {
|
|
1626
|
+
Object.keys(filters).forEach((key) => {
|
|
1627
|
+
const filterValue = filters[key].toLowerCase();
|
|
1628
|
+
if (filterValue) {
|
|
1629
|
+
rows = rows.filter((row) => {
|
|
1630
|
+
const cellValue = String(row[key] || "").toLowerCase();
|
|
1631
|
+
return cellValue.includes(filterValue);
|
|
1632
|
+
});
|
|
1633
|
+
}
|
|
1634
|
+
});
|
|
1635
|
+
}
|
|
1636
|
+
return rows;
|
|
1637
|
+
}, [tableData, filters, isFilterRowVisible]);
|
|
1638
|
+
const handleEnterKeyPressInEditor = useCallback4((rowIndex, columnKey, currentColumns) => {
|
|
1639
|
+
if (dataGridRef.current && tableDefinition) {
|
|
1640
|
+
const currentColumnIndex = currentColumns.findIndex((col) => col.key === columnKey);
|
|
1641
|
+
if (currentColumnIndex !== -1) {
|
|
1642
|
+
let nextColumnIndex = currentColumnIndex + 1;
|
|
1643
|
+
let nextRowIndex = rowIndex;
|
|
1644
|
+
let foundNextTarget = false;
|
|
1645
|
+
while (!foundNextTarget) {
|
|
1646
|
+
if (nextColumnIndex >= currentColumns.length) {
|
|
1647
|
+
nextColumnIndex = 0;
|
|
1648
|
+
nextRowIndex++;
|
|
1649
|
+
if (nextRowIndex >= filteredRows.length) {
|
|
1650
|
+
nextRowIndex = 0;
|
|
1651
|
+
nextColumnIndex = 0;
|
|
1652
|
+
if (filteredRows.length === 0 || rowIndex === filteredRows.length - 1 && currentColumnIndex === currentColumns.length - 1) {
|
|
1653
|
+
foundNextTarget = true;
|
|
1654
|
+
break;
|
|
1655
|
+
}
|
|
1656
|
+
}
|
|
1657
|
+
}
|
|
1658
|
+
const nextColumn = currentColumns[nextColumnIndex];
|
|
1659
|
+
if (nextColumn) {
|
|
1660
|
+
const fieldDefinition = tableDefinition.fields.find((f) => f.name === nextColumn.key);
|
|
1661
|
+
const isEditableField = fieldDefinition?.editable !== false;
|
|
1662
|
+
if (nextColumn.key !== "filterToggle" && nextColumn.key !== "deleteAction" && isEditableField) {
|
|
1663
|
+
foundNextTarget = true;
|
|
1664
|
+
} else {
|
|
1665
|
+
nextColumnIndex++;
|
|
1666
|
+
}
|
|
1667
|
+
} else {
|
|
1668
|
+
nextColumnIndex++;
|
|
1669
|
+
}
|
|
1670
|
+
}
|
|
1671
|
+
if (foundNextTarget) {
|
|
1672
|
+
dataGridRef.current.selectCell({ rowIdx: nextRowIndex, idx: nextColumnIndex }, { enableEditor: false, scrollIntoView: true });
|
|
1673
|
+
}
|
|
1674
|
+
}
|
|
1675
|
+
}
|
|
1676
|
+
}, [filteredRows, tableDefinition]);
|
|
1677
|
+
const columns = useMemo2(() => {
|
|
1678
|
+
if (!tableDefinition) return [];
|
|
1679
|
+
const fieldsToShow = tableDefinition.fields.filter((field) => {
|
|
1680
|
+
const fixedFieldEntry = fixedFields?.find((f) => f.fieldName === field.name);
|
|
1681
|
+
return !(fixedFieldEntry && fixedFieldEntry.until === void 0);
|
|
1682
|
+
});
|
|
1683
|
+
const defaultColumns = fieldsToShow.map((field) => {
|
|
1684
|
+
const isFixedField = fixedFields?.some((f) => f.fieldName === field.name);
|
|
1685
|
+
const isFieldEditable = field.editable !== false && !isFixedField;
|
|
1686
|
+
return {
|
|
1687
|
+
key: field.name,
|
|
1688
|
+
name: field.label || cambiarGuionesBajosPorEspacios(field.name),
|
|
1689
|
+
resizable: true,
|
|
1690
|
+
sortable: true,
|
|
1691
|
+
editable: isFieldEditable,
|
|
1692
|
+
// Usar la nueva bandera de editable
|
|
1693
|
+
flexGrow: 1,
|
|
1694
|
+
minWidth: 60,
|
|
1695
|
+
isPK: field.isPk,
|
|
1696
|
+
renderHeaderCell: (props) => /* @__PURE__ */ jsx9(PkHeaderRenderer_default, { ...props }),
|
|
1697
|
+
renderSummaryCell: ({ column }) => {
|
|
1698
|
+
const fixedFieldEntry = fixedFields?.find((f) => f.fieldName === column.key);
|
|
1699
|
+
if (fixedFieldEntry && fixedFieldEntry.until === void 0) return null;
|
|
1700
|
+
return isFilterRowVisible ? /* @__PURE__ */ jsx9(
|
|
1701
|
+
FilterInputRender_default,
|
|
1702
|
+
{
|
|
1703
|
+
column,
|
|
1704
|
+
filters,
|
|
1705
|
+
setFilters
|
|
1706
|
+
}
|
|
1707
|
+
) : null;
|
|
1708
|
+
},
|
|
1709
|
+
renderCell: (props) => {
|
|
1710
|
+
const rowId = getPrimaryKeyValues(props.row, primaryKey);
|
|
1711
|
+
const fieldDefinition = tableDefinition.fields.find((f) => f.name === props.column.key);
|
|
1712
|
+
if (fieldDefinition?.clientSide) {
|
|
1713
|
+
const ClientSideComponent = clientSides[fieldDefinition.clientSide];
|
|
1714
|
+
if (ClientSideComponent) {
|
|
1715
|
+
return /* @__PURE__ */ jsx9(
|
|
1716
|
+
ClientSideComponent,
|
|
1717
|
+
{
|
|
1718
|
+
...props,
|
|
1719
|
+
fieldDefinition,
|
|
1720
|
+
tableDefinition,
|
|
1721
|
+
primaryKey
|
|
1722
|
+
}
|
|
1723
|
+
);
|
|
1724
|
+
} else {
|
|
1725
|
+
return /* @__PURE__ */ jsx9(
|
|
1726
|
+
FallbackClientSideRenderer_default,
|
|
1727
|
+
{
|
|
1728
|
+
...props,
|
|
1729
|
+
fieldDefinition,
|
|
1730
|
+
tableDefinition,
|
|
1731
|
+
primaryKey
|
|
1732
|
+
}
|
|
1733
|
+
);
|
|
1734
|
+
}
|
|
1735
|
+
}
|
|
1736
|
+
let cellBackgroundColor = "transparent";
|
|
1737
|
+
if (cellFeedback && cellFeedback.rowId === rowId && cellFeedback.columnKey === props.column.key) {
|
|
1738
|
+
cellBackgroundColor = cellFeedback.type === "error" ? theme.palette.error.light : theme.palette.success.light;
|
|
1739
|
+
} else {
|
|
1740
|
+
const isNewRowLocalCheck = props.row[NEW_ROW_INDICATOR];
|
|
1741
|
+
const isMandatory = tableDefinition.primaryKey.includes(props.column.key) || tableDefinition.fields.find((f) => f.name === props.column.key)?.nullable === false;
|
|
1742
|
+
const hasValue = props.row[props.column.key] !== null && props.row[props.column.key] !== void 0 && String(props.row[props.column.key]).trim() !== "";
|
|
1743
|
+
const isFixedFieldCurrent = fixedFields?.some((f) => f.fieldName === props.column.key);
|
|
1744
|
+
if (isFixedFieldCurrent) {
|
|
1745
|
+
cellBackgroundColor = theme.palette.action.selected;
|
|
1746
|
+
} else if (isNewRowLocalCheck && isMandatory && !hasValue || localCellChanges.has(rowId) && localCellChanges.get(rowId)?.has(props.column.key)) {
|
|
1747
|
+
cellBackgroundColor = theme.palette.info.light;
|
|
1748
|
+
}
|
|
1749
|
+
}
|
|
1750
|
+
return /* @__PURE__ */ jsx9(
|
|
1751
|
+
Box4,
|
|
1752
|
+
{
|
|
1753
|
+
sx: {
|
|
1754
|
+
position: "absolute",
|
|
1755
|
+
top: 0,
|
|
1756
|
+
left: 0,
|
|
1757
|
+
width: "100%",
|
|
1758
|
+
height: "100%",
|
|
1759
|
+
backgroundColor: cellBackgroundColor,
|
|
1760
|
+
transition: "background-color 0.3s ease-in-out",
|
|
1761
|
+
display: "flex",
|
|
1762
|
+
alignItems: "center",
|
|
1763
|
+
paddingLeft: "8px",
|
|
1764
|
+
boxSizing: "border-box"
|
|
1765
|
+
},
|
|
1766
|
+
children: /* @__PURE__ */ jsx9(
|
|
1767
|
+
PkCellRenderer_default,
|
|
1768
|
+
{
|
|
1769
|
+
...props,
|
|
1770
|
+
column: { ...props.column, isPK: !!field.isPk }
|
|
1771
|
+
}
|
|
1772
|
+
)
|
|
1773
|
+
}
|
|
1774
|
+
);
|
|
1775
|
+
}
|
|
1776
|
+
};
|
|
1777
|
+
});
|
|
1778
|
+
const filterToggleColumn = {
|
|
1779
|
+
key: "filterToggle",
|
|
1780
|
+
name: "",
|
|
1781
|
+
width: 50,
|
|
1782
|
+
resizable: false,
|
|
1783
|
+
sortable: false,
|
|
1784
|
+
frozen: true,
|
|
1785
|
+
renderHeaderCell: () => /* @__PURE__ */ jsx9(
|
|
1786
|
+
IconButton,
|
|
1787
|
+
{
|
|
1788
|
+
color: "inherit",
|
|
1789
|
+
onClick: toggleFilterVisibility,
|
|
1790
|
+
size: "small",
|
|
1791
|
+
title: isFilterRowVisible ? "Ocultar filtros" : "Mostrar filtros",
|
|
1792
|
+
sx: { p: 0.5 },
|
|
1793
|
+
children: isFilterRowVisible ? /* @__PURE__ */ jsx9(SearchOffIcon, { sx: { fontSize: 20 } }) : /* @__PURE__ */ jsx9(SearchIcon, { sx: { fontSize: 20 } })
|
|
1794
|
+
}
|
|
1795
|
+
),
|
|
1796
|
+
renderSummaryCell: () => null
|
|
1797
|
+
};
|
|
1798
|
+
const deleteActionColumn = {
|
|
1799
|
+
key: "deleteAction",
|
|
1800
|
+
name: "",
|
|
1801
|
+
width: 50,
|
|
1802
|
+
resizable: false,
|
|
1803
|
+
sortable: false,
|
|
1804
|
+
frozen: true,
|
|
1805
|
+
renderHeaderCell: () => null,
|
|
1806
|
+
renderSummaryCell: () => null,
|
|
1807
|
+
renderCell: ({ row }) => {
|
|
1808
|
+
if (!tableDefinition.allow?.delete) {
|
|
1809
|
+
return null;
|
|
1810
|
+
}
|
|
1811
|
+
return /* @__PURE__ */ jsx9(Box4, { sx: { display: "flex", justifyContent: "center", alignItems: "center", height: "100%" }, children: /* @__PURE__ */ jsx9(
|
|
1812
|
+
Button2,
|
|
1813
|
+
{
|
|
1814
|
+
variant: "outlined",
|
|
1815
|
+
color: "error",
|
|
1816
|
+
size: "small",
|
|
1817
|
+
onClick: () => handleDeleteRow(row),
|
|
1818
|
+
title: "Eliminar fila",
|
|
1819
|
+
sx: {
|
|
1820
|
+
minWidth: 35,
|
|
1821
|
+
height: 30,
|
|
1822
|
+
p: 0.5,
|
|
1823
|
+
"& .MuiButton-startIcon": { m: 0 }
|
|
1824
|
+
},
|
|
1825
|
+
children: /* @__PURE__ */ jsx9(DeleteIcon, { sx: { fontSize: 18 } })
|
|
1826
|
+
}
|
|
1827
|
+
) });
|
|
1828
|
+
}
|
|
1829
|
+
};
|
|
1830
|
+
const allColumns = [filterToggleColumn, deleteActionColumn, ...defaultColumns];
|
|
1831
|
+
return allColumns.map((col) => {
|
|
1832
|
+
if (col.editable) {
|
|
1833
|
+
const fieldDefinition = tableDefinition.fields.find((f) => f.name === col.key);
|
|
1834
|
+
const isFixedField = fixedFields?.some((f) => f.fieldName === col.key);
|
|
1835
|
+
const isFieldEditableByUI = fieldDefinition?.editable !== false && !isFixedField;
|
|
1836
|
+
if (!isFieldEditableByUI) {
|
|
1837
|
+
return { ...col, renderEditCell: void 0 };
|
|
1838
|
+
}
|
|
1839
|
+
return {
|
|
1840
|
+
...col,
|
|
1841
|
+
renderEditCell: (props) => {
|
|
1842
|
+
return /* @__PURE__ */ jsx9(
|
|
1843
|
+
InputRendered_default,
|
|
1844
|
+
{
|
|
1845
|
+
...props,
|
|
1846
|
+
tableDefinition,
|
|
1847
|
+
setCellFeedback,
|
|
1848
|
+
onEnterPress: (rowIndex, columnKey) => handleEnterKeyPressInEditor(rowIndex, columnKey, allColumns),
|
|
1849
|
+
setTableData,
|
|
1850
|
+
setLocalCellChanges,
|
|
1851
|
+
localCellChanges,
|
|
1852
|
+
primaryKey
|
|
1853
|
+
}
|
|
1854
|
+
);
|
|
1855
|
+
}
|
|
1856
|
+
};
|
|
1857
|
+
}
|
|
1858
|
+
return col;
|
|
1859
|
+
});
|
|
1860
|
+
}, [
|
|
1861
|
+
tableDefinition,
|
|
1862
|
+
isFilterRowVisible,
|
|
1863
|
+
filters,
|
|
1864
|
+
toggleFilterVisibility,
|
|
1865
|
+
cellFeedback,
|
|
1866
|
+
primaryKey,
|
|
1867
|
+
theme.palette.success.light,
|
|
1868
|
+
theme.palette.error.light,
|
|
1869
|
+
theme.palette.info.light,
|
|
1870
|
+
theme.palette.action.selected,
|
|
1871
|
+
// Añade el color de campos fijos
|
|
1872
|
+
handleEnterKeyPressInEditor,
|
|
1873
|
+
setTableData,
|
|
1874
|
+
localCellChanges,
|
|
1875
|
+
handleDeleteRow,
|
|
1876
|
+
fixedFields
|
|
1877
|
+
// Añade fixedFields como dependencia
|
|
1878
|
+
]);
|
|
1879
|
+
const showNoRowsMessage = filteredRows.length === 0 && !loading && !error;
|
|
1880
|
+
const handleRowsChange = useCallback4((updatedRows) => {
|
|
1881
|
+
setTableData(updatedRows);
|
|
1882
|
+
}, []);
|
|
1883
|
+
const handleCellClick = useCallback4((args) => {
|
|
1884
|
+
const fieldDefinition = tableDefinition?.fields.find((f) => f.name === args.column.key);
|
|
1885
|
+
const isFixedField = fixedFields?.some((f) => f.fieldName === args.column.key);
|
|
1886
|
+
const isEditable = fieldDefinition?.editable !== false && !isFixedField;
|
|
1887
|
+
console.log("Clicked column index:", args.column.idx);
|
|
1888
|
+
console.log("Clicked row index:", args.rowIdx);
|
|
1889
|
+
console.log("Is editable:", isEditable);
|
|
1890
|
+
}, [tableDefinition, fixedFields]);
|
|
1891
|
+
if (loading) {
|
|
1892
|
+
return /* @__PURE__ */ jsxs4(Box4, { display: "flex", justifyContent: "center", alignItems: "center", minHeight: "200px", children: [
|
|
1893
|
+
/* @__PURE__ */ jsx9(CircularProgress, {}),
|
|
1894
|
+
/* @__PURE__ */ jsx9(Typography5, { variant: "h6", sx: { ml: 2 }, children: "Cargando tabla..." })
|
|
1895
|
+
] });
|
|
1896
|
+
}
|
|
1897
|
+
if (error) {
|
|
1898
|
+
return /* @__PURE__ */ jsx9(Box4, { display: "flex", justifyContent: "center", alignItems: "center", minHeight: "200px", children: /* @__PURE__ */ jsx9(Alert, { severity: "error", children: error.message }) });
|
|
1899
|
+
}
|
|
1900
|
+
if (!tableDefinition) {
|
|
1901
|
+
return /* @__PURE__ */ jsx9(Box4, { display: "flex", justifyContent: "center", alignItems: "center", minHeight: "200px", children: /* @__PURE__ */ jsx9(Alert, { severity: "warning", children: "No se pudo cargar la definici\xF3n de la tabla." }) });
|
|
1902
|
+
}
|
|
1903
|
+
return /* @__PURE__ */ jsxs4(Box4, { sx: { p: 0, display: "flex", flexDirection: "column", height: "100%", boxSizing: "border-box" }, children: [
|
|
1904
|
+
/* @__PURE__ */ jsx9(Box4, { sx: { display: "flex", justifyContent: "space-between", alignItems: "center", px: 2, pt: 2, pb: 1 }, children: /* @__PURE__ */ jsx9(Typography5, { variant: "h4", gutterBottom: true, sx: { m: 0 }, children: cambiarGuionesBajosPorEspacios(tableDefinition.title || tableDefinition.name) }) }),
|
|
1905
|
+
tableDefinition.allow?.insert && /* @__PURE__ */ jsx9(Box4, { sx: { display: "flex", px: 2 }, children: /* @__PURE__ */ jsx9(
|
|
1906
|
+
Button2,
|
|
1907
|
+
{
|
|
1908
|
+
variant: "contained",
|
|
1909
|
+
onClick: handleAddRow,
|
|
1910
|
+
startIcon: /* @__PURE__ */ jsx9(AddIcon, {}),
|
|
1911
|
+
children: "Nuevo Registro"
|
|
1912
|
+
}
|
|
1913
|
+
) }),
|
|
1914
|
+
/* @__PURE__ */ jsx9(Box4, { sx: { px: 2, pt: 2, pb: 1, fontSize: "0.9rem" }, children: filteredRows.length === tableData.length ? /* @__PURE__ */ jsxs4(Box4, { children: [
|
|
1915
|
+
"mostrando ",
|
|
1916
|
+
`${tableData.length} registros`
|
|
1917
|
+
] }) : /* @__PURE__ */ jsx9(Fragment, { children: /* @__PURE__ */ jsxs4(Box4, { children: [
|
|
1918
|
+
"mostrando ",
|
|
1919
|
+
`${filteredRows.length} registros filtrados`
|
|
1920
|
+
] }) }) }),
|
|
1921
|
+
/* @__PURE__ */ jsxs4(
|
|
1922
|
+
Box4,
|
|
1923
|
+
{
|
|
1924
|
+
sx: {
|
|
1925
|
+
flexGrow: showNoRowsMessage ? 0 : 1,
|
|
1926
|
+
height: showNoRowsMessage ? "150px" : "100%",
|
|
1927
|
+
boxSizing: "border-box",
|
|
1928
|
+
position: "relative",
|
|
1929
|
+
overflowX: "auto",
|
|
1930
|
+
overflowY: "auto",
|
|
1931
|
+
px: 2,
|
|
1932
|
+
pb: 2
|
|
1933
|
+
},
|
|
1934
|
+
children: [
|
|
1935
|
+
/* @__PURE__ */ jsx9(
|
|
1936
|
+
DataGrid,
|
|
1937
|
+
{
|
|
1938
|
+
ref: dataGridRef,
|
|
1939
|
+
columns,
|
|
1940
|
+
rows: filteredRows.map((row) => ({
|
|
1941
|
+
...row,
|
|
1942
|
+
style: exitingRowIds.has(getPrimaryKeyValues(row, primaryKey)) ? { maxHeight: 0, opacity: 0, overflow: "hidden" } : { maxHeight: "35px", opacity: 1 }
|
|
1943
|
+
})),
|
|
1944
|
+
enableVirtualization: true,
|
|
1945
|
+
rowKeyGetter: (row) => getPrimaryKeyValues(row, primaryKey),
|
|
1946
|
+
onSelectedRowsChange: setSelectedRows,
|
|
1947
|
+
onRowsChange: handleRowsChange,
|
|
1948
|
+
selectedRows,
|
|
1949
|
+
rowHeight: (row) => exitingRowIds.has(getPrimaryKeyValues(row, primaryKey)) ? 0 : 35,
|
|
1950
|
+
style: { height: "100%", width: "100%", boxSizing: "border-box" },
|
|
1951
|
+
headerRowHeight: 35,
|
|
1952
|
+
topSummaryRows: isFilterRowVisible ? [{ id: "filterRow" }] : void 0,
|
|
1953
|
+
summaryRowHeight: isFilterRowVisible ? 35 : 0,
|
|
1954
|
+
onCellClick: handleCellClick
|
|
1955
|
+
}
|
|
1956
|
+
),
|
|
1957
|
+
showNoRowsMessage && /* @__PURE__ */ jsx9(
|
|
1958
|
+
Box4,
|
|
1959
|
+
{
|
|
1960
|
+
sx: {
|
|
1961
|
+
position: "absolute",
|
|
1962
|
+
top: isFilterRowVisible ? "70px" : "36px",
|
|
1963
|
+
left: (theme2) => theme2.spacing(2),
|
|
1964
|
+
right: (theme2) => theme2.spacing(2),
|
|
1965
|
+
bottom: (theme2) => theme2.spacing(2),
|
|
1966
|
+
display: "flex",
|
|
1967
|
+
justifyContent: "center",
|
|
1968
|
+
alignItems: "center",
|
|
1969
|
+
backgroundColor: "rgba(255, 255, 255, 0.9)",
|
|
1970
|
+
color: (theme2) => theme2.palette.text.secondary,
|
|
1971
|
+
border: (theme2) => `1px solid ${theme2.palette.divider}`,
|
|
1972
|
+
borderRadius: "4px",
|
|
1973
|
+
zIndex: 1
|
|
1974
|
+
},
|
|
1975
|
+
children: /* @__PURE__ */ jsx9(Typography5, { variant: "h6", children: "No hay filas para mostrar." })
|
|
1976
|
+
}
|
|
1977
|
+
)
|
|
1978
|
+
]
|
|
1979
|
+
}
|
|
1980
|
+
),
|
|
1981
|
+
/* @__PURE__ */ jsx9(
|
|
1982
|
+
ConfirmDialog,
|
|
1983
|
+
{
|
|
1984
|
+
open: openConfirmDialog,
|
|
1985
|
+
onClose: handleConfirmDelete,
|
|
1986
|
+
title: "Confirmar Eliminaci\xF3n",
|
|
1987
|
+
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."
|
|
1988
|
+
}
|
|
1989
|
+
)
|
|
1990
|
+
] });
|
|
1991
|
+
};
|
|
1992
|
+
var GenericDataGrid_default = GenericDataGrid;
|
|
1993
|
+
|
|
1994
|
+
// src/App.tsx
|
|
1995
|
+
import React11, { useEffect as useEffect7 } from "react";
|
|
1996
|
+
import { BrowserRouter, Routes, Route, useLocation as useLocation4, Navigate as Navigate2 } from "react-router-dom";
|
|
1997
|
+
|
|
1998
|
+
// src/components/MainLayout.tsx
|
|
1999
|
+
import { useEffect as useEffect3 } from "react";
|
|
2000
|
+
import { Outlet } from "react-router-dom";
|
|
2001
|
+
import {
|
|
2002
|
+
Box as Box7,
|
|
2003
|
+
AppBar,
|
|
2004
|
+
Toolbar,
|
|
2005
|
+
Typography as Typography8,
|
|
2006
|
+
Button as Button3,
|
|
2007
|
+
Drawer,
|
|
2008
|
+
CssBaseline,
|
|
2009
|
+
IconButton as IconButton2,
|
|
2010
|
+
useTheme as useTheme2,
|
|
2011
|
+
useMediaQuery
|
|
2012
|
+
} from "@mui/material";
|
|
2013
|
+
|
|
2014
|
+
// src/contexts/AppContext.tsx
|
|
2015
|
+
import { createContext as createContext2, useContext as useContext2, useState as useState5, useEffect as useEffect2, useCallback as useCallback5, useMemo as useMemo3 } from "react";
|
|
2016
|
+
import { useNavigate } from "react-router-dom";
|
|
2017
|
+
import { useSelector as useSelector2, useDispatch as useDispatch2 } from "react-redux";
|
|
2018
|
+
import { jsx as jsx10 } from "react/jsx-runtime";
|
|
2019
|
+
var AuthContext = createContext2(void 0);
|
|
2020
|
+
var useApp = () => {
|
|
2021
|
+
const context = useContext2(AuthContext);
|
|
2022
|
+
if (!context) {
|
|
2023
|
+
throw new Error("useApp must be used within an AppProvider");
|
|
2024
|
+
}
|
|
2025
|
+
const clientContext = useSelector2((state) => state.clientContext);
|
|
2026
|
+
return { ...context, clientContext };
|
|
2027
|
+
};
|
|
2028
|
+
var AppProvider = ({ children }) => {
|
|
2029
|
+
console.log("AppProvider rendered/re-rendered");
|
|
2030
|
+
const [isLoggedIn, setIsLoggedIn] = useState5(false);
|
|
2031
|
+
const [showSessionExpiredMessage, setShowSessionExpiredMessage] = useState5(false);
|
|
2032
|
+
const dispatch = useDispatch2();
|
|
2033
|
+
const clientContext = useSelector2((state) => state.clientContext);
|
|
2034
|
+
const navigate = useNavigate();
|
|
2035
|
+
const checkSession = useCallback5(async () => {
|
|
2036
|
+
try {
|
|
2037
|
+
const response = await fetchApi("/keep-alive.json", { method: "GET" });
|
|
2038
|
+
if (response.ok) {
|
|
2039
|
+
setIsLoggedIn(true);
|
|
2040
|
+
setShowSessionExpiredMessage(false);
|
|
2041
|
+
if (clientContext.status === "idle" || clientContext.status === "failed") {
|
|
2042
|
+
console.log("Client context needs loading/reloading, dispatching fetchClientContext thunk...");
|
|
2043
|
+
try {
|
|
2044
|
+
await dispatch(fetchClientContext()).unwrap();
|
|
2045
|
+
console.log("Client context data loaded successfully by Redux.");
|
|
2046
|
+
} catch (loadError) {
|
|
2047
|
+
console.error("Error loading client context data during session check:", loadError);
|
|
2048
|
+
}
|
|
2049
|
+
}
|
|
2050
|
+
} else {
|
|
2051
|
+
setIsLoggedIn(false);
|
|
2052
|
+
dispatch(clearClientContext());
|
|
2053
|
+
if (!showSessionExpiredMessage && window.location.pathname !== "/login") {
|
|
2054
|
+
setShowSessionExpiredMessage(true);
|
|
2055
|
+
}
|
|
2056
|
+
}
|
|
2057
|
+
} catch (error) {
|
|
2058
|
+
console.error("Error checking session:", error);
|
|
2059
|
+
setIsLoggedIn(false);
|
|
2060
|
+
dispatch(clearClientContext());
|
|
2061
|
+
if (!showSessionExpiredMessage && window.location.pathname !== "/login") {
|
|
2062
|
+
setShowSessionExpiredMessage(true);
|
|
2063
|
+
}
|
|
2064
|
+
}
|
|
2065
|
+
}, [dispatch, clientContext.status, showSessionExpiredMessage]);
|
|
2066
|
+
useEffect2(() => {
|
|
2067
|
+
checkSession();
|
|
2068
|
+
const intervalId = setInterval(checkSession, 15 * 1e3);
|
|
2069
|
+
return () => {
|
|
2070
|
+
clearInterval(intervalId);
|
|
2071
|
+
};
|
|
2072
|
+
}, [checkSession]);
|
|
2073
|
+
const authContextValue = useMemo3(() => ({
|
|
2074
|
+
isLoggedIn,
|
|
2075
|
+
setIsLoggedIn,
|
|
2076
|
+
checkSession,
|
|
2077
|
+
showSessionExpiredMessage,
|
|
2078
|
+
setShowSessionExpiredMessage
|
|
2079
|
+
}), [
|
|
2080
|
+
isLoggedIn,
|
|
2081
|
+
setIsLoggedIn,
|
|
2082
|
+
checkSession,
|
|
2083
|
+
showSessionExpiredMessage,
|
|
2084
|
+
setShowSessionExpiredMessage
|
|
2085
|
+
]);
|
|
2086
|
+
return /* @__PURE__ */ jsx10(AuthContext.Provider, { value: authContextValue, children });
|
|
2087
|
+
};
|
|
2088
|
+
|
|
2089
|
+
// src/components/MainLayout.tsx
|
|
2090
|
+
import LogoutIcon from "@mui/icons-material/Logout";
|
|
2091
|
+
import MenuIcon from "@mui/icons-material/Menu";
|
|
2092
|
+
import ChevronLeftIcon from "@mui/icons-material/ChevronLeft";
|
|
2093
|
+
|
|
2094
|
+
// src/components/SideMenu.tsx
|
|
2095
|
+
import { List, ListItem, ListItemButton, ListItemIcon, ListItemText, Divider, Box as Box6, Typography as Typography7, Collapse } from "@mui/material";
|
|
2096
|
+
import ExpandLess from "@mui/icons-material/ExpandLess";
|
|
2097
|
+
import ExpandMore from "@mui/icons-material/ExpandMore";
|
|
2098
|
+
import TableChartIcon from "@mui/icons-material/TableChart";
|
|
2099
|
+
import FolderIcon from "@mui/icons-material/Folder";
|
|
2100
|
+
import DnsIcon from "@mui/icons-material/Dns";
|
|
2101
|
+
import HomeIcon from "@mui/icons-material/Home";
|
|
2102
|
+
import WarningAmberIcon3 from "@mui/icons-material/WarningAmber";
|
|
2103
|
+
import DesktopWindowsIcon from "@mui/icons-material/DesktopWindows";
|
|
2104
|
+
import UnfoldMoreIcon from "@mui/icons-material/UnfoldMore";
|
|
2105
|
+
import UnfoldLessIcon from "@mui/icons-material/UnfoldLess";
|
|
2106
|
+
import { useNavigate as useNavigate2, useLocation } from "react-router-dom";
|
|
2107
|
+
import { blue, orange, teal, red, grey } from "@mui/material/colors";
|
|
2108
|
+
|
|
2109
|
+
// src/pages/WScreens.tsx
|
|
2110
|
+
import { Box as Box5, Typography as Typography6, Paper } from "@mui/material";
|
|
2111
|
+
import ConstructionIcon from "@mui/icons-material/Construction";
|
|
2112
|
+
import WarningAmberIcon2 from "@mui/icons-material/WarningAmber";
|
|
2113
|
+
import { jsx as jsx11, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
2114
|
+
var MyCustomDashboard = ({ screenName }) => {
|
|
2115
|
+
return /* @__PURE__ */ jsx11(Box5, { sx: { p: 4, display: "flex", flexDirection: "column", alignItems: "center", justifyContent: "center", height: "100%" }, children: /* @__PURE__ */ jsxs5(Paper, { elevation: 3, sx: { p: 4, textAlign: "center", maxWidth: 600 }, children: [
|
|
2116
|
+
/* @__PURE__ */ jsxs5(Typography6, { variant: "h5", component: "h1", gutterBottom: true, children: [
|
|
2117
|
+
"\xA1Bienvenido a tu WScreen: ",
|
|
2118
|
+
screenName,
|
|
2119
|
+
"!"
|
|
2120
|
+
] }),
|
|
2121
|
+
/* @__PURE__ */ jsx11(Typography6, { variant: "body1", color: "text.secondary", children: "Esta es una pantalla de interfaz de usuario personalizada." }),
|
|
2122
|
+
/* @__PURE__ */ jsx11(Box5, { sx: { mt: 3 }, children: /* @__PURE__ */ jsx11(ConstructionIcon, { sx: { fontSize: 80, color: "primary.main" } }) })
|
|
2123
|
+
] }) });
|
|
2124
|
+
};
|
|
2125
|
+
var FallbackWScreen = ({ screenName }) => {
|
|
2126
|
+
return /* @__PURE__ */ jsx11(Box5, { sx: { p: 4, display: "flex", flexDirection: "column", alignItems: "center", justifyContent: "center", height: "100%" }, children: /* @__PURE__ */ jsxs5(Paper, { elevation: 3, sx: { p: 4, textAlign: "center", maxWidth: 600, backgroundColor: "warning.light", border: "1px solid orange" }, children: [
|
|
2127
|
+
/* @__PURE__ */ jsx11(Typography6, { variant: "h5", component: "h1", gutterBottom: true, color: "warning.dark", children: "WScreen No Implementada" }),
|
|
2128
|
+
/* @__PURE__ */ jsxs5(Typography6, { variant: "body1", color: "warning.dark", children: [
|
|
2129
|
+
'No se encontr\xF3 un componente implementado para la **WScreen**: **`"$',
|
|
2130
|
+
screenName,
|
|
2131
|
+
'"`**. Por favor, verifica el `menuType` en la definici\xF3n del men\xFA o aseg\xFArate de que el componente est\xE9 correctamente importado y mapeado en el frontend.'
|
|
2132
|
+
] }),
|
|
2133
|
+
/* @__PURE__ */ jsx11(Box5, { sx: { mt: 3 }, children: /* @__PURE__ */ jsx11(WarningAmberIcon2, { sx: { fontSize: 80, color: "warning.dark" } }) })
|
|
2134
|
+
] }) });
|
|
2135
|
+
};
|
|
2136
|
+
var wScreens = {
|
|
2137
|
+
"MyCustomDashboard": MyCustomDashboard
|
|
2138
|
+
// Agrega más componentes de wScreen aquí:
|
|
2139
|
+
// 'AnotherWScreen': AnotherWScreenComponent,
|
|
2140
|
+
};
|
|
2141
|
+
var WScreens_default = FallbackWScreen;
|
|
2142
|
+
|
|
2143
|
+
// src/components/SideMenu.tsx
|
|
2144
|
+
import { Fragment as Fragment2, jsx as jsx12, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
2145
|
+
var MenuListItem = ({ item, level, onMenuItemClick }) => {
|
|
2146
|
+
const navigate = useNavigate2();
|
|
2147
|
+
const location = useLocation();
|
|
2148
|
+
const open = useSubMenuOpenState(item.name);
|
|
2149
|
+
const dispatch = useAppDispatch();
|
|
2150
|
+
const handleClick = () => {
|
|
2151
|
+
if (item.menuType === "menu") {
|
|
2152
|
+
dispatch(toggleSubMenu(item.name));
|
|
2153
|
+
} else {
|
|
2154
|
+
let path = "";
|
|
2155
|
+
const queryParams = new URLSearchParams();
|
|
2156
|
+
if (item.menuType === "table") {
|
|
2157
|
+
path = `/menu/${item.name}`;
|
|
2158
|
+
if (item.td) queryParams.append("td", JSON.stringify(item.td));
|
|
2159
|
+
if (item.fc) queryParams.append("fc", JSON.stringify(item.fc));
|
|
2160
|
+
if (queryParams.toString()) {
|
|
2161
|
+
path = `${path}?${queryParams.toString()}`;
|
|
2162
|
+
}
|
|
2163
|
+
} else if (item.menuType === "proc") {
|
|
2164
|
+
path = `/procedures/${item.name}`;
|
|
2165
|
+
} else {
|
|
2166
|
+
const WScreenComponent = wScreens[item.menuType];
|
|
2167
|
+
if (WScreenComponent !== void 0) {
|
|
2168
|
+
path = `/wScreens/${item.menuType}`;
|
|
2169
|
+
} else {
|
|
2170
|
+
path = `/wScreens-fallback/${item.menuType}`;
|
|
2171
|
+
console.warn(`Menu type '${item.menuType}' no reconocido o WScreen no mapeada.`);
|
|
2172
|
+
}
|
|
2173
|
+
}
|
|
2174
|
+
if (path) {
|
|
2175
|
+
navigate(path);
|
|
2176
|
+
}
|
|
2177
|
+
if (onMenuItemClick) {
|
|
2178
|
+
onMenuItemClick();
|
|
2179
|
+
}
|
|
2180
|
+
}
|
|
2181
|
+
};
|
|
2182
|
+
const getIcon = (item2) => {
|
|
2183
|
+
switch (item2.menuType) {
|
|
2184
|
+
case "table":
|
|
2185
|
+
return /* @__PURE__ */ jsx12(TableChartIcon, { sx: { color: blue[700] } });
|
|
2186
|
+
case "proc":
|
|
2187
|
+
return /* @__PURE__ */ jsx12(DnsIcon, { sx: { color: teal[700] } });
|
|
2188
|
+
case "menu":
|
|
2189
|
+
return /* @__PURE__ */ jsx12(FolderIcon, { sx: { color: orange[800] } });
|
|
2190
|
+
default:
|
|
2191
|
+
const WScreenComponent = wScreens[item2.menuType];
|
|
2192
|
+
if (WScreenComponent !== void 0) {
|
|
2193
|
+
return /* @__PURE__ */ jsx12(DesktopWindowsIcon, { sx: { color: grey[700] } });
|
|
2194
|
+
}
|
|
2195
|
+
return /* @__PURE__ */ jsx12(WarningAmberIcon3, { sx: { color: red[500] } });
|
|
2196
|
+
}
|
|
2197
|
+
};
|
|
2198
|
+
const currentPath = location.pathname;
|
|
2199
|
+
let isSelected = false;
|
|
2200
|
+
if (item.menuType === "table") {
|
|
2201
|
+
isSelected = currentPath === `/menu/table/${item.name}`;
|
|
2202
|
+
} else if (item.menuType === "proc") {
|
|
2203
|
+
isSelected = currentPath === `/procedures/${item.name}`;
|
|
2204
|
+
} else {
|
|
2205
|
+
isSelected = currentPath.startsWith(`/wScreens/${item.menuType}`) || currentPath.startsWith(`/wScreens-fallback/${item.menuType}`);
|
|
2206
|
+
}
|
|
2207
|
+
return /* @__PURE__ */ jsxs6(Fragment2, { children: [
|
|
2208
|
+
/* @__PURE__ */ jsxs6(
|
|
2209
|
+
ListItemButton,
|
|
2210
|
+
{
|
|
2211
|
+
onClick: handleClick,
|
|
2212
|
+
sx: { pl: level * 2 },
|
|
2213
|
+
selected: isSelected,
|
|
2214
|
+
children: [
|
|
2215
|
+
/* @__PURE__ */ jsx12(ListItemIcon, { sx: { minWidth: "38px" }, children: getIcon(item) }),
|
|
2216
|
+
/* @__PURE__ */ jsx12(ListItemText, { primary: item.label || item.name }),
|
|
2217
|
+
item.menuType === "menu" ? open ? /* @__PURE__ */ jsx12(ExpandLess, {}) : /* @__PURE__ */ jsx12(ExpandMore, {}) : null
|
|
2218
|
+
]
|
|
2219
|
+
}
|
|
2220
|
+
),
|
|
2221
|
+
item.menuType === "menu" && /* @__PURE__ */ jsx12(Collapse, { in: open, timeout: "auto", unmountOnExit: true, children: /* @__PURE__ */ jsx12(List, { component: "div", disablePadding: true, children: item.menuContent.map((subItem) => /* @__PURE__ */ jsx12(
|
|
2222
|
+
MenuListItem,
|
|
2223
|
+
{
|
|
2224
|
+
item: subItem,
|
|
2225
|
+
level: level + 1,
|
|
2226
|
+
onMenuItemClick
|
|
2227
|
+
},
|
|
2228
|
+
subItem.name
|
|
2229
|
+
)) }) })
|
|
2230
|
+
] });
|
|
2231
|
+
};
|
|
2232
|
+
var SideMenu = ({ onMenuItemClick }) => {
|
|
2233
|
+
const { clientContext } = useApp();
|
|
2234
|
+
const navigate = useNavigate2();
|
|
2235
|
+
const location = useLocation();
|
|
2236
|
+
const dispatch = useAppDispatch();
|
|
2237
|
+
const subMenuOpenStates = useAppSelector((state) => state.menuUi.subMenuOpenStates);
|
|
2238
|
+
const allSubMenusKeys = Object.keys(subMenuOpenStates);
|
|
2239
|
+
const openSubMenusCount = allSubMenusKeys.filter((key) => subMenuOpenStates[key]).length;
|
|
2240
|
+
const isMostlyOpen = allSubMenusKeys.length > 0 && openSubMenusCount / allSubMenusKeys.length > 0.5;
|
|
2241
|
+
const handleHomeClick = () => {
|
|
2242
|
+
navigate("/home");
|
|
2243
|
+
if (onMenuItemClick) {
|
|
2244
|
+
onMenuItemClick();
|
|
2245
|
+
}
|
|
2246
|
+
};
|
|
2247
|
+
const handleToggleAllSubMenus = () => {
|
|
2248
|
+
dispatch(setAllSubMenusOpen(!isMostlyOpen));
|
|
2249
|
+
};
|
|
2250
|
+
if (!clientContext || !clientContext.menu) {
|
|
2251
|
+
return /* @__PURE__ */ jsx12(Box6, { sx: { p: 2, textAlign: "center" }, children: /* @__PURE__ */ jsx12(Typography7, { variant: "body2", color: "text.secondary", children: "Cargando men\xFA..." }) });
|
|
2252
|
+
}
|
|
2253
|
+
const isHomeSelected = location.pathname === "/home";
|
|
2254
|
+
return /* @__PURE__ */ jsxs6(Box6, { sx: { width: "100%", flexShrink: 0 }, children: [
|
|
2255
|
+
clientContext.menu.some((item) => item.menuType === "menu") && /* @__PURE__ */ jsx12(ListItem, { disablePadding: true, children: /* @__PURE__ */ jsxs6(ListItemButton, { onClick: handleToggleAllSubMenus, children: [
|
|
2256
|
+
/* @__PURE__ */ jsx12(ListItemIcon, { sx: { minWidth: "38px" }, children: isMostlyOpen ? /* @__PURE__ */ jsx12(UnfoldLessIcon, {}) : /* @__PURE__ */ jsx12(UnfoldMoreIcon, {}) }),
|
|
2257
|
+
/* @__PURE__ */ jsx12(ListItemText, { primary: isMostlyOpen ? "colapsar " : "expandir" })
|
|
2258
|
+
] }) }),
|
|
2259
|
+
/* @__PURE__ */ jsx12(Divider, {}),
|
|
2260
|
+
/* @__PURE__ */ jsxs6(List, { children: [
|
|
2261
|
+
/* @__PURE__ */ jsx12(ListItem, { disablePadding: true, children: /* @__PURE__ */ jsxs6(ListItemButton, { onClick: handleHomeClick, selected: isHomeSelected, children: [
|
|
2262
|
+
/* @__PURE__ */ jsx12(ListItemIcon, { sx: { minWidth: "38px" }, children: /* @__PURE__ */ jsx12(HomeIcon, {}) }),
|
|
2263
|
+
/* @__PURE__ */ jsx12(ListItemText, { primary: "Inicio" })
|
|
2264
|
+
] }) }),
|
|
2265
|
+
/* @__PURE__ */ jsx12(Divider, {}),
|
|
2266
|
+
clientContext.menu.map((menuItem) => /* @__PURE__ */ jsx12(
|
|
2267
|
+
MenuListItem,
|
|
2268
|
+
{
|
|
2269
|
+
item: menuItem,
|
|
2270
|
+
level: 1,
|
|
2271
|
+
onMenuItemClick
|
|
2272
|
+
},
|
|
2273
|
+
menuItem.name
|
|
2274
|
+
))
|
|
2275
|
+
] })
|
|
2276
|
+
] });
|
|
2277
|
+
};
|
|
2278
|
+
var SideMenu_default = SideMenu;
|
|
2279
|
+
|
|
2280
|
+
// src/hooks/useLogout.tsx
|
|
2281
|
+
import { useCallback as useCallback6 } from "react";
|
|
2282
|
+
import { useNavigate as useNavigate3 } from "react-router-dom";
|
|
2283
|
+
import { useDispatch as useDispatch3 } from "react-redux";
|
|
2284
|
+
var useLogout = () => {
|
|
2285
|
+
const { setIsLoggedIn } = useApp();
|
|
2286
|
+
const dispatch = useDispatch3();
|
|
2287
|
+
const navigate = useNavigate3();
|
|
2288
|
+
const logout = useCallback6(async () => {
|
|
2289
|
+
try {
|
|
2290
|
+
const response = await fetchApi("/logout", { method: "GET" });
|
|
2291
|
+
if (response.status === 401 || response.ok) {
|
|
2292
|
+
console.log("Sesi\xF3n cerrada correctamente o ya deslogueado");
|
|
2293
|
+
} else {
|
|
2294
|
+
console.error("Error al cerrar sesi\xF3n:", await response.text());
|
|
2295
|
+
}
|
|
2296
|
+
} catch (error) {
|
|
2297
|
+
console.error("Error de red al intentar cerrar sesi\xF3n:", error);
|
|
2298
|
+
} finally {
|
|
2299
|
+
setIsLoggedIn(false);
|
|
2300
|
+
dispatch(clearClientContext());
|
|
2301
|
+
navigate("/login", { replace: true });
|
|
2302
|
+
}
|
|
2303
|
+
}, [setIsLoggedIn, dispatch, navigate]);
|
|
2304
|
+
return logout;
|
|
2305
|
+
};
|
|
2306
|
+
var useLogout_default = useLogout;
|
|
2307
|
+
|
|
2308
|
+
// src/components/MainLayout.tsx
|
|
2309
|
+
import { jsx as jsx13, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
2310
|
+
var drawerWidth = 240;
|
|
2311
|
+
var MainLayout = () => {
|
|
2312
|
+
const { clientContext } = useApp();
|
|
2313
|
+
const logout = useLogout_default();
|
|
2314
|
+
const isDrawerOpen = useIsDrawerOpen();
|
|
2315
|
+
const dispatch = useAppDispatch();
|
|
2316
|
+
const theme = useTheme2();
|
|
2317
|
+
const isMobile = useMediaQuery(theme.breakpoints.down("sm"));
|
|
2318
|
+
useEffect3(() => {
|
|
2319
|
+
if (isMobile && isDrawerOpen) {
|
|
2320
|
+
dispatch(setDrawerOpen(false));
|
|
2321
|
+
}
|
|
2322
|
+
}, [isMobile, isDrawerOpen, dispatch]);
|
|
2323
|
+
const handleToggleDrawer = () => {
|
|
2324
|
+
dispatch(toggleDrawer());
|
|
2325
|
+
};
|
|
2326
|
+
const handleDrawerCloseMobile = () => {
|
|
2327
|
+
if (isMobile && isDrawerOpen) {
|
|
2328
|
+
dispatch(setDrawerOpen(false));
|
|
2329
|
+
}
|
|
2330
|
+
};
|
|
2331
|
+
if (!clientContext) {
|
|
2332
|
+
return /* @__PURE__ */ jsx13(Box7, { sx: { display: "flex", justifyContent: "center", alignItems: "center", height: "100vh" }, children: /* @__PURE__ */ jsx13(Typography8, { children: "Cargando dise\xF1o de la aplicaci\xF3n..." }) });
|
|
2333
|
+
}
|
|
2334
|
+
const appBarOffset = theme.mixins.toolbar;
|
|
2335
|
+
return /* @__PURE__ */ jsxs7(Box7, { sx: { display: "flex", height: "100vh" }, children: [
|
|
2336
|
+
/* @__PURE__ */ jsx13(CssBaseline, {}),
|
|
2337
|
+
/* @__PURE__ */ jsx13(
|
|
2338
|
+
AppBar,
|
|
2339
|
+
{
|
|
2340
|
+
position: "fixed",
|
|
2341
|
+
sx: {
|
|
2342
|
+
zIndex: (theme2) => theme2.zIndex.drawer + 1,
|
|
2343
|
+
transition: (theme2) => theme2.transitions.create(["width", "margin"], {
|
|
2344
|
+
easing: theme2.transitions.easing.sharp,
|
|
2345
|
+
duration: theme2.transitions.duration.leavingScreen
|
|
2346
|
+
}),
|
|
2347
|
+
...isDrawerOpen && {
|
|
2348
|
+
width: `calc(100% - ${drawerWidth}px)`,
|
|
2349
|
+
marginLeft: `${drawerWidth}px`,
|
|
2350
|
+
transition: (theme2) => theme2.transitions.create(["width", "margin"], {
|
|
2351
|
+
easing: theme2.transitions.easing.easeOut,
|
|
2352
|
+
duration: theme2.transitions.duration.enteringScreen
|
|
2353
|
+
})
|
|
2354
|
+
}
|
|
2355
|
+
},
|
|
2356
|
+
children: /* @__PURE__ */ jsxs7(Toolbar, { children: [
|
|
2357
|
+
/* @__PURE__ */ jsx13(
|
|
2358
|
+
IconButton2,
|
|
2359
|
+
{
|
|
2360
|
+
color: "inherit",
|
|
2361
|
+
"aria-label": "open drawer",
|
|
2362
|
+
onClick: handleToggleDrawer,
|
|
2363
|
+
edge: "start",
|
|
2364
|
+
sx: {
|
|
2365
|
+
marginRight: 2.2
|
|
2366
|
+
},
|
|
2367
|
+
children: isDrawerOpen ? /* @__PURE__ */ jsx13(ChevronLeftIcon, {}) : /* @__PURE__ */ jsx13(MenuIcon, {})
|
|
2368
|
+
}
|
|
2369
|
+
),
|
|
2370
|
+
/* @__PURE__ */ jsx13(Typography8, { variant: "h6", noWrap: true, component: "div", sx: { flexGrow: 1 }, children: isDrawerOpen ? "" : clientContext.config.title }),
|
|
2371
|
+
/* @__PURE__ */ jsx13(Typography8, { variant: "subtitle1", component: "div", sx: { mr: 2 }, children: clientContext.username }),
|
|
2372
|
+
/* @__PURE__ */ jsx13(
|
|
2373
|
+
Button3,
|
|
2374
|
+
{
|
|
2375
|
+
color: "inherit",
|
|
2376
|
+
onClick: logout,
|
|
2377
|
+
startIcon: /* @__PURE__ */ jsx13(LogoutIcon, {}),
|
|
2378
|
+
children: "Salir"
|
|
2379
|
+
}
|
|
2380
|
+
)
|
|
2381
|
+
] })
|
|
2382
|
+
}
|
|
2383
|
+
),
|
|
2384
|
+
/* @__PURE__ */ jsxs7(
|
|
2385
|
+
Drawer,
|
|
2386
|
+
{
|
|
2387
|
+
variant: "persistent",
|
|
2388
|
+
anchor: "left",
|
|
2389
|
+
open: isDrawerOpen,
|
|
2390
|
+
sx: {
|
|
2391
|
+
width: drawerWidth,
|
|
2392
|
+
flexShrink: 0,
|
|
2393
|
+
"& .MuiDrawer-paper": {
|
|
2394
|
+
width: drawerWidth,
|
|
2395
|
+
boxSizing: "border-box",
|
|
2396
|
+
overflowX: "hidden",
|
|
2397
|
+
overflowY: "auto"
|
|
2398
|
+
}
|
|
2399
|
+
},
|
|
2400
|
+
children: [
|
|
2401
|
+
/* @__PURE__ */ jsx13(
|
|
2402
|
+
Toolbar,
|
|
2403
|
+
{
|
|
2404
|
+
sx: {
|
|
2405
|
+
display: "flex",
|
|
2406
|
+
alignItems: "center",
|
|
2407
|
+
justifyContent: "flex-end",
|
|
2408
|
+
px: 1,
|
|
2409
|
+
fontSize: "1.3rem",
|
|
2410
|
+
minHeight: theme.mixins.toolbar.minHeight
|
|
2411
|
+
},
|
|
2412
|
+
children: isDrawerOpen ? clientContext.config.title : ""
|
|
2413
|
+
}
|
|
2414
|
+
),
|
|
2415
|
+
/* @__PURE__ */ jsx13(SideMenu_default, { onMenuItemClick: handleDrawerCloseMobile })
|
|
2416
|
+
]
|
|
2417
|
+
}
|
|
2418
|
+
),
|
|
2419
|
+
/* @__PURE__ */ jsx13(
|
|
2420
|
+
Box7,
|
|
2421
|
+
{
|
|
2422
|
+
component: "main",
|
|
2423
|
+
sx: {
|
|
2424
|
+
flexGrow: 1,
|
|
2425
|
+
transition: (theme2) => theme2.transitions.create("margin", {
|
|
2426
|
+
easing: theme2.transitions.easing.sharp,
|
|
2427
|
+
duration: theme2.transitions.duration.leavingScreen
|
|
2428
|
+
}),
|
|
2429
|
+
marginLeft: `-${drawerWidth}px`,
|
|
2430
|
+
...isDrawerOpen && {
|
|
2431
|
+
transition: (theme2) => theme2.transitions.create("margin", {
|
|
2432
|
+
easing: theme2.transitions.easing.easeOut,
|
|
2433
|
+
duration: theme2.transitions.duration.enteringScreen
|
|
2434
|
+
}),
|
|
2435
|
+
marginLeft: 0
|
|
2436
|
+
},
|
|
2437
|
+
minWidth: 0,
|
|
2438
|
+
flexShrink: 0,
|
|
2439
|
+
// Asegúrate de que el paddingTop sea suficiente para la AppBar
|
|
2440
|
+
paddingTop: `${appBarOffset.minHeight}px`,
|
|
2441
|
+
height: "100%",
|
|
2442
|
+
boxSizing: "border-box",
|
|
2443
|
+
display: "flex",
|
|
2444
|
+
flexDirection: "column",
|
|
2445
|
+
width: isDrawerOpen ? `calc(100% - ${drawerWidth}px)` : "100%"
|
|
2446
|
+
},
|
|
2447
|
+
children: /* @__PURE__ */ jsx13(Outlet, {})
|
|
2448
|
+
}
|
|
2449
|
+
)
|
|
2450
|
+
] });
|
|
2451
|
+
};
|
|
2452
|
+
var MainLayout_default = MainLayout;
|
|
2453
|
+
|
|
2454
|
+
// src/components/SessionExpiredMessage.tsx
|
|
2455
|
+
import { Box as Box8, Typography as Typography9, Button as Button4, Modal } from "@mui/material";
|
|
2456
|
+
import { useNavigate as useNavigate4 } from "react-router-dom";
|
|
2457
|
+
import { jsx as jsx14, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
2458
|
+
var style = {
|
|
2459
|
+
position: "absolute",
|
|
2460
|
+
top: "50%",
|
|
2461
|
+
left: "50%",
|
|
2462
|
+
transform: "translate(-50%, -50%)",
|
|
2463
|
+
width: 400,
|
|
2464
|
+
bgcolor: "background.paper",
|
|
2465
|
+
border: "2px solid #000",
|
|
2466
|
+
boxShadow: 24,
|
|
2467
|
+
p: 4,
|
|
2468
|
+
textAlign: "center",
|
|
2469
|
+
borderRadius: 2
|
|
2470
|
+
};
|
|
2471
|
+
var SessionExpiredMessage = () => {
|
|
2472
|
+
const { showSessionExpiredMessage, setShowSessionExpiredMessage, setIsLoggedIn } = useApp();
|
|
2473
|
+
const navigate = useNavigate4();
|
|
2474
|
+
const handleClose = () => {
|
|
2475
|
+
setShowSessionExpiredMessage(false);
|
|
2476
|
+
setIsLoggedIn(false);
|
|
2477
|
+
navigate("/login", { replace: true });
|
|
2478
|
+
};
|
|
2479
|
+
return /* @__PURE__ */ jsx14(
|
|
2480
|
+
Modal,
|
|
2481
|
+
{
|
|
2482
|
+
open: showSessionExpiredMessage,
|
|
2483
|
+
onClose: () => {
|
|
2484
|
+
},
|
|
2485
|
+
"aria-labelledby": "session-expired-modal-title",
|
|
2486
|
+
"aria-describedby": "session-expired-modal-description",
|
|
2487
|
+
disableEscapeKeyDown: true,
|
|
2488
|
+
slotProps: {
|
|
2489
|
+
backdrop: {
|
|
2490
|
+
// Esto es crucial en MUI v5: detiene la propagación del evento de clic en el backdrop,
|
|
2491
|
+
// impidiendo que el modal se cierre al hacer clic fuera.
|
|
2492
|
+
onClick: (event) => event.stopPropagation(),
|
|
2493
|
+
sx: {
|
|
2494
|
+
backgroundColor: "rgba(100, 100, 100, 0.95)"
|
|
2495
|
+
// Ajusta el color y la opacidad para un fondo más oscuro
|
|
2496
|
+
}
|
|
2497
|
+
}
|
|
2498
|
+
},
|
|
2499
|
+
children: /* @__PURE__ */ jsxs8(Box8, { sx: style, children: [
|
|
2500
|
+
/* @__PURE__ */ jsx14(Typography9, { id: "session-expired-modal-title", variant: "h6", component: "h2", gutterBottom: true, children: "\xA1Sesi\xF3n Expirada!" }),
|
|
2501
|
+
/* @__PURE__ */ jsx14(Typography9, { 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." }),
|
|
2502
|
+
/* @__PURE__ */ jsx14(Button4, { variant: "contained", color: "primary", onClick: handleClose, children: "Ir al Login" })
|
|
2503
|
+
] })
|
|
2504
|
+
}
|
|
2505
|
+
);
|
|
2506
|
+
};
|
|
2507
|
+
var SessionExpiredMessage_default = SessionExpiredMessage;
|
|
2508
|
+
|
|
2509
|
+
// src/pages/HomePage.tsx
|
|
2510
|
+
import { Box as Box9, Typography as Typography10 } from "@mui/material";
|
|
2511
|
+
import { jsx as jsx15, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
2512
|
+
var HomePage = () => {
|
|
2513
|
+
const { clientContext } = useApp();
|
|
2514
|
+
return /* @__PURE__ */ jsxs9(Box9, { sx: { p: 3 }, children: [
|
|
2515
|
+
/* @__PURE__ */ jsx15(Typography10, { variant: "h4", component: "h1", gutterBottom: true, children: `Bienvenido/a ${clientContext?.username}` }),
|
|
2516
|
+
/* @__PURE__ */ jsx15(Typography10, { variant: "body1", children: "Usa el men\xFA lateral para navegar por las diferentes secciones." })
|
|
2517
|
+
] });
|
|
2518
|
+
};
|
|
2519
|
+
var HomePage_default = HomePage;
|
|
2520
|
+
|
|
2521
|
+
// src/pages/LogoutPage.tsx
|
|
2522
|
+
import { useEffect as useEffect4 } from "react";
|
|
2523
|
+
import { Box as Box10, Typography as Typography11, CircularProgress as CircularProgress2 } from "@mui/material";
|
|
2524
|
+
import { jsx as jsx16, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
2525
|
+
var LogoutPage = () => {
|
|
2526
|
+
const logout = useLogout_default();
|
|
2527
|
+
useEffect4(() => {
|
|
2528
|
+
logout();
|
|
2529
|
+
}, [logout]);
|
|
2530
|
+
return /* @__PURE__ */ jsxs10(Box10, { sx: {
|
|
2531
|
+
display: "flex",
|
|
2532
|
+
flexDirection: "column",
|
|
2533
|
+
justifyContent: "center",
|
|
2534
|
+
alignItems: "center",
|
|
2535
|
+
height: "100vh",
|
|
2536
|
+
textAlign: "center"
|
|
2537
|
+
}, children: [
|
|
2538
|
+
/* @__PURE__ */ jsx16(CircularProgress2, { size: 60 }),
|
|
2539
|
+
/* @__PURE__ */ jsx16(Typography11, { variant: "h6", sx: { mt: 2 }, children: "Cerrando sesi\xF3n..." })
|
|
2540
|
+
] });
|
|
2541
|
+
};
|
|
2542
|
+
var LogoutPage_default = LogoutPage;
|
|
2543
|
+
|
|
2544
|
+
// src/pages/LoginPage.tsx
|
|
2545
|
+
import { useState as useState6 } from "react";
|
|
2546
|
+
import { Button as Button5, TextField, Typography as Typography12, Alert as Alert2, AlertTitle, Box as Box11, CircularProgress as CircularProgress3 } from "@mui/material";
|
|
2547
|
+
import { useForm, Controller } from "react-hook-form";
|
|
2548
|
+
import { zodResolver } from "@hookform/resolvers/zod";
|
|
2549
|
+
import * as z from "zod";
|
|
2550
|
+
import { useNavigate as useNavigate5 } from "react-router-dom";
|
|
2551
|
+
import { useDispatch as useDispatch4 } from "react-redux";
|
|
2552
|
+
import { Fragment as Fragment3, jsx as jsx17, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
2553
|
+
var loginSchema = z.object({
|
|
2554
|
+
username: z.string().min(1, "El usuario es requerido"),
|
|
2555
|
+
// Añadir validación básica
|
|
2556
|
+
password: z.string().min(1, "La contrase\xF1a es requerida")
|
|
2557
|
+
// Añadir validación básica
|
|
2558
|
+
});
|
|
2559
|
+
var LoginPage = () => {
|
|
2560
|
+
const navigate = useNavigate5();
|
|
2561
|
+
const [loginError, setLoginError] = useState6(null);
|
|
2562
|
+
const [isSubmitting, setIsSubmitting] = useState6(false);
|
|
2563
|
+
const { setIsLoggedIn, checkSession } = useApp();
|
|
2564
|
+
const dispatch = useDispatch4();
|
|
2565
|
+
const {
|
|
2566
|
+
control,
|
|
2567
|
+
handleSubmit,
|
|
2568
|
+
formState: { errors },
|
|
2569
|
+
reset
|
|
2570
|
+
} = useForm({
|
|
2571
|
+
resolver: zodResolver(loginSchema),
|
|
2572
|
+
defaultValues: {
|
|
2573
|
+
username: "",
|
|
2574
|
+
password: ""
|
|
2575
|
+
}
|
|
2576
|
+
});
|
|
2577
|
+
const onSubmit = async (data) => {
|
|
2578
|
+
setIsSubmitting(true);
|
|
2579
|
+
setLoginError(null);
|
|
2580
|
+
try {
|
|
2581
|
+
const body = new URLSearchParams({
|
|
2582
|
+
username: data.username,
|
|
2583
|
+
password: data.password
|
|
2584
|
+
});
|
|
2585
|
+
const loginResponse = await fetchApi("/login", {
|
|
2586
|
+
method: "POST",
|
|
2587
|
+
body
|
|
2588
|
+
// URLSearchParams se envía directamente como body para form-urlencoded
|
|
2589
|
+
// Asegúrate de que el Content-Type en el backend maneje 'application/x-www-form-urlencoded'
|
|
2590
|
+
});
|
|
2591
|
+
if (!loginResponse.ok || !loginResponse.url.endsWith("/menu")) {
|
|
2592
|
+
const errorText = "Credenciales incorrectas o error al iniciar sesi\xF3n";
|
|
2593
|
+
throw new Error(errorText);
|
|
2594
|
+
}
|
|
2595
|
+
setIsLoggedIn(true);
|
|
2596
|
+
await dispatch(fetchClientContext()).unwrap();
|
|
2597
|
+
console.log("Login exitoso y clientContext cargado.");
|
|
2598
|
+
navigate("/home");
|
|
2599
|
+
reset();
|
|
2600
|
+
} catch (error) {
|
|
2601
|
+
console.error("Error al iniciar sesi\xF3n:", error);
|
|
2602
|
+
setIsLoggedIn(false);
|
|
2603
|
+
setLoginError(error.message || "Ocurri\xF3 un error al iniciar sesi\xF3n. Int\xE9ntalo de nuevo.");
|
|
2604
|
+
} finally {
|
|
2605
|
+
setIsSubmitting(false);
|
|
2606
|
+
}
|
|
2607
|
+
};
|
|
2608
|
+
return /* @__PURE__ */ jsx17(
|
|
2609
|
+
Box11,
|
|
2610
|
+
{
|
|
2611
|
+
display: "flex",
|
|
2612
|
+
alignItems: "center",
|
|
2613
|
+
justifyContent: "center",
|
|
2614
|
+
minHeight: "100vh",
|
|
2615
|
+
bgcolor: "#f5f5f5",
|
|
2616
|
+
children: /* @__PURE__ */ jsxs11(
|
|
2617
|
+
Box11,
|
|
2618
|
+
{
|
|
2619
|
+
width: "100%",
|
|
2620
|
+
maxWidth: "400px",
|
|
2621
|
+
padding: 4,
|
|
2622
|
+
bgcolor: "white",
|
|
2623
|
+
borderRadius: 8,
|
|
2624
|
+
boxShadow: 3,
|
|
2625
|
+
children: [
|
|
2626
|
+
/* @__PURE__ */ jsx17(Typography12, { variant: "h5", align: "center", gutterBottom: true, children: "Iniciar Sesi\xF3n" }),
|
|
2627
|
+
/* @__PURE__ */ jsxs11("form", { onSubmit: handleSubmit(onSubmit), className: "space-y-4", children: [
|
|
2628
|
+
/* @__PURE__ */ jsxs11("div", { children: [
|
|
2629
|
+
/* @__PURE__ */ jsx17("label", { htmlFor: "username", children: /* @__PURE__ */ jsx17(Typography12, { variant: "subtitle1", component: "div", sx: { fontWeight: "medium" }, children: "Usuario" }) }),
|
|
2630
|
+
/* @__PURE__ */ jsx17(
|
|
2631
|
+
Controller,
|
|
2632
|
+
{
|
|
2633
|
+
name: "username",
|
|
2634
|
+
control,
|
|
2635
|
+
render: ({ field }) => /* @__PURE__ */ jsx17(
|
|
2636
|
+
TextField,
|
|
2637
|
+
{
|
|
2638
|
+
...field,
|
|
2639
|
+
type: "text",
|
|
2640
|
+
placeholder: "Ingresa tu usuario",
|
|
2641
|
+
fullWidth: true,
|
|
2642
|
+
margin: "normal",
|
|
2643
|
+
error: !!errors.username,
|
|
2644
|
+
helperText: errors.username?.message,
|
|
2645
|
+
disabled: isSubmitting
|
|
2646
|
+
}
|
|
2647
|
+
)
|
|
2648
|
+
}
|
|
2649
|
+
)
|
|
2650
|
+
] }),
|
|
2651
|
+
/* @__PURE__ */ jsxs11("div", { children: [
|
|
2652
|
+
/* @__PURE__ */ jsx17("label", { htmlFor: "password", children: /* @__PURE__ */ jsx17(Typography12, { variant: "subtitle1", component: "div", sx: { fontWeight: "medium" }, children: "Contrase\xF1a" }) }),
|
|
2653
|
+
/* @__PURE__ */ jsx17(
|
|
2654
|
+
Controller,
|
|
2655
|
+
{
|
|
2656
|
+
name: "password",
|
|
2657
|
+
control,
|
|
2658
|
+
render: ({ field }) => /* @__PURE__ */ jsx17(
|
|
2659
|
+
TextField,
|
|
2660
|
+
{
|
|
2661
|
+
...field,
|
|
2662
|
+
type: "password",
|
|
2663
|
+
placeholder: "Ingresa tu contrase\xF1a",
|
|
2664
|
+
fullWidth: true,
|
|
2665
|
+
margin: "normal",
|
|
2666
|
+
error: !!errors.password,
|
|
2667
|
+
helperText: errors.password?.message,
|
|
2668
|
+
disabled: isSubmitting
|
|
2669
|
+
}
|
|
2670
|
+
)
|
|
2671
|
+
}
|
|
2672
|
+
)
|
|
2673
|
+
] }),
|
|
2674
|
+
/* @__PURE__ */ jsx17(Button5, { type: "submit", fullWidth: true, variant: "contained", color: "primary", disabled: isSubmitting, sx: { mt: 2 }, children: isSubmitting ? /* @__PURE__ */ jsxs11(Fragment3, { children: [
|
|
2675
|
+
/* @__PURE__ */ jsx17(CircularProgress3, { size: 20, sx: { mr: 1 } }),
|
|
2676
|
+
"Iniciando sesi\xF3n..."
|
|
2677
|
+
] }) : "Iniciar Sesi\xF3n" })
|
|
2678
|
+
] }),
|
|
2679
|
+
loginError && /* @__PURE__ */ jsxs11(Alert2, { severity: "error", sx: { mt: 2, maxHeight: "200px" }, children: [
|
|
2680
|
+
" ",
|
|
2681
|
+
/* @__PURE__ */ jsx17(AlertTitle, { children: "Error" }),
|
|
2682
|
+
loginError
|
|
2683
|
+
] })
|
|
2684
|
+
]
|
|
2685
|
+
}
|
|
2686
|
+
)
|
|
2687
|
+
}
|
|
2688
|
+
);
|
|
2689
|
+
};
|
|
2690
|
+
var LoginPage_default = LoginPage;
|
|
2691
|
+
|
|
2692
|
+
// src/components/ProcedureForm.tsx
|
|
2693
|
+
import React7, { useState as useState7, useCallback as useCallback7, useMemo as useMemo4 } from "react";
|
|
2694
|
+
import { useParams } from "react-router-dom";
|
|
2695
|
+
import {
|
|
2696
|
+
TextField as TextField2,
|
|
2697
|
+
Button as Button6,
|
|
2698
|
+
FormControl,
|
|
2699
|
+
InputLabel,
|
|
2700
|
+
Select,
|
|
2701
|
+
MenuItem,
|
|
2702
|
+
Checkbox,
|
|
2703
|
+
FormControlLabel,
|
|
2704
|
+
FormHelperText,
|
|
2705
|
+
Typography as Typography14,
|
|
2706
|
+
Box as Box13,
|
|
2707
|
+
CircularProgress as CircularProgress4,
|
|
2708
|
+
Alert as Alert3,
|
|
2709
|
+
Divider as Divider2,
|
|
2710
|
+
Paper as Paper3
|
|
2711
|
+
} from "@mui/material";
|
|
2712
|
+
|
|
2713
|
+
// src/pages/procedure-results/SuccessDisplay.tsx
|
|
2714
|
+
import { Box as Box12, Typography as Typography13, Paper as Paper2 } from "@mui/material";
|
|
2715
|
+
import { jsx as jsx18, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
2716
|
+
var SuccessDisplay = ({ data }) => {
|
|
2717
|
+
return /* @__PURE__ */ jsxs12(Paper2, { elevation: 2, sx: { p: 2, mt: 2, bgcolor: "success.light", color: "success.contrastText" }, children: [
|
|
2718
|
+
/* @__PURE__ */ jsx18(Typography13, { variant: "h6", sx: { fontSize: "1rem", mb: 1 }, children: "\xA1Operaci\xF3n Exitosa!" }),
|
|
2719
|
+
/* @__PURE__ */ jsx18(Typography13, { variant: "body2", sx: { fontSize: "0.85rem" }, children: "Detalles del resultado:" }),
|
|
2720
|
+
/* @__PURE__ */ jsx18(Box12, { sx: { bgcolor: "success.dark", p: 1, borderRadius: 1, mt: 1, overflowX: "auto" }, children: /* @__PURE__ */ jsx18("pre", { style: { margin: 0, fontSize: "0.75rem", color: "white" }, children: JSON.stringify(data, null, 2) }) }),
|
|
2721
|
+
/* @__PURE__ */ jsx18(Typography13, { variant: "body2", sx: { fontSize: "0.8rem", mt: 1 }, children: "Puedes revisar los detalles anteriores o cerrar este mensaje." })
|
|
2722
|
+
] });
|
|
2723
|
+
};
|
|
2724
|
+
var SuccessDisplay_default = SuccessDisplay;
|
|
2725
|
+
|
|
2726
|
+
// src/pages/procedure-results/resultsOk.ts
|
|
2727
|
+
var resultsOk = {
|
|
2728
|
+
"successful_operation": SuccessDisplay_default
|
|
2729
|
+
};
|
|
2730
|
+
var extendResultsOk = (newComponents) => {
|
|
2731
|
+
resultsOk = { ...resultsOk, ...newComponents };
|
|
2732
|
+
};
|
|
2733
|
+
|
|
2734
|
+
// src/components/ProcedureForm.tsx
|
|
2735
|
+
import { jsx as jsx19, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
2736
|
+
var ProcedureForm = () => {
|
|
2737
|
+
const { procedureName } = useParams();
|
|
2738
|
+
const { clientContext } = useApp();
|
|
2739
|
+
const { callApi, loading: apiLoading, error: apiError } = useApiCall();
|
|
2740
|
+
const [validationErrors, setValidationErrors] = useState7({});
|
|
2741
|
+
const [successMessage, setSuccessMessage] = useState7(null);
|
|
2742
|
+
const [executionLog, setExecutionLog] = useState7([]);
|
|
2743
|
+
const [procedureResultData, setProcedureResultData] = useState7(null);
|
|
2744
|
+
const procedure = useMemo4(() => {
|
|
2745
|
+
if (procedureName && clientContext?.procedure) {
|
|
2746
|
+
return clientContext.procedure[procedureName];
|
|
2747
|
+
}
|
|
2748
|
+
return void 0;
|
|
2749
|
+
}, [procedureName, clientContext]);
|
|
2750
|
+
const [formValues, setFormValues] = useState7(() => {
|
|
2751
|
+
if (!procedure) return {};
|
|
2752
|
+
const initialValues = {};
|
|
2753
|
+
procedure.parameters.forEach((param) => {
|
|
2754
|
+
if (param.defaultValue !== void 0) {
|
|
2755
|
+
initialValues[param.name] = param.defaultValue;
|
|
2756
|
+
} else if (param.specialDefaultValue) {
|
|
2757
|
+
switch (param.specialDefaultValue) {
|
|
2758
|
+
case "current_date":
|
|
2759
|
+
initialValues[param.name] = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
2760
|
+
break;
|
|
2761
|
+
case "current_datetime":
|
|
2762
|
+
const now = /* @__PURE__ */ new Date();
|
|
2763
|
+
initialValues[param.name] = now.toISOString().substring(0, 16);
|
|
2764
|
+
break;
|
|
2765
|
+
default:
|
|
2766
|
+
initialValues[param.name] = param.specialDefaultValue;
|
|
2767
|
+
break;
|
|
2768
|
+
}
|
|
2769
|
+
} else {
|
|
2770
|
+
initialValues[param.name] = "";
|
|
2771
|
+
}
|
|
2772
|
+
});
|
|
2773
|
+
return initialValues;
|
|
2774
|
+
});
|
|
2775
|
+
React7.useEffect(() => {
|
|
2776
|
+
if (procedure) {
|
|
2777
|
+
setValidationErrors({});
|
|
2778
|
+
setSuccessMessage(null);
|
|
2779
|
+
setProcedureResultData(null);
|
|
2780
|
+
const newInitialValues = {};
|
|
2781
|
+
procedure.parameters.forEach((param) => {
|
|
2782
|
+
if (param.defaultValue !== void 0) {
|
|
2783
|
+
newInitialValues[param.name] = param.defaultValue;
|
|
2784
|
+
} else if (param.specialDefaultValue) {
|
|
2785
|
+
switch (param.specialDefaultValue) {
|
|
2786
|
+
case "current_date":
|
|
2787
|
+
newInitialValues[param.name] = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
2788
|
+
break;
|
|
2789
|
+
case "current_datetime":
|
|
2790
|
+
const now = /* @__PURE__ */ new Date();
|
|
2791
|
+
newInitialValues[param.name] = now.toISOString().substring(0, 16);
|
|
2792
|
+
break;
|
|
2793
|
+
default:
|
|
2794
|
+
newInitialValues[param.name] = param.specialDefaultValue;
|
|
2795
|
+
break;
|
|
2796
|
+
}
|
|
2797
|
+
} else {
|
|
2798
|
+
newInitialValues[param.name] = "";
|
|
2799
|
+
}
|
|
2800
|
+
});
|
|
2801
|
+
setFormValues(newInitialValues);
|
|
2802
|
+
setExecutionLog([]);
|
|
2803
|
+
}
|
|
2804
|
+
}, [procedure]);
|
|
2805
|
+
const addLogMessage = useCallback7((message, isError = false) => {
|
|
2806
|
+
const timestamp = (/* @__PURE__ */ new Date()).toLocaleTimeString("es-AR");
|
|
2807
|
+
setExecutionLog((prev) => [...prev, `[${timestamp}] ${isError ? "ERROR: " : ""}${message}`]);
|
|
2808
|
+
}, []);
|
|
2809
|
+
const handleChange = useCallback7((e, child) => {
|
|
2810
|
+
const { name, value } = e.target;
|
|
2811
|
+
let newValue = value;
|
|
2812
|
+
if (e.target.type === "checkbox") {
|
|
2813
|
+
newValue = e.target.checked;
|
|
2814
|
+
}
|
|
2815
|
+
setFormValues((prevValues) => ({
|
|
2816
|
+
...prevValues,
|
|
2817
|
+
[name]: newValue
|
|
2818
|
+
}));
|
|
2819
|
+
setValidationErrors((prev) => ({ ...prev, [name]: null }));
|
|
2820
|
+
setSuccessMessage(null);
|
|
2821
|
+
setProcedureResultData(null);
|
|
2822
|
+
}, []);
|
|
2823
|
+
const handleSubmit = async (e) => {
|
|
2824
|
+
e.preventDefault();
|
|
2825
|
+
setValidationErrors({});
|
|
2826
|
+
setSuccessMessage(null);
|
|
2827
|
+
setExecutionLog([]);
|
|
2828
|
+
setProcedureResultData(null);
|
|
2829
|
+
if (!procedure) {
|
|
2830
|
+
addLogMessage("Error: La definici\xF3n del procedimiento no est\xE1 disponible.", true);
|
|
2831
|
+
return;
|
|
2832
|
+
}
|
|
2833
|
+
addLogMessage(`Iniciando ejecuci\xF3n del procedimiento: ${procedure.action}...`);
|
|
2834
|
+
const paramsToSend = {};
|
|
2835
|
+
let currentValidationErrors = {};
|
|
2836
|
+
let hasOverallError = false;
|
|
2837
|
+
for (const param of procedure.parameters) {
|
|
2838
|
+
let value = formValues[param.name];
|
|
2839
|
+
let processedValue = value;
|
|
2840
|
+
let paramError = null;
|
|
2841
|
+
switch (param.typeName) {
|
|
2842
|
+
case "decimal":
|
|
2843
|
+
case "double":
|
|
2844
|
+
if (value === "" || value === null) {
|
|
2845
|
+
processedValue = null;
|
|
2846
|
+
} else {
|
|
2847
|
+
processedValue = parseFloat(value);
|
|
2848
|
+
if (isNaN(processedValue)) {
|
|
2849
|
+
paramError = `El valor para "${param.label || param.name}" no es un n\xFAmero v\xE1lido.`;
|
|
2850
|
+
}
|
|
2851
|
+
}
|
|
2852
|
+
break;
|
|
2853
|
+
case "integer":
|
|
2854
|
+
case "bigint":
|
|
2855
|
+
if (value === "" || value === null) {
|
|
2856
|
+
processedValue = null;
|
|
2857
|
+
} else {
|
|
2858
|
+
processedValue = parseInt(value, 10);
|
|
2859
|
+
if (isNaN(processedValue)) {
|
|
2860
|
+
paramError = `El valor para "${param.label || param.name}" no es un entero v\xE1lido.`;
|
|
2861
|
+
}
|
|
2862
|
+
}
|
|
2863
|
+
break;
|
|
2864
|
+
case "boolean":
|
|
2865
|
+
processedValue = !!value;
|
|
2866
|
+
break;
|
|
2867
|
+
case "jsonb":
|
|
2868
|
+
case "jsona":
|
|
2869
|
+
if (value === "" || value === null) {
|
|
2870
|
+
processedValue = null;
|
|
2871
|
+
} else {
|
|
2872
|
+
try {
|
|
2873
|
+
processedValue = JSON.parse(value);
|
|
2874
|
+
} catch (jsonError) {
|
|
2875
|
+
paramError = `Error en el formato JSON para "${param.label || param.name}": ${jsonError.message}`;
|
|
2876
|
+
}
|
|
2877
|
+
}
|
|
2878
|
+
break;
|
|
2879
|
+
case "bytea":
|
|
2880
|
+
processedValue = value instanceof File ? value : value === "" ? null : value;
|
|
2881
|
+
break;
|
|
2882
|
+
case "text":
|
|
2883
|
+
case "date":
|
|
2884
|
+
case "timestamp":
|
|
2885
|
+
case "time":
|
|
2886
|
+
case "interval":
|
|
2887
|
+
case "tsrange":
|
|
2888
|
+
case "time_range":
|
|
2889
|
+
case "daterange":
|
|
2890
|
+
default:
|
|
2891
|
+
processedValue = value === "" ? null : value;
|
|
2892
|
+
break;
|
|
2893
|
+
}
|
|
2894
|
+
const hasDefaultValue = param.defaultValue !== void 0 || param.specialDefaultValue !== void 0;
|
|
2895
|
+
const isEmpty = processedValue === null || processedValue === void 0 || typeof processedValue === "string" && processedValue.trim() === "";
|
|
2896
|
+
if (!hasDefaultValue && isEmpty) {
|
|
2897
|
+
paramError = `El campo "${param.label || param.name}" es obligatorio y no puede estar vac\xEDo.`;
|
|
2898
|
+
}
|
|
2899
|
+
if (paramError) {
|
|
2900
|
+
currentValidationErrors[param.name] = paramError;
|
|
2901
|
+
hasOverallError = true;
|
|
2902
|
+
addLogMessage(`Error de validaci\xF3n para "${param.label || param.name}": ${paramError}`, true);
|
|
2903
|
+
}
|
|
2904
|
+
paramsToSend[param.name] = processedValue;
|
|
2905
|
+
}
|
|
2906
|
+
if (hasOverallError) {
|
|
2907
|
+
setValidationErrors(currentValidationErrors);
|
|
2908
|
+
addLogMessage("No se puede ejecutar el procedimiento debido a errores de validaci\xF3n en el formulario.", true);
|
|
2909
|
+
return;
|
|
2910
|
+
}
|
|
2911
|
+
addLogMessage(`Par\xE1metros a enviar: ${JSON.stringify(paramsToSend, null, 2)}`);
|
|
2912
|
+
try {
|
|
2913
|
+
addLogMessage("Invocando procedimiento a trav\xE9s de useApiCall...");
|
|
2914
|
+
const result = await callApi(procedure.action, paramsToSend);
|
|
2915
|
+
if (result !== void 0) {
|
|
2916
|
+
setSuccessMessage(procedure.resultOk || "Procedimiento ejecutado con \xE9xito.");
|
|
2917
|
+
addLogMessage("Procedimiento ejecutado con \xE9xito.");
|
|
2918
|
+
addLogMessage(`Resultado: ${JSON.stringify(result, null, 2)}`);
|
|
2919
|
+
setProcedureResultData(result);
|
|
2920
|
+
console.log("Resultado del procedimiento:", result);
|
|
2921
|
+
} else {
|
|
2922
|
+
addLogMessage("Procedimiento finalizado con errores.", true);
|
|
2923
|
+
}
|
|
2924
|
+
} catch (err) {
|
|
2925
|
+
console.error("Error al ejecutar el procedimiento (capturado en ProcedureForm):", err);
|
|
2926
|
+
addLogMessage(`Error en la ejecuci\xF3n: ${err.message || "Error desconocido."}`, true);
|
|
2927
|
+
} finally {
|
|
2928
|
+
addLogMessage("Ejecuci\xF3n finalizada.");
|
|
2929
|
+
}
|
|
2930
|
+
};
|
|
2931
|
+
const renderInputField = useCallback7((param) => {
|
|
2932
|
+
const hasError = !!validationErrors[param.name];
|
|
2933
|
+
const errorMessage = validationErrors[param.name];
|
|
2934
|
+
const commonProps = {
|
|
2935
|
+
id: param.name,
|
|
2936
|
+
name: param.name,
|
|
2937
|
+
label: param.label || param.name,
|
|
2938
|
+
variant: "outlined",
|
|
2939
|
+
fullWidth: true,
|
|
2940
|
+
margin: "dense",
|
|
2941
|
+
required: !(param.defaultValue !== void 0 || param.specialDefaultValue !== void 0),
|
|
2942
|
+
size: "small",
|
|
2943
|
+
helperText: errorMessage || param.description,
|
|
2944
|
+
error: hasError,
|
|
2945
|
+
disabled: apiLoading,
|
|
2946
|
+
onChange: handleChange,
|
|
2947
|
+
sx: { fontSize: "0.8rem" }
|
|
2948
|
+
};
|
|
2949
|
+
if (param.options && param.options.length > 0) {
|
|
2950
|
+
return /* @__PURE__ */ jsxs13(FormControl, { fullWidth: true, margin: "dense", size: "small", error: hasError, required: commonProps.required, children: [
|
|
2951
|
+
/* @__PURE__ */ jsx19(InputLabel, { id: `${param.name}-label`, sx: { fontSize: "0.8rem" }, children: param.label || param.name }),
|
|
2952
|
+
/* @__PURE__ */ jsxs13(
|
|
2953
|
+
Select,
|
|
2954
|
+
{
|
|
2955
|
+
labelId: `${param.name}-label`,
|
|
2956
|
+
value: formValues[param.name] === void 0 ? "" : formValues[param.name],
|
|
2957
|
+
onChange: handleChange,
|
|
2958
|
+
name: param.name,
|
|
2959
|
+
id: param.name,
|
|
2960
|
+
label: param.label || param.name,
|
|
2961
|
+
disabled: apiLoading,
|
|
2962
|
+
sx: { fontSize: "0.8rem" },
|
|
2963
|
+
renderValue: (selected) => /* @__PURE__ */ jsx19(Typography14, { sx: { fontSize: "0.8rem" }, children: selected }),
|
|
2964
|
+
children: [
|
|
2965
|
+
(!commonProps.required || formValues[param.name] === "") && /* @__PURE__ */ jsx19(MenuItem, { value: "", sx: { fontSize: "0.8rem" }, children: /* @__PURE__ */ jsx19("em", { children: "Seleccione..." }) }),
|
|
2966
|
+
param.options.map((option) => /* @__PURE__ */ jsx19(MenuItem, { value: option, sx: { fontSize: "0.8rem" }, children: option }, option))
|
|
2967
|
+
]
|
|
2968
|
+
}
|
|
2969
|
+
),
|
|
2970
|
+
(param.description || errorMessage) && /* @__PURE__ */ jsx19(FormHelperText, { sx: { fontSize: "0.7rem" }, children: errorMessage || param.description })
|
|
2971
|
+
] });
|
|
2972
|
+
}
|
|
2973
|
+
switch (param.typeName) {
|
|
2974
|
+
case "text":
|
|
2975
|
+
case "interval":
|
|
2976
|
+
case "tsrange":
|
|
2977
|
+
case "time_range":
|
|
2978
|
+
case "daterange":
|
|
2979
|
+
return /* @__PURE__ */ jsx19(TextField2, { type: "text", value: formValues[param.name] || "", ...commonProps });
|
|
2980
|
+
case "decimal":
|
|
2981
|
+
case "double":
|
|
2982
|
+
return /* @__PURE__ */ jsx19(TextField2, { type: "number", inputProps: { step: "any", style: { fontSize: "0.8rem" } }, value: formValues[param.name] || "", ...commonProps });
|
|
2983
|
+
case "integer":
|
|
2984
|
+
case "bigint":
|
|
2985
|
+
return /* @__PURE__ */ jsx19(TextField2, { type: "number", inputProps: { step: "1", style: { fontSize: "0.8rem" } }, value: formValues[param.name] || "", ...commonProps });
|
|
2986
|
+
case "boolean":
|
|
2987
|
+
return /* @__PURE__ */ jsx19(
|
|
2988
|
+
FormControlLabel,
|
|
2989
|
+
{
|
|
2990
|
+
control: /* @__PURE__ */ jsx19(
|
|
2991
|
+
Checkbox,
|
|
2992
|
+
{
|
|
2993
|
+
checked: !!formValues[param.name],
|
|
2994
|
+
onChange: handleChange,
|
|
2995
|
+
name: param.name,
|
|
2996
|
+
id: param.name,
|
|
2997
|
+
disabled: apiLoading,
|
|
2998
|
+
size: "small"
|
|
2999
|
+
}
|
|
3000
|
+
),
|
|
3001
|
+
label: /* @__PURE__ */ jsx19(Typography14, { sx: { fontSize: "0.8rem", color: hasError ? "error.main" : "inherit" }, children: param.label || param.name }),
|
|
3002
|
+
sx: { mt: 1, mb: 0 }
|
|
3003
|
+
}
|
|
3004
|
+
);
|
|
3005
|
+
case "date":
|
|
3006
|
+
case "timestamp":
|
|
3007
|
+
case "time":
|
|
3008
|
+
return /* @__PURE__ */ jsx19(TextField2, { type: param.typeName === "date" ? "date" : param.typeName === "timestamp" ? "datetime-local" : "time", value: formValues[param.name] || "", ...commonProps, InputLabelProps: { shrink: true, sx: { fontSize: "0.8rem" } } });
|
|
3009
|
+
case "jsonb":
|
|
3010
|
+
case "jsona":
|
|
3011
|
+
return /* @__PURE__ */ jsx19(TextField2, { multiline: true, rows: 5, value: formValues[param.name] || "", ...commonProps, InputProps: { sx: { fontSize: "0.8rem" } } });
|
|
3012
|
+
case "bytea":
|
|
3013
|
+
return /* @__PURE__ */ jsxs13(FormControl, { fullWidth: true, margin: "dense", error: hasError, required: commonProps.required, children: [
|
|
3014
|
+
/* @__PURE__ */ jsx19(Typography14, { variant: "body2", color: "textSecondary", component: "label", htmlFor: param.name, sx: { fontSize: "0.8rem", color: hasError ? "error.main" : "text.secondary" }, children: param.label || param.name }),
|
|
3015
|
+
/* @__PURE__ */ jsx19(
|
|
3016
|
+
"input",
|
|
3017
|
+
{
|
|
3018
|
+
type: "file",
|
|
3019
|
+
id: param.name,
|
|
3020
|
+
name: param.name,
|
|
3021
|
+
onChange: (e) => {
|
|
3022
|
+
const files = e.target.files;
|
|
3023
|
+
setFormValues((prev) => ({ ...prev, [param.name]: files && files.length > 0 ? files[0] : void 0 }));
|
|
3024
|
+
},
|
|
3025
|
+
disabled: apiLoading,
|
|
3026
|
+
style: { padding: "6px 0", fontSize: "0.8rem" }
|
|
3027
|
+
}
|
|
3028
|
+
),
|
|
3029
|
+
(param.description || errorMessage) && /* @__PURE__ */ jsx19(FormHelperText, { sx: { fontSize: "0.7rem" }, children: errorMessage || param.description })
|
|
3030
|
+
] });
|
|
3031
|
+
default:
|
|
3032
|
+
return /* @__PURE__ */ jsx19(TextField2, { type: "text", value: formValues[param.name] || "", ...commonProps });
|
|
3033
|
+
}
|
|
3034
|
+
}, [formValues, handleChange, apiLoading, validationErrors]);
|
|
3035
|
+
const ResultDisplayContent = useMemo4(() => {
|
|
3036
|
+
if (!procedureResultData || !procedure?.resultOk) return null;
|
|
3037
|
+
const ComponentToRender = resultsOk[procedure.resultOk];
|
|
3038
|
+
if (ComponentToRender) {
|
|
3039
|
+
return /* @__PURE__ */ jsx19(ComponentToRender, { data: procedureResultData });
|
|
3040
|
+
} else {
|
|
3041
|
+
return /* @__PURE__ */ jsxs13(Paper3, { elevation: 2, sx: { p: 2, mt: 0, bgcolor: "warning.light" }, children: [
|
|
3042
|
+
/* @__PURE__ */ jsxs13(Typography14, { variant: "h6", sx: { fontSize: "1rem", mb: 1 }, children: [
|
|
3043
|
+
"el componente para resolver el resultOk: '",
|
|
3044
|
+
procedure.resultOk,
|
|
3045
|
+
"' definido en el procedure no existe o no est\xE1 mapeado."
|
|
3046
|
+
] }),
|
|
3047
|
+
/* @__PURE__ */ jsx19(Box13, { sx: {
|
|
3048
|
+
bgcolor: "warning.dark",
|
|
3049
|
+
p: 1,
|
|
3050
|
+
borderRadius: 1
|
|
3051
|
+
}, children: /* @__PURE__ */ jsx19("pre", { style: { margin: 0, fontSize: "0.75rem", color: "white" }, children: JSON.stringify(procedureResultData, null, 2) }) })
|
|
3052
|
+
] });
|
|
3053
|
+
}
|
|
3054
|
+
}, [procedureResultData, procedure]);
|
|
3055
|
+
if (!procedure) {
|
|
3056
|
+
return /* @__PURE__ */ jsxs13(Box13, { sx: {
|
|
3057
|
+
p: 2,
|
|
3058
|
+
width: "100%",
|
|
3059
|
+
boxSizing: "border-box",
|
|
3060
|
+
mt: 0,
|
|
3061
|
+
bgcolor: "background.paper",
|
|
3062
|
+
borderRadius: 2,
|
|
3063
|
+
boxShadow: 3,
|
|
3064
|
+
textAlign: "center"
|
|
3065
|
+
}, children: [
|
|
3066
|
+
/* @__PURE__ */ jsx19(CircularProgress4, { sx: { mb: 2 } }),
|
|
3067
|
+
/* @__PURE__ */ jsx19(Typography14, { variant: "h6", color: "text.secondary", children: "Cargando procedimiento o no encontrado..." })
|
|
3068
|
+
] });
|
|
3069
|
+
}
|
|
3070
|
+
return (
|
|
3071
|
+
// Esta es la Box más externa que ahora controlará el scroll
|
|
3072
|
+
/* @__PURE__ */ jsxs13(Box13, { sx: {
|
|
3073
|
+
p: 2,
|
|
3074
|
+
ml: 1,
|
|
3075
|
+
mt: 2,
|
|
3076
|
+
mr: 1,
|
|
3077
|
+
boxSizing: "border-box",
|
|
3078
|
+
bgcolor: "background.paper",
|
|
3079
|
+
borderRadius: 2,
|
|
3080
|
+
boxShadow: 3,
|
|
3081
|
+
fontSize: "0.8rem",
|
|
3082
|
+
maxHeight: "calc(100vh - 100px)",
|
|
3083
|
+
// Ajusta esta altura máxima según el espacio disponible en tu layout
|
|
3084
|
+
overflowY: "auto",
|
|
3085
|
+
// Habilita el scroll vertical para todo el contenido de esta Box
|
|
3086
|
+
overflowX: "hidden"
|
|
3087
|
+
// Oculta el scroll horizontal si no es necesario para el contenedor principal
|
|
3088
|
+
}, children: [
|
|
3089
|
+
/* @__PURE__ */ jsx19(Typography14, { variant: "h5", component: "h2", gutterBottom: true, align: "left", children: cambiarGuionesBajosPorEspacios(procedure.proceedLabel || procedure.action) }),
|
|
3090
|
+
Object.values(validationErrors).some((err) => err !== null) && /* @__PURE__ */ jsxs13(Alert3, { severity: "error", sx: { mb: 2, fontSize: "0.8rem" }, children: [
|
|
3091
|
+
"Por favor, corrige los errores en el formulario antes de enviar.",
|
|
3092
|
+
/* @__PURE__ */ jsx19("ul", { children: Object.values(validationErrors).map((err, idx) => err && /* @__PURE__ */ jsx19("li", { children: err }, idx)) })
|
|
3093
|
+
] }),
|
|
3094
|
+
!Object.values(validationErrors).some((err) => err !== null) && apiError && /* @__PURE__ */ jsx19(Alert3, { severity: "error", sx: { mb: 2, fontSize: "0.8rem" }, children: apiError.message }),
|
|
3095
|
+
!Object.values(validationErrors).some((err) => err !== null) && !apiError && successMessage && /* @__PURE__ */ jsx19(Alert3, { severity: "success", sx: { mb: 2, fontSize: "0.8rem" }, children: successMessage }),
|
|
3096
|
+
/* @__PURE__ */ jsxs13("form", { onSubmit: handleSubmit, children: [
|
|
3097
|
+
procedure.parameters.map((param) => /* @__PURE__ */ jsx19("div", { children: renderInputField(param) }, param.name)),
|
|
3098
|
+
/* @__PURE__ */ jsx19(
|
|
3099
|
+
Button6,
|
|
3100
|
+
{
|
|
3101
|
+
type: "submit",
|
|
3102
|
+
variant: "contained",
|
|
3103
|
+
color: "primary",
|
|
3104
|
+
disabled: apiLoading || Object.values(validationErrors).some((err) => err !== null),
|
|
3105
|
+
sx: { mt: 2 },
|
|
3106
|
+
size: "medium",
|
|
3107
|
+
startIcon: apiLoading ? /* @__PURE__ */ jsx19(CircularProgress4, { size: 20, color: "inherit" }) : null,
|
|
3108
|
+
children: apiLoading ? "Ejecutando..." : procedure.proceedLabel || "Ejecutar"
|
|
3109
|
+
}
|
|
3110
|
+
)
|
|
3111
|
+
] }),
|
|
3112
|
+
ResultDisplayContent && /* @__PURE__ */ jsxs13(Box13, { sx: { mt: 2 }, children: [
|
|
3113
|
+
" ",
|
|
3114
|
+
ResultDisplayContent
|
|
3115
|
+
] }),
|
|
3116
|
+
executionLog.length > 0 && /* @__PURE__ */ jsxs13(Box13, { sx: { mt: 3 }, children: [
|
|
3117
|
+
/* @__PURE__ */ jsx19(Divider2, { sx: { mb: 2 } }),
|
|
3118
|
+
/* @__PURE__ */ jsx19(Typography14, { variant: "h6", gutterBottom: true, sx: { fontSize: "0.9rem" }, children: "Registro de Ejecuci\xF3n" }),
|
|
3119
|
+
/* @__PURE__ */ jsx19(
|
|
3120
|
+
Box13,
|
|
3121
|
+
{
|
|
3122
|
+
sx: {
|
|
3123
|
+
bgcolor: "grey.100",
|
|
3124
|
+
p: 2,
|
|
3125
|
+
borderRadius: 1,
|
|
3126
|
+
maxHeight: "200px",
|
|
3127
|
+
// Este log puede tener su propio scroll interno si es muy largo
|
|
3128
|
+
overflowY: "auto",
|
|
3129
|
+
fontFamily: "monospace",
|
|
3130
|
+
fontSize: "0.75rem",
|
|
3131
|
+
whiteSpace: "pre-wrap"
|
|
3132
|
+
},
|
|
3133
|
+
children: executionLog.map((log, index) => /* @__PURE__ */ jsx19(
|
|
3134
|
+
Typography14,
|
|
3135
|
+
{
|
|
3136
|
+
component: "pre",
|
|
3137
|
+
sx: {
|
|
3138
|
+
margin: 0,
|
|
3139
|
+
color: log.includes("ERROR:") ? "error.main" : "text.primary",
|
|
3140
|
+
fontSize: "inherit"
|
|
3141
|
+
},
|
|
3142
|
+
children: log
|
|
3143
|
+
},
|
|
3144
|
+
index
|
|
3145
|
+
))
|
|
3146
|
+
}
|
|
3147
|
+
)
|
|
3148
|
+
] })
|
|
3149
|
+
] })
|
|
3150
|
+
);
|
|
3151
|
+
};
|
|
3152
|
+
var ProcedureForm_default = ProcedureForm;
|
|
3153
|
+
|
|
3154
|
+
// src/App.tsx
|
|
3155
|
+
import { Provider } from "react-redux";
|
|
3156
|
+
import { PersistGate } from "redux-persist/integration/react";
|
|
3157
|
+
|
|
3158
|
+
// src/components/PrivateRoute.tsx
|
|
3159
|
+
import { useEffect as useEffect5 } from "react";
|
|
3160
|
+
import { Navigate, useLocation as useLocation2 } from "react-router-dom";
|
|
3161
|
+
import { Fragment as Fragment4, jsx as jsx20 } from "react/jsx-runtime";
|
|
3162
|
+
var PrivateRoute = ({ children }) => {
|
|
3163
|
+
const location = useLocation2();
|
|
3164
|
+
const dispatch = useAppDispatch();
|
|
3165
|
+
const clientContextStatus = useClientContextStatus();
|
|
3166
|
+
const isAuthenticated = clientContextStatus === "succeeded";
|
|
3167
|
+
const isLoadingAuth = clientContextStatus === "loading";
|
|
3168
|
+
console.log(`[PrivateRoute] Render: Path=${location.pathname}, AuthStatus=${clientContextStatus}, IsAuthenticated=${isAuthenticated}, IsLoadingAuth=${isLoadingAuth}`);
|
|
3169
|
+
useEffect5(() => {
|
|
3170
|
+
console.log(`[PrivateRoute] Effect: Path=${location.pathname}, AuthStatus=${clientContextStatus}, IsAuthenticated=${isAuthenticated}, IsLoadingAuth=${isLoadingAuth}`);
|
|
3171
|
+
if (!isAuthenticated && !isLoadingAuth && location.pathname !== "/login") {
|
|
3172
|
+
const path = location.pathname + location.search;
|
|
3173
|
+
console.log(`[PrivateRoute] ACTION: Dispatching setRedirectPath(${path})`);
|
|
3174
|
+
dispatch(setRedirectPath(path));
|
|
3175
|
+
} else if (isAuthenticated) {
|
|
3176
|
+
console.log(`[PrivateRoute] User is authenticated, no redirectPath set.`);
|
|
3177
|
+
} else if (isLoadingAuth) {
|
|
3178
|
+
console.log(`[PrivateRoute] Still loading authentication.`);
|
|
3179
|
+
} else if (location.pathname === "/login") {
|
|
3180
|
+
console.log(`[PrivateRoute] Currently on /login, not setting redirectPath.`);
|
|
3181
|
+
}
|
|
3182
|
+
}, [isAuthenticated, isLoadingAuth, location, dispatch, clientContextStatus]);
|
|
3183
|
+
if (isLoadingAuth) {
|
|
3184
|
+
console.log(`[PrivateRoute] Returning loading state...`);
|
|
3185
|
+
return /* @__PURE__ */ jsx20("p", { children: "Verificando autenticaci\xF3n..." });
|
|
3186
|
+
}
|
|
3187
|
+
if (!isAuthenticated) {
|
|
3188
|
+
console.log(`[PrivateRoute] User not authenticated, navigating to /login`);
|
|
3189
|
+
return /* @__PURE__ */ jsx20(Navigate, { to: "/login", replace: true });
|
|
3190
|
+
}
|
|
3191
|
+
console.log(`[PrivateRoute] User authenticated, rendering children.`);
|
|
3192
|
+
return /* @__PURE__ */ jsx20(Fragment4, { children });
|
|
3193
|
+
};
|
|
3194
|
+
var PrivateRoute_default = PrivateRoute;
|
|
3195
|
+
|
|
3196
|
+
// src/components/InitialRedirectHandler.tsx
|
|
3197
|
+
import { useEffect as useEffect6 } from "react";
|
|
3198
|
+
import { useLocation as useLocation3, useNavigate as useNavigate6 } from "react-router-dom";
|
|
3199
|
+
var InitialRedirectHandler = () => {
|
|
3200
|
+
const location = useLocation3();
|
|
3201
|
+
const navigate = useNavigate6();
|
|
3202
|
+
const dispatch = useAppDispatch();
|
|
3203
|
+
const redirectPath = useRedirectPath();
|
|
3204
|
+
const clientContextStatus = useClientContextStatus();
|
|
3205
|
+
useEffect6(() => {
|
|
3206
|
+
dispatch(setCurrentPath(location.pathname + location.search));
|
|
3207
|
+
}, [location, dispatch]);
|
|
3208
|
+
useEffect6(() => {
|
|
3209
|
+
if (clientContextStatus === "succeeded") {
|
|
3210
|
+
if (redirectPath && redirectPath !== "/login") {
|
|
3211
|
+
console.log("Redirigiendo a la ruta guardada:", redirectPath);
|
|
3212
|
+
navigate(redirectPath);
|
|
3213
|
+
dispatch(setRedirectPath(null));
|
|
3214
|
+
} else if (location.pathname === "/login" || location.pathname === "/") {
|
|
3215
|
+
console.log("Usuario autenticado, redirigiendo a /home por defecto.");
|
|
3216
|
+
navigate("/home");
|
|
3217
|
+
}
|
|
3218
|
+
}
|
|
3219
|
+
}, [clientContextStatus, redirectPath, location.pathname, navigate, dispatch]);
|
|
3220
|
+
return null;
|
|
3221
|
+
};
|
|
3222
|
+
var InitialRedirectHandler_default = InitialRedirectHandler;
|
|
3223
|
+
|
|
3224
|
+
// src/pages/GenericDataGridPage.tsx
|
|
3225
|
+
import { useParams as useParams2 } from "react-router-dom";
|
|
3226
|
+
import { Box as Box14, Alert as Alert4, Typography as Typography15 } from "@mui/material";
|
|
3227
|
+
import { jsx as jsx21, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
3228
|
+
var GenericDataGridPage = () => {
|
|
3229
|
+
const { tableName } = useParams2();
|
|
3230
|
+
if (!tableName) {
|
|
3231
|
+
return /* @__PURE__ */ jsx21(Box14, { display: "flex", justifyContent: "center", alignItems: "center", minHeight: "200px", children: /* @__PURE__ */ jsxs14(Alert4, { severity: "error", children: [
|
|
3232
|
+
/* @__PURE__ */ jsx21(Typography15, { variant: "h6", children: "Error: Nombre de tabla no especificado en la URL." }),
|
|
3233
|
+
/* @__PURE__ */ jsx21(Typography15, { variant: "body1", children: "Por favor, aseg\xFArate de que la URL contenga el nombre de la tabla (ej. `/data/users`)." })
|
|
3234
|
+
] }) });
|
|
3235
|
+
}
|
|
3236
|
+
return /* @__PURE__ */ jsx21(GenericDataGrid_default, { tableName, fixedFields: [] });
|
|
3237
|
+
};
|
|
3238
|
+
var GenericDataGridPage_default = GenericDataGridPage;
|
|
3239
|
+
|
|
3240
|
+
// src/pages/MenuTablePage.tsx
|
|
3241
|
+
import { useMemo as useMemo5 } from "react";
|
|
3242
|
+
import { useParams as useParams3 } from "react-router-dom";
|
|
3243
|
+
import { Box as Box15, Alert as Alert5, Typography as Typography16 } from "@mui/material";
|
|
3244
|
+
import { jsx as jsx22, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
3245
|
+
var MenuTablePage = () => {
|
|
3246
|
+
const { menuName } = useParams3();
|
|
3247
|
+
const { clientContext } = useApp();
|
|
3248
|
+
const findMenuItem = (items, nameToFind) => {
|
|
3249
|
+
for (const item of items) {
|
|
3250
|
+
if (item.name === nameToFind && item.menuType === "table") {
|
|
3251
|
+
return item;
|
|
3252
|
+
}
|
|
3253
|
+
if (item.menuType === "menu" && item.menuContent) {
|
|
3254
|
+
const found = findMenuItem(item.menuContent, nameToFind);
|
|
3255
|
+
if (found) return found;
|
|
3256
|
+
}
|
|
3257
|
+
}
|
|
3258
|
+
return void 0;
|
|
3259
|
+
};
|
|
3260
|
+
const { currentTableName, currentFixedFields } = useMemo5(() => {
|
|
3261
|
+
let tableName = void 0;
|
|
3262
|
+
let fixedFields = [];
|
|
3263
|
+
if (menuName && clientContext && clientContext.menu) {
|
|
3264
|
+
const menuItem = findMenuItem(clientContext.menu, menuName);
|
|
3265
|
+
if (menuItem) {
|
|
3266
|
+
tableName = menuItem.table || menuItem.name;
|
|
3267
|
+
if (menuItem.ff) {
|
|
3268
|
+
Object.keys(menuItem.ff || []).forEach((fixedFieldKey) => {
|
|
3269
|
+
fixedFields.push({
|
|
3270
|
+
fieldName: fixedFieldKey,
|
|
3271
|
+
//@ts-ignore
|
|
3272
|
+
value: menuItem.ff[fixedFieldKey]
|
|
3273
|
+
});
|
|
3274
|
+
});
|
|
3275
|
+
}
|
|
3276
|
+
} else {
|
|
3277
|
+
console.warn(`[${menuName}] \xCDtem de men\xFA '${menuName}' no encontrado o no es de tipo 'table' en clientContext.menu.`);
|
|
3278
|
+
}
|
|
3279
|
+
}
|
|
3280
|
+
return {
|
|
3281
|
+
currentTableName: tableName,
|
|
3282
|
+
currentFixedFields: fixedFields
|
|
3283
|
+
};
|
|
3284
|
+
}, [menuName, clientContext]);
|
|
3285
|
+
if (!currentTableName) {
|
|
3286
|
+
return /* @__PURE__ */ jsx22(Box15, { display: "flex", justifyContent: "center", alignItems: "center", minHeight: "200px", children: /* @__PURE__ */ jsxs15(Alert5, { severity: "error", children: [
|
|
3287
|
+
/* @__PURE__ */ jsx22(Typography16, { variant: "h6", children: "Error: No se pudo cargar la informaci\xF3n de la tabla." }),
|
|
3288
|
+
/* @__PURE__ */ jsx22(Typography16, { variant: "body1", children: "Verifique la configuraci\xF3n del men\xFA o el nombre de la tabla en la URL." })
|
|
3289
|
+
] }) });
|
|
3290
|
+
}
|
|
3291
|
+
return /* @__PURE__ */ jsx22(
|
|
3292
|
+
GenericDataGrid_default,
|
|
3293
|
+
{
|
|
3294
|
+
tableName: currentTableName,
|
|
3295
|
+
fixedFields: currentFixedFields
|
|
3296
|
+
}
|
|
3297
|
+
);
|
|
3298
|
+
};
|
|
3299
|
+
var MenuTablePage_default = MenuTablePage;
|
|
3300
|
+
|
|
3301
|
+
// src/App.tsx
|
|
3302
|
+
import { jsx as jsx23, jsxs as jsxs16 } from "react/jsx-runtime";
|
|
3303
|
+
var LocationTracker = () => {
|
|
3304
|
+
const location = useLocation4();
|
|
3305
|
+
const dispatch = useAppDispatch();
|
|
3306
|
+
useEffect7(() => {
|
|
3307
|
+
dispatch(setCurrentPath(location.pathname + location.search));
|
|
3308
|
+
}, [location, dispatch]);
|
|
3309
|
+
return null;
|
|
3310
|
+
};
|
|
3311
|
+
function FrontendPlusReactRoutes({ myRoutes, myWScreens }) {
|
|
3312
|
+
const allWScreens = { ...wScreens, ...myWScreens || {} };
|
|
3313
|
+
return /* @__PURE__ */ jsxs16(Routes, { children: [
|
|
3314
|
+
/* @__PURE__ */ jsx23(Route, { path: "/login", element: /* @__PURE__ */ jsx23(LoginPage_default, {}) }),
|
|
3315
|
+
/* @__PURE__ */ jsx23(Route, { path: "/logout", element: /* @__PURE__ */ jsx23(LogoutPage_default, {}) }),
|
|
3316
|
+
/* @__PURE__ */ jsxs16(Route, { element: /* @__PURE__ */ jsxs16(PrivateRoute_default, { children: [
|
|
3317
|
+
/* @__PURE__ */ jsx23(InitialRedirectHandler_default, {}),
|
|
3318
|
+
/* @__PURE__ */ jsx23(MainLayout_default, {})
|
|
3319
|
+
] }), children: [
|
|
3320
|
+
/* @__PURE__ */ jsx23(Route, { path: "/", element: /* @__PURE__ */ jsx23(HomePage_default, {}) }),
|
|
3321
|
+
/* @__PURE__ */ jsx23(Route, { path: "/home", element: /* @__PURE__ */ jsx23(HomePage_default, {}) }),
|
|
3322
|
+
/* @__PURE__ */ jsx23(Route, { path: "/table/:tableName", element: /* @__PURE__ */ jsx23(GenericDataGridPage_default, {}) }),
|
|
3323
|
+
/* @__PURE__ */ jsx23(Route, { path: "/menu/:menuName", element: /* @__PURE__ */ jsx23(MenuTablePage_default, {}) }),
|
|
3324
|
+
/* @__PURE__ */ jsx23(Route, { path: "/procedures/:procedureName", element: /* @__PURE__ */ jsx23(ProcedureForm_default, {}) }),
|
|
3325
|
+
Object.keys(allWScreens).map((screenName) => /* @__PURE__ */ jsx23(
|
|
3326
|
+
Route,
|
|
3327
|
+
{
|
|
3328
|
+
path: `/wScreens/${screenName}`,
|
|
3329
|
+
element: React11.createElement(wScreens[screenName], { screenName })
|
|
3330
|
+
},
|
|
3331
|
+
screenName
|
|
3332
|
+
)),
|
|
3333
|
+
/* @__PURE__ */ jsx23(
|
|
3334
|
+
Route,
|
|
3335
|
+
{
|
|
3336
|
+
path: "/wScreens-fallback/:screenName",
|
|
3337
|
+
element: /* @__PURE__ */ jsx23(WScreens_default, { screenName: ":screenName" })
|
|
3338
|
+
}
|
|
3339
|
+
),
|
|
3340
|
+
/* @__PURE__ */ jsx23(Route, { path: "*", element: /* @__PURE__ */ jsx23("div", { style: { marginTop: "20px", marginLeft: "10px" }, children: "404 - Recurso No Encontrado" }) })
|
|
3341
|
+
] }),
|
|
3342
|
+
myRoutes,
|
|
3343
|
+
/* @__PURE__ */ jsx23(Route, { path: "*", element: /* @__PURE__ */ jsx23(Navigate2, { to: "/", replace: true }) })
|
|
3344
|
+
] });
|
|
3345
|
+
}
|
|
3346
|
+
var App = ({
|
|
3347
|
+
myRoutes,
|
|
3348
|
+
myWScreens,
|
|
3349
|
+
myClientSides,
|
|
3350
|
+
myResultsOk
|
|
3351
|
+
}) => {
|
|
3352
|
+
useEffect7(() => {
|
|
3353
|
+
if (myClientSides) {
|
|
3354
|
+
extendClientSides(myClientSides);
|
|
3355
|
+
}
|
|
3356
|
+
if (myResultsOk) {
|
|
3357
|
+
extendResultsOk(myResultsOk);
|
|
3358
|
+
}
|
|
3359
|
+
}, [myClientSides, myResultsOk]);
|
|
3360
|
+
return /* @__PURE__ */ jsx23(Provider, { store, children: /* @__PURE__ */ jsx23(PersistGate, { loading: null, persistor, children: /* @__PURE__ */ jsxs16(BrowserRouter, { children: [
|
|
3361
|
+
/* @__PURE__ */ jsx23(LocationTracker, {}),
|
|
3362
|
+
/* @__PURE__ */ jsx23(AppProvider, { children: /* @__PURE__ */ jsxs16(SnackbarProvider, { children: [
|
|
3363
|
+
/* @__PURE__ */ jsx23(
|
|
3364
|
+
FrontendPlusReactRoutes,
|
|
3365
|
+
{
|
|
3366
|
+
myRoutes,
|
|
3367
|
+
myWScreens
|
|
3368
|
+
}
|
|
3369
|
+
),
|
|
3370
|
+
/* @__PURE__ */ jsx23(SessionExpiredMessage_default, {})
|
|
3371
|
+
] }) })
|
|
3372
|
+
] }) }) });
|
|
3373
|
+
};
|
|
3374
|
+
var App_default = App;
|
|
3375
|
+
export {
|
|
3376
|
+
App_default as App,
|
|
3377
|
+
AppProvider,
|
|
3378
|
+
ConfirmDialog,
|
|
3379
|
+
FrontendPlusReactRoutes,
|
|
3380
|
+
GenericDataGrid_default as GenericDataGrid,
|
|
3381
|
+
MainLayout_default as MainLayout,
|
|
3382
|
+
SnackbarProvider,
|
|
3383
|
+
cambiarGuionesBajosPorEspacios,
|
|
3384
|
+
clientSides,
|
|
3385
|
+
extendClientSides,
|
|
3386
|
+
resultsOk as resultComponents,
|
|
3387
|
+
useApiCall,
|
|
3388
|
+
useApp,
|
|
3389
|
+
useLogout_default as useLogout,
|
|
3390
|
+
useSnackbar,
|
|
3391
|
+
wScreens
|
|
3392
|
+
};
|
|
3393
|
+
//# sourceMappingURL=index.js.map
|