Improvment groops

pull/7/head
Manuel Aranda Rosales 2024-11-20 15:36:32 +01:00
parent 0e3e3f56e3
commit 7a095a0f47
12 changed files with 140 additions and 57 deletions

View File

@ -190,7 +190,6 @@ mat-spinner {
.result-card.small-card { .result-card.small-card {
width: 100%; width: 100%;
max-width: 180px; max-width: 180px;
height: 100%;
padding: 10px; padding: 10px;
margin: 10px 10px 10px 10px; margin: 10px 10px 10px 10px;
border-radius: 8px; border-radius: 8px;
@ -202,23 +201,23 @@ mat-spinner {
.result-card { .result-card {
&.card-og-live { &.card-og-live {
background-color: #4caf50; /* Verde */ background-color: yellow; /* Verde */
color: white; color: white;
} }
&.card-busy { &.card-busy {
background-color: #f44336; /* Naranja */ background-color: indianred; /* Naranja */
color: white; color: white;
} }
&.card-windows { &.card-windows {
background-color: #2196f3; /* Azul */ background-color: cornflowerblue; /* Azul */
color: white; color: white;
} }
&.card-linux { &.card-linux {
background-color: #9c27b0; /* Púrpura */ background-color: mediumpurple; /* Púrpura */
color: white; color: white;
} }
&.card-macos { &.card-macos {
background-color: #ff9800; /* Rojo */ background-color: cornflowerblue; /* Rojo */
color: white; color: white;
} }
&.card-off { &.card-off {
@ -286,6 +285,10 @@ mat-card {
color: white; color: white;
} }
.view-mode-buttons {
padding: 20px;
}
.view-mode-buttons button.active { .view-mode-buttons button.active {
font-weight: bold; font-weight: bold;
color: #3f51b5; color: #3f51b5;
@ -317,6 +320,20 @@ mat-card {
font-size: 12px; font-size: 12px;
} }
.no-results {
display: flex;
justify-content: center;
align-items: center;
height: 100%; /* Ajusta según el contenedor padre */
text-align: center;
}
.no-results p {
font-size: 1.5rem; /* Tamaño de fuente más grande */
font-weight: bold; /* Negrita para mejor visibilidad */
color: #555; /* Cambia el color según tu diseño */
}
.result-card-list p { .result-card-list p {
margin: 0; margin: 0;
} }
@ -324,3 +341,57 @@ mat-card {
.result-list { .result-list {
height: auto; height: auto;
} }
/* Estilo general para la tarjeta */
.result-card {
border-radius: 8px;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
transition: transform 0.3s ease, box-shadow 0.3s ease;
}
.result-card:hover {
transform: translateY(-4px);
box-shadow: 0 6px 12px rgba(0, 0, 0, 0.15);
}
/* Centrar contenido para clientes */
.centered-content {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
text-align: center;
}
.client-info p {
margin: 0.5rem 0;
font-size: 1rem;
color: #333;
}
.client-info .client-name {
font-size: 0.9rem;
color: #555;
}
.client-info .client-text {
font-size: 0.8rem;
color: #555;
}
.client-info strong {
font-weight: bold;
color: black;
}
.result-title {
font-size: 1.2rem;
font-weight: bold;
color: #333;
}
.client-image {
width: 100%;
height: auto;
}

View File

@ -27,7 +27,8 @@
<mat-icon>list</mat-icon> Lista <mat-icon>list</mat-icon> Lista
</button> </button>
<button mat-button (click)="toggleSelectAll()"> <button mat-button (click)="toggleSelectAll()">
<mat-icon>checkbox</mat-icon> Seleccionar/Deseleccionar Todos</button> <mat-icon>checkbox</mat-icon> Seleccionar/Deseleccionar Todos
</button>
</div> </div>
<div class="main-content"> <div class="main-content">
@ -63,11 +64,9 @@
<div class="results" joyrideStep="resultsStep" text="Aquí verás los resultados de tu búsqueda filtrada."> <div class="results" joyrideStep="resultsStep" text="Aquí verás los resultados de tu búsqueda filtrada.">
<ng-container *ngIf="filteredResults && filteredResults.length > 0; else noResults"> <ng-container *ngIf="filteredResults && filteredResults.length > 0; else noResults">
<ng-container *ngIf="viewMode === 'grid'"> <ng-container *ngIf="viewMode === 'grid'">
<mat-grid-list cols="8" rowHeight="1:1"> <mat-grid-list cols="7" rowHeight="1:1">
<mat-grid-tile *ngFor="let result of filteredResults"> <mat-grid-tile *ngFor="let result of filteredResults">
<mat-card <mat-card class="result-card small-card" [ngClass]="{
class="result-card small-card"
[ngClass]="{
'card-og-live': result.status === 'og-live', 'card-og-live': result.status === 'og-live',
'card-busy': result.status === 'busy', 'card-busy': result.status === 'busy',
'card-windows': result.status === 'windows' || result.status === 'windows-session', 'card-windows': result.status === 'windows' || result.status === 'windows-session',
@ -80,21 +79,23 @@
(change)="onCheckboxChange($event, result.name, result['@id'])" (change)="onCheckboxChange($event, result.name, result['@id'])"
class="result-checkbox"> class="result-checkbox">
</mat-checkbox> </mat-checkbox>
<mat-card-title class="result-title">{{ result.name }}</mat-card-title> <mat-card-title *ngIf="result.type !== 'client'" class="result-title">{{ result.name }}</mat-card-title>
<mat-card-content class="result-content"> <mat-card-content *ngIf="result.type === 'client'" class="result-content centered-content" >
<p class="result-type">{{ result.type !== 'client' ? result.type : '' }}</p> <div class="client-info">
<p class="result-ip" *ngIf="result.type === 'client'">{{ result.ip }}</p> <p class="client-name">{{ result.name }}</p>
<p class="result-mac" *ngIf="result.type === 'client'">{{ result.mac }}</p> <p class="client-text">{{ result.ip }}</p>
<p class="client-text"> {{ result.mac }}</p>
<p *ngIf="result.type !== 'client'" i18n="@@internalUnits" class="result-internal-units">Unidades internas: {{ result.children.length }}</p> </div>
<p *ngIf="result.type !== 'client'" i18n="@@clients" class="result-clients">Clientes: {{ result.clients.length }}</p> </mat-card-content>
<mat-card-content *ngIf="result.type !== 'client'" class="result-content">
<p i18n="@@internalUnits" class="result-internal-units">Unidades internas: {{ result.children.length }}</p>
<p i18n="@@clients" class="result-clients">Clientes: {{ result.clients.length }}</p>
</mat-card-content> </mat-card-content>
</mat-card> </mat-card>
</mat-grid-tile> </mat-grid-tile>
</mat-grid-list> </mat-grid-list>
</ng-container> </ng-container>
<ng-container *ngIf="viewMode === 'list'"> <ng-container *ngIf="viewMode === 'list'">
<div class="result-list" *ngFor="let result of filteredResults"> <div class="result-list" *ngFor="let result of filteredResults">
<mat-card class="result-card-list"> <mat-card class="result-card-list">
@ -117,8 +118,11 @@
</ng-container> </ng-container>
<ng-template #noResults> <ng-template #noResults>
<div class="no-results">
<p i18n="@@noResultsMessage">No hay resultados para mostrar.</p> <p i18n="@@noResultsMessage">No hay resultados para mostrar.</p>
</div>
</ng-template> </ng-template>
</div> </div>
</div> </div>
</div> </div>

View File

@ -144,6 +144,13 @@
gap: 20px; gap: 20px;
} }
.client-button-row {
display: flex;
flex-wrap: wrap;
justify-content: space-between; /* Distribuye el espacio entre los gráficos */
gap: 20px; /* Añade espacio entre los gráficos */
}
.buttons-row { .buttons-row {
display: flex; display: flex;
flex-direction: column; flex-direction: column;

View File

@ -1,6 +1,7 @@
<div class="header-container"> <div class="header-container">
<h2 class="title" i18n="@@adminImagesTitle">Datos de cliente</h2> <h2 class="title" i18n="@@adminImagesTitle">Datos de cliente</h2>
<div class="calendar-button-row"> <div class="client-button-row">
<button mat-flat-button color="primary" (click)="onEditClick($event, clientData.uuid)" i18n="@@editImage">Editar</button>
<button mat-flat-button color="primary" [matMenuTriggerFor]="commandMenu">Comandos</button> <button mat-flat-button color="primary" [matMenuTriggerFor]="commandMenu">Comandos</button>
</div> </div>
<mat-menu #commandMenu="matMenu"> <mat-menu #commandMenu="matMenu">

View File

@ -5,6 +5,7 @@ import {MatTableDataSource} from "@angular/material/table";
import {PartitionAssistantComponent} from "./partition-assistant/partition-assistant.component"; import {PartitionAssistantComponent} from "./partition-assistant/partition-assistant.component";
import {MatDialog} from "@angular/material/dialog"; import {MatDialog} from "@angular/material/dialog";
import {Router} from "@angular/router"; import {Router} from "@angular/router";
import {EditClientComponent} from "../../shared/clients/edit-client/edit-client.component";
interface ClientInfo { interface ClientInfo {
property: string; property: string;
@ -179,6 +180,11 @@ export class ClientMainViewComponent implements OnInit {
this.isDiskUsageEmpty = this.diskUsageData.length === 0; this.isDiskUsageEmpty = this.diskUsageData.length === 0;
} }
onEditClick(event: MouseEvent, uuid: string): void {
event.stopPropagation();
const dialogRef = this.dialog.open(EditClientComponent, { data: { uuid }, width: '900px' } );
dialogRef.afterClosed().subscribe();
}
getStrokeOffset(partitions: any[], index: number): number { getStrokeOffset(partitions: any[], index: number): number {
const totalSize = partitions.reduce((acc, part) => acc + (part.size / 1024), 0); const totalSize = partitions.reduce((acc, part) => acc + (part.size / 1024), 0);

View File

@ -9,11 +9,11 @@
<div class="select-container"> <div class="select-container">
<mat-form-field appearance="fill" class="full-width"> <mat-form-field appearance="fill" class="full-width">
<mat-label>Nombre canónico</mat-label> <mat-label>Nombre canónico</mat-label>
<input matInput [(ngModel)]="name" placeholder="Nombre canónico" required> <input matInput [(ngModel)]="name" placeholder="Nombre canónico. En minúscula y sin espacios" required>
</mat-form-field> </mat-form-field>
<mat-form-field appearance="fill" class="full-width"> <mat-form-field appearance="fill" class="full-width">
<mat-label>Seleccione imagen</mat-label> <mat-label>Seleccione imagen creada previamente</mat-label>
<mat-select [(ngModel)]="selectedImage"> <mat-select [(ngModel)]="selectedImage">
<mat-option>--</mat-option> <mat-option>--</mat-option>
<mat-option *ngFor="let image of images" [value]="image['@id']">{{ image.name }}</mat-option> <mat-option *ngFor="let image of images" [value]="image['@id']">{{ image.name }}</mat-option>
@ -27,6 +27,7 @@
<td mat-cell *matCellDef="let row"> <td mat-cell *matCellDef="let row">
<mat-radio-group <mat-radio-group
[(ngModel)]="selectedPartition" [(ngModel)]="selectedPartition"
[disabled]="!row.operativeSystem"
> >
<mat-radio-button [value]="row"> <mat-radio-button [value]="row">
</mat-radio-button> </mat-radio-button>

View File

@ -1,7 +1,7 @@
import {Component, EventEmitter, Output} from '@angular/core'; import {Component, EventEmitter, Output} from '@angular/core';
import {HttpClient} from "@angular/common/http"; import {HttpClient} from "@angular/common/http";
import {ToastrService} from "ngx-toastr"; import {ToastrService} from "ngx-toastr";
import {ActivatedRoute} from "@angular/router"; import {ActivatedRoute, Router} from "@angular/router";
import {MatButton} from "@angular/material/button"; import {MatButton} from "@angular/material/button";
import {MatDivider} from "@angular/material/divider"; import {MatDivider} from "@angular/material/divider";
import {NgForOf, NgIf} from "@angular/common"; import {NgForOf, NgIf} from "@angular/common";
@ -103,7 +103,9 @@ export class CreateImageComponent {
constructor( constructor(
private http: HttpClient, private http: HttpClient,
private toastService: ToastrService, private toastService: ToastrService,
private route: ActivatedRoute private route: ActivatedRoute,
private router: Router,
) {} ) {}
ngOnInit() { ngOnInit() {
@ -132,7 +134,7 @@ export class CreateImageComponent {
} }
loadImages() { loadImages() {
const url = `${this.baseUrl}/images?created=true&page=1&itemsPerPage=1000`; const url = `${this.baseUrl}/images?created=false&page=1&itemsPerPage=1000`;
this.http.get(url).subscribe( this.http.get(url).subscribe(
(response: any) => { (response: any) => {
this.images = response['hydra:member']; this.images = response['hydra:member'];
@ -156,7 +158,8 @@ export class CreateImageComponent {
this.http.post(`${this.baseUrl}/images`, payload) this.http.post(`${this.baseUrl}/images`, payload)
.subscribe({ .subscribe({
next: (response) => { next: (response) => {
this.toastService.success('Imagen creada exitosamente'); this.toastService.success('Petición de creación de imagen enviada');
this.router.navigate(['/images']);
}, },
error: (error) => { error: (error) => {
console.error('Error:', error); console.error('Error:', error);

View File

@ -64,7 +64,7 @@ button{
} }
.chip-busy { .chip-busy {
background-color: red !important; background-color: indianred !important;
color: black; color: black;
} }
@ -76,17 +76,17 @@ button{
.chip-windows, .chip-windows,
.chip-windows-session, .chip-windows-session,
.chip-macos { .chip-macos {
background-color: blue !important; background-color: cornflowerblue !important;
color: white; color: white;
} }
.chip-linux, .chip-linux,
.chip-linux-session { .chip-linux-session {
background-color: purple !important; background-color: mediumpurple !important;
color: white; color: white;
} }
.chip-off { .chip-off {
background-color: grey !important; background-color: darkgrey !important;
color: white; color: white;
} }

View File

@ -3,7 +3,7 @@
<mat-dialog-content> <mat-dialog-content>
<div class="button-container"> <div class="button-container">
<button <button
*ngFor="let command of commands" *ngFor="let command of arrayCommands"
mat-raised-button mat-raised-button
color="primary" color="primary"
class="button-action" class="button-action"

View File

@ -14,31 +14,21 @@ import { RouterLink } from '@angular/router';
export class AcctionsModalComponent { export class AcctionsModalComponent {
baseUrl: string = import.meta.env.NG_APP_BASE_API_URL; baseUrl: string = import.meta.env.NG_APP_BASE_API_URL;
selectedElements: any; selectedElements: any;
commands: any[] = [];
displayedColumns: string[] = ['name', 'createdBy', 'createdAt']; displayedColumns: string[] = ['name', 'createdBy', 'createdAt'];
filteredCommands = [...this.commands];
arrayCommands: any[] = [
{name: 'Enceder', slug: 'power-on'},
{name: 'Apagar', slug: 'power-off'},
{name: 'Reiniciar', slug: 'reboot'},
{name: 'Iniciar Sesión', slug: 'login'},
{name: 'Inventario Software', slug: 'software-inventory'},
{name: 'Inventario Hardware', slug: 'hardware-inventory'},
{name: 'Ejecutar script', slug: 'run-script'},
];
private apiUrl = `${this.baseUrl}/commands?page=1&itemsPerPage=40`; private apiUrl = `${this.baseUrl}/commands?page=1&itemsPerPage=40`;
ngOnInit(): void { ngOnInit(): void {
this.loadCommands();
}
applyFilter(event: Event) {
const filterValue = (event.target as HTMLInputElement).value.toLowerCase();
this.filteredCommands = this.commands.filter(command =>
command.name.toLowerCase().includes(filterValue)
);
}
loadCommands(): void {
this.http.get<any>(this.apiUrl).subscribe(
(data) => {
this.commands = data['hydra:member'];
},
(error) => {
console.error('Error fetching commands', error);
}
);
} }
constructor( constructor(

View File

@ -48,7 +48,7 @@ export class CreateClientComponent implements OnInit {
this.clientForm = this.fb.group({ this.clientForm = this.fb.group({
organizationalUnit: [this.data.organizationalUnit ? this.data.organizationalUnit['@id'] : null, Validators.required], organizationalUnit: [this.data.organizationalUnit ? this.data.organizationalUnit['@id'] : null, Validators.required],
name: ['', Validators.required], name: ['', Validators.required],
serialNumber: ['', Validators.required], serialNumber: [''],
netiface: null, netiface: null,
netDriver: null, netDriver: null,
mac: ['', Validators.required], mac: ['', Validators.required],