diff --git a/ogWebconsole/src/app/components/commands/main-commands/execute-command/boot-so-partition/boot-so-partition.component.html b/ogWebconsole/src/app/components/commands/main-commands/execute-command/boot-so-partition/boot-so-partition.component.html index 15769b1..6ca9131 100644 --- a/ogWebconsole/src/app/components/commands/main-commands/execute-command/boot-so-partition/boot-so-partition.component.html +++ b/ogWebconsole/src/app/components/commands/main-commands/execute-command/boot-so-partition/boot-so-partition.component.html @@ -22,8 +22,8 @@
+ (click)="toggleClientSelection(client)" + [ngClass]="{'selected-client': client.selected}" > { - if (client.status === 'og-live') { - client.selected = true; - } - }); + this.data.clients.forEach((client: { selected: boolean; status: string }) => client.selected = true); - this.selectedClients = this.data.clients.filter( - (client: { status: string }) => client.status === 'og-live' - ); + this.selectedClients = this.data.clients.filter((client: { selected: boolean }) => client.selected); - this.selectedModelClient = this.data.clients.find( - (client: { status: string }) => client.status === 'og-live' - ) || null; + this.selectedModelClient = this.data.clients.find((client: { selected: boolean }) => client.selected) || null; if (this.selectedModelClient) { this.loadPartitions(this.selectedModelClient); diff --git a/ogWebconsole/src/app/components/groups/components/client-main-view/partition-assistant/partition-assistant.component.css b/ogWebconsole/src/app/components/groups/components/client-main-view/partition-assistant/partition-assistant.component.css index aa7ed80..baaa2b0 100644 --- a/ogWebconsole/src/app/components/groups/components/client-main-view/partition-assistant/partition-assistant.component.css +++ b/ogWebconsole/src/app/components/groups/components/client-main-view/partition-assistant/partition-assistant.component.css @@ -1,138 +1,420 @@ +/* ===== ESTILOS PRINCIPALES ===== */ .partition-assistant { - padding: 40px; + padding: 32px; margin: 20px; - background-color: #eaeff6; - border-radius: 12px; + background: white !important; + border-radius: 16px; + box-shadow: 0 4px 20px rgba(0, 0, 0, 0.08); + border: 1px solid #bbdefb; } +/* ===== HEADER ===== */ .header-container { display: flex; justify-content: space-between; align-items: center; - padding: 10px 10px; - border-bottom: 1px solid #ddd; + padding: 24px 32px; + background: white; + border-radius: 12px; + margin-bottom: 20px; +} + +.header-container-title { + flex-grow: 1; + text-align: left; +} + +.header-container-title h2 { + margin: 0 0 8px 0; + color: #333; + font-weight: 600; +} + +.header-container-title h4 { + margin: 0; + font-size: 16px; + opacity: 0.9; + font-weight: 400; +} + +/* ===== DESTINATION BADGE ===== */ +.destination-info { + margin-top: 12px; +} + +.destination-badge { + display: inline-flex; + align-items: center; + background: #e3f2fd; + color: #1565c0; + padding: 12px 16px; + border-radius: 12px; + border: 1px solid #bbdefb; + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05); + transition: all 0.2s ease; +} + +.destination-icon { + font-size: 20px; + width: 20px; + height: 20px; + margin-right: 12px; + color: #1976d2; +} + +.destination-content { + display: flex; + flex-direction: column; + gap: 2px; +} + +.destination-label { + font-size: 11px; + font-weight: 500; + text-transform: uppercase; + letter-spacing: 0.5px; + color: #1976d2; + line-height: 1; +} + +.destination-value { + font-size: 14px; + font-weight: 600; + line-height: 1.2; + max-width: 200px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + color: #0d47a1; +} + +/* ===== BOTONES ===== */ +.button-row { + display: flex; + gap: 12px; + align-items: center; +} + +.action-button { + color: white; + border: none; + padding: 12px 24px; + border-radius: 8px; + font-weight: 500; + transition: all 0.3s ease; + cursor: pointer; + margin-top: 10px; + margin-bottom: 10px; + margin-right: 16px; +} + +.action-button:hover:not(:disabled) { + transform: translateY(-1px); + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2); +} + +.action-button:disabled { + opacity: 0.5; + cursor: not-allowed; +} + +.row-button { + display: flex; + align-items: center; + gap: 30px; +} + +/* ===== SELECTOR DE DISCO ===== */ +.disk-selector-card { + padding: 32px; + margin: 20px; + background: white !important; + border-radius: 16px; + box-shadow: 0 4px 20px rgba(0, 0, 0, 0.08); + border: 1px solid #bbdefb; + overflow: hidden; +} + +.card-header { + display: flex; + align-items: center; + padding: 24px 32px; + background: transparent; + color: #1976d2; + border-bottom: 1.5px solid #1976d2; +} + +.card-icon { + font-size: 28px; + width: 28px; + height: 28px; + margin-right: 16px; + color: #1976d2; +} + +.card-title h3 { + margin: 0 0 4px 0; + font-size: 20px; + font-weight: 600; + color: #1976d2; +} + +.card-title p { + margin: 0; + font-size: 14px; + opacity: 0.9; + color: #1976d2; +} + +.card-content { + padding: 24px 32px; +} + +.disk-select-field { + width: 100%; + margin-bottom: 20px; +} + +/* Opciones del select */ +::ng-deep .disk-option { + display: flex; + justify-content: space-between; + align-items: center; + width: 100%; + padding: 8px 0; +} + +.disk-info { + display: flex; + flex-direction: column; + gap: 4px; +} + +.disk-name { + font-weight: 600; + font-size: 16px; + color: #2c3e50; } .disk-size { - font-size: 1rem; - font-weight: 600; - color: #555; + font-size: 14px; + color: #6c757d; + font-weight: 500; } -.partition-table { - width: 100%; - border-collapse: collapse; - overflow: hidden; - margin-bottom: 20px; -} - -.partition-table th { - color: #333; - padding: 12px; - font-weight: 600; -} - -.partition-table td { - padding: 10px; - text-align: center; -} - -.partition-table select, -.partition-table input[type="number"], -.partition-table input[type="checkbox"] { - padding: 5px; - width: 100%; -} - -.actions { +.disk-details { display: flex; - justify-content: flex-end; - padding-top: 10px; + flex-direction: column; + align-items: flex-end; + gap: 4px; } -button.mat-button { - background-color: #007bff; - color: white; +.partitions-count { + font-size: 12px; + color: #667eea; + font-weight: 500; + background: rgba(102, 126, 234, 0.1); + padding: 2px 8px; + border-radius: 12px; } -button.mat-button:hover { - background-color: #0056b3; +.usage-percent { + font-size: 12px; + color: #6c757d; + font-weight: 500; } -button.mat-flat-button { - background-color: #28a745; - color: white; -} - -button.mat-flat-button:hover { - background-color: #218838; -} - -button.remove-btn { - background-color: #dc3545; - color: white; - border-radius: 4px; - padding: 7px 10px; -} - -button.remove-btn:hover { - background-color: #c82333; -} - -.error-message { - color: #dc3545; - font-size: 0.9rem; - padding: 10px; - background-color: #f8d7da; - border-radius: 4px; - margin-top: 10px; -} - -.partition-assistant .row { +/* Información de selección */ +.selection-info { display: flex; - flex-wrap: wrap; - margin-bottom: 20px; -} - -.form-container { - flex: 0 0 65%; - max-width: 65%; - padding-right: 20px; - box-sizing: border-box; -} - -.chart-container { - flex: 0 0 35%; - max-width: 35%; -} - -.partition-bar { - display: flex; - height: 40px; - margin: 20px 0; -} - -.partition-segment { - display: flex; - justify-content: center; align-items: center; - text-align: center; - font-size: 10px; - color: white; - height: 100%; + padding: 16px 20px; + background: #e8f5e8; + border: 1px solid #c8e6c9; + border-radius: 12px; + margin-top: 16px; } -.chart-container ngx-charts-pie-chart { - display: block; - align-content: center; - justify-self: center; +.info-icon { + font-size: 20px; + width: 20px; + height: 20px; + margin-right: 12px; + color: #388e3c; } -.disk-select { +.info-text { + display: flex; + flex-direction: column; + gap: 2px; +} + +.info-title { + font-size: 14px; + font-weight: 600; + color: #2e7d32; +} + +.info-subtitle { + font-size: 12px; + color: #388e3c; +} + +/* Mensaje cuando no hay discos */ +.no-disks-message { + display: flex; + align-items: center; + padding: 16px 20px; + background: #fff3e0; + border: 1px solid #ffcc02; + border-radius: 12px; + margin-top: 16px; +} + +.warning-icon { + font-size: 20px; + width: 20px; + height: 20px; + margin-right: 12px; + color: #f57c00; +} + +.message-text { + display: flex; + flex-direction: column; + gap: 2px; +} + +.message-title { + font-size: 14px; + font-weight: 600; + color: #e65100; +} + +.message-subtitle { + font-size: 12px; + color: #f57c00; +} + +/* ===== INFO BADGES ===== */ +.info-badge { + display: inline-flex; + align-items: center; + background: #e8f5e8; + color: #2e7d32; + padding: 12px 16px; + border-radius: 12px; + border: 1px solid #c8e6c9; + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05); + transition: all 0.2s ease; + margin: 0 8px; +} + +.info-badge:hover { + transform: translateY(-1px); + box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); +} + +.info-content { + display: flex; + flex-direction: column; + gap: 2px; +} + +.info-label { + font-size: 11px; + font-weight: 500; + text-transform: uppercase; + letter-spacing: 0.5px; + color: #388e3c; + line-height: 1; +} + +.info-value { + font-size: 14px; + font-weight: 600; + line-height: 1.2; + max-width: 150px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + color: #1b5e20; +} + +/* Badge específico para firmware */ +.info-badge:first-of-type { + background: #e3f2fd; + border-color: #bbdefb; +} + +.info-badge:first-of-type .info-icon { + color: #1976d2; +} + +.info-badge:first-of-type .info-label { + color: #1976d2; +} + +.info-badge:first-of-type .info-value { + color: #0d47a1; +} + +/* Badge específico para tabla de particiones */ +.info-badge:last-of-type { + background: #fff3e0; + border-color: #ffcc02; +} + +.info-badge:last-of-type .info-icon { + color: #f57c00; +} + +.info-badge:last-of-type .info-label { + color: #f57c00; +} + +.info-badge:last-of-type .info-value { + color: #e65100; +} + +/* ===== SELECTOR DE CLIENTES ===== */ +.select-container { + margin-top: 20px; + align-items: center; + width: 100%; + box-sizing: border-box; padding: 20px; - margin: 10px auto; } +/* Expansion panel */ +::ng-deep .mat-expansion-panel { + box-shadow: 0 4px 20px rgba(0, 0, 0, 0.08) !important; + border-radius: 12px !important; + margin-bottom: 20px; + background: #f7fbff !important; + border: 1px solid #bbdefb !important; +} + +::ng-deep .mat-expansion-panel-header { + padding: 20px 24px !important; + border-radius: 12px !important; +} + +::ng-deep .mat-expansion-panel-header-title { + font-weight: 600 !important; + color: #2c3e50 !important; +} + +::ng-deep .mat-expansion-panel-header-description { + color: #6c757d !important; +} + +.mat-expansion-panel-header-description { + justify-content: space-between; + align-items: center; +} + +/* Grid de clientes */ .clients-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(140px, 1fr)); @@ -143,6 +425,40 @@ button.remove-btn:hover { position: relative; } +.client-card { + background: #ffffff; + border-radius: 6px; + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); + overflow: hidden; + position: relative; + padding: 8px; + text-align: center; + cursor: pointer; + transition: background-color 0.3s, transform 0.2s; +} + +.client-card:hover { + background-color: #f0f0f0; + transform: scale(1.02); +} + +.selected-client { + background: linear-gradient(135deg, #8fa1f0 0%, #9b7bc8 100%); + color: white; + border-color: #667eea; +} + +.selected-client .client-name, +.selected-client .client-ip { + color: white; +} + +.client-image { + width: 40px; + height: 40px; + margin: 0 auto 8px; +} + .client-details { margin-top: 4px; } @@ -165,38 +481,7 @@ button.remove-btn:hover { color: #666; } -.header-container-title { - flex-grow: 1; - text-align: left; - padding-left: 1em; -} - -.select-container { - margin-top: 20px; - align-items: center; - width: 100%; - box-sizing: border-box; - padding-left: 1em; - padding-right: 1em; -} - -.client-card { - background: #ffffff; - border-radius: 6px; - box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); - overflow: hidden; - position: relative; - padding: 8px; - text-align: center; - cursor: pointer; - transition: background-color 0.3s, transform 0.2s; - - &:hover { - background-color: #f0f0f0; - transform: scale(1.02); - } -} - +/* Tooltip personalizado */ ::ng-deep .custom-tooltip { white-space: pre-line !important; max-width: 200px; @@ -206,67 +491,267 @@ button.remove-btn:hover { border-radius: 4px; } -.selected-client { - background-color: #a0c2e5 !important; - color: white !important; -} - -.button-row { +/* ===== LAYOUT PRINCIPAL ===== */ +.row { display: flex; - padding-right: 1em; + flex-wrap: wrap; + margin-bottom: 20px; } -.disabled-client { - pointer-events: none; - opacity: 0.5; -} - -.row-button { - display: flex; - align-items: center; - gap: 30px; -} - - -.action-button { - margin-top: 10px; - margin-bottom: 10px; -} - -.mat-expansion-panel-header-description { - justify-content: space-between; - align-items: center; +.form-container { + flex: 0 0 65%; + max-width: 65%; + padding-right: 20px; + box-sizing: border-box; + background: white; + border-radius: 16px; + border: none; } +/* ===== INFORMACIÓN DEL DISCO ===== */ .disk-space-info-container { - display: flex; - justify-self: start; - margin-top: 10px; - gap: 10px; + margin: 24px 0; + background: none; + border-radius: 0; + border: none; + padding: 0; } -.disk-space-info { - padding: 16px; - background-color: #f9f9f9; - border-radius: 12px; - box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1); +.disk-space-card { display: flex; + gap: 24px; + margin-bottom: 20px; + flex-wrap: wrap; +} + +.space-info-item { + display: flex; + align-items: center; gap: 12px; - margin: 16px auto; + padding: 16px 20px; + background: #f8f9fa; + border-radius: 12px; + border: 1px solid #e9ecef; + min-width: 180px; } -.chip-free { - background-color: #d0f0c0; /* verde claro */ - color: #2e7d32; +.space-icon { + font-size: 24px; + width: 24px; + height: 24px; +} + +.used-icon { + color: #dc3545; +} + +.free-icon { + color: #28a745; +} + +.total-icon { + color: #007bff; +} + +.space-details { + display: flex; + flex-direction: column; + gap: 4px; +} + +.space-label { + font-size: 12px; font-weight: 500; + color: #6c757d; + text-transform: uppercase; + letter-spacing: 0.5px; } -.chip-full { - background-color: #ffcccb; /* rojo claro */ - color: #c62828; - font-weight: 500; +.space-value { + font-size: 16px; + font-weight: 600; + color: #212529; } +/* Barra de uso del disco */ +.disk-usage-bar { + margin-top: 16px; +} + +.usage-bar-container { + width: 100%; + height: 12px; + background: #e9ecef; + border-radius: 6px; + overflow: hidden; + margin-bottom: 8px; +} + +.usage-bar-fill { + height: 100%; + background: linear-gradient(90deg, #28a745, #20c997); + border-radius: 6px; + transition: width 0.3s ease; +} + +.usage-percentage { + font-size: 14px; + font-weight: 600; + color: #666; + margin-top: 8px; + text-align: center; +} + +/* ===== TABLA DE PARTICIONES ===== */ +.partition-table { + width: 100%; + border-collapse: collapse; + table-layout: fixed; +} + +.partition-table th { + background: white !important; + color: #495057; + padding: 16px 12px; + font-weight: 600; + text-align: left; + border-bottom: 2px solid #e9ecef; + font-size: 14px; +} + +.partition-table th:nth-child(1), .partition-table td:nth-child(1) { width: 5%; } +.partition-table th:nth-child(2), .partition-table td:nth-child(2) { width: 20%; } +.partition-table th:nth-child(3), .partition-table td:nth-child(3) { width: 20%; } +.partition-table th:nth-child(4), .partition-table td:nth-child(4) { width: 15%; } +.partition-table th:nth-child(5), .partition-table td:nth-child(5) { width: 15%; } +.partition-table th:nth-child(6), .partition-table td:nth-child(6) { width: 5%; } +.partition-table th:nth-child(7), .partition-table td:nth-child(7) { width: 5%; } + +.partition-table td { + padding: 6px 8px; + border-bottom: 1px solid #f1f3f4; + vertical-align: middle; +} + +.partition-table select, +.partition-table input[type="number"], +.partition-table input[type="checkbox"] { + padding: 5px; + width: 100%; +} + +.remove-btn { + background-color: #dc3545; + color: white !important; + border-radius: 4px !important; + border: none !important; + cursor: pointer !important; + border-radius: 4px !important; + padding: 7px 10px !important; +} + +.remove-btn:hover { + background-color: #c82333; +} + +/* ===== GRÁFICA ===== */ +.chart-container { + flex: 0 0 35%; + max-width: 35%; + align-self: center; + justify-self: center; +} + +.chart-header { + text-align: center; + margin-bottom: 20px; +} + +.chart-header h3 { + margin: 0 0 8px 0; + color: #2c3e50; + font-weight: 600; + font-size: 18px; +} + +.chart-header p { + margin: 0; + color: #6c757d; + font-size: 14px; +} + +.chart-container ngx-charts-pie-chart { + width: 100% !important; + min-width: 0; +} + +/* Forzar la leyenda debajo del gráfico */ +::ng-deep .chart-container ngx-charts-pie-chart .chart-legend { + position: relative !important; + top: auto !important; + left: auto !important; + right: auto !important; + bottom: auto !important; + display: block !important; + margin-top: 20px !important; +} + +::ng-deep .chart-container ngx-charts-pie-chart .chart-legend .legend-labels { + display: flex !important; + flex-direction: column !important; + align-items: center !important; + justify-content: center !important; +} + +::ng-deep .chart-container ngx-charts-pie-chart .chart-legend .legend-label { + display: flex !important; + align-items: center !important; + margin: 5px 0 !important; +} + +/* ===== ESTADOS DE ADVERTENCIA ===== */ +/* Advertencia (90% a 99% usado) */ +.warning { + color: #ff9800 !important; +} + +.usage-bar-fill.warning { + background: linear-gradient(90deg, #ff9800, #ffb74d) !important; +} + +.free-icon.warning { + color: #ff9800 !important; +} + +/* Peligro (100% o más usado) */ +.danger { + color: #f44336 !important; + font-weight: bold !important; +} + +.usage-bar-fill.danger { + background: linear-gradient(90deg, #f44336, #ef5350) !important; + animation: pulse 2s infinite; +} + +.free-icon.danger { + color: #f44336 !important; + animation: pulse 2s infinite; +} + +@keyframes pulse { + 0% { + opacity: 1; + } + 50% { + opacity: 0.7; + } + 100% { + opacity: 1; + } +} + +/* ===== INSTRUCCIONES ===== */ .instructions-box { margin-top: 15px; background-color: #f5f5f5; @@ -275,15 +760,88 @@ button.remove-btn:hover { border-radius: 6px; } -.instructions-textarea textarea { +.instructions-card { + background: #f5f5f5; + box-shadow: none !important; + margin-top: 20px; + border-radius: 16px; + border: none; +} + +.instructions-card pre { font-family: monospace; white-space: pre; + background: #f8f9fa; + padding: 16px; + border-radius: 8px; + border: 1px solid #e9ecef; + overflow-x: auto; + font-size: 14px; + line-height: 1.5; } -.instructions-card { - background-color: #f5f5f5; - box-shadow: none !important; - margin-top: 15px; +/* ===== RESPONSIVE ===== */ +@media (max-width: 768px) { + .header-container { + flex-direction: column; + gap: 16px; + text-align: center; + } + + .button-row { + flex-direction: column; + gap: 8px; + } + + .destination-badge { + flex-direction: column; + text-align: center; + } + + .destination-icon { + margin-right: 0; + margin-bottom: 8px; + } + + .destination-value { + max-width: none; + } + + .destination-label { + text-align: center; + } + + .form-section { + padding: 20px; + } + + .disk-space-card { + flex-direction: column; + gap: 12px; + } + + .space-info-item { + min-width: auto; + } + + .row { + flex-direction: column; + } + + .chart-container { + flex: none; + width: 100%; + margin-top: 20px; + } + + .partition-table { + font-size: 12px; + } + + .partition-table th, + .partition-table td { + padding: 8px 4px; + } } diff --git a/ogWebconsole/src/app/components/groups/components/client-main-view/partition-assistant/partition-assistant.component.html b/ogWebconsole/src/app/components/groups/components/client-main-view/partition-assistant/partition-assistant.component.html index 76c4a11..4624d67 100644 --- a/ogWebconsole/src/app/components/groups/components/client-main-view/partition-assistant/partition-assistant.component.html +++ b/ogWebconsole/src/app/components/groups/components/client-main-view/partition-assistant/partition-assistant.component.html @@ -5,9 +5,15 @@

{{ 'partitionTitle' | translate }}

-

- {{ runScriptTitle }} -

+
+
+ cloud_download +
+ Destino + {{ runScriptTitle }} +
+
+
@@ -19,9 +25,9 @@
-
-
@@ -46,7 +52,7 @@
@@ -77,18 +83,52 @@
- -
- - Seleccionar disco - - - Disco {{ disk.diskNumber }} ({{ (disk.totalDiskSize / 1024).toFixed(2) }} GB) - - - +
+
+ storage +
+

Selección de Disco

+

Elige el disco donde se realizarán las operaciones de particionado

+
+
+ +
+ + Seleccionar disco + + +
+
+ Disco {{ disk.diskNumber }} + {{ (disk.totalDiskSize / 1024).toFixed(2) }} GB +
+
+ {{ (disk.percentage || 0).toFixed(1) }}% usado +
+
+
+
+ Selecciona el disco que deseas particionar +
+ +
+ info +
+ Disco seleccionado: {{ selectedDisk.diskNumber }} + Tamaño total: {{ (selectedDisk.totalDiskSize / 1024).toFixed(2) }} GB +
+
+ +
+ warning +
+ No hay discos disponibles + Asegúrate de que el cliente modelo tenga discos configurados +
+
+
@@ -108,33 +148,66 @@
- - Firmware: {{ selectedModelClient.firmwareType }} - - - Tabla de particiones: {{ partitionCode }} - + +
+ memory +
+ Firmware + {{ selectedModelClient.firmwareType }} +
+
+ +
+ storage +
+ Tabla de particiones + {{ partitionCode }} +
+
-
-
- Espacio usado: {{ selectedDisk.used | number:'1.2-2' }} MB -
- -
- Espacio libre: {{ (selectedDisk.totalDiskSize - selectedDisk.used) | number:'1.2-2' }} MB -
- -
- Espacio total: {{ selectedDisk.totalDiskSize | number:'1.2-2' }} MB -
-
-
- +
+
+
+ storage +
+ Espacio usado + {{ selectedDisk.used | number:'1.2-2' }} MB +
+
+ +
+ cloud_done +
+ Espacio libre + {{ (selectedDisk.totalDiskSize - selectedDisk.used) | number:'1.2-2' }} MB +
+
+ +
+ dns +
+ Espacio total + {{ selectedDisk.totalDiskSize | number:'1.2-2' }} MB +
+
+
+ +
+
+
+
+ {{ ((selectedDisk.used / selectedDisk.totalDiskSize) * 100) | number:'1.1-1' }}% usado +
+
+ +
@@ -182,11 +255,29 @@
Partición
- -
- + +
+
+

Distribución de Particiones

+
+
+ + + diff --git a/ogWebconsole/src/app/components/groups/components/client-main-view/partition-assistant/partition-assistant.component.ts b/ogWebconsole/src/app/components/groups/components/client-main-view/partition-assistant/partition-assistant.component.ts index cb77c97..859f0b3 100644 --- a/ogWebconsole/src/app/components/groups/components/client-main-view/partition-assistant/partition-assistant.component.ts +++ b/ogWebconsole/src/app/components/groups/components/client-main-view/partition-assistant/partition-assistant.component.ts @@ -7,6 +7,7 @@ import { FILESYSTEM_TYPES } from '../../../../../shared/constants/filesystem-typ import { ConfigService } from '@services/config.service'; import {CreateTaskComponent} from "../../../../commands/commands-task/create-task/create-task.component"; import {MatDialog} from "@angular/material/dialog"; +import {QueueConfirmationModalComponent} from "../../../../../shared/queue-confirmation-modal/queue-confirmation-modal.component"; interface Partition { uuid?: string; @@ -46,7 +47,7 @@ export class PartitionAssistantComponent implements OnInit{ runScriptContext: any = null; showInstructions = false; - view: [number, number] = [400, 300]; + view: [number, number] = [300, 200]; showLegend = true; showLabels = true; allSelected = true; @@ -74,19 +75,11 @@ export class PartitionAssistantComponent implements OnInit{ } }); this.clientId = this.clientData?.length ? this.clientData[0]['@id'] : null; - this.clientData.forEach((client: { selected: boolean; status: string}) => { - if (client.status === 'og-live') { - client.selected = true; - } - }); + this.clientData.forEach((client: { selected: boolean; status: string}) => { client.selected = true; }); - this.selectedClients = this.clientData.filter( - (client: { status: string }) => client.status === 'og-live' - ); + this.selectedClients = this.clientData.filter((client: { selected: boolean; status: string}) => client.selected); - this.selectedModelClient = this.clientData.find( - (client: { status: string }) => client.status === 'og-live' - ) || null; + this.selectedModelClient = this.clientData.find((client: { selected: boolean; status: string}) => client.selected) || null; if (this.selectedModelClient) { this.loadPartitions(this.selectedModelClient); @@ -136,15 +129,18 @@ export class PartitionAssistantComponent implements OnInit{ toggleSelectAll() { this.allSelected = !this.allSelected; - this.clientData.forEach((client: { selected: boolean; status: string }) => { - if (client.status === "og-live") { - client.selected = this.allSelected; - } - }); + this.clientData.forEach((client: { selected: boolean; status: string }) => { client.selected = this.allSelected; }); } initializeDisks() { this.disks = []; + + // Verificar que hay datos válidos + if (!this.data || !this.data.partitions || !Array.isArray(this.data.partitions)) { + console.warn('No hay datos de particiones válidos'); + return; + } + const partitionsFromData = this.data.partitions; this.originalPartitions = JSON.parse(JSON.stringify(partitionsFromData)); @@ -320,56 +316,63 @@ export class PartitionAssistantComponent implements OnInit{ return; } - this.loading = true; - const totalPartitionSize = this.selectedDisk.partitions .filter((partition: any) => !partition.removed) .reduce((sum: any, partition: any) => sum + partition.size, 0); if (totalPartitionSize > this.selectedDisk.totalDiskSize) { this.toastService.error('El tamaño total de las particiones en el disco seleccionado excede el tamaño total del disco.'); - this.loading = false; return; } const modifiedPartitions = this.selectedDisk.partitions.filter((partition: { removed: any; format: any; }) => !partition.removed || partition.format); if (modifiedPartitions.length === 0) { - this.loading = false; this.toastService.info('No hay cambios para guardar en el disco seleccionado.'); return; } - const newPartitions = modifiedPartitions.map((partition: { partitionNumber: any; memoryUsage: any; size: any; partitionCode: any; filesystem: any; uuid: any; removed: any; format: any; }) => ({ - diskNumber: this.selectedDisk.diskNumber, - partitionNumber: partition.partitionNumber, - memoryUsage: partition.memoryUsage, - size: partition.size, - partitionCode: partition.partitionCode, - filesystem: partition.filesystem, - uuid: partition.uuid, - removed: partition.removed || false, - format: partition.format || false, - })); + const dialogRef = this.dialog.open(QueueConfirmationModalComponent, { + width: '400px', + disableClose: true, + hasBackdrop: true, + backdropClass: 'non-clickable-backdrop' + }); - if (newPartitions.length > 0) { - const bulkPayload = { - partitions: newPartitions, - clients: this.selectedClients.map((client: any) => client.uuid), - }; + dialogRef.afterClosed().subscribe(result => { + if (result !== undefined) { + this.loading = true; + const newPartitions = modifiedPartitions.map((partition: { partitionNumber: any; memoryUsage: any; size: any; partitionCode: any; filesystem: any; uuid: any; removed: any; format: any; }) => ({ + diskNumber: this.selectedDisk.diskNumber, + partitionNumber: partition.partitionNumber, + memoryUsage: partition.memoryUsage, + size: partition.size, + partitionCode: partition.partitionCode, + filesystem: partition.filesystem, + uuid: partition.uuid, + removed: partition.removed || false, + format: partition.format || false, + })); - this.http.post(this.apiUrl, bulkPayload).subscribe( - (response) => { - this.toastService.success('Particiones creadas exitosamente para el disco seleccionado.'); - this.loading = false; - this.router.navigate(['/commands-logs']); - }, - (error) => { - this.loading = false; - this.toastService.error('Error al crear las particiones.'); - } - ); - } + const bulkPayload = { + partitions: newPartitions, + clients: this.selectedClients.map((client: any) => client.uuid), + queue: result + }; + + this.http.post(this.apiUrl, bulkPayload).subscribe( + (response) => { + this.toastService.success('Particiones creadas exitosamente para el disco seleccionado.'); + this.loading = false; + this.router.navigate(['/commands-logs']); + }, + (error) => { + this.loading = false; + this.toastService.error('Error al crear las particiones.'); + } + ); + } + }); } @@ -409,11 +412,20 @@ export class PartitionAssistantComponent implements OnInit{ generateChartData(partitions: Partition[]): any[] { - return partitions.map((partition) => ({ - name: `Partición ${partition.partitionNumber}`, - value: partition.percentage, - color: partition.color - })); + const colors = [ + '#FF6B6B', '#4ECDC4', '#45B7D1', '#96CEB4', '#FFEAA7', + '#DDA0DD', '#98D8C8', '#F7DC6F', '#BB8FCE', '#85C1E9', + '#F8C471', '#82E0AA', '#F1948A', '#85C1E9', '#D7BDE2' + ]; + + return partitions + .filter(partition => !partition.removed) + .map((partition, index) => ({ + name: `Partición ${partition.partitionNumber}`, + value: partition.size, + color: colors[index % colors.length], + partition: partition + })); } updateDiskChart(disk: any) { @@ -478,38 +490,50 @@ export class PartitionAssistantComponent implements OnInit{ } generateInstructions(): void { - if (!this.selectedDisk || !this.selectedDisk.partitions) { - this.generatedInstructions = 'No hay particiones configuradas para generar instrucciones.'; - return; + this.showInstructions = true; + this.generatedInstructions = `og-partition --disk ${this.selectedDiskNumber} --partitions ${this.selectedDisk.partitions.map((p: Partition) => `${p.partitionNumber}:${p.size}:${p.partitionCode}:${p.filesystem}:${p.format}`).join(',')}`; + } + + onDiskSelected(diskNumber: number) { + this.selectedDiskNumber = diskNumber; + this.scrollToPartitionTable(); + } + + onDiskSelectionChange() { + if (this.selectedDiskNumber) { + this.scrollToPartitionTable(); } + } - const diskNumber = this.selectedDisk.diskNumber; - const partitionTable = this.partitionCode || 'MSDOS'; + scrollToPartitionTable() { + // Pequeño delay para asegurar que el contenido se haya renderizado + setTimeout(() => { + const diskInfo = document.getElementById('disk-info'); + + if (diskInfo) { + diskInfo.scrollIntoView({ + behavior: 'smooth', + block: 'start', + inline: 'nearest' + }); + } + }, 100); + } - let instructions = `ogCreatePartitionTable ${diskNumber} ${partitionTable}\n`; - instructions += `ogEcho log session "[0] $MSG_HELP_ogCreatePartitions"\n`; - instructions += `ogEcho session "[10] $MSG_HELP_ogUnmountAll ${diskNumber}"\n`; - instructions += `ogUnmountAll ${diskNumber} 2>/dev/null\n`; - instructions += `ogUnmountCache\n`; - instructions += `ogEcho session "[30] $MSG_HELP_ogUpdatePartitionTable ${diskNumber}"\n`; - instructions += `ogDeletePartitionTable ${diskNumber}\n`; - instructions += `ogUpdatePartitionTable ${diskNumber}\n`; - - this.selectedDisk.partitions.forEach((partition: { removed: any; partitionNumber: any; partitionCode: any; filesystem: any; size: any; format: any; }, index: any) => { - if (partition.removed) return; - - const partNumber = partition.partitionNumber; - const partType = partition.partitionCode; - const fs = partition.filesystem; - const size = partition.size; - const shouldFormat = partition.format ? 'yes' : 'no'; - - instructions += `ogCreatePartition ${diskNumber} ${partNumber} ${partType} ${fs} ${size}MB ${shouldFormat}\n`; - }); - - instructions += `ogExecAndLog command session ogListPartitions ${diskNumber}\n`; - - this.generatedInstructions = instructions; - this.showInstructions = true + scrollToExecuteButton() { + console.log('scrollToExecuteButton llamado'); + + const executeButton = document.getElementById('execute-button'); + console.log('Botón ejecutar encontrado:', executeButton); + + if (executeButton) { + executeButton.scrollIntoView({ + behavior: 'smooth', + block: 'center' + }); + console.log('Scroll hacia botón ejecutar completado'); + } else { + console.error('No se encontró el botón execute-button'); + } } } diff --git a/ogWebconsole/src/app/components/groups/components/client-main-view/run-script-assistant/run-script-assistant.component.css b/ogWebconsole/src/app/components/groups/components/client-main-view/run-script-assistant/run-script-assistant.component.css index 7c31624..363d89a 100644 --- a/ogWebconsole/src/app/components/groups/components/client-main-view/run-script-assistant/run-script-assistant.component.css +++ b/ogWebconsole/src/app/components/groups/components/client-main-view/run-script-assistant/run-script-assistant.component.css @@ -1,4 +1,3 @@ - .divider { margin: 20px 0; } @@ -102,10 +101,287 @@ table { display: flex; justify-content: space-between; align-items: center; - padding: 10px 10px; - border-bottom: 1px solid #ddd; + padding: 24px 32px; + background: white; + border-radius: 12px; + margin-bottom: 20px; } +.header-container-title { + flex-grow: 1; + text-align: left; +} + +.header-container-title h2 { + margin: 0 0 8px 0; + color: #333; + font-weight: 600; +} + +.header-container-title h4 { + margin: 0; + font-size: 16px; + opacity: 0.9; + font-weight: 400; +} + +.button-row { + display: flex; + padding-right: 1em; + gap: 12px; + align-items: center; +} + +.action-button { + margin-top: 10px; + margin-bottom: 10px; + color: white; + border: none; + padding: 12px 24px; + border-radius: 8px; + font-weight: 500; + transition: all 0.3s ease; + cursor: pointer; +} + +.action-button:hover:not(:disabled) { + transform: translateY(-1px); + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2); +} + +.action-button:disabled { + opacity: 0.5; + cursor: not-allowed; +} + +.select-container { + background: white !important; + margin-top: 20px; + align-items: center; + padding: 20px; + box-sizing: border-box; +} + +.form-section { + background: white !important; + border-radius: 16px; + padding: 20px !important; + margin-bottom: 24px; + box-shadow: 0 4px 20px rgba(0, 0, 0, 0.08); + border: 1px solid #bbdefb; +} + +.form-section-title { + display: flex; + align-items: center; + gap: 12px; + margin-bottom: 24px; + font-size: 20px; + font-weight: 600; + color: #2c3e50; + padding-bottom: 16px; + border-bottom: 2px solid #f8f9fa; +} + +.form-section-title mat-icon { + color: #667eea; + font-size: 24px; + width: 24px; + height: 24px; +} + +/* Badges y chips */ +.destination-badge { + display: inline-flex; + align-items: center; + background: #e3f2fd; + color: #1565c0; + padding: 12px 16px; + border-radius: 12px; + border: 1px solid #bbdefb; + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05); + transition: all 0.2s ease; +} + +.destination-icon { + font-size: 20px; + width: 20px; + height: 20px; + margin-right: 12px; + color: #1976d2; +} + +.destination-content { + display: flex; + flex-direction: column; + gap: 2px; +} + +.destination-label { + font-size: 11px; + font-weight: 500; + text-transform: uppercase; + letter-spacing: 0.5px; + color: #1976d2; + line-height: 1; +} + +.destination-value { + font-size: 14px; + font-weight: 600; + line-height: 1.2; + max-width: 200px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + color: #0d47a1; +} + +.info-badge { + display: inline-flex; + align-items: center; + background: #e8f5e8; + color: #2e7d32; + padding: 12px 16px; + border-radius: 12px; + border: 1px solid #c8e6c9; + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05); + transition: all 0.2s ease; + margin: 0 8px; +} + +.info-badge:hover { + transform: translateY(-1px); + box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); +} + +.info-content { + display: flex; + flex-direction: column; + gap: 2px; +} + +.info-label { + font-size: 11px; + font-weight: 500; + text-transform: uppercase; + letter-spacing: 0.5px; + color: #388e3c; + line-height: 1; +} + +.info-value { + font-size: 14px; + font-weight: 600; + line-height: 1.2; + max-width: 150px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + color: #1b5e20; +} + +/* Clientes y tarjetas */ +.clients-grid { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(140px, 1fr)); + gap: 12px; + margin-top: 20px; +} + +.client-item { + position: relative; +} + +.client-card { + background: white; + border-radius: 8px; + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08); + overflow: hidden; + position: relative; + padding: 12px; + text-align: center; + cursor: pointer; + transition: all 0.3s ease; + border: 2px solid transparent; +} + +.client-card:hover { + transform: translateY(-2px); + box-shadow: 0 4px 16px rgba(0, 0, 0, 0.15); + border-color: #667eea; +} + +.client-image { + width: 32px; + height: 32px; + margin-bottom: 8px; +} + +.client-details { + margin-bottom: 12px; +} + +.client-name { + font-size: 12px; + font-weight: 600; + color: #2c3e50; + margin-bottom: 2px; + display: block; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +.client-ip { + font-size: 10px; + color: #6c757d; + display: block; + margin-bottom: 1px; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +.selected-client { + background: linear-gradient(135deg, #8fa1f0 0%, #9b7bc8 100%); + color: white; + border-color: #667eea; +} + +.selected-client .client-name, +.selected-client .client-ip { + color: white; +} + +::ng-deep .mat-expansion-panel { + box-shadow: 0 4px 20px rgba(0, 0, 0, 0.08) !important; + border-radius: 12px !important; + margin-bottom: 20px; + background: #f7fbff !important; + border: 1px solid #bbdefb !important; +} + +::ng-deep .mat-expansion-panel-header { + padding: 20px 24px !important; + border-radius: 12px !important; +} + +::ng-deep .mat-expansion-panel-header-title { + font-weight: 600 !important; + color: #2c3e50 !important; +} + +::ng-deep .mat-expansion-panel-header-description { + color: #6c757d !important; +} + +.mat-expansion-panel-header-description { + justify-content: space-between; + align-items: center; +} + + .mat-elevation-z8 { box-shadow: 0px 0px 0px rgba(0,0,0,0.2); } @@ -116,117 +392,11 @@ table { margin-bottom: 30px; } -.clients-grid { - display: grid; - grid-template-columns: repeat(auto-fill, minmax(140px, 1fr)); - gap: 8px; -} - -.client-item { - position: relative; -} - -.client-card { - background: #ffffff; - border-radius: 6px; - box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); - overflow: hidden; - position: relative; - padding: 8px; - text-align: center; - cursor: pointer; - transition: background-color 0.3s, transform 0.2s; - - &:hover { - background-color: #f0f0f0; - transform: scale(1.02); - } -} - -.client-details { - margin-top: 4px; -} - -.client-name { - font-size: 0.9em; - font-weight: 600; - color: #333; - margin-bottom: 5px; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - max-width: 150px; - display: inline-block; -} - -.client-ip { - display: block; - font-size: 0.9em; - color: #666; -} - -.header-container-title { - flex-grow: 1; - text-align: left; - padding-left: 1em; -} - -.button-row { - display: flex; - padding-right: 1em; -} - -.client-card { - background: #ffffff; - border-radius: 6px; - box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); - overflow: hidden; - position: relative; - padding: 8px; - text-align: center; - cursor: pointer; - transition: background-color 0.3s, transform 0.2s; - - &:hover { - background-color: #f0f0f0; - transform: scale(1.02); - } -} - -::ng-deep .custom-tooltip { - white-space: pre-line !important; - max-width: 200px; - background: rgba(0, 0, 0, 0.8); - color: white; - padding: 8px; - border-radius: 4px; -} - -.selected-client { - background-color: #a0c2e5 !important; - color: white !important; -} - -.button-row { - display: flex; - padding-right: 1em; -} - .disabled-client { pointer-events: none; opacity: 0.5; } -.action-button { - margin-top: 10px; - margin-bottom: 10px; -} - -.mat-expansion-panel-header-description { - justify-content: space-between; - align-items: center; -} - .new-command-container { display: flex; flex-direction: column; @@ -261,15 +431,85 @@ table { width: 100%; } -.script-selector-card { - margin: 20px 20px; - padding: 16px; +/* Secciones del formulario */ +.form-section { + background: white !important; + border-radius: 8px; + padding: 24px; + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); + margin-bottom: 20px; + border: 1px solid #bbdefb; + padding: 20px; } +.form-section-title { + font-size: 18px; + font-weight: 600; + color: #333; + margin-bottom: 20px; + display: flex; + align-items: center; + gap: 8px; +} + +.form-section-title mat-icon { + color: #2196f3; +} .toggle-options { display: flex; - justify-content: start; - margin: 16px 0; + gap: 10px; + margin-bottom: 20px; } +.selected-toggle { + background: linear-gradient(135deg, #8fa1f0 0%, #9b7bc8 100%) !important; + color: white !important; +} +mat-spinner { + margin: 20px auto; + display: block; +} + +/* Estilo para hacer el backdrop no clickeable */ +::ng-deep .non-clickable-backdrop { + pointer-events: none !important; +} + +::ng-deep .action-chip { + margin: 8px !important; + padding: 12px 20px !important; + border-radius: px !important; + font-weight: 500 !important; + font-size: 14px !important; + transition: all 0.3s ease !important; + border: 2px solid transparent !important; + background: white !important; + color: #6c757d !important; + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1) !important; + cursor: pointer !important; + display: flex !important; + align-items: center !important; + gap: 8px !important; + min-height: 48px !important; +} + +::ng-deep .action-chip:hover { + transform: translateY(-2px) !important; + box-shadow: 0 4px 16px rgba(0, 0, 0, 0.15) !important; +} + +::ng-deep .action-chip.mat-mdc-chip-selected { + border-color: #667eea !important; + box-shadow: 0 4px 16px rgba(102, 126, 234, 0.2) !important; +} + +::ng-deep .create-chip.mat-mdc-chip-selected { + background: linear-gradient(135deg, #28a745 0%, #20c997 100%) !important; + color: white !important; +} + +::ng-deep .update-chip.mat-mdc-chip-selected { + background: linear-gradient(135deg, #007bff 0%, #0056b3 100%) !important; + color: white !important; +} \ No newline at end of file diff --git a/ogWebconsole/src/app/components/groups/components/client-main-view/run-script-assistant/run-script-assistant.component.html b/ogWebconsole/src/app/components/groups/components/client-main-view/run-script-assistant/run-script-assistant.component.html index c4daeef..a17794d 100644 --- a/ogWebconsole/src/app/components/groups/components/client-main-view/run-script-assistant/run-script-assistant.component.html +++ b/ogWebconsole/src/app/components/groups/components/client-main-view/run-script-assistant/run-script-assistant.component.html @@ -10,12 +10,12 @@
- +
-
-
@@ -40,8 +40,8 @@
@@ -62,55 +62,69 @@
- +
- - Seleccione el tipo de comando - -
- - - edit Nuevo Script - - - storage Script Guardado - - -
- -
- - Ingrese el script - - - -
- -
- - Seleccione script a ejecutar - - {{ script.name }} - - -
- -
-
-

Script:

-
+
+
+ code + Configuración de script
-
-

Ingrese los parámetros:

-
- - {{ paramName }} - - +
+ + + Nuevo Script + + + Script Guardado + + +
+ + +
+ + Ingrese el script + + + +
+ +
+ + Seleccione script a ejecutar + + {{ script.name }} + + +
+ +
+
+

Script:

+
+
+ +
+

Ingrese los parámetros:

+
+ + {{ paramName }} + + +
- +
+ + + \ No newline at end of file diff --git a/ogWebconsole/src/app/components/groups/components/client-main-view/run-script-assistant/run-script-assistant.component.spec.ts b/ogWebconsole/src/app/components/groups/components/client-main-view/run-script-assistant/run-script-assistant.component.spec.ts index d4531e6..89fca6c 100644 --- a/ogWebconsole/src/app/components/groups/components/client-main-view/run-script-assistant/run-script-assistant.component.spec.ts +++ b/ogWebconsole/src/app/components/groups/components/client-main-view/run-script-assistant/run-script-assistant.component.spec.ts @@ -28,6 +28,7 @@ import { MatProgressSpinnerModule } from '@angular/material/progress-spinner'; import {MatIconModule} from "@angular/material/icon"; import {MatCardModule} from "@angular/material/card"; import {MatButtonToggleModule} from "@angular/material/button-toggle"; +import { MatChipsModule } from "@angular/material/chips"; export function HttpLoaderFactory(http: HttpClient) { return new TranslateHttpLoader(http); @@ -63,6 +64,7 @@ describe('RunScriptAssistantComponent', () => { MatIconModule, MatCardModule, MatButtonToggleModule, + MatChipsModule, ToastrModule.forRoot(), HttpClientTestingModule, TranslateModule.forRoot({ diff --git a/ogWebconsole/src/app/components/groups/components/client-main-view/run-script-assistant/run-script-assistant.component.ts b/ogWebconsole/src/app/components/groups/components/client-main-view/run-script-assistant/run-script-assistant.component.ts index 2909ac5..b1135d9 100644 --- a/ogWebconsole/src/app/components/groups/components/client-main-view/run-script-assistant/run-script-assistant.component.ts +++ b/ogWebconsole/src/app/components/groups/components/client-main-view/run-script-assistant/run-script-assistant.component.ts @@ -7,6 +7,7 @@ import { ActivatedRoute, Router } from "@angular/router"; import { SaveScriptComponent } from "./save-script/save-script.component"; import { MatDialog } from "@angular/material/dialog"; import {CreateTaskComponent} from "../../../../commands/commands-task/create-task/create-task.component"; +import {QueueConfirmationModalComponent} from "../../../../../shared/queue-confirmation-modal/queue-confirmation-modal.component"; @Component({ selector: 'app-run-script-assistant', @@ -53,15 +54,9 @@ export class RunScriptAssistantComponent implements OnInit{ } }); this.clientId = this.clientData?.length ? this.clientData[0]['@id'] : null; - this.clientData.forEach((client: { selected: boolean; status: string}) => { - if (client.status === 'og-live') { - client.selected = true; - } - }); + this.clientData.forEach((client: { selected: boolean; status: string}) => { client.selected = true; }); - this.selectedClients = this.clientData.filter( - (client: { status: string }) => client.status === 'og-live' - ); + this.selectedClients = this.clientData.filter((client: { selected: boolean; status: string}) => client.selected); this.loadScripts() } @@ -122,18 +117,12 @@ export class RunScriptAssistantComponent implements OnInit{ } updateSelectedClients() { - this.selectedClients = this.clientData.filter( - (client: { selected: boolean; status: string }) => client.selected && client.status === "og-live" - ); + this.selectedClients = this.clientData.filter((client: { selected: boolean; status: string}) => client.selected); } toggleSelectAll() { this.allSelected = !this.allSelected; - this.clientData.forEach((client: { selected: boolean; status: string }) => { - if (client.status === "og-live") { - client.selected = this.allSelected; - } - }); + this.clientData.forEach((client: { selected: boolean; status: string }) => { client.selected = this.allSelected; }); } getPartitionsTooltip(client: any): string { @@ -179,23 +168,33 @@ export class RunScriptAssistantComponent implements OnInit{ } save(): void { - this.loading = true; + const dialogRef = this.dialog.open(QueueConfirmationModalComponent, { + width: '400px', + disableClose: true, + hasBackdrop: true + }); - this.http.post(`${this.baseUrl}/commands/run-script`, { - clients: this.selectedClients.map((client: any) => client.uuid), - script: this.commandType === 'existing' ? this.scriptContent : this.newScript, - }).subscribe( - response => { - this.toastService.success('Script ejecutado correctamente'); - this.dataChange.emit(); - this.router.navigate(['/commands-logs']); - }, - error => { - this.toastService.error('Error al ejecutar el script'); + dialogRef.afterClosed().subscribe(result => { + if (result !== undefined) { + this.loading = true; + this.http.post(`${this.baseUrl}/commands/run-script`, { + clients: this.selectedClients.map((client: any) => client.uuid), + script: this.commandType === 'existing' ? this.scriptContent : this.newScript, + queue: result + }).subscribe( + response => { + this.toastService.success('Script ejecutado correctamente'); + this.dataChange.emit(); + this.router.navigate(['/commands-logs']); + this.loading = false; + }, + error => { + this.toastService.error('Error al ejecutar el script'); + this.loading = false; + } + ); } - ); - - this.loading = false; + }); } openScheduleModal(): void { diff --git a/ogWebconsole/src/app/components/groups/shared/organizational-units/show-organizational-unit/show-organizational-unit.component.ts b/ogWebconsole/src/app/components/groups/shared/organizational-units/show-organizational-unit/show-organizational-unit.component.ts index 417f0d7..ee02949 100644 --- a/ogWebconsole/src/app/components/groups/shared/organizational-units/show-organizational-unit/show-organizational-unit.component.ts +++ b/ogWebconsole/src/app/components/groups/shared/organizational-units/show-organizational-unit/show-organizational-unit.component.ts @@ -92,7 +92,7 @@ export class ShowOrganizationalUnitComponent implements OnInit { { property: 'Router', value: this.ou.networkSettings.router }, { property: 'NTP', value: this.ou.networkSettings.ntp }, { property: 'Modo P2P', value: this.ou.networkSettings.p2pMode }, - { property: 'Tiempo P2P', value: this.ou.networkSettings.p2pTime }, + ...(this.ou.networkSettings.p2pMode === 'seeder' ? [{ property: 'Tiempo P2P (minutos)', value: this.ou.networkSettings.p2pTime }] : []), { property: 'Mcast IP', value: this.ou.networkSettings.mcastIp }, { property: 'Mcast Speed', value: this.ou.networkSettings.mcastSpeed }, { property: 'Mcast Port', value: this.ou.networkSettings.mcastPort }, diff --git a/ogWebconsole/src/app/components/login/login.component.ts b/ogWebconsole/src/app/components/login/login.component.ts index 4a58364..c5738be 100644 --- a/ogWebconsole/src/app/components/login/login.component.ts +++ b/ogWebconsole/src/app/components/login/login.component.ts @@ -65,7 +65,7 @@ export class LoginComponent { this.openSnackBar(false, 'Bienvenido ' + this.auth.username); this.router.navigateByUrl('/groups'); this.dialog.open(GlobalStatusComponent, { - width: '45vw', + width: '65vw', height: '80vh', }); } diff --git a/ogWebconsole/src/app/layout/header/header.component.css b/ogWebconsole/src/app/layout/header/header.component.css index 72b60ae..7e7c1dd 100644 --- a/ogWebconsole/src/app/layout/header/header.component.css +++ b/ogWebconsole/src/app/layout/header/header.component.css @@ -2,8 +2,52 @@ mat-toolbar { /*height: 7vh;*/ min-height: 65px; min-width: 375px; - background-color: #e2e8f0; + background: rgba(226, 232, 240, 0.8); + backdrop-filter: blur(10px); + -webkit-backdrop-filter: blur(10px); color: black; + position: fixed; + top: 0; + left: 0; + right: 0; + z-index: 1000; + box-shadow: 0 2px 20px rgba(0, 0, 0, 0.1); + transition: all 0.3s ease; + display: flex; + align-items: center; + justify-content: flex-start; + gap: 16px; + padding: 0 16px; +} + +/* Estilos específicos para el botón del sidebar */ +.navbar-icon { + color: #3f51b5; + font-size: 24px; + width: 24px; + height: 24px; +} + +/* Asegurar que el botón del sidebar sea visible */ +mat-toolbar button[mat-icon-button] { + display: flex; + align-items: center; + justify-content: center; + min-width: 48px; + height: 48px; + border-radius: 50%; + transition: all 0.3s ease; + color: #3f51b5; + background-color: transparent; + border: none; + cursor: pointer; + margin-right: 8px; +} + +mat-toolbar button[mat-icon-button]:hover { + background-color: rgba(63, 81, 181, 0.1); + transform: scale(1.05); + box-shadow: 0 2px 8px rgba(63, 81, 181, 0.2); } .navbar-actions-row { @@ -11,6 +55,7 @@ mat-toolbar { justify-content: end; align-items: center; flex-grow: 1; + gap: 8px; } .navbar-buttons-row { @@ -71,6 +116,7 @@ mat-toolbar { display: flex; justify-content: center; align-items: center; + gap: 8px; } .trace-button .mat-icon { @@ -81,3 +127,17 @@ mat-toolbar { margin-right: 2vh; } } + +.menu-toggle-right { + position: absolute; + right: 16px; + top: 50%; + transform: translateY(-50%); + z-index: 1100; +} + +@media (max-width: 576px) { + .menu-toggle-right { + right: 8px; + } +} diff --git a/ogWebconsole/src/app/layout/header/header.component.html b/ogWebconsole/src/app/layout/header/header.component.html index 28d1c25..353e3da 100644 --- a/ogWebconsole/src/app/layout/header/header.component.html +++ b/ogWebconsole/src/app/layout/header/header.component.html @@ -3,12 +3,11 @@ matTooltipShowDelay="1000"> - -