Creado componente compartido para mostrar la selección de particiones en los comandos crear imagen y deploy de imagenes con un diseño separado por disco
parent
208d89d589
commit
629a00dedf
|
|
@ -172,6 +172,7 @@ import { HardwareProfileComponent } from './components/hardware-profile/hardware
|
|||
import { HardwareCollectionModalComponent } from './components/hardware-profile/hardware-collection-modal/hardware-collection-modal.component';
|
||||
import { HardwareTypeComponent } from './components/hardware-type/hardware-type.component';
|
||||
import { ShowDetailsComponent } from './components/hardware-type/show-details/show-details.component';
|
||||
import { DiskPartitionSelectorComponent } from './components/groups/shared/disk-partition-selector/disk-partition-selector.component';
|
||||
export function HttpLoaderFactory(http: HttpClient) {
|
||||
return new TranslateHttpLoader(http, './locale/', '.json');
|
||||
}
|
||||
|
|
@ -348,7 +349,7 @@ registerLocaleData(localeEs, 'es-ES');
|
|||
progressAnimation: 'increasing',
|
||||
closeButton: true
|
||||
}
|
||||
), MatGridList, MatTree, MatTreeNode, MatNestedTreeNode, MatTreeNodeToggle, MatTreeNodeDef, MatTreeNodePadding, MatTreeNodeOutlet, MatPaginator, MatGridTile, MatExpansionPanel, MatExpansionPanelTitle, MatExpansionPanelDescription, MatRadioGroup, MatRadioButton, MatAutocompleteTrigger, NgOptimizedImage
|
||||
), MatGridList, MatTree, MatTreeNode, MatNestedTreeNode, MatTreeNodeToggle, MatTreeNodeDef, MatTreeNodePadding, MatTreeNodeOutlet, MatPaginator, MatGridTile, MatExpansionPanel, MatExpansionPanelTitle, MatExpansionPanelDescription, MatRadioGroup, MatRadioButton, MatAutocompleteTrigger, NgOptimizedImage, DiskPartitionSelectorComponent
|
||||
],
|
||||
schemas: [
|
||||
CUSTOM_ELEMENTS_SCHEMA,
|
||||
|
|
|
|||
|
|
@ -224,39 +224,13 @@
|
|||
</div>
|
||||
|
||||
<div class="partition-table-container">
|
||||
<table mat-table [dataSource]="dataSource">
|
||||
<ng-container matColumnDef="select">
|
||||
<th mat-header-cell *matHeaderCellDef i18n="@@columnActions" style="text-align: start">Seleccionar partición</th>
|
||||
<td mat-cell *matCellDef="let row">
|
||||
<mat-radio-group
|
||||
[(ngModel)]="selectedPartition"
|
||||
[disabled]="!row.operativeSystem"
|
||||
>
|
||||
<mat-radio-button [value]="row">
|
||||
</mat-radio-button>
|
||||
</mat-radio-group>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngFor="let column of columns" [matColumnDef]="column.columnDef">
|
||||
<th mat-header-cell *matHeaderCellDef> {{ column.header }} </th>
|
||||
<td mat-cell *matCellDef="let image">
|
||||
<ng-container *ngIf="column.columnDef !== 'size'">
|
||||
{{ column.cell(image) }}
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngIf="column.columnDef === 'size'">
|
||||
<div style="display: flex; flex-direction: column;">
|
||||
<span> {{ image.size }} MB</span>
|
||||
<span style="font-size: 0.75rem; color: gray;">{{ image.size / 1024 }} GB</span>
|
||||
</div>
|
||||
</ng-container>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
|
||||
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
|
||||
</table>
|
||||
<app-disk-partition-selector
|
||||
[(selectedPartition)]="selectedPartition"
|
||||
[partitions]="dataSource.data"
|
||||
[columns]="columns"
|
||||
[displayedColumns]="displayedColumns"
|
||||
[disableCondition]="isPartitionDisabled">
|
||||
</app-disk-partition-selector>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -62,12 +62,11 @@ export class CreateClientImageComponent implements OnInit{
|
|||
return this.gitData && this.gitData.repo && this.gitData.branch;
|
||||
}
|
||||
|
||||
isPartitionDisabled = (row: any): boolean => {
|
||||
return !row.operativeSystem;
|
||||
};
|
||||
|
||||
columns = [
|
||||
{
|
||||
columnDef: 'diskNumber',
|
||||
header: 'Disco',
|
||||
cell: (partition: any) => partition.diskNumber
|
||||
},
|
||||
{
|
||||
columnDef: 'partitionNumber',
|
||||
header: 'Particion',
|
||||
|
|
|
|||
|
|
@ -590,6 +590,11 @@ table {
|
|||
}
|
||||
}
|
||||
|
||||
.partition-table-container {
|
||||
overflow-x: auto;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.commits-table-container {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,9 +16,7 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="button-row">
|
||||
<button class="action-button" id="execute-button"
|
||||
[disabled]="!isFormValid()"
|
||||
(click)="save()">Ejecutar</button>
|
||||
<button class="action-button" id="execute-button" [disabled]="!isFormValid()" (click)="save()">Ejecutar</button>
|
||||
</div>
|
||||
|
||||
<div class="button-row">
|
||||
|
|
@ -28,9 +26,7 @@
|
|||
</div>
|
||||
|
||||
<div class="button-row">
|
||||
<button class="action-button" color="accent"
|
||||
[disabled]="!isFormValid()"
|
||||
(click)="openScheduleModal()">
|
||||
<button class="action-button" color="accent" [disabled]="!isFormValid()" (click)="openScheduleModal()">
|
||||
Opciones de programación
|
||||
</button>
|
||||
</div>
|
||||
|
|
@ -49,7 +45,8 @@
|
|||
<div class="section-hint" (click)="$event.stopPropagation()">
|
||||
<mat-icon>info</mat-icon>
|
||||
<span>
|
||||
Puedes marcar o desmarcar un cliente haciendo clic en el área del ordenador. Además, selecciona con "Modelo" el equipo que actuará como modelo.
|
||||
Puedes marcar o desmarcar un cliente haciendo clic en el área del ordenador. Además, selecciona con "Modelo" el
|
||||
equipo que actuará como modelo.
|
||||
</span>
|
||||
</div>
|
||||
|
||||
|
|
@ -61,17 +58,11 @@
|
|||
|
||||
<div class="clients-grid">
|
||||
<div *ngFor="let client of clientData" class="client-item">
|
||||
<div class="client-card"
|
||||
(click)="toggleClientSelection(client)"
|
||||
[ngClass]="{'selected-client': client.selected}"
|
||||
[matTooltip]="getPartitionsTooltip(client)"
|
||||
matTooltipPosition="above"
|
||||
matTooltipClass="custom-tooltip">
|
||||
<div class="client-card" (click)="toggleClientSelection(client)"
|
||||
[ngClass]="{'selected-client': client.selected}" [matTooltip]="getPartitionsTooltip(client)"
|
||||
matTooltipPosition="above" matTooltipClass="custom-tooltip">
|
||||
|
||||
<img
|
||||
[src]="'assets/images/computer_' + client.status + '.svg'"
|
||||
alt="Client Icon"
|
||||
class="client-image" />
|
||||
<img [src]="'assets/images/computer_' + client.status + '.svg'" alt="Client Icon" class="client-image" />
|
||||
|
||||
<div class="client-details">
|
||||
<span class="client-name">{{ client.name | slice:0:20 }}</span>
|
||||
|
|
@ -82,9 +73,7 @@
|
|||
|
||||
<div class="model-selector" (click)="$event.stopPropagation()">
|
||||
<mat-radio-group [(ngModel)]="selectedModelClient" (change)="onModelSelected(selectedModelClient)">
|
||||
<mat-radio-button [value]="client"
|
||||
color="primary"
|
||||
(click)="$event.stopPropagation()">
|
||||
<mat-radio-button [value]="client" color="primary" (click)="$event.stopPropagation()">
|
||||
Modelo
|
||||
</mat-radio-button>
|
||||
</mat-radio-group>
|
||||
|
|
@ -104,7 +93,7 @@
|
|||
<mat-icon>image</mat-icon>
|
||||
Configuración de imagen
|
||||
</div>
|
||||
|
||||
|
||||
<div class="selector">
|
||||
<mat-form-field appearance="fill" class="half-width">
|
||||
<mat-label>Tipo de imagen</mat-label>
|
||||
|
|
@ -119,7 +108,8 @@
|
|||
<div *ngIf="imageType === 'git'" class="filters-row git-gap">
|
||||
<mat-form-field appearance="fill" style="width: 300px;">
|
||||
<mat-label>Seleccionar Repositorio</mat-label>
|
||||
<mat-select [(ngModel)]="selectedGitRepository" (selectionChange)="onGitRepositoryChange($event.value)" [disabled]="loadingRepositories">
|
||||
<mat-select [(ngModel)]="selectedGitRepository" (selectionChange)="onGitRepositoryChange($event.value)"
|
||||
[disabled]="loadingRepositories">
|
||||
<mat-option *ngFor="let repo of repositories" [value]="repo">
|
||||
{{ repo }}
|
||||
</mat-option>
|
||||
|
|
@ -129,7 +119,8 @@
|
|||
|
||||
<mat-form-field appearance="fill" style="width: 300px;">
|
||||
<mat-label>Seleccionar Rama</mat-label>
|
||||
<mat-select [(ngModel)]="selectedBranch" (selectionChange)="onGitBranchChange()" [disabled]="loadingBranches || !selectedRepository">
|
||||
<mat-select [(ngModel)]="selectedBranch" (selectionChange)="onGitBranchChange()"
|
||||
[disabled]="loadingBranches || !selectedRepository">
|
||||
<mat-option *ngFor="let branch of branches" [value]="branch">
|
||||
{{ branch }}
|
||||
</mat-option>
|
||||
|
|
@ -176,8 +167,8 @@
|
|||
<th mat-header-cell *matHeaderCellDef>Tags</th>
|
||||
<td mat-cell *matCellDef="let commit">
|
||||
<mat-chip-list>
|
||||
<mat-chip *ngFor="let tag of commit.tags" color="primary" selected class="custom-tag-chip"
|
||||
style="background: rgba(102, 126, 234, 0.1) !important; color: #667eea !important; border: 1px solid rgba(102, 126, 234, 0.3) !important; border-radius: 8px !important; font-weight: 500 !important; font-size: 10px !important; padding: 2px 6px !important; margin: 1px !important; box-shadow: none !important;">
|
||||
<mat-chip *ngFor="let tag of commit.tags" color="primary" selected class="custom-tag-chip"
|
||||
style="background: rgba(102, 126, 234, 0.1) !important; color: #667eea !important; border: 1px solid rgba(102, 126, 234, 0.3) !important; border-radius: 8px !important; font-weight: 500 !important; font-size: 10px !important; padding: 2px 6px !important; margin: 1px !important; box-shadow: none !important;">
|
||||
{{ tag }}
|
||||
</mat-chip>
|
||||
<span *ngIf="!commit.tags || commit.tags.length === 0" class="no-tags-text">Sin tags</span>
|
||||
|
|
@ -198,7 +189,7 @@
|
|||
</mat-form-field>
|
||||
<mat-form-field appearance="fill" class="full-width">
|
||||
<mat-label>Seleccione imagen</mat-label>
|
||||
<mat-select [(ngModel)]="selectedImage" name="selectedImage" [disabled] = "!imageType" >
|
||||
<mat-select [(ngModel)]="selectedImage" name="selectedImage" [disabled]="!imageType">
|
||||
<mat-option *ngFor="let image of images" [value]="image">
|
||||
<div class="unit-name"> {{ image.name }}</div>
|
||||
<div style="font-size: smaller; color: gray;">{{ image.description }}</div>
|
||||
|
|
@ -212,13 +203,82 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Sección: Opciones avanzadas -->
|
||||
<div class="form-section" id="advanced-options"
|
||||
*ngIf="isMethod('udpcast') || isMethod('uftp') || isMethod('udpcast-direct') || isMethod('p2p')">
|
||||
<div class="form-section-title">
|
||||
<mat-icon>settings</mat-icon>
|
||||
<span *ngIf="isMethod('udpcast') || isMethod('uftp') || isMethod('udpcast-direct')">Opciones multicast</span>
|
||||
<span *ngIf="isMethod('p2p')">Opciones torrent</span>
|
||||
</div>
|
||||
|
||||
<div class="input-group" *ngIf="isMethod('udpcast') || isMethod('uftp') || isMethod('udpcast-direct')">
|
||||
<mat-form-field appearance="fill" class="input-field">
|
||||
<mat-label>Puerto</mat-label>
|
||||
<input matInput [(ngModel)]="mcastPort" name="mcastPort" type="number"
|
||||
[required]="isMethod('udpcast') || isMethod('uftp') || isMethod('udpcast-direct')">
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field appearance="fill" class="input-field">
|
||||
<mat-label>Dirección</mat-label>
|
||||
<input matInput [(ngModel)]="mcastIp" name="mcastIp"
|
||||
[required]="isMethod('udpcast') || isMethod('uftp') || isMethod('udpcast-direct')">
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field appearance="fill" class="input-field">
|
||||
<mat-label i18n="@@mcastModeLabel">Modo Multicast</mat-label>
|
||||
<mat-select [(ngModel)]="mcastMode" name="mcastMode"
|
||||
[required]="isMethod('udpcast') || isMethod('uftp') || isMethod('udpcast-direct')">
|
||||
<mat-option *ngFor="let option of multicastModeOptions" [value]="option.value">
|
||||
{{ option.name }}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field appearance="fill" class="input-field">
|
||||
<mat-label>Velocidad</mat-label>
|
||||
<input matInput [(ngModel)]="mcastSpeed" name="mcastSpeed" type="number"
|
||||
[required]="isMethod('udpcast') || isMethod('uftp') || isMethod('udpcast-direct')">
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field appearance="fill" class="input-field">
|
||||
<mat-label>Máximo Clientes</mat-label>
|
||||
<input matInput [(ngModel)]="mcastMaxClients" name="mcastMaxClients" type="number"
|
||||
[required]="isMethod('udpcast') || isMethod('uftp') || isMethod('udpcast-direct')">
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field appearance="fill" class="input-field">
|
||||
<mat-label>Tiempo Máximo de Espera</mat-label>
|
||||
<input matInput [(ngModel)]="mcastMaxTime" name="mcastMaxTime" type="number"
|
||||
[required]="isMethod('udpcast') || isMethod('uftp') || isMethod('udpcast-direct')">
|
||||
</mat-form-field>
|
||||
</div>
|
||||
|
||||
<div class="input-group" *ngIf="isMethod('p2p')">
|
||||
<mat-form-field appearance="fill" class="input-field">
|
||||
<mat-label i18n="@@p2pModeLabel">Modo P2P</mat-label>
|
||||
<mat-select [(ngModel)]="p2pMode" name="p2pMode" [required]="isMethod('p2p')">
|
||||
<mat-option *ngFor="let option of p2pModeOptions" [value]="option.value">
|
||||
{{ option.name }}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field appearance="fill" class="input-field" *ngIf="p2pMode === 'seeder'">
|
||||
<mat-label>Semilla (minutos)</mat-label>
|
||||
<input matInput [(ngModel)]="p2pTime" name="p2pTime" type="number"
|
||||
[required]="isMethod('p2p') && p2pMode === 'seeder'">
|
||||
</mat-form-field>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Sección: Selección de partición -->
|
||||
<div class="form-section" id="partition-selection">
|
||||
<div class="form-section-title">
|
||||
<mat-icon>storage</mat-icon>
|
||||
Selección de partición
|
||||
</div>
|
||||
|
||||
|
||||
<div class="partition-table-container">
|
||||
<div *ngIf="showInstructions" class="instructions-box">
|
||||
<mat-card class="instructions-card">
|
||||
|
|
@ -234,107 +294,16 @@
|
|||
</mat-card>
|
||||
</div>
|
||||
|
||||
<table mat-table [dataSource]="filteredPartitions">
|
||||
<ng-container matColumnDef="select">
|
||||
<th mat-header-cell *matHeaderCellDef style="text-align: start">Seleccionar partición</th>
|
||||
<td mat-cell *matCellDef="let row">
|
||||
<mat-radio-group [(ngModel)]="selectedPartition" name="selectedPartition">
|
||||
<mat-radio-button [value]="row">
|
||||
</mat-radio-button>
|
||||
</mat-radio-group>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngFor="let column of columns" [matColumnDef]="column.columnDef">
|
||||
<th mat-header-cell *matHeaderCellDef> {{ column.header }} </th>
|
||||
<td mat-cell *matCellDef="let image">
|
||||
{{ column.cell(image) }}
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
|
||||
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Sección: Opciones avanzadas -->
|
||||
<div class="form-section" id="advanced-options" *ngIf="isMethod('udpcast') || isMethod('uftp') || isMethod('udpcast-direct') || isMethod('p2p')">
|
||||
<div class="form-section-title">
|
||||
<mat-icon>settings</mat-icon>
|
||||
<span *ngIf="isMethod('udpcast') || isMethod('uftp') || isMethod('udpcast-direct')">Opciones multicast</span>
|
||||
<span *ngIf="isMethod('p2p')">Opciones torrent</span>
|
||||
</div>
|
||||
|
||||
<div class="input-group" *ngIf="isMethod('udpcast') || isMethod('uftp') || isMethod('udpcast-direct')">
|
||||
<mat-form-field appearance="fill" class="input-field">
|
||||
<mat-label>Puerto</mat-label>
|
||||
<input matInput [(ngModel)]="mcastPort" name="mcastPort" type="number"
|
||||
[required]="isMethod('udpcast') || isMethod('uftp') || isMethod('udpcast-direct')">
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field appearance="fill" class="input-field">
|
||||
<mat-label>Dirección</mat-label>
|
||||
<input matInput [(ngModel)]="mcastIp" name="mcastIp"
|
||||
[required]="isMethod('udpcast') || isMethod('uftp') || isMethod('udpcast-direct')">
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field appearance="fill" class="input-field">
|
||||
<mat-label i18n="@@mcastModeLabel">Modo Multicast</mat-label>
|
||||
<mat-select [(ngModel)]="mcastMode" name="mcastMode"
|
||||
[required]="isMethod('udpcast') || isMethod('uftp') || isMethod('udpcast-direct')">
|
||||
<mat-option *ngFor="let option of multicastModeOptions" [value]="option.value">
|
||||
{{ option.name }}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field appearance="fill" class="input-field">
|
||||
<mat-label>Velocidad</mat-label>
|
||||
<input matInput [(ngModel)]="mcastSpeed" name="mcastSpeed" type="number"
|
||||
[required]="isMethod('udpcast') || isMethod('uftp') || isMethod('udpcast-direct')">
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field appearance="fill" class="input-field">
|
||||
<mat-label>Máximo Clientes</mat-label>
|
||||
<input matInput [(ngModel)]="mcastMaxClients" name="mcastMaxClients" type="number"
|
||||
[required]="isMethod('udpcast') || isMethod('uftp') || isMethod('udpcast-direct')">
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field appearance="fill" class="input-field">
|
||||
<mat-label>Tiempo Máximo de Espera</mat-label>
|
||||
<input matInput [(ngModel)]="mcastMaxTime" name="mcastMaxTime" type="number"
|
||||
[required]="isMethod('udpcast') || isMethod('uftp') || isMethod('udpcast-direct')">
|
||||
</mat-form-field>
|
||||
</div>
|
||||
|
||||
<div class="input-group" *ngIf="isMethod('p2p')">
|
||||
<mat-form-field appearance="fill" class="input-field">
|
||||
<mat-label i18n="@@p2pModeLabel">Modo P2P</mat-label>
|
||||
<mat-select [(ngModel)]="p2pMode" name="p2pMode"
|
||||
[required]="isMethod('p2p')">
|
||||
<mat-option *ngFor="let option of p2pModeOptions" [value]="option.value">
|
||||
{{ option.name }}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field appearance="fill" class="input-field" *ngIf="p2pMode === 'seeder'">
|
||||
<mat-label>Semilla (minutos)</mat-label>
|
||||
<input matInput [(ngModel)]="p2pTime" name="p2pTime" type="number"
|
||||
[required]="isMethod('p2p') && p2pMode === 'seeder'">
|
||||
</mat-form-field>
|
||||
<app-disk-partition-selector
|
||||
[(selectedPartition)]="selectedPartition"
|
||||
[partitions]="filteredPartitions"
|
||||
[columns]="columns"
|
||||
[displayedColumns]="displayedColumns">
|
||||
</app-disk-partition-selector>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<app-scroll-to-top
|
||||
[threshold]="100"
|
||||
targetElement=".header-container"
|
||||
position="bottom-right"
|
||||
[showTooltip]="true"
|
||||
tooltipText="Volver arriba"
|
||||
tooltipPosition="left">
|
||||
</app-scroll-to-top>
|
||||
|
||||
|
||||
<app-scroll-to-top [threshold]="100" targetElement=".header-container" position="bottom-right" [showTooltip]="true"
|
||||
tooltipText="Volver arriba" tooltipPosition="left">
|
||||
</app-scroll-to-top>
|
||||
|
|
@ -57,6 +57,7 @@ export class DeployImageComponent implements OnInit{
|
|||
selectedClients: any[] = [];
|
||||
selectedModelClient: any = null;
|
||||
filteredPartitions: any[] = [];
|
||||
|
||||
selectedRepository: any = null;
|
||||
imageType: string = 'monolithic';
|
||||
|
||||
|
|
@ -70,14 +71,9 @@ export class DeployImageComponent implements OnInit{
|
|||
|
||||
dataSource = new MatTableDataSource<any>();
|
||||
columns = [
|
||||
{
|
||||
columnDef: 'diskNumber',
|
||||
header: 'Disco',
|
||||
cell: (partition: any) => `${partition.diskNumber}`
|
||||
},
|
||||
{
|
||||
columnDef: 'partitionNumber',
|
||||
header: 'Particion',
|
||||
header: 'Partición',
|
||||
cell: (partition: any) => `${partition.partitionNumber}`
|
||||
},
|
||||
{
|
||||
|
|
|
|||
|
|
@ -0,0 +1,51 @@
|
|||
/* Formatting specific to grouped partition selector */
|
||||
.disk-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 32px;
|
||||
padding-top: 16px;
|
||||
}
|
||||
|
||||
.disk-card-wrapper {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.disk-mat-card {
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.disk-card-header {
|
||||
background-color: #f5f5f5;
|
||||
padding: 16px 20px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
border-bottom: 1px solid #e0e0e0;
|
||||
}
|
||||
|
||||
.disk-card-title {
|
||||
margin: 0;
|
||||
font-size: 1.2rem;
|
||||
color: #3f51b5;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.disk-card-layout {
|
||||
display: flex;
|
||||
align-items: stretch;
|
||||
background: white;
|
||||
gap: 0;
|
||||
}
|
||||
|
||||
.disk-table-container {
|
||||
flex: 1;
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
.disk-table {
|
||||
width: 100%;
|
||||
box-shadow: none !important;
|
||||
border: none !important;
|
||||
}
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
<div class="disk-container">
|
||||
@for (disk of diskUsageData; track disk.diskNumber) {
|
||||
<div class="disk-card-wrapper">
|
||||
<mat-card class="disk-mat-card mat-elevation-z4">
|
||||
<div class="disk-card-header">
|
||||
<h3 class="disk-card-title">Disco {{ disk.diskNumber }}</h3>
|
||||
</div>
|
||||
|
||||
<div class="disk-card-layout">
|
||||
<div class="disk-table-container">
|
||||
<table mat-table [dataSource]="disk.partitions" class="disk-table">
|
||||
|
||||
<ng-container matColumnDef="select">
|
||||
<th mat-header-cell *matHeaderCellDef style="text-align: start">Seleccionar</th>
|
||||
<td mat-cell *matCellDef="let row">
|
||||
<mat-radio-group
|
||||
[ngModel]="selectedPartition"
|
||||
(ngModelChange)="onPartitionSelected($event)"
|
||||
name="selectedPartitionGroup"
|
||||
[disabled]="disableCondition(row)">
|
||||
<mat-radio-button [value]="row"></mat-radio-button>
|
||||
</mat-radio-group>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
@for (column of columns; track column.columnDef) {
|
||||
<ng-container [matColumnDef]="column.columnDef">
|
||||
<th mat-header-cell *matHeaderCellDef> {{ column.header }} </th>
|
||||
<td mat-cell *matCellDef="let partition">
|
||||
@if (column.columnDef === 'size') {
|
||||
<div style="display: flex; flex-direction: column;">
|
||||
<span>{{ partition.size }} MB</span>
|
||||
<span style="font-size: 0.75rem; color: gray;">{{ partition.size / 1024 | number:'1.0-2' }} GB</span>
|
||||
</div>
|
||||
} @else {
|
||||
{{ column.cell ? column.cell(partition) : partition[column.columnDef] }}
|
||||
}
|
||||
</td>
|
||||
</ng-container>
|
||||
}
|
||||
|
||||
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
|
||||
<tr mat-row *matRowDef="let row; columns: displayedColumns;"
|
||||
(click)="onPartitionSelected(row)"
|
||||
[ngStyle]="{'cursor': disableCondition(row) ? 'default' : 'pointer', 'opacity': disableCondition(row) ? '0.5' : '1'}">
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</mat-card>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
import { Component, Input, Output, EventEmitter, OnChanges, SimpleChanges } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { MatCardModule } from '@angular/material/card';
|
||||
import { MatTableModule } from '@angular/material/table';
|
||||
import { MatRadioModule } from '@angular/material/radio';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
|
||||
@Component({
|
||||
selector: 'app-disk-partition-selector',
|
||||
standalone: true,
|
||||
imports: [CommonModule, MatCardModule, MatTableModule, MatRadioModule, FormsModule],
|
||||
templateUrl: './disk-partition-selector.component.html',
|
||||
styleUrl: './disk-partition-selector.component.css'
|
||||
})
|
||||
export class DiskPartitionSelectorComponent implements OnChanges {
|
||||
@Input() partitions: any[] = [];
|
||||
@Input() columns: any[] = [];
|
||||
@Input() displayedColumns: string[] = [];
|
||||
@Input() selectedPartition: any;
|
||||
@Input() disableCondition: (row: any) => boolean = () => false;
|
||||
|
||||
@Output() selectedPartitionChange = new EventEmitter<any>();
|
||||
|
||||
diskUsageData: any[] = [];
|
||||
|
||||
ngOnChanges(changes: SimpleChanges): void {
|
||||
if (changes['partitions']) {
|
||||
this.calculateDiskUsage(this.partitions || []);
|
||||
}
|
||||
}
|
||||
|
||||
calculateDiskUsage(partitions: any[]) {
|
||||
this.diskUsageData = [];
|
||||
const grouped = partitions.reduce((acc: any, curr: any) => {
|
||||
if (!acc[curr.diskNumber]) {
|
||||
acc[curr.diskNumber] = [];
|
||||
}
|
||||
acc[curr.diskNumber].push(curr);
|
||||
return acc;
|
||||
}, {});
|
||||
|
||||
for (const diskNum in grouped) {
|
||||
if (grouped.hasOwnProperty(diskNum)) {
|
||||
this.diskUsageData.push({
|
||||
diskNumber: diskNum,
|
||||
partitions: grouped[diskNum]
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onPartitionSelected(row: any) {
|
||||
if (!this.disableCondition(row)) {
|
||||
this.selectedPartition = row;
|
||||
this.selectedPartitionChange.emit(this.selectedPartition);
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue