diff --git a/CHANGELOG.md b/CHANGELOG.md index 0d7818b..b8898ad 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## [0.22.0] - 2025-09-03 +### Added +- Nueva ux a la hora de gestionar tareas programadas. +- En modificar imagen git, nueva opcion para "forzar push". +### Improved +- Nuevo manejo de errores en el modulo de ogRepository. + +--- ## [0.21.0] - 2025-08-28 ### Added - Se ha incluido una integracion con el agente, para generar los scripts que se llaman al particionar. diff --git a/ogWebconsole/src/app/components/commands/commands-task/create-task-schedule/create-task-schedule.component.html b/ogWebconsole/src/app/components/commands/commands-task/create-task-schedule/create-task-schedule.component.html index 186ff83..ac8f63f 100644 --- a/ogWebconsole/src/app/components/commands/commands-task/create-task-schedule/create-task-schedule.component.html +++ b/ogWebconsole/src/app/components/commands/commands-task/create-task-schedule/create-task-schedule.component.html @@ -8,7 +8,7 @@ Repetición - {{ type | titlecase }} + {{ opt.label }} diff --git a/ogWebconsole/src/app/components/commands/commands-task/create-task-schedule/create-task-schedule.component.ts b/ogWebconsole/src/app/components/commands/commands-task/create-task-schedule/create-task-schedule.component.ts index 5822467..afdedf8 100644 --- a/ogWebconsole/src/app/components/commands/commands-task/create-task-schedule/create-task-schedule.component.ts +++ b/ogWebconsole/src/app/components/commands/commands-task/create-task-schedule/create-task-schedule.component.ts @@ -14,7 +14,10 @@ export class CreateTaskScheduleComponent implements OnInit{ form: FormGroup; baseUrl: string; apiUrl: string; - recurrenceTypes = ['none', 'custom']; + recurrenceTypes = [ + { value: 'none', label: 'Sin repetición' }, + { value: 'custom', label: 'Repetición personalizada' } + ]; weekDays: string[] = ['monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday', 'sunday']; isSingleDateSelected: boolean = true; monthsList: string[] = [ @@ -108,12 +111,27 @@ export class CreateTaskScheduleComponent implements OnInit{ } formatExecutionTime(time: string | Date): string { - const date = (time instanceof Date) ? time : new Date(time); - if (isNaN(date.getTime())) { - console.error('Invalid execution time:', time); + if (typeof time === 'string') { + const hhmmMatch = time.match(/^\d{2}:\d{2}/); + if (hhmmMatch) { + return hhmmMatch[0]; + } + const parsed = new Date(time); + if (!isNaN(parsed.getTime())) { + const hours = String(parsed.getHours()).padStart(2, '0'); + const minutes = String(parsed.getMinutes()).padStart(2, '0'); + return `${hours}:${minutes}`; + } return ''; } - return date.toISOString().substring(11, 16); + + if (time instanceof Date && !isNaN(time.getTime())) { + const hours = String(time.getHours()).padStart(2, '0'); + const minutes = String(time.getMinutes()).padStart(2, '0'); + return `${hours}:${minutes}`; + } + + return ''; } convertDateToLocalISO(date: Date): string { @@ -191,7 +209,7 @@ export class CreateTaskScheduleComponent implements OnInit{ private calculateNextExecutionAndCount(): void { const recurrence = this.form.get('recurrenceType')?.value; const time = this.form.get('executionTime')?.value; - + if (recurrence === 'none') { const execDate = this.form.get('executionDate')?.value; if (execDate && time) { @@ -200,31 +218,102 @@ export class CreateTaskScheduleComponent implements OnInit{ this.nextExecutionDate.setHours(parseInt(hours), parseInt(minutes), 0, 0); this.executionCount = 1; } - } else { - const startDate = this.form.get('recurrenceDetails.initDate')?.value; - const endDate = this.form.get('recurrenceDetails.endDate')?.value; - const days = Object.keys(this.selectedDays).filter(day => this.selectedDays[day]); - const months = Object.keys(this.selectedMonths).filter(month => this.selectedMonths[month]); - - if (startDate && endDate && days.length > 0 && months.length > 0) { - // Calcular próxima ejecución (simplificado) - this.nextExecutionDate = new Date(startDate); - const [hours, minutes] = time.split(':'); - this.nextExecutionDate.setHours(parseInt(hours), parseInt(minutes), 0, 0); - - // Calcular número aproximado de ejecuciones - this.executionCount = this.calculateExecutionCount(startDate, endDate, days.length, months.length); - } + return; } + + const startDateValue = this.form.get('recurrenceDetails.initDate')?.value; + const endDateValue = this.form.get('recurrenceDetails.endDate')?.value; + + const selectedDayNames = Object.keys(this.selectedDays).filter(day => this.selectedDays[day]); + const selectedMonthNames = Object.keys(this.selectedMonths).filter(month => this.selectedMonths[month]); + + if (!startDateValue || !endDateValue || selectedDayNames.length === 0 || selectedMonthNames.length === 0) { + this.nextExecutionDate = null; + this.executionCount = 0; + return; + } + + const startDate = new Date(startDateValue); + const endDate = new Date(endDateValue); + + const selectedDayIndices = new Set(selectedDayNames.map(name => this.getDayIndexFromName(name))); + const selectedMonthIndices = new Set(selectedMonthNames.map(name => this.getMonthIndexFromName(name))); + + // Conteo exacto de ejecuciones en el rango [startDate, endDate] + this.executionCount = this.calculateExecutionCountExact(startDate, endDate, selectedDayIndices, selectedMonthIndices); + + // Próxima ejecución >= ahora dentro del rango y criterios + this.nextExecutionDate = this.findNextExecutionDate(startDate, endDate, time, selectedDayIndices, selectedMonthIndices); } - private calculateExecutionCount(startDate: Date, endDate: Date, daysCount: number, monthsCount: number): number { - const start = new Date(startDate); + private calculateExecutionCountExact(startDate: Date, endDate: Date, selectedDays: Set, selectedMonths: Set): number { + const cursor = new Date(startDate); + cursor.setHours(0, 0, 0, 0); const end = new Date(endDate); - const daysDiff = Math.ceil((end.getTime() - start.getTime()) / (1000 * 60 * 60 * 24)); - - // Aproximación: días seleccionados por semana * semanas * meses activos - return Math.ceil((daysCount / 7) * (daysDiff / 7) * (monthsCount / 12)); + end.setHours(23, 59, 59, 999); + + let count = 0; + while (cursor <= end) { + if (selectedMonths.has(cursor.getMonth()) && selectedDays.has(cursor.getDay())) { + count += 1; + } + cursor.setDate(cursor.getDate() + 1); + } + return count; + } + + private findNextExecutionDate(startDate: Date, endDate: Date, time: string, selectedDays: Set, selectedMonths: Set): Date | null { + const now = new Date(); + + const startCandidate = new Date(Math.max(new Date(startDate).setHours(0, 0, 0, 0), new Date(now).setHours(0, 0, 0, 0))); + const endLimit = new Date(endDate); + endLimit.setHours(23, 59, 59, 999); + + const [hours, minutes] = (time || '00:00').split(':'); + + const candidate = new Date(startCandidate); + while (candidate <= endLimit) { + if (selectedMonths.has(candidate.getMonth()) && selectedDays.has(candidate.getDay())) { + const candidateDateTime = new Date(candidate); + candidateDateTime.setHours(parseInt(hours), parseInt(minutes), 0, 0); + if (candidateDateTime >= now) { + return candidateDateTime; + } + } + candidate.setDate(candidate.getDate() + 1); + } + return null; + } + + private getDayIndexFromName(dayName: string): number { + const mapping: { [key: string]: number } = { + sunday: 0, + monday: 1, + tuesday: 2, + wednesday: 3, + thursday: 4, + friday: 5, + saturday: 6 + }; + return mapping[dayName.toLowerCase()] ?? -1; + } + + private getMonthIndexFromName(monthName: string): number { + const mapping: { [key: string]: number } = { + january: 0, + february: 1, + march: 2, + april: 3, + may: 4, + june: 5, + july: 6, + august: 7, + september: 8, + october: 9, + november: 10, + december: 11 + }; + return mapping[monthName.toLowerCase()] ?? -1; } formatDate(date: string | Date): string { diff --git a/ogWebconsole/src/app/components/commands/commands-task/show-task-schedule/show-task-schedule.component.css b/ogWebconsole/src/app/components/commands/commands-task/show-task-schedule/show-task-schedule.component.css index 4d1d26b..70bff3e 100644 --- a/ogWebconsole/src/app/components/commands/commands-task/show-task-schedule/show-task-schedule.component.css +++ b/ogWebconsole/src/app/components/commands/commands-task/show-task-schedule/show-task-schedule.component.css @@ -69,48 +69,287 @@ table { } .mat-elevation-z8 { - box-shadow: 0px 0px 0px rgba(0, 0, 0, 0.2); + border-radius: 12px; + overflow: hidden; + box-shadow: none; } -.paginator-container { +.mat-header-cell { + background-color: #f8f9fa; + font-weight: 600; + color: #495057; + padding: 16px 8px; + border-bottom: 2px solid #e9ecef; +} + +.mat-cell { + padding: 16px 8px; + border-bottom: 1px solid #f1f3f4; +} + +.recurrence-type-container { display: flex; - justify-content: end; - margin-bottom: 30px; + justify-content: center; } -mat-spinner { - margin: 0 auto; - align-self: center; -} - -.subnets-button-row { +.recurrence-chip { display: flex; - gap: 15px; + align-items: center; + padding: 7px 12px; + border-radius: 20px; + min-width: 200px; + transition: all 0.3s ease; + margin: 4px 0; } +.recurrence-icon { + margin-right: 12px; + font-size: 20px; + width: 20px; + height: 20px; +} + +.recurrence-content { + flex: 1; +} + +.recurrence-label { + font-weight: 600; + font-size: 14px; + margin-bottom: 4px; +} + +.recurrence-details { + font-size: 12px; + opacity: 0.8; + line-height: 1.2; +} + +/* Colores para diferentes tipos de recurrencia */ +.recurrence-none { + background-color: #667eea; + color: white; +} + +.recurrence-daily { + background-color: #f093fb; + color: white; +} + +.recurrence-weekly { + background-color: #4facfe; + color: white; +} + +.recurrence-monthly { + background-color: #43e97b; + color: white; +} + +.recurrence-yearly { + background-color: #fa709a; + color: white; +} + +.recurrence-custom { + background-color: #ff9a9e; + color: #333; +} + +/* Estilos para el campo executionTime */ +.time-display { + display: flex; + align-items: center; + justify-content: center; + padding: 8px 12px; + background-color: #667eea; + color: white; + border-radius: 16px; + min-width: 100px; +} + +.time-icon { + margin-right: 8px; + font-size: 16px; + width: 16px; + height: 16px; +} + +.time-value { + font-weight: 600; + font-size: 14px; +} + +/* Estilos para el campo nextExecution */ +.next-execution { + display: flex; + align-items: center; + justify-content: center; + padding: 8px 12px; + background-color: #4facfe; + color: white; + border-radius: 16px; + min-width: 120px; +} + +.execution-icon { + margin-right: 8px; + font-size: 16px; + width: 16px; + height: 16px; +} + +/* Estilos para el campo daysOfWeek */ +.days-display { + text-align: center; +} + +.days-header { + display: flex; + align-items: center; + justify-content: center; + margin-bottom: 8px; + color: #495057; +} + +.days-icon { + margin-right: 6px; + font-size: 16px; + width: 16px; + height: 16px; + color: #4facfe; +} + +.days-count { + font-size: 12px; + font-weight: 500; +} + +.days-chips { + display: flex; + flex-wrap: wrap; + gap: 4px; + justify-content: center; +} + +.day-chip { + background-color: #4facfe; + color: white; + padding: 4px 8px; + border-radius: 12px; + font-size: 11px; + font-weight: 600; + min-width: 32px; + text-align: center; +} + +/* Estilos para el campo months */ +.months-display { + text-align: center; +} + +.months-header { + display: flex; + align-items: center; + justify-content: center; + margin-bottom: 8px; + color: #495057; +} + +.months-icon { + margin-right: 6px; + font-size: 16px; + width: 16px; + height: 16px; + color: #43e97b; +} + +.months-count { + font-size: 12px; + font-weight: 500; +} + +.months-chips { + display: flex; + flex-wrap: wrap; + gap: 4px; + justify-content: center; +} + +.month-chip { + background-color: #43e97b; + color: white; + padding: 4px 8px; + border-radius: 12px; + font-size: 11px; + font-weight: 600; + min-width: 32px; + text-align: center; +} + +/* Estilos para el campo enabled */ +.status-container { + display: flex; + justify-content: center; +} + +.status-indicator { + display: flex; + align-items: center; + padding: 8px 16px; + border-radius: 20px; + font-weight: 600; + font-size: 14px; + min-width: 100px; + justify-content: center; +} + +.status-active { + background-color: #43e97b; + color: white; +} + +.status-inactive { + background-color: #ff9a9e; + color: #333; +} + +.status-icon { + margin-right: 8px; + font-size: 16px; + width: 16px; + height: 16px; +} + +/* Estilos para datos no definidos */ +.no-data { + text-align: center; + padding: 8px; +} + +.no-data-text { + color: #6c757d; + font-style: italic; + font-size: 12px; +} + +/* Estilos para el header de acciones */ .header-actions { + margin-bottom: 20px; display: flex; justify-content: flex-end; - margin-bottom: 20px; - padding: 16px; - background: #f8f9fa; - border-radius: 8px; } .action-button { + color: white; + border: none; + padding: 12px 24px; + font-weight: 600; + cursor: pointer; display: flex; align-items: center; gap: 8px; - padding: 12px 24px; - color: white; - border: none; - font-weight: 500; - cursor: pointer; - transition: background-color 0.2s ease; -} - -.action-button:hover { - background: #1565c0; + transition: all 0.3s ease; } .action-button mat-icon { @@ -119,90 +358,60 @@ mat-spinner { height: 20px; } -.create-button { - color: white; - border: none; - padding: 12px 24px; - font-weight: 500; -} - -.create-button mat-icon { - margin-right: 8px; -} - +/* Estilos para el contenedor de búsqueda */ .search-container { display: flex; gap: 16px; - margin: 20px 0; + margin-bottom: 20px; flex-wrap: wrap; } .search-string { + flex: 1; min-width: 250px; } -/* Estilos para los chips de días y meses */ -.days-display, .months-display { +/* Estilos para el paginador */ +.paginator-container { + margin-top: 20px; display: flex; - flex-wrap: wrap; - gap: 4px; + justify-content: center; } -.day-chip, .month-chip { - background: #e3f2fd; - color: #1976d2; - padding: 4px 8px; - border-radius: 12px; - font-size: 0.75rem; - font-weight: 500; - border: 1px solid #bbdefb; +/* Estilos para los botones de acción en la tabla */ +.mat-column-actions .mat-cell { + text-align: center; } -/* Estilos para la próxima ejecución */ -.next-execution { - display: flex; - align-items: center; - gap: 8px; - color: #555; +.mat-column-actions button { + margin: 0 4px; + transition: all 0.3s ease; } -.execution-icon { - font-size: 18px; - color: #2196f3; +.mat-column-actions button:hover { + transform: scale(1.1); } -/* Mejoras en la tabla */ -.mat-table { - border-radius: 8px; - overflow: hidden; -} - -.mat-header-cell { - background: #f5f5f5; - font-weight: 600; - color: #333; -} - -.mat-row:hover { - background: #f8f9fa; -} - -/* Responsive */ +/* Responsive design */ @media (max-width: 768px) { + .recurrence-chip { + min-width: 160px; + padding: 10px 12px; + } + + .recurrence-label { + font-size: 13px; + } + + .recurrence-details { + font-size: 11px; + } + .search-container { flex-direction: column; } .search-string { - min-width: auto; - width: 100%; - } - - .header-actions { - justify-content: center; - } - - .create-button { - width: 100%; + min-width: 100%; } } diff --git a/ogWebconsole/src/app/components/commands/commands-task/show-task-schedule/show-task-schedule.component.html b/ogWebconsole/src/app/components/commands/commands-task/show-task-schedule/show-task-schedule.component.html index c9f5526..38eccee 100644 --- a/ogWebconsole/src/app/components/commands/commands-task/show-task-schedule/show-task-schedule.component.html +++ b/ogWebconsole/src/app/components/commands/commands-task/show-task-schedule/show-task-schedule.component.html @@ -44,24 +44,22 @@ - - - No programado -
- {{ schedule.executionDate | date }} +
+
+ {{ column.cell(schedule).icon }} +
+
{{ column.cell(schedule).label }}
+
{{ column.cell(schedule).details }}
- - - Programado -
- {{ schedule.recurrenceDetails?.initDate | date }} → {{ schedule.recurrenceDetails?.endDate | date}} -
-
- +
+
- {{ schedule.executionTime | date: 'HH:mm' }} +
+ schedule + {{ schedule.executionTime | date: 'HH:mm' }} +
@@ -72,16 +70,26 @@ -
- {{ day | slice:0:3 }} +
+
+ {{ day }} +
+
+
+ No definido
-
- {{ month | slice:0:3 }} +
+
+ {{ month }} +
+
+
+ No definido
@@ -92,14 +100,12 @@ - - - Activo - - - Inactivo - - +
+
+ {{ schedule.enabled ? 'check_circle' : 'cancel' }} + {{ schedule.enabled ? 'Activo' : 'Inactivo' }} +
+
diff --git a/ogWebconsole/src/app/components/commands/commands-task/show-task-schedule/show-task-schedule.component.ts b/ogWebconsole/src/app/components/commands/commands-task/show-task-schedule/show-task-schedule.component.ts index aa84bd8..83c0486 100644 --- a/ogWebconsole/src/app/components/commands/commands-task/show-task-schedule/show-task-schedule.component.ts +++ b/ogWebconsole/src/app/components/commands/commands-task/show-task-schedule/show-task-schedule.component.ts @@ -27,11 +27,11 @@ export class ShowTaskScheduleComponent implements OnInit{ columns = [ { columnDef: 'id', header: 'ID', cell: (schedule: any) => schedule.id }, - { columnDef: 'recurrenceType', header: 'Recurrencia', cell: (schedule: any) => schedule.recurrenceType }, + { columnDef: 'recurrenceType', header: 'Tipo de Programación', cell: (schedule: any) => this.getRecurrenceTypeDisplay(schedule) }, { columnDef: 'executionTime', header: 'Hora de ejecución', cell: (schedule: any) => this.datePipe.transform(schedule.executionTime, 'HH:mm') }, { columnDef: 'nextExecution', header: 'Próxima ejecución', cell: (schedule: any) => this.calculateNextExecution(schedule) }, - { columnDef: 'daysOfWeek', header: 'Días de la semana', cell: (schedule: any) => schedule.recurrenceDetails?.daysOfWeek || [] }, - { columnDef: 'months', header: 'Meses', cell: (schedule: any) => schedule.recurrenceDetails?.months || [] }, + { columnDef: 'daysOfWeek', header: 'Días de la semana', cell: (schedule: any) => this.formatDaysOfWeek(schedule.recurrenceDetails?.daysOfWeek) }, + { columnDef: 'months', header: 'Meses', cell: (schedule: any) => this.formatMonths(schedule.recurrenceDetails?.months) }, { columnDef: 'enabled', header: 'Estado', cell: (schedule: any) => schedule.enabled } ]; @@ -121,23 +121,49 @@ export class ShowTaskScheduleComponent implements OnInit{ try { if (schedule.recurrenceType === 'none') { - if (schedule.executionDate) { - const execDate = new Date(schedule.executionDate); + if (schedule.executionDate && schedule.executionTime) { + const executionDate = new Date(schedule.executionDate); + const [hours, minutes] = this.parseExecutionTime(schedule.executionTime); + const fullExecutionDateTime = new Date( + executionDate.getFullYear(), + executionDate.getMonth(), + executionDate.getDate(), + hours, + minutes, + 0, + 0 + ); + const now = new Date(); - - if (execDate < now) { + if (fullExecutionDateTime < now) { return 'Ya ejecutada'; } - - return this.datePipe.transform(execDate, 'dd/MM/yyyy HH:mm') || 'Fecha inválida'; + + return this.datePipe.transform(fullExecutionDateTime, 'dd/MM/yyyy HH:mm') || 'Fecha inválida'; } - return 'Sin fecha'; + return 'Sin fecha/hora definida'; } + // Personalizada (u otros tipos con detalles): calcular siguiente ejecución real if (schedule.recurrenceDetails) { - const days = schedule.recurrenceDetails.daysOfWeek?.join(', ') || 'Todos'; - const months = schedule.recurrenceDetails.months?.join(', ') || 'Todos'; - return `${days} - ${months}`; + const startDate = schedule.recurrenceDetails.initDate ? new Date(schedule.recurrenceDetails.initDate) : null; + const endDate = schedule.recurrenceDetails.endDate ? new Date(schedule.recurrenceDetails.endDate) : null; + const days = Array.isArray(schedule.recurrenceDetails.daysOfWeek) ? schedule.recurrenceDetails.daysOfWeek : []; + const months = Array.isArray(schedule.recurrenceDetails.months) ? schedule.recurrenceDetails.months : []; + + if (!startDate || !endDate || days.length === 0 || months.length === 0) { + return 'Configuración incompleta'; + } + + const selectedDayIndices = new Set(days.map((d: string) => this.getDayIndexFromName(d))); + const selectedMonthIndices = new Set(months.map((m: string) => this.getMonthIndexFromName(m))); + const [hours, minutes] = this.parseExecutionTime(schedule.executionTime); + + const next = this.findNextExecutionDate(startDate, endDate, hours, minutes, selectedDayIndices, selectedMonthIndices); + if (next) { + return this.datePipe.transform(next, 'dd/MM/yyyy HH:mm') || 'Fecha inválida'; + } + return 'No hay próximas ejecuciones'; } return 'Configuración incompleta'; @@ -146,6 +172,76 @@ export class ShowTaskScheduleComponent implements OnInit{ } } + private parseExecutionTime(executionTime: any): [number, number] { + if (typeof executionTime === 'string') { + const match = executionTime.match(/^(\d{2}):(\d{2})/); + if (match) { + return [parseInt(match[1], 10), parseInt(match[2], 10)]; + } + const parsed = new Date(executionTime); + if (!isNaN(parsed.getTime())) { + return [parsed.getHours(), parsed.getMinutes()]; + } + return [0, 0]; + } + if (executionTime instanceof Date && !isNaN(executionTime.getTime())) { + return [executionTime.getHours(), executionTime.getMinutes()]; + } + return [0, 0]; + } + + private findNextExecutionDate(startDate: Date, endDate: Date, hours: number, minutes: number, selectedDays: Set, selectedMonths: Set): Date | null { + const now = new Date(); + + const startCandidate = new Date(Math.max(new Date(startDate).setHours(0, 0, 0, 0), new Date(now).setHours(0, 0, 0, 0))); + const endLimit = new Date(endDate); + endLimit.setHours(23, 59, 59, 999); + + const cursor = new Date(startCandidate); + while (cursor <= endLimit) { + if (selectedMonths.has(cursor.getMonth()) && selectedDays.has(cursor.getDay())) { + const candidateDateTime = new Date(cursor); + candidateDateTime.setHours(hours, minutes, 0, 0); + if (candidateDateTime >= now) { + return candidateDateTime; + } + } + cursor.setDate(cursor.getDate() + 1); + } + return null; + } + + private getDayIndexFromName(dayName: string): number { + const mapping: { [key: string]: number } = { + sunday: 0, + monday: 1, + tuesday: 2, + wednesday: 3, + thursday: 4, + friday: 5, + saturday: 6 + }; + return mapping[dayName?.toLowerCase?.()] ?? -1; + } + + private getMonthIndexFromName(monthName: string): number { + const mapping: { [key: string]: number } = { + january: 0, + february: 1, + march: 2, + april: 3, + may: 4, + june: 5, + july: 6, + august: 7, + september: 8, + october: 9, + november: 10, + december: 11 + }; + return mapping[monthName?.toLowerCase?.()] ?? -1; + } + onPageChange(event: any): void { this.page = event.pageIndex; this.itemsPerPage = event.pageSize; @@ -155,4 +251,105 @@ export class ShowTaskScheduleComponent implements OnInit{ onNoClick(): void { this.dialogRef.close(false); } + + getRecurrenceTypeDisplay(schedule: any): any { + if (schedule.recurrenceType === 'none') { + return { + type: 'none', + label: 'Ejecución única', + icon: 'event', + color: 'primary', + details: schedule.executionDate ? + `Fecha: ${this.datePipe.transform(schedule.executionDate, 'dd/MM/yyyy')}` : + 'Sin fecha definida' + }; + } else if (schedule.recurrenceType === 'daily') { + return { + type: 'daily', + label: 'Diaria', + icon: 'repeat', + color: 'accent', + details: 'Todos los días' + }; + } else if (schedule.recurrenceType === 'weekly') { + return { + type: 'weekly', + label: 'Semanal', + icon: 'view_week', + color: 'accent', + details: schedule.recurrenceDetails?.daysOfWeek?.length > 0 ? + `Días: ${schedule.recurrenceDetails.daysOfWeek.join(', ')}` : + 'Todos los días' + }; + } else if (schedule.recurrenceType === 'monthly') { + return { + type: 'monthly', + label: 'Mensual', + icon: 'calendar_month', + color: 'accent', + details: schedule.recurrenceDetails?.months?.length > 0 ? + `Meses: ${schedule.recurrenceDetails.months.join(', ')}` : + 'Todos los meses' + }; + } else if (schedule.recurrenceType === 'yearly') { + return { + type: 'yearly', + label: 'Anual', + icon: 'event_note', + color: 'accent', + details: 'Una vez al año' + }; + } else { + return { + type: 'custom', + label: 'Personalizada', + icon: 'settings', + color: 'warn', + details: 'Configuración especial' + }; + } + } + + formatDaysOfWeek(days: string[]): any { + if (!days || days.length === 0) return null; + + const dayMap: { [key: string]: string } = { + 'monday': 'Lun', + 'tuesday': 'Mar', + 'wednesday': 'Mié', + 'thursday': 'Jue', + 'friday': 'Vie', + 'saturday': 'Sáb', + 'sunday': 'Dom' + }; + + return { + days: days.map(day => dayMap[day.toLowerCase()] || day), + count: days.length + }; + } + + formatMonths(months: string[]): any { + if (!months || months.length === 0) return null; + + const monthMap: { [key: string]: string } = { + 'january': 'Ene', + 'february': 'Feb', + 'march': 'Mar', + 'april': 'Abr', + 'may': 'May', + 'june': 'Jun', + 'july': 'Jul', + 'august': 'Ago', + 'september': 'Sep', + 'october': 'Oct', + 'november': 'Nov', + 'december': 'Dic' + }; + + return { + months: months.map(month => monthMap[month.toLowerCase()] || month), + count: months.length + }; + } } diff --git a/ogWebconsole/src/app/components/commands/commands-task/show-task-script/show-task-script.component.ts b/ogWebconsole/src/app/components/commands/commands-task/show-task-script/show-task-script.component.ts index 8cf5458..9be4dc7 100644 --- a/ogWebconsole/src/app/components/commands/commands-task/show-task-script/show-task-script.component.ts +++ b/ogWebconsole/src/app/components/commands/commands-task/show-task-script/show-task-script.component.ts @@ -28,8 +28,8 @@ export class ShowTaskScriptComponent implements OnInit{ { columnDef: 'id', header: 'ID', cell: (client: any) => client.id }, { columnDef: 'order', header: 'Orden', cell: (client: any) => client.order }, { columnDef: 'content', header: 'Script', cell: (client: any) => client.content }, - { columnDef: 'type', header: 'Type', cell: (client: any) => client.type }, - { columnDef: 'parameters', header: 'Parameters', cell: (client: any) => client.parameters }, + { columnDef: 'type', header: 'Tipo', cell: (client: any) => client.type }, + { columnDef: 'parameters', header: 'Parámetros', cell: (client: any) => client.parameters }, ]; displayedColumns: string[] = ['id', 'order', 'type', 'parameters', 'content', 'actions']; diff --git a/ogWebconsole/src/app/components/groups/components/client-main-view/create-image/create-image.component.html b/ogWebconsole/src/app/components/groups/components/client-main-view/create-image/create-image.component.html index c19f0d8..e2e79a6 100644 --- a/ogWebconsole/src/app/components/groups/components/client-main-view/create-image/create-image.component.html +++ b/ogWebconsole/src/app/components/groups/components/client-main-view/create-image/create-image.component.html @@ -124,6 +124,13 @@
+ +
+ + Opción 'Forzar push' + +
+