utn-cli 2.0.59 → 2.0.61

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.
@@ -27,8 +27,8 @@ export async function createComponent() {
27
27
  if (dbDir) {
28
28
  const sqlPath = path.join(currentDir, dbDir.name, 'docker-scripts/1-crear estructura.sql');
29
29
  if (fs.existsSync(sqlPath)) {
30
- console.log(`Buscando tabla para el servicio "${tituloCard}" en ${sqlPath}...`);
31
- tableInfo = findTableByComment(sqlPath, tituloCard);
30
+ console.log(`Buscando tabla para el servicio "${nombreServicio}" en ${sqlPath}...`);
31
+ tableInfo = findTableByComment(sqlPath, nombreServicio);
32
32
  if (tableInfo) {
33
33
  console.log(`Tabla encontrada: ${tableInfo.tableName} en la base de datos ${tableInfo.dbName}`);
34
34
  } else {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "utn-cli",
3
- "version": "2.0.59",
3
+ "version": "2.0.61",
4
4
  "description": "Herramienta CLI unificada para la gestión de plantillas en SIGU.",
5
5
  "main": "index.js",
6
6
  "type": "module",
@@ -1,240 +1,5 @@
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;
1
+ .mensaje {
2
+ margin-top: 1%;
22
3
  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
4
  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 {
114
- color: #0069B4;
115
- background-color: #e3f2fd;
116
- }
117
-
118
- .metodo-post {
119
- color: #518a5f;
120
- background-color: #e8f5e9;
121
- }
122
-
123
- .metodo-put {
124
- color: #FFA757;
125
- background-color: #fff3e0;
126
- }
127
-
128
- .metodo-delete {
129
- color: #F82617;
130
- background-color: #ffebee;
131
- }
132
-
133
- .metodo-default {
134
- color: #7d7d7d;
135
- background-color: #f5f5f5;
136
- }
137
-
138
- .item-contenido {
139
- flex: 1;
140
- display: flex;
141
- flex-direction: column;
142
- min-width: 0;
143
- /* Evita que el flex desborde */
144
- }
145
-
146
- .item-titulo {
147
- font-size: 14px;
148
- color: #002f6b;
149
- font-weight: 600;
150
- word-break: break-all;
151
- margin-bottom: 2px;
152
- display: flex;
153
- align-items: center;
154
- gap: 8px;
155
- flex-wrap: wrap;
156
- }
157
-
158
- .badge-sesion-actual {
159
- background-color: #e8f5e9;
160
- color: #2e7d32;
161
- font-size: 10px;
162
- padding: 2px 8px;
163
- border-radius: 12px;
164
- border: 1px solid #c8e6c9;
165
- text-transform: uppercase;
166
- font-weight: 700;
167
- white-space: nowrap;
168
- }
169
-
170
- .item-detalles {
171
- display: flex;
172
- flex-wrap: wrap;
173
- gap: 8px;
174
- font-size: 12px;
175
- color: #5f6368;
176
- }
177
-
178
- .item-detalles span {
179
- display: flex;
180
- align-items: center;
181
- gap: 3px;
182
- white-space: nowrap;
183
- }
184
-
185
- .item-detalles mat-icon {
186
- font-size: 14px;
187
- width: 14px;
188
- height: 14px;
189
- }
190
-
191
- .detalle-dispositivo mat-icon {
192
- color: #673ab7;
193
- }
194
-
195
- .detalle-browser mat-icon {
196
- color: #5f6368;
197
- }
198
-
199
- .detalle-ip mat-icon {
200
- color: #0069B4;
201
- }
202
-
203
- .detalle-pais mat-icon {
204
- color: #F87600;
205
- }
206
-
207
- .item-fecha {
208
- font-size: 11px;
209
- color: #9aa0a6;
210
- white-space: nowrap;
211
- margin-left: 12px;
212
- display: flex;
213
- flex-direction: column;
214
- align-items: flex-end;
215
- font-family: 'Roboto Mono', monospace;
216
- flex-shrink: 0;
217
- }
218
-
219
- mat-progress-bar {
220
- height: 4px;
221
- border-radius: 2px;
222
- margin-bottom: 10px;
223
- }
224
-
225
- @media (max-width: 600px) {
226
- .actividad-item {
227
- flex-direction: column;
228
- align-items: flex-start;
229
- }
230
-
231
- .item-icono {
232
- margin-bottom: 12px;
233
- }
234
-
235
- .item-fecha {
236
- margin-left: 0;
237
- margin-top: 12px;
238
- align-items: flex-start;
239
- }
240
5
  }
@@ -1,60 +1,23 @@
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>
1
+ <h3 mat-dialog-title>{{ data.titulo }}</h3>
5
2
 
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
9
- <strong>soporte@utn.ac.cr</strong>.</p>
10
- </div>
11
- </div>
12
-
13
- @if(cargando){
14
- <mat-progress-bar mode="indeterminate"></mat-progress-bar>
3
+ <mat-dialog-content>
4
+ <p>{{ data.mensaje }}</p>
5
+ @if(SolicitaMensaje){
6
+ <mat-form-field class="mensaje">
7
+ <mat-label>Agregar comentario</mat-label>
8
+ <textarea matInput placeholder="Explicación del motivo de aprobación o rechazo"
9
+ [(ngModel)]="MensajeBrindado"></textarea>
10
+ </mat-form-field>
15
11
  }
16
12
 
17
- <div class="lista-actividad">
18
- @if(actividad.length === 0 && !cargando) {
19
- <p class="sin-datos">No hay actividad reciente.</p>
20
- }
13
+ </mat-dialog-content>
14
+
15
+ <mat-dialog-actions>
16
+ @if(data.textoCerrar){
17
+ <button mat-button (click)="onClose()">{{ data.textoCerrar }}</button>
18
+ }
21
19
 
22
- @for (item of actividad; track item.Consecutivo) {
23
- <div class="actividad-item">
24
- <div class="item-icono" [ngClass]="{
25
- 'metodo-get': item.Metodo === 'GET',
26
- 'metodo-post': item.Metodo === 'POST',
27
- 'metodo-put': item.Metodo === 'PUT',
28
- 'metodo-delete': item.Metodo === 'DELETE'
29
- }">
30
- <mat-icon [matTooltip]="item.Metodo">{{ getIcon(item.Metodo) }}</mat-icon>
31
- </div>
32
- <div class="item-contenido">
33
- <div class="item-titulo">
34
- {{ item.URL }}
35
- @if(esSesionActual(item.Token)){
36
- <span class="badge-sesion-actual">Sesión actual</span>
37
- }
38
- </div>
39
- <div class="item-detalles">
40
- <span class="detalle-dispositivo">
41
- <mat-icon>{{ item.Dispositivo === 'Móvil' ? 'smartphone' : (item.Dispositivo === 'Tablet' ? 'tablet' :
42
- 'laptop') }}</mat-icon>
43
- {{ item.Dispositivo }}
44
- </span>
45
- <span class="detalle-browser"><mat-icon>public</mat-icon> {{ item.Navegador }}</span>
46
- <span class="detalle-ip"><mat-icon>lan</mat-icon> {{ item.IP }}</span>
47
- <span class="detalle-pais"><mat-icon>location_on</mat-icon> {{ item.Pais }}</span>
48
- </div>
49
- </div>
50
- <div class="item-fecha">
51
- <span>{{ item.Fecha | date: 'dd/MM/yyyy' }}</span>
52
- <strong>{{ item.Fecha | date: 'HH:mm:ss' }}</strong>
53
- <button mat-icon-button color="warn" matTooltip="Cerrar esta sesión" (click)="cerrarSesion(item.Token)">
54
- <mat-icon>logout</mat-icon>
55
- </button>
56
- </div>
57
- </div>
58
- }
59
- </div>
60
- </div>
20
+ @if(data.textoAceptar){
21
+ <button mat-button (click)="onAccept()" cdkFocusInitial>{{ data.textoAceptar }}</button>
22
+ }
23
+ </mat-dialog-actions>
@@ -1,86 +1,65 @@
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';
1
+ import { Component, Inject } from '@angular/core';
7
2
  import { MatButtonModule } from '@angular/material/button';
8
- import { MatDialog } from '@angular/material/dialog';
9
- import { MensajeConfirmacionComponent } from '../mensaje-confirmacion/mensaje-confirmacion';
10
- import { DatosGlobalesService } from '../../../datos-globales.service';
3
+ import {
4
+ MAT_DIALOG_DATA,
5
+ MatDialogActions,
6
+ MatDialogContent,
7
+ MatDialogRef,
8
+ MatDialogTitle
9
+ } from '@angular/material/dialog';
10
+ import { MatFormFieldModule } from '@angular/material/form-field';
11
+ import { MatInputModule } from '@angular/material/input';
12
+ import { FormsModule } from '@angular/forms';
13
+
14
+ export interface DialogData {
15
+ titulo: string;
16
+ mensaje: string;
17
+ textoCerrar?: string;
18
+ textoAceptar?: string;
19
+ SolicitaMensaje?: string;
20
+ onClose?: () => void;
21
+ onAccept?: (MensajeBrindado: any) => void;
22
+ }
11
23
 
12
24
  @Component({
13
- selector: 'app-gestion-actividad',
14
- standalone: true,
15
- imports: [CommonModule, MatIconModule, MatTooltipModule, MatProgressBarModule, MatButtonModule],
16
- templateUrl: './gestion-actividad.component.html',
17
- styleUrls: ['./gestion-actividad.component.css']
25
+ selector: 'app-dialogo',
26
+ templateUrl: './mensaje-confirmacion.component.html',
27
+ styleUrls: ['./mensaje-confirmacion.component.css'],
28
+ imports: [
29
+ MatButtonModule,
30
+ MatDialogTitle,
31
+ MatDialogContent,
32
+ MatDialogActions,
33
+ MatFormFieldModule,
34
+ MatInputModule,
35
+ FormsModule
36
+ ]
18
37
  })
19
- export class GestionActividadComponent implements OnInit {
20
- public actividad: any[] = [];
21
- public cargando = false;
22
- private tokenActual = '';
23
-
24
- constructor(private http: HttpClient, private datosGlobalesService: DatosGlobalesService, private dialog: MatDialog) { }
38
+ export class MensajeConfirmacionComponent {
25
39
 
26
- ngOnInit(): void {
27
- this.tokenActual = this.datosGlobalesService.ObtenerToken().split(' ')[1] || '';
28
- this.obtenerActividad();
29
- }
40
+ SolicitaMensaje: string | undefined;
30
41
 
31
- obtenerActividad(): void {
32
- this.cargando = true;
33
- this.http.get(`${this.datosGlobalesService.ObtenerURL()}misc/ListarActividades`).subscribe({
34
- next: (datos: any) => {
35
- this.actividad = datos.body;
36
- },
37
- error: (error) => {
38
- console.error('Error al obtener actividad:', error);
39
- this.cargando = false;
40
- },
41
- complete: () => {
42
- this.cargando = false;
43
- }
44
- });
45
- }
42
+ public MensajeBrindado: string = '';
46
43
 
47
- cerrarSesion(token: string): void {
48
- this.dialog.open(MensajeConfirmacionComponent, {
49
- data: {
50
- titulo: 'Confirmación',
51
- mensaje: '¿Está seguro de que desea cerrar esta sesión?',
52
- textoCerrar: 'Cancelar',
53
- textoAceptar: 'Cerrar sesión',
54
- onClose: () => { },
55
- onAccept: () => {
56
- this.http.delete(`${this.datosGlobalesService.ObtenerURL()}misc/cerrarSesionPorToken/${token}`).subscribe({
57
- next: () => {
58
- if (token === this.tokenActual) {
59
- this.datosGlobalesService.RedirigirALogin();
60
- } else {
61
- this.obtenerActividad();
62
- }
63
- },
64
- error: (error) => {
65
- console.error('Error al cerrar sesión:', error);
66
- }
67
- });
68
- },
69
- },
70
- });
44
+ constructor(
45
+ public dialogRef: MatDialogRef<MensajeConfirmacionComponent>,
46
+ @Inject(MAT_DIALOG_DATA) public data: DialogData
47
+ ) {
48
+ this.dialogRef.disableClose = true;
49
+ this.SolicitaMensaje = this.data.SolicitaMensaje;
71
50
  }
72
51
 
73
- esSesionActual(token: string): boolean {
74
- return token === this.tokenActual;
52
+ onClose(): void {
53
+ if (this.data.onClose) {
54
+ this.data.onClose();
55
+ }
56
+ this.dialogRef.close();
75
57
  }
76
58
 
77
- getIcon(metodo: string): string {
78
- switch (metodo) {
79
- case 'GET': return 'search';
80
- case 'POST': return 'add_circle';
81
- case 'PUT': return 'edit';
82
- case 'DELETE': return 'delete';
83
- default: return 'help_outline';
59
+ onAccept(): void {
60
+ if (this.data.onAccept) {
61
+ this.data.onAccept(this.MensajeBrindado);
84
62
  }
63
+ this.dialogRef.close(this.MensajeBrindado);
85
64
  }
86
65
  }
@@ -113,7 +113,7 @@ export class GestionTablaXYZComponent {
113
113
  mostrarDetalleDelRegistro(LicenciaId: any): void {
114
114
  let data = {};
115
115
  this.http
116
- .get(`${this.datosGlobalesService.ObtenerURL()}licencias/datosDeUnaLicencia/${LicenciaId}`)
116
+ .get(`${this.datosGlobalesService.ObtenerURL()}XYZ/datosDeUnaLicencia/${LicenciaId}`)
117
117
  .subscribe({
118
118
  next: (datos: any) => {
119
119
  let data = datos.body[0];
@@ -136,7 +136,7 @@ export class GestionTablaXYZComponent {
136
136
  }
137
137
  firmaFuncionario(LicenciaId: any): void {
138
138
  this.http
139
- .post(`${this.datosGlobalesService.ObtenerURL()}licencias/firmaFuncionario`, { LicenciaId })
139
+ .post(`${this.datosGlobalesService.ObtenerURL()}XYZ/firmaFuncionario`, { LicenciaId })
140
140
  .subscribe({
141
141
  next: (datos: any) => {
142
142
  this.obtenerDatosParaPoblarLaTabla();
@@ -160,7 +160,7 @@ export class GestionTablaXYZComponent {
160
160
  }
161
161
  eliminar(LicenciaId: any): void {
162
162
  this.http
163
- .post(`${this.datosGlobalesService.ObtenerURL()}licencias/borrar`, { LicenciaId })
163
+ .post(`${this.datosGlobalesService.ObtenerURL()}XYZ/borrar`, { LicenciaId })
164
164
  .subscribe({
165
165
  next: (datos: any) => {
166
166
  this.obtenerDatosParaPoblarLaTabla();
@@ -196,7 +196,7 @@ export class GestionTablaXYZComponent {
196
196
  }
197
197
 
198
198
  obtenerDatosParaPoblarLaTabla() {
199
- this.http.get(`${this.datosGlobalesService.ObtenerURL()}licencias/listar`).subscribe({
199
+ this.http.get(`${this.datosGlobalesService.ObtenerURL()}XYZ/listar`).subscribe({
200
200
  next: (datos: any) => {
201
201
  if (datos.error) {
202
202
  console.error('Problemas al obtener los registros:', datos.error);
@@ -216,7 +216,7 @@ export class GestionTablaXYZComponent {
216
216
  });
217
217
  }
218
218
  obtenerTiposLicencias() {
219
- this.http.get(`${this.datosGlobalesService.ObtenerURL()}licencias/tipos`).subscribe({
219
+ this.http.get(`${this.datosGlobalesService.ObtenerURL()}XYZ/tipos`).subscribe({
220
220
  next: (datos: any) => {
221
221
  if (datos.error) {
222
222
  console.error('Problemas al intentar obtener los registros:', datos.error);
@@ -231,7 +231,7 @@ export class GestionTablaXYZComponent {
231
231
  });
232
232
  }
233
233
  Agregar(incapacidad: any) {
234
- this.http.post(`${this.datosGlobalesService.ObtenerURL()}licencias/agregar`, incapacidad).subscribe({
234
+ this.http.post(`${this.datosGlobalesService.ObtenerURL()}XYZ/agregar`, incapacidad).subscribe({
235
235
  next: (datos: any) => {
236
236
  if (datos.error) {
237
237
  console.log('Problemas al intentar obtener los registros:', datos.error);
@@ -245,7 +245,7 @@ export class GestionTablaXYZComponent {
245
245
  });
246
246
  }
247
247
  Actualizar(incapacidad: any) {
248
- this.http.post(`${this.datosGlobalesService.ObtenerURL()}licencias/actualizar`, incapacidad).subscribe({
248
+ this.http.post(`${this.datosGlobalesService.ObtenerURL()}XYZ/actualizar`, incapacidad).subscribe({
249
249
  next: (datos: any) => {
250
250
  if (datos.error) {
251
251
  console.log('Problemas al intentar obtener los registros:', datos.error);
@@ -260,7 +260,7 @@ export class GestionTablaXYZComponent {
260
260
  }
261
261
  DescargarReporte() {
262
262
  this.cargando = true;
263
- this.http.get(`${this.datosGlobalesService.ObtenerURL()}licencias/reporte`, {
263
+ this.http.get(`${this.datosGlobalesService.ObtenerURL()}XYZ/reporte`, {
264
264
  responseType: 'text'
265
265
  }).subscribe({
266
266
  next: (datos: any) => {