utn-cli 2.0.52 → 2.0.54
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/commands/backend.js +63 -0
- package/commands/createComponent.js +59 -37
- package/package.json +1 -1
- package/templates/backend/rutas/misc.js +17 -0
- package/templates/backend/server.js +4 -2
- package/templates/backend/servicios/Nucleo/Miscelaneas.js +54 -9
- package/templates/frontend/src/app/Componentes/Nucleo/gestion-actividad/gestion-actividad.component.css +193 -0
- package/templates/frontend/src/app/Componentes/Nucleo/gestion-actividad/gestion-actividad.component.html +50 -0
- package/templates/frontend/src/app/Componentes/Nucleo/gestion-actividad/gestion-actividad.component.ts +61 -0
- package/templates/frontend/src/app/Componentes/Nucleo/tabla/paginador-personalizado.ts +3 -0
- package/templates/frontend/src/app/Paginas/Nucleo/contenedor-componentes/contenedor-componentes.component.css +52 -6
- package/templates/frontend/src/app/Paginas/Nucleo/contenedor-componentes/contenedor-componentes.component.html +28 -14
- package/templates/frontend/src/app/Paginas/Nucleo/contenedor-componentes/contenedor-componentes.component.ts +8 -1
- package/templates/frontend/src/app/app.config.ts +1 -4
- package/templates/frontend/src/app/app.routes.ts +2 -0
package/commands/backend.js
CHANGED
|
@@ -229,6 +229,7 @@ export async function addServiceBackend(nombreServicio = null, opciones = { cerr
|
|
|
229
229
|
// Si tenemos información de la tabla, generamos el CRUD
|
|
230
230
|
if (tableInfo) {
|
|
231
231
|
generarCRUDBackend(newServicioPath, newRutaPath, Servicio, tableInfo);
|
|
232
|
+
actualizarArchivoRest(Servicio, tableInfo);
|
|
232
233
|
}
|
|
233
234
|
|
|
234
235
|
// Reemplazar el título amigable si se proporciona
|
|
@@ -392,6 +393,68 @@ Router.get('/reporte', async (solicitud, respuesta, next) => {
|
|
|
392
393
|
fs.writeFileSync(rutaPath, contenidoRutas);
|
|
393
394
|
}
|
|
394
395
|
|
|
396
|
+
function actualizarArchivoRest(nombreServicio, tableInfo) {
|
|
397
|
+
const archivos = fs.readdirSync(process.cwd());
|
|
398
|
+
const archivoRest = archivos.find(f => f.endsWith('.rest'));
|
|
399
|
+
|
|
400
|
+
if (!archivoRest) return;
|
|
401
|
+
|
|
402
|
+
const { columns, primaryKey } = tableInfo;
|
|
403
|
+
const nombreServicioLower = nombreServicio.toLowerCase();
|
|
404
|
+
|
|
405
|
+
// Crear objeto de ejemplo para agregar/actualizar
|
|
406
|
+
const ejemploCuerpo = {};
|
|
407
|
+
columns.forEach(col => {
|
|
408
|
+
ejemploCuerpo[col.name] = col.type.includes('INT') ? 1 : 'Ejemplo';
|
|
409
|
+
});
|
|
410
|
+
|
|
411
|
+
const nuevoContenido = `
|
|
412
|
+
#
|
|
413
|
+
# Rutas del servicio ${nombreServicio}
|
|
414
|
+
#
|
|
415
|
+
|
|
416
|
+
### Listar registros
|
|
417
|
+
GET {{ BASE_URL }}/${nombreServicio}/listar HTTP/1.1
|
|
418
|
+
Authorization: Bearer {{ AUTH_TOKEN }}
|
|
419
|
+
Content-Type: application/json
|
|
420
|
+
Origin: {{ BASE_URL }}
|
|
421
|
+
|
|
422
|
+
### Agregar registro
|
|
423
|
+
POST {{ BASE_URL }}/${nombreServicio}/agregar HTTP/1.1
|
|
424
|
+
Authorization: Bearer {{ AUTH_TOKEN }}
|
|
425
|
+
Content-Type: application/json
|
|
426
|
+
Origin: {{ BASE_URL }}
|
|
427
|
+
|
|
428
|
+
${JSON.stringify(ejemploCuerpo, null, 2)}
|
|
429
|
+
|
|
430
|
+
### Actualizar registro
|
|
431
|
+
POST {{ BASE_URL }}/${nombreServicio}/actualizar HTTP/1.1
|
|
432
|
+
Authorization: Bearer {{ AUTH_TOKEN }}
|
|
433
|
+
Content-Type: application/json
|
|
434
|
+
Origin: {{ BASE_URL }}
|
|
435
|
+
|
|
436
|
+
${JSON.stringify(ejemploCuerpo, null, 2)}
|
|
437
|
+
|
|
438
|
+
### Borrar registro
|
|
439
|
+
POST {{ BASE_URL }}/${nombreServicio}/borrar HTTP/1.1
|
|
440
|
+
Authorization: Bearer {{ AUTH_TOKEN }}
|
|
441
|
+
Content-Type: application/json
|
|
442
|
+
Origin: {{ BASE_URL }}
|
|
443
|
+
|
|
444
|
+
{
|
|
445
|
+
"${primaryKey}": ${ejemploCuerpo[primaryKey] ? (typeof ejemploCuerpo[primaryKey] === 'number' ? ejemploCuerpo[primaryKey] : '"' + ejemploCuerpo[primaryKey] + '"') : 1}
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
### Generar reporte CSV
|
|
449
|
+
GET {{ BASE_URL }}/${nombreServicio}/reporte HTTP/1.1
|
|
450
|
+
Authorization: Bearer {{ AUTH_TOKEN }}
|
|
451
|
+
Content-Type: application/json
|
|
452
|
+
Origin: {{ BASE_URL }}
|
|
453
|
+
`;
|
|
454
|
+
|
|
455
|
+
fs.appendFileSync(archivoRest, nuevoContenido);
|
|
456
|
+
}
|
|
457
|
+
|
|
395
458
|
export function showBackendVersion() {
|
|
396
459
|
mostrarVersion(path.join(__dirname, '../package.json'));
|
|
397
460
|
closeReadLine();
|
|
@@ -79,49 +79,71 @@ export async function createComponent() {
|
|
|
79
79
|
function findTableByComment(sqlPath, serviceTitle) {
|
|
80
80
|
const content = fs.readFileSync(sqlPath, 'utf-8');
|
|
81
81
|
|
|
82
|
-
//
|
|
83
|
-
|
|
84
|
-
const tableRegex = /CREATE OR REPLACE TABLE `(.+?)`\.`(.+?)` \(([\s\S]+?)\) ENGINE = InnoDB.+?COMMENT = '.*?(?:servicio de |almacena los datos del servicio de |almacena los datos del servicio de: )?([\s\S]+?)';/gi;
|
|
82
|
+
// Dividir el archivo por cada definición de tabla
|
|
83
|
+
const tableBlocks = content.split(/CREATE OR REPLACE TABLE/i).slice(1);
|
|
85
84
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
const
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
const
|
|
85
|
+
for (const block of tableBlocks) {
|
|
86
|
+
// Reconstruir el inicio para facilitar el regex
|
|
87
|
+
const fullBlock = 'CREATE OR REPLACE TABLE' + block;
|
|
88
|
+
|
|
89
|
+
// Regex para extraer DB, Tabla, Cuerpo y Comentario de este bloque específico
|
|
90
|
+
const tableRegex = /CREATE OR REPLACE TABLE `(.+?)`\.`(.+?)` \(([\s\S]+?)\) ENGINE = InnoDB.+?COMMENT = '([\s\S]+?)';/gi;
|
|
91
|
+
const match = tableRegex.exec(fullBlock);
|
|
92
|
+
|
|
93
|
+
if (match) {
|
|
94
|
+
const dbName = match[1];
|
|
95
|
+
const tableName = match[2];
|
|
96
|
+
const tableBody = match[3];
|
|
97
|
+
const tableComment = match[4].trim();
|
|
92
98
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
99
|
+
// Verificar si el comentario coincide con el título del servicio
|
|
100
|
+
if (tableComment.toLowerCase().includes(serviceTitle.toLowerCase()) || serviceTitle.toLowerCase().includes(tableComment.toLowerCase())) {
|
|
101
|
+
const columns = [];
|
|
102
|
+
let primaryKey = '';
|
|
97
103
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
104
|
+
// Limpiar el cuerpo para procesar líneas individualmente
|
|
105
|
+
const lines = tableBody.split('\n').map(l => l.trim()).filter(l => l.length > 0);
|
|
106
|
+
|
|
107
|
+
for (const line of lines) {
|
|
108
|
+
// Ignorar líneas que no definen columnas reales (PRIMARY KEY, KEY, CONSTRAINT)
|
|
109
|
+
if (line.toUpperCase().startsWith('PRIMARY KEY')) {
|
|
110
|
+
const pkMatch = line.match(/PRIMARY KEY \(`(.+?)`\)/i);
|
|
111
|
+
if (pkMatch) primaryKey = pkMatch[1];
|
|
112
|
+
continue;
|
|
113
|
+
}
|
|
114
|
+
if (line.toUpperCase().startsWith('KEY') || line.toUpperCase().startsWith('CONSTRAINT') || line.toUpperCase().startsWith('UNIQUE')) {
|
|
115
|
+
continue;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// Regex para extraer nombre de columna, tipo y comentario
|
|
119
|
+
const colMatch = line.match(/^`(.+?)` (.+?)(?: COMMENT '(.+?)')?,?$/i);
|
|
120
|
+
if (colMatch) {
|
|
121
|
+
const colName = colMatch[1];
|
|
122
|
+
// Excluir metadatos automáticos
|
|
123
|
+
if (colName !== 'LastUpdate' && colName !== 'LastUser') {
|
|
124
|
+
columns.push({
|
|
125
|
+
name: colName,
|
|
126
|
+
type: colMatch[2].replace(/,$/, ''), // Limpiar coma final si existe
|
|
127
|
+
alias: colMatch[3] || colName
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
}
|
|
109
131
|
}
|
|
110
|
-
}
|
|
111
132
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
133
|
+
// Si no se encontró PK en las líneas, buscarla de nuevo con un regex más flexible en todo el cuerpo
|
|
134
|
+
if (!primaryKey) {
|
|
135
|
+
const pkMatch = tableBody.match(/PRIMARY KEY \(`(.+?)`\)/i);
|
|
136
|
+
if (pkMatch) primaryKey = pkMatch[1];
|
|
137
|
+
}
|
|
117
138
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
139
|
+
return {
|
|
140
|
+
dbName,
|
|
141
|
+
tableName,
|
|
142
|
+
columns,
|
|
143
|
+
primaryKey,
|
|
144
|
+
serviceTitle
|
|
145
|
+
};
|
|
146
|
+
}
|
|
125
147
|
}
|
|
126
148
|
}
|
|
127
149
|
return null;
|
package/package.json
CHANGED
|
@@ -4,6 +4,23 @@ const Router = express.Router();
|
|
|
4
4
|
const Miscelaneo = require('./../servicios/Nucleo/Miscelaneas.js');
|
|
5
5
|
const ManejadorDeErrores = require('../servicios/Nucleo/ManejadorDeErrores.js');
|
|
6
6
|
|
|
7
|
+
Router.get('/ListarActividades', async (solicitud, respuesta, next) => {
|
|
8
|
+
try {
|
|
9
|
+
if (await Miscelaneo.validarTokenV2(solicitud.headers.authorization) && await Miscelaneo.validarAccesoDelOrigen(solicitud)) {
|
|
10
|
+
try {
|
|
11
|
+
return respuesta.json({ body: await Miscelaneo.ListarActividades(solicitud.headers.authorization), error: undefined });
|
|
12
|
+
} catch (error) {
|
|
13
|
+
const MensajeDeError = 'No fue posible listar las actividades';
|
|
14
|
+
console.error(new ManejadorDeErrores(MensajeDeError, ManejadorDeErrores.obtenerNumeroDeLinea(), true, `Dirección IP: ${solicitud.ip}`));
|
|
15
|
+
return respuesta.status(500).json({ body: undefined, error: MensajeDeError });
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
return respuesta.status(401).json({ body: undefined, error: ManejadorDeErrores.mensajeDeError401() });
|
|
19
|
+
} catch (error) {
|
|
20
|
+
next(error);
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
|
|
7
24
|
Router.get('/UsuariosActuales', async (solicitud, respuesta, next) => {
|
|
8
25
|
try {
|
|
9
26
|
if (await Miscelaneo.validarTokenV2(solicitud.headers.authorization) && await Miscelaneo.validarAccesoDelOrigen(solicitud)) {
|
|
@@ -30,7 +30,7 @@ app.use(async (solicitud, respuesta, next) => {
|
|
|
30
30
|
cookies: solicitud.cookies,
|
|
31
31
|
signedCookies: solicitud.signedCookies,
|
|
32
32
|
userAgent: solicitud.get('User-Agent'),
|
|
33
|
-
authUser: solicitud.
|
|
33
|
+
authUser: await Miscelaneo.obtenerDatosDelUsuario(solicitud.headers.authorization) ?? null,
|
|
34
34
|
};
|
|
35
35
|
try {
|
|
36
36
|
const { ejecutarConsultaSIGU } = require('./servicios/Nucleo/db.js');
|
|
@@ -61,7 +61,9 @@ asignarRutasAExpress(app);
|
|
|
61
61
|
|
|
62
62
|
app.use((error, solicitud, respuesta, next) => {
|
|
63
63
|
const { envioDeCorreo } = require('./servicios/Nucleo/EnvioDeCorreos.js');
|
|
64
|
-
|
|
64
|
+
const route = solicitud.originalUrl;
|
|
65
|
+
const message = `<b>Ruta consultada:</b> ${route}<BR /><BR />` + error.stack;
|
|
66
|
+
envioDeCorreo(process.env.DESTINATARIODEINFORMESDEERROR, 'Informe de error desde: ' + process.env.NOMBRECANONICODELMODULO, message);
|
|
65
67
|
console.error(error.stack);
|
|
66
68
|
respuesta.status(500).send('Error interno del servidor, el detalle del mismo fue enviado a ' + process.env.DESTINATARIODEINFORMESDEERROR);
|
|
67
69
|
});
|
|
@@ -40,6 +40,51 @@ class Miscelaneo {
|
|
|
40
40
|
this.EnlaceDeAcceso = undefined;
|
|
41
41
|
};
|
|
42
42
|
|
|
43
|
+
async ListarActividades(Datos) {
|
|
44
|
+
try {
|
|
45
|
+
const decoded = await this.obtenerDatosDelUsuario(Datos);
|
|
46
|
+
const RUTAS_EXCLUIDAS = [
|
|
47
|
+
'/misc',
|
|
48
|
+
'/Actividad',
|
|
49
|
+
'/misc/ListarActividades',
|
|
50
|
+
'/misc/obtenerNotificaciones',
|
|
51
|
+
'/misc/configurarFrontend',
|
|
52
|
+
'/ConsentimientoInformado/ConsentimientoInformado',
|
|
53
|
+
'/misc/obtenerMensajesModulares',
|
|
54
|
+
'/misc/obtenerDetalleDelModulo',
|
|
55
|
+
'/misc/validarToken',
|
|
56
|
+
'/misc/UsuariosActuales',
|
|
57
|
+
'/misc/obtenerEnlaceDePortal',
|
|
58
|
+
'/Personas/PermisoExtra'
|
|
59
|
+
];
|
|
60
|
+
const datos = await ejecutarConsultaSIGU(`
|
|
61
|
+
SELECT
|
|
62
|
+
Consecutivo,
|
|
63
|
+
LastUpdate AS Fecha,
|
|
64
|
+
JSON_VALUE(Solicitud, '$.ip') AS IP,
|
|
65
|
+
JSON_VALUE(Solicitud, '$.userAgent') AS Navegador,
|
|
66
|
+
JSON_VALUE(Solicitud, '$.method') AS Metodo,
|
|
67
|
+
JSON_VALUE(Solicitud, '$.originalUrl') AS URL,
|
|
68
|
+
IFNULL(JSON_VALUE(Solicitud, '$.country'), 'Costa Rica') AS Pais,
|
|
69
|
+
CASE
|
|
70
|
+
WHEN JSON_VALUE(Solicitud, '$.userAgent') LIKE '%Mobile%' THEN 'Móvil'
|
|
71
|
+
WHEN JSON_VALUE(Solicitud, '$.userAgent') LIKE '%Android%' AND JSON_VALUE(Solicitud, '$.userAgent') NOT LIKE '%Mobile%' THEN 'Tablet'
|
|
72
|
+
WHEN JSON_VALUE(Solicitud, '$.userAgent') LIKE '%iPad%' THEN 'Tablet'
|
|
73
|
+
ELSE 'PC'
|
|
74
|
+
END AS Dispositivo
|
|
75
|
+
FROM SIGU.SIGU_BitacoraDeSolicitudes
|
|
76
|
+
WHERE JSON_VALUE(Solicitud, '$.authUser.uid') = ?
|
|
77
|
+
AND JSON_VALUE(Solicitud, '$.originalUrl') NOT IN (?)
|
|
78
|
+
ORDER BY Consecutivo DESC
|
|
79
|
+
LIMIT 100
|
|
80
|
+
`, [decoded.uid, RUTAS_EXCLUIDAS]);
|
|
81
|
+
return datos;
|
|
82
|
+
} catch (error) {
|
|
83
|
+
console.error('Error al listar actividad:', error);
|
|
84
|
+
return [];
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
43
88
|
async UsuariosActuales() {
|
|
44
89
|
const ConexionSigu = await crearObjetoConexionSIGU();
|
|
45
90
|
const Actuales = await ConexionSigu.query("SELECT COUNT(DISTINCT `Identificador`) AS `Total` FROM `SIGU`.`SIGU_Sesiones` WHERE `LastUpdate` >= NOW() - INTERVAL 2 HOUR");
|
|
@@ -494,15 +539,15 @@ class Miscelaneo {
|
|
|
494
539
|
}
|
|
495
540
|
|
|
496
541
|
async generarLastUser(Solicitud) {
|
|
497
|
-
|
|
498
|
-
try {
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
} catch (error) {
|
|
504
|
-
|
|
505
|
-
}
|
|
542
|
+
const Resultado = await this.obtenerDatosDelUsuario(Solicitud.headers.authorization);
|
|
543
|
+
// try {
|
|
544
|
+
// Resultado = await this.obtenerDatosDelUsuario(Solicitud.headers.authorization);
|
|
545
|
+
// if (!Resultado) {
|
|
546
|
+
// throw new ManejadorDeErrores(ManejadorDeErrores.mensajeDeErrorVerificacionDeToken(), ManejadorDeErrores.obtenerNumeroDeLinea());
|
|
547
|
+
// }
|
|
548
|
+
// } catch (error) {
|
|
549
|
+
// console.log(error);
|
|
550
|
+
// }
|
|
506
551
|
let LastUser = '';
|
|
507
552
|
if (Resultado) {
|
|
508
553
|
LastUser = Resultado.uid;
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
.contenedor-actividad {
|
|
2
|
+
background-color: transparent;
|
|
3
|
+
margin: 0;
|
|
4
|
+
padding: 10px;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
.header-actividad {
|
|
8
|
+
background-color: white;
|
|
9
|
+
padding: 20px 24px;
|
|
10
|
+
border-radius: 12px;
|
|
11
|
+
margin-bottom: 20px;
|
|
12
|
+
border: 1px solid #e0e6ed;
|
|
13
|
+
box-shadow: 0 2px 4px rgba(0,0,0,0.05);
|
|
14
|
+
text-align: left;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
.header-actividad h2 {
|
|
18
|
+
margin: 0;
|
|
19
|
+
color: #002f6b;
|
|
20
|
+
font-size: 1.5rem;
|
|
21
|
+
font-weight: 700;
|
|
22
|
+
display: flex;
|
|
23
|
+
align-items: center;
|
|
24
|
+
gap: 12px;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
.header-actividad h2 mat-icon {
|
|
28
|
+
font-size: 28px;
|
|
29
|
+
width: 28px;
|
|
30
|
+
height: 28px;
|
|
31
|
+
color: #0b4fce;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
.header-actividad p {
|
|
35
|
+
margin: 8px 0 0 0;
|
|
36
|
+
color: #5f6368;
|
|
37
|
+
font-size: 0.95rem;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
.mensaje-informativo {
|
|
41
|
+
display: flex;
|
|
42
|
+
align-items: center;
|
|
43
|
+
gap: 12px;
|
|
44
|
+
background-color: #e3f2fd;
|
|
45
|
+
border-left: 4px solid #1976d2;
|
|
46
|
+
padding: 12px 16px;
|
|
47
|
+
margin-top: 20px;
|
|
48
|
+
border-radius: 4px;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
.mensaje-informativo mat-icon {
|
|
52
|
+
color: #1976d2;
|
|
53
|
+
font-size: 24px;
|
|
54
|
+
width: 24px;
|
|
55
|
+
height: 24px;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
.mensaje-informativo p {
|
|
59
|
+
margin: 0 !important;
|
|
60
|
+
font-size: 13.5px !important;
|
|
61
|
+
color: #0d47a1 !important;
|
|
62
|
+
line-height: 1.4;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
.mensaje-informativo strong {
|
|
66
|
+
color: #d32f2f;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
.lista-actividad {
|
|
70
|
+
display: flex;
|
|
71
|
+
flex-direction: column;
|
|
72
|
+
gap: 12px;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
.actividad-item {
|
|
76
|
+
display: flex;
|
|
77
|
+
align-items: center;
|
|
78
|
+
padding: 16px;
|
|
79
|
+
background-color: white;
|
|
80
|
+
border: 1px solid #e0e6ed;
|
|
81
|
+
border-radius: 12px;
|
|
82
|
+
transition: all 0.3s cubic-bezier(0.25, 0.8, 0.25, 1);
|
|
83
|
+
box-shadow: 0 2px 4px rgba(0,0,0,0.05);
|
|
84
|
+
text-align: left;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
.actividad-item:hover {
|
|
88
|
+
transform: translateY(-2px);
|
|
89
|
+
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
|
|
90
|
+
border-color: #0b4fce;
|
|
91
|
+
background-color: #f0f7ff;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
.item-icono {
|
|
95
|
+
margin-right: 12px;
|
|
96
|
+
display: flex;
|
|
97
|
+
align-items: center;
|
|
98
|
+
justify-content: center;
|
|
99
|
+
width: 40px;
|
|
100
|
+
height: 40px;
|
|
101
|
+
border-radius: 50%;
|
|
102
|
+
background-color: #f1f3f4;
|
|
103
|
+
flex-shrink: 0;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
.item-icono mat-icon {
|
|
107
|
+
font-size: 20px;
|
|
108
|
+
width: 20px;
|
|
109
|
+
height: 20px;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/* Colores por método */
|
|
113
|
+
.metodo-get { color: #0069B4; background-color: #e3f2fd; }
|
|
114
|
+
.metodo-post { color: #518a5f; background-color: #e8f5e9; }
|
|
115
|
+
.metodo-put { color: #FFA757; background-color: #fff3e0; }
|
|
116
|
+
.metodo-delete { color: #F82617; background-color: #ffebee; }
|
|
117
|
+
.metodo-default { color: #7d7d7d; background-color: #f5f5f5; }
|
|
118
|
+
|
|
119
|
+
.item-contenido {
|
|
120
|
+
flex: 1;
|
|
121
|
+
display: flex;
|
|
122
|
+
flex-direction: column;
|
|
123
|
+
min-width: 0; /* Evita que el flex desborde */
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
.item-titulo {
|
|
127
|
+
font-size: 14px;
|
|
128
|
+
color: #002f6b;
|
|
129
|
+
font-weight: 600;
|
|
130
|
+
word-break: break-all;
|
|
131
|
+
margin-bottom: 2px;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
.item-detalles {
|
|
135
|
+
display: flex;
|
|
136
|
+
flex-wrap: wrap;
|
|
137
|
+
gap: 8px;
|
|
138
|
+
font-size: 12px;
|
|
139
|
+
color: #5f6368;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
.item-detalles span {
|
|
143
|
+
display: flex;
|
|
144
|
+
align-items: center;
|
|
145
|
+
gap: 3px;
|
|
146
|
+
white-space: nowrap;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
.item-detalles mat-icon {
|
|
150
|
+
font-size: 14px;
|
|
151
|
+
width: 14px;
|
|
152
|
+
height: 14px;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
.detalle-dispositivo mat-icon { color: #673ab7; }
|
|
156
|
+
.detalle-browser mat-icon { color: #5f6368; }
|
|
157
|
+
.detalle-ip mat-icon { color: #0069B4; }
|
|
158
|
+
.detalle-pais mat-icon { color: #F87600; }
|
|
159
|
+
|
|
160
|
+
.item-fecha {
|
|
161
|
+
font-size: 11px;
|
|
162
|
+
color: #9aa0a6;
|
|
163
|
+
white-space: nowrap;
|
|
164
|
+
margin-left: 12px;
|
|
165
|
+
display: flex;
|
|
166
|
+
flex-direction: column;
|
|
167
|
+
align-items: flex-end;
|
|
168
|
+
font-family: 'Roboto Mono', monospace;
|
|
169
|
+
flex-shrink: 0;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
mat-progress-bar {
|
|
173
|
+
height: 4px;
|
|
174
|
+
border-radius: 2px;
|
|
175
|
+
margin-bottom: 10px;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
@media (max-width: 600px) {
|
|
179
|
+
.actividad-item {
|
|
180
|
+
flex-direction: column;
|
|
181
|
+
align-items: flex-start;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
.item-icono {
|
|
185
|
+
margin-bottom: 12px;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
.item-fecha {
|
|
189
|
+
margin-left: 0;
|
|
190
|
+
margin-top: 12px;
|
|
191
|
+
align-items: flex-start;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
<div class="contenedor-actividad">
|
|
2
|
+
<div class="header-actividad">
|
|
3
|
+
<h2><mat-icon>history</mat-icon> Actividad reciente de la cuenta</h2>
|
|
4
|
+
<p>Historial de acciones realizadas en el sistema</p>
|
|
5
|
+
|
|
6
|
+
<div class="mensaje-informativo">
|
|
7
|
+
<mat-icon>info</mat-icon>
|
|
8
|
+
<p>Si tiene dudas sobre la información que ve en pantalla, por favor comparta una captura de pantalla al correo <strong>soporte@utn.ac.cr</strong>.</p>
|
|
9
|
+
</div>
|
|
10
|
+
</div>
|
|
11
|
+
|
|
12
|
+
@if(cargando){
|
|
13
|
+
<mat-progress-bar mode="indeterminate"></mat-progress-bar>
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
<div class="lista-actividad">
|
|
17
|
+
@if(actividad.length === 0 && !cargando) {
|
|
18
|
+
<p class="sin-datos">No hay actividad reciente.</p>
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
@for (item of actividad; track item.Consecutivo) {
|
|
22
|
+
<div class="actividad-item">
|
|
23
|
+
<div class="item-icono" [ngClass]="{
|
|
24
|
+
'metodo-get': item.Metodo === 'GET',
|
|
25
|
+
'metodo-post': item.Metodo === 'POST',
|
|
26
|
+
'metodo-put': item.Metodo === 'PUT',
|
|
27
|
+
'metodo-delete': item.Metodo === 'DELETE'
|
|
28
|
+
}">
|
|
29
|
+
<mat-icon [matTooltip]="item.Metodo">{{ getIcon(item.Metodo) }}</mat-icon>
|
|
30
|
+
</div>
|
|
31
|
+
<div class="item-contenido">
|
|
32
|
+
<div class="item-titulo">{{ item.URL }}</div>
|
|
33
|
+
<div class="item-detalles">
|
|
34
|
+
<span class="detalle-dispositivo">
|
|
35
|
+
<mat-icon>{{ item.Dispositivo === 'Móvil' ? 'smartphone' : (item.Dispositivo === 'Tablet' ? 'tablet' : 'laptop') }}</mat-icon>
|
|
36
|
+
{{ item.Dispositivo }}
|
|
37
|
+
</span>
|
|
38
|
+
<span class="detalle-browser"><mat-icon>public</mat-icon> {{ item.Navegador }}</span>
|
|
39
|
+
<span class="detalle-ip"><mat-icon>lan</mat-icon> {{ item.IP }}</span>
|
|
40
|
+
<span class="detalle-pais"><mat-icon>location_on</mat-icon> {{ item.Pais }}</span>
|
|
41
|
+
</div>
|
|
42
|
+
</div>
|
|
43
|
+
<div class="item-fecha">
|
|
44
|
+
<span>{{ item.Fecha | date: 'dd/MM/yyyy' }}</span>
|
|
45
|
+
<strong>{{ item.Fecha | date: 'HH:mm:ss' }}</strong>
|
|
46
|
+
</div>
|
|
47
|
+
</div>
|
|
48
|
+
}
|
|
49
|
+
</div>
|
|
50
|
+
</div>
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { Component, OnInit } from '@angular/core';
|
|
2
|
+
import { CommonModule } from '@angular/common';
|
|
3
|
+
import { HttpClient } from '@angular/common/http';
|
|
4
|
+
import { MatIconModule } from '@angular/material/icon';
|
|
5
|
+
import { MatTooltipModule } from '@angular/material/tooltip';
|
|
6
|
+
import { MatProgressBarModule } from '@angular/material/progress-bar';
|
|
7
|
+
import { DatosGlobalesService } from '../../../datos-globales.service';
|
|
8
|
+
|
|
9
|
+
@Component({
|
|
10
|
+
selector: 'app-gestion-actividad',
|
|
11
|
+
standalone: true,
|
|
12
|
+
imports: [CommonModule, MatIconModule, MatTooltipModule, MatProgressBarModule],
|
|
13
|
+
templateUrl: './gestion-actividad.component.html',
|
|
14
|
+
styleUrls: ['./gestion-actividad.component.css']
|
|
15
|
+
})
|
|
16
|
+
export class GestionActividadComponent implements OnInit {
|
|
17
|
+
public actividad: any[] = [];
|
|
18
|
+
public cargando = false;
|
|
19
|
+
|
|
20
|
+
constructor(private http: HttpClient, private datosGlobalesService: DatosGlobalesService) { }
|
|
21
|
+
|
|
22
|
+
ngOnInit(): void {
|
|
23
|
+
this.obtenerActividad();
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
obtenerActividad(): void {
|
|
27
|
+
this.http.get(`${this.datosGlobalesService.ObtenerURL()}misc/ListarActividades`).subscribe({
|
|
28
|
+
next: (datos: any) => {
|
|
29
|
+
this.actividad = datos.body;
|
|
30
|
+
},
|
|
31
|
+
error: (error) => {
|
|
32
|
+
console.error('Error al obtener actividad:', error);
|
|
33
|
+
this.cargando = false;
|
|
34
|
+
},
|
|
35
|
+
complete: () => {
|
|
36
|
+
this.cargando = false;
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
// this.cargando = true;
|
|
40
|
+
// this.http.get<any[]>(`${this.datosGlobalesService.ObtenerURL()}Actividad`).subscribe({
|
|
41
|
+
// next: (datos) => {
|
|
42
|
+
// this.actividad = datos;
|
|
43
|
+
// this.cargando = false;
|
|
44
|
+
// },
|
|
45
|
+
// error: (error) => {
|
|
46
|
+
// console.error('Error al obtener actividad:', error);
|
|
47
|
+
// this.cargando = false;
|
|
48
|
+
// }
|
|
49
|
+
// });
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
getIcon(metodo: string): string {
|
|
53
|
+
switch (metodo) {
|
|
54
|
+
case 'GET': return 'search';
|
|
55
|
+
case 'POST': return 'add_circle';
|
|
56
|
+
case 'PUT': return 'edit';
|
|
57
|
+
case 'DELETE': return 'delete';
|
|
58
|
+
default: return 'help_outline';
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
@@ -1,4 +1,7 @@
|
|
|
1
|
+
import { Injectable } from '@angular/core';
|
|
1
2
|
import { MatPaginatorIntl } from '@angular/material/paginator';
|
|
3
|
+
|
|
4
|
+
@Injectable()
|
|
2
5
|
export class PaginadorPersonalizado extends MatPaginatorIntl {
|
|
3
6
|
override itemsPerPageLabel = 'Elementos por página:';
|
|
4
7
|
override nextPageLabel = 'Siguiente página';
|
|
@@ -38,6 +38,15 @@
|
|
|
38
38
|
border: none;
|
|
39
39
|
background: none;
|
|
40
40
|
cursor: pointer;
|
|
41
|
+
transition: all 0.2s ease;
|
|
42
|
+
padding: 4px;
|
|
43
|
+
border-radius: 50%;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
.botonDeNavegacion:hover {
|
|
47
|
+
background-color: rgba(25, 118, 210, 0.1);
|
|
48
|
+
transform: scale(1.1);
|
|
49
|
+
color: #0b4fce;
|
|
41
50
|
}
|
|
42
51
|
|
|
43
52
|
/* Contenedor */
|
|
@@ -107,27 +116,24 @@
|
|
|
107
116
|
|
|
108
117
|
.pie-col {
|
|
109
118
|
display: flex;
|
|
110
|
-
gap:
|
|
119
|
+
gap: 5px;
|
|
111
120
|
align-items: center;
|
|
112
121
|
flex: 1;
|
|
113
|
-
/* Cada columna ocupará el mismo espacio */
|
|
114
122
|
overflow: hidden;
|
|
115
|
-
/* Evita que el contenido desborde el tercio asignado */
|
|
116
123
|
}
|
|
117
124
|
|
|
118
125
|
.pie-col.izquierda {
|
|
119
126
|
justify-content: flex-start;
|
|
120
|
-
direction: ltr;
|
|
121
127
|
}
|
|
122
128
|
|
|
123
129
|
.pie-col.centro {
|
|
124
130
|
justify-content: center;
|
|
131
|
+
flex: 0 1 auto;
|
|
132
|
+
min-width: 0;
|
|
125
133
|
}
|
|
126
134
|
|
|
127
135
|
.pie-col.derecha {
|
|
128
136
|
justify-content: flex-end;
|
|
129
|
-
flex-direction: row-reverse;
|
|
130
|
-
direction: rtl;
|
|
131
137
|
}
|
|
132
138
|
|
|
133
139
|
/* Página */
|
|
@@ -225,3 +231,43 @@
|
|
|
225
231
|
opacity: 1;
|
|
226
232
|
}
|
|
227
233
|
}
|
|
234
|
+
|
|
235
|
+
/* Estilos para el mat-menu de aplicaciones */
|
|
236
|
+
::ng-deep .mat-mdc-menu-panel {
|
|
237
|
+
border-radius: 12px !important;
|
|
238
|
+
border: 1px solid rgba(0, 47, 107, 0.1) !important;
|
|
239
|
+
box-shadow: 0 10px 25px rgba(0, 0, 0, 0.15) !important;
|
|
240
|
+
margin-top: 8px !important;
|
|
241
|
+
background-color: white !important;
|
|
242
|
+
min-width: 200px !important;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
::ng-deep .mat-mdc-menu-item {
|
|
246
|
+
height: 48px !important;
|
|
247
|
+
padding: 0 20px !important;
|
|
248
|
+
transition: background-color 0.2s ease !important;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
::ng-deep .mat-mdc-menu-item:hover {
|
|
252
|
+
background-color: #f0f7ff !important;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
::ng-deep .mat-mdc-menu-item .mat-icon {
|
|
256
|
+
color: #002f6b !important;
|
|
257
|
+
margin-right: 12px !important;
|
|
258
|
+
font-size: 22px !important;
|
|
259
|
+
width: 22px !important;
|
|
260
|
+
height: 22px !important;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
::ng-deep .mat-mdc-menu-item span {
|
|
264
|
+
font-size: 14px !important;
|
|
265
|
+
font-weight: 500 !important;
|
|
266
|
+
color: #444 !important;
|
|
267
|
+
margin-left: 0 !important;
|
|
268
|
+
/* Material sometimes adds weird margins */
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
::ng-deep .mat-mdc-menu-item:hover span {
|
|
272
|
+
color: #0b4fce !important;
|
|
273
|
+
}
|
|
@@ -7,14 +7,14 @@
|
|
|
7
7
|
</div>
|
|
8
8
|
<div class="pie-col derecha">
|
|
9
9
|
@if(TienePermiso) {
|
|
10
|
-
<button class="botonDeNavegacion" matTooltip="Salir"
|
|
10
|
+
<button class="botonDeNavegacion" matTooltip="Salir" (click)="Salir()">
|
|
11
11
|
<mat-icon>logout</mat-icon>
|
|
12
12
|
</button>
|
|
13
|
-
<button class="botonDeNavegacion" matTooltip="Perfil"
|
|
13
|
+
<button class="botonDeNavegacion" matTooltip="Perfil" (click)="irAPerfil()">
|
|
14
14
|
<mat-icon>person</mat-icon>
|
|
15
15
|
</button>
|
|
16
16
|
} @else {
|
|
17
|
-
<button class="botonDeNavegacion" matTooltip="Entrar"
|
|
17
|
+
<button class="botonDeNavegacion" matTooltip="Entrar" (click)="Entrar()">
|
|
18
18
|
<mat-icon>login</mat-icon>
|
|
19
19
|
</button>
|
|
20
20
|
}
|
|
@@ -28,16 +28,16 @@
|
|
|
28
28
|
<div [ngClass]="claseDelContenedor">
|
|
29
29
|
@if(TienePermiso) {
|
|
30
30
|
<div class="botonesDeNavegacion">
|
|
31
|
-
<button class="botonDeNavegacion" matTooltip="Ir atrás"
|
|
31
|
+
<button class="botonDeNavegacion" matTooltip="Ir atrás" (click)="irAtras()">
|
|
32
32
|
<mat-icon>arrow_back</mat-icon>
|
|
33
33
|
</button>
|
|
34
|
-
<button class="botonDeNavegacion" matTooltip="Ir al menú del módulo"
|
|
34
|
+
<button class="botonDeNavegacion" matTooltip="Ir al menú del módulo" (click)="irAlMenuDeModulo()">
|
|
35
35
|
<mat-icon>menu</mat-icon>
|
|
36
36
|
</button>
|
|
37
|
-
<!-- <button class="botonDeNavegacion" matTooltip="Ir al móudulo padre"
|
|
37
|
+
<!-- <button class="botonDeNavegacion" matTooltip="Ir al móudulo padre" (click)="irAlModuloPadre()">
|
|
38
38
|
<mat-icon>apps</mat-icon>
|
|
39
39
|
</button> -->
|
|
40
|
-
<button class="botonDeNavegacion" matTooltip="Ir al inicio"
|
|
40
|
+
<button class="botonDeNavegacion" matTooltip="Ir al inicio" (click)="irAlInicio()">
|
|
41
41
|
<mat-icon>home</mat-icon>
|
|
42
42
|
</button>
|
|
43
43
|
</div>
|
|
@@ -79,8 +79,25 @@
|
|
|
79
79
|
</div>
|
|
80
80
|
</div>
|
|
81
81
|
<div class="pie-col derecha">
|
|
82
|
+
<button class="botonDeNavegacion" matTooltip="Aplicaciones" [matMenuTriggerFor]="menuAplicaciones">
|
|
83
|
+
<mat-icon>keyboard_arrow_up</mat-icon>
|
|
84
|
+
</button>
|
|
85
|
+
|
|
86
|
+
<mat-menu #menuAplicaciones="matMenu">
|
|
87
|
+
<button mat-menu-item (click)="irASugerencias()">
|
|
88
|
+
<mat-icon>lightbulb</mat-icon>
|
|
89
|
+
<span>Sugerencias</span>
|
|
90
|
+
</button>
|
|
91
|
+
@if(TienePermiso) {
|
|
92
|
+
<button mat-menu-item (click)="irAActividad()">
|
|
93
|
+
<mat-icon>history</mat-icon>
|
|
94
|
+
<span>Actividad de la cuenta</span>
|
|
95
|
+
</button>
|
|
96
|
+
}
|
|
97
|
+
</mat-menu>
|
|
98
|
+
|
|
82
99
|
@if(TienePermiso) {
|
|
83
|
-
<button class="botonDeNavegacion" matTooltip="Mensajes"
|
|
100
|
+
<button class="botonDeNavegacion" matTooltip="Mensajes" (click)="irAMensajes()">
|
|
84
101
|
@if (Mensajes.length > 0) {
|
|
85
102
|
<mat-icon>mark_email_unread</mat-icon>
|
|
86
103
|
} @else {
|
|
@@ -89,21 +106,18 @@
|
|
|
89
106
|
</button>
|
|
90
107
|
}
|
|
91
108
|
@if(EnlaceDelVideo !== '-') {
|
|
92
|
-
<button class="botonDeNavegacion" matTooltip="Vídeo"
|
|
109
|
+
<button class="botonDeNavegacion" matTooltip="Vídeo" (click)="irAVideo()">
|
|
93
110
|
<mat-icon>live_tv</mat-icon>
|
|
94
111
|
</button>
|
|
95
112
|
}
|
|
96
113
|
@if(EnlaceDelManual !== '-') {
|
|
97
|
-
<button class="botonDeNavegacion" matTooltip="Ayuda"
|
|
114
|
+
<button class="botonDeNavegacion" matTooltip="Ayuda" (click)="irAAyuda()">
|
|
98
115
|
<mat-icon>help</mat-icon>
|
|
99
116
|
</button>
|
|
100
117
|
}
|
|
101
|
-
<button class="botonDeNavegacion" matTooltip="Reporte"
|
|
118
|
+
<button class="botonDeNavegacion" matTooltip="Reporte" (click)="irASoporte()">
|
|
102
119
|
<mat-icon>support_agent</mat-icon>
|
|
103
120
|
</button>
|
|
104
|
-
<button class="botonDeNavegacion" matTooltip="Sugerencias" mat-button (click)="irASugerencias()">
|
|
105
|
-
<mat-icon>lightbulb</mat-icon>
|
|
106
|
-
</button>
|
|
107
121
|
</div>
|
|
108
122
|
</div>
|
|
109
123
|
</div>
|
|
@@ -11,9 +11,11 @@ import { MensajesComponent } from '../../../Componentes/Nucleo/mensajes/mensajes
|
|
|
11
11
|
import { MensajeConfirmacionHTMLComponent } from '../../../Componentes/Nucleo/mensaje-confirmacion-html/mensaje-confirmacion-html';
|
|
12
12
|
import { ReporteDeSugerenciasComponent } from '../../../Componentes/Nucleo/reporte-de-sugerencias/reporte-de-sugerencias.component';
|
|
13
13
|
|
|
14
|
+
import { MatMenuModule } from '@angular/material/menu';
|
|
15
|
+
|
|
14
16
|
@Component({
|
|
15
17
|
selector: 'app-contenedor-componentes',
|
|
16
|
-
imports: [RouterOutlet, MatIconModule, MatTooltipModule, CommonModule],
|
|
18
|
+
imports: [RouterOutlet, MatIconModule, MatTooltipModule, CommonModule, MatMenuModule],
|
|
17
19
|
templateUrl: './contenedor-componentes.component.html',
|
|
18
20
|
styleUrl: './contenedor-componentes.component.css'
|
|
19
21
|
})
|
|
@@ -210,6 +212,11 @@ export class ContenedorComponentesComponent implements OnInit, OnDestroy {
|
|
|
210
212
|
this.dialog.open(ReporteDeSugerenciasComponent);
|
|
211
213
|
}
|
|
212
214
|
|
|
215
|
+
irAActividad(): void {
|
|
216
|
+
const url = new URL(window.location.href);
|
|
217
|
+
window.location.href = `${url.origin}/Actividad`;
|
|
218
|
+
}
|
|
219
|
+
|
|
213
220
|
ngOnDestroy() {
|
|
214
221
|
if (this.intervaloUsuarios) {
|
|
215
222
|
clearInterval(this.intervaloUsuarios);
|
|
@@ -3,7 +3,6 @@ import { provideRouter } from '@angular/router';
|
|
|
3
3
|
|
|
4
4
|
import { routes } from './app.routes';
|
|
5
5
|
import { provideClientHydration, withEventReplay } from '@angular/platform-browser';
|
|
6
|
-
import { provideAnimationsAsync } from '@angular/platform-browser/animations/async';
|
|
7
6
|
import { provideHttpClient, withFetch, withInterceptors } from '@angular/common/http';
|
|
8
7
|
import { MatPaginatorIntl } from '@angular/material/paginator';
|
|
9
8
|
import { PaginadorPersonalizado } from './Componentes/Nucleo/tabla/paginador-personalizado';
|
|
@@ -16,10 +15,8 @@ export const appConfig: ApplicationConfig = {
|
|
|
16
15
|
{ provide: MatPaginatorIntl, useClass: PaginadorPersonalizado },
|
|
17
16
|
provideZoneChangeDetection({ eventCoalescing: true }),
|
|
18
17
|
provideRouter(routes),
|
|
19
|
-
provideClientHydration(withEventReplay()),
|
|
20
|
-
provideAnimationsAsync(),
|
|
21
18
|
provideHttpClient(withFetch()),
|
|
22
|
-
provideClientHydration(),
|
|
19
|
+
provideClientHydration(withEventReplay()),
|
|
23
20
|
provideCharts(withDefaultRegisterables()),
|
|
24
21
|
...AnalyticsModule.forRoot().providers!,
|
|
25
22
|
provideHttpClient(withInterceptors([AuthInterceptor]))
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Routes } from '@angular/router';
|
|
2
|
+
import { GestionActividadComponent } from './Componentes/Nucleo/gestion-actividad/gestion-actividad.component';
|
|
2
3
|
import { GestionTablaComponent } from './Paginas/gestion-tabla/gestion-tabla.component';
|
|
3
4
|
import { ContenedorPrincipalComponent } from './Paginas/contenedor-principal/contenedor-principal.component';
|
|
4
5
|
import { GestionTablaJefeComponent } from './Paginas/gestion-tabla-jefe/gestion-tabla-jefe.component';
|
|
@@ -7,6 +8,7 @@ import { GestionDeReportesComponent } from './Paginas/gestion-de-reportes/gestio
|
|
|
7
8
|
import { GestionIframe1Component } from './Paginas/gestion-iframe1/gestion-iframe1.component';
|
|
8
9
|
|
|
9
10
|
export const routes: Routes = [
|
|
11
|
+
{ path: 'Actividad', component: GestionActividadComponent },
|
|
10
12
|
{ path: '', component: ContenedorPrincipalComponent },
|
|
11
13
|
{ path: 'tabla', component: GestionTablaComponent },
|
|
12
14
|
{ path: 'aprobaciones', component: GestionTablaJefeComponent},
|