refs #1558. Add client/subnet new UX modal
testing/ogGui-multibranch/pipeline/head There was a failure building this commit
Details
testing/ogGui-multibranch/pipeline/head There was a failure building this commit
Details
parent
bae2069661
commit
b29a3f58f1
|
@ -27,6 +27,14 @@
|
|||
</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
<mat-form-field appearance="fill" class="full-width">
|
||||
<mat-label>Vista tarjetas</mat-label>
|
||||
<mat-select formControlName="groupsView" required>
|
||||
<mat-option *ngFor="let option of views" [value]="option.value" >
|
||||
{{ option.name }}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
</form>
|
||||
</mat-dialog-content>
|
||||
<mat-dialog-actions class="action-container">
|
||||
|
|
|
@ -24,6 +24,11 @@ export class AddUserModalComponent implements OnInit {
|
|||
organizationalUnits: any[] = [];
|
||||
userId: string | null = null;
|
||||
|
||||
protected views = [
|
||||
{value: 'card', name: 'Tarjetas'},
|
||||
{value: 'list', name: 'Listado'},
|
||||
];
|
||||
|
||||
constructor(
|
||||
public dialogRef: MatDialogRef<AddUserModalComponent>,
|
||||
@Inject(MAT_DIALOG_DATA) public data: any,
|
||||
|
@ -36,6 +41,7 @@ export class AddUserModalComponent implements OnInit {
|
|||
username: ['', Validators.required],
|
||||
password: ['', Validators.required],
|
||||
role: ['', Validators.required],
|
||||
groupsView: ['card', Validators.required],
|
||||
organizationalUnits: [[]]
|
||||
});
|
||||
}
|
||||
|
@ -55,15 +61,14 @@ export class AddUserModalComponent implements OnInit {
|
|||
load(): void {
|
||||
this.dataService.getUser(this.data).subscribe({
|
||||
next: (response) => {
|
||||
console.log(response);
|
||||
|
||||
const organizationalUnitIds = response.allowedOrganizationalUnits.map((unit: any) => unit['@id']);
|
||||
|
||||
// Patch the values to the form
|
||||
this.userForm.patchValue({
|
||||
username: response.username,
|
||||
role: response.userGroups[0]['@id'],
|
||||
organizationalUnits: organizationalUnitIds
|
||||
role: response.userGroups.length > 0 ? response.userGroups[0]['@id'] : null,
|
||||
organizationalUnits: organizationalUnitIds,
|
||||
groupsView: response.groupsView
|
||||
});
|
||||
|
||||
this.userId = response['@id'];
|
||||
|
@ -85,7 +90,8 @@ export class AddUserModalComponent implements OnInit {
|
|||
allowedOrganizationalUnits: this.userForm.value.organizationalUnit,
|
||||
password: this.userForm.value.password,
|
||||
enabled: true,
|
||||
userGroups: [this.userForm.value.role ]
|
||||
userGroups: [this.userForm.value.role ],
|
||||
groupsView: this.userForm.value.groupsView
|
||||
};
|
||||
|
||||
if (this.userId) {
|
||||
|
|
|
@ -32,6 +32,11 @@ export class UsersComponent implements OnInit {
|
|||
header: 'Nombre de Usuario',
|
||||
cell: (user: any) => `${user.username}`
|
||||
},
|
||||
{
|
||||
columnDef: 'groupsView',
|
||||
header: 'Vista de Grupos',
|
||||
cell: (user: any) => `${user.groupsView}`
|
||||
},
|
||||
{
|
||||
columnDef: 'allowedOrganizationalUnits',
|
||||
header: 'Unidades Organizacionales Permitidas',
|
||||
|
|
|
@ -27,3 +27,16 @@ mat-dialog-actions {
|
|||
gap: 1em;
|
||||
padding: 1.5em;
|
||||
}
|
||||
|
||||
.clients-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr); /* 3 columnas */
|
||||
gap: 5px; /* Espaciado entre elementos */
|
||||
}
|
||||
|
||||
.checkbox-group label {
|
||||
font-weight: bold;
|
||||
display: block;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
<app-loading [isLoading]="loading"></app-loading>
|
||||
|
||||
<h2 mat-dialog-title>Añade clientes a {{data.subnetName}}</h2>
|
||||
|
||||
<mat-dialog-content>
|
||||
|
@ -10,7 +12,12 @@
|
|||
|
||||
<div class="checkbox-group">
|
||||
<label>Clientes</label>
|
||||
<div *ngIf="clients.length > 0">
|
||||
|
||||
<button class="action-button" (click)="toggleSelectAll()" [disabled]="clients.length === 0">
|
||||
{{ allSelected ? 'Deseleccionar todos' : 'Seleccionar todos' }}
|
||||
</button>
|
||||
|
||||
<div *ngIf="clients.length > 0" class="clients-grid">
|
||||
<mat-checkbox *ngFor="let client of clients"
|
||||
(change)="toggleClientSelection(client.uuid)"
|
||||
[checked]="selectedClients.includes(client.uuid)">
|
||||
|
|
|
@ -18,6 +18,7 @@ export class AddClientsToSubnetComponent implements OnInit {
|
|||
loading: boolean = true;
|
||||
unitControl = new FormControl();
|
||||
childUnitControl = new FormControl();
|
||||
allSelected: boolean = false;
|
||||
|
||||
constructor(
|
||||
private http: HttpClient,
|
||||
|
@ -43,7 +44,7 @@ export class AddClientsToSubnetComponent implements OnInit {
|
|||
}
|
||||
|
||||
loadChildUnits(event: any) {
|
||||
this.http.get<any>(`${this.baseUrl}/clients?organizationalUnit.id=${event.value.id}`).subscribe(
|
||||
this.http.get<any>(`${this.baseUrl}/clients?organizationalUnit.id=${event.value.id}&exists[subnet]=false`).subscribe(
|
||||
response => {
|
||||
this.clients = response['hydra:member'];
|
||||
},
|
||||
|
@ -51,37 +52,49 @@ export class AddClientsToSubnetComponent implements OnInit {
|
|||
);
|
||||
}
|
||||
|
||||
toggleClientSelection(clientId: string): void {
|
||||
const index = this.selectedClients.indexOf(clientId);
|
||||
if (index >= 0) {
|
||||
this.selectedClients.splice(index, 1);
|
||||
} else {
|
||||
this.selectedClients.push(clientId);
|
||||
}
|
||||
}
|
||||
|
||||
save() {
|
||||
this.loading = true;
|
||||
const postData = { clients: this.selectedClients.map(clientId => `/clients/${clientId}`) };
|
||||
|
||||
this.http.post(`${this.baseUrl}/og-dhcp/server/${this.data.subnetUuid}/post-host`, postData).subscribe(
|
||||
(response: any) => {
|
||||
this.dialog.open(OperationResultDialogComponent, {
|
||||
width: '600px',
|
||||
width: '800px',
|
||||
data: {
|
||||
success: response.success || [],
|
||||
errors: response.errors || []
|
||||
}
|
||||
});
|
||||
|
||||
this.loading = false;
|
||||
this.dialogRef.close(this.selectedClients);
|
||||
},
|
||||
error => {
|
||||
console.error(`Error al asignar el cliente:`, error);
|
||||
this.toastService.error(`Error al asignar el cliente: ${error.error['hydra:description']}`);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
toggleSelectAll() {
|
||||
if (this.allSelected) {
|
||||
this.selectedClients = [];
|
||||
} else {
|
||||
this.selectedClients = this.clients.map(client => client.uuid);
|
||||
}
|
||||
this.allSelected = !this.allSelected;
|
||||
}
|
||||
|
||||
toggleClientSelection(uuid: string) {
|
||||
const index = this.selectedClients.indexOf(uuid);
|
||||
if (index === -1) {
|
||||
this.selectedClients.push(uuid);
|
||||
} else {
|
||||
this.selectedClients.splice(index, 1);
|
||||
}
|
||||
|
||||
this.allSelected = this.selectedClients.length === this.clients.length;
|
||||
}
|
||||
|
||||
close() {
|
||||
this.dialogRef.close();
|
||||
}
|
||||
|
|
|
@ -39,4 +39,11 @@ form {
|
|||
justify-content: flex-end;
|
||||
gap: 1em;
|
||||
padding: 1.5em;
|
||||
}
|
||||
}
|
||||
|
||||
.step-title {
|
||||
font-family: 'Roboto', sans-serif;
|
||||
color: #3f51b5;
|
||||
margin: 40px 0 15px 0;
|
||||
display: block;
|
||||
}
|
||||
|
|
|
@ -1,68 +1,38 @@
|
|||
<h2 mat-dialog-title>{{ isEditMode ? 'Editar' : 'Añadir' }} subred</h2>
|
||||
|
||||
<mat-dialog-content>
|
||||
<mat-tab-group>
|
||||
<mat-tab label="Subred">
|
||||
<div class="spacing-container">
|
||||
<mat-form-field appearance="fill" class="full-width">
|
||||
<mat-label>Nombre</mat-label>
|
||||
<input matInput [(ngModel)]="name" placeholder="Nombre de la subred" required>
|
||||
</mat-form-field>
|
||||
<mat-form-field appearance="fill" class="full-width">
|
||||
<mat-label>Netmask</mat-label>
|
||||
<input matInput [(ngModel)]="netmask" placeholder="Netmask" required>
|
||||
</mat-form-field>
|
||||
<mat-form-field appearance="fill" class="full-width">
|
||||
<mat-label>Dirección IP</mat-label>
|
||||
<input matInput [(ngModel)]="ipAddress" placeholder="Dirección IP" required>
|
||||
</mat-form-field>
|
||||
<div class="spacing-container">
|
||||
<mat-form-field appearance="fill" class="full-width">
|
||||
<mat-label>Nombre</mat-label>
|
||||
<input matInput [(ngModel)]="name" placeholder="Nombre de la subred" required>
|
||||
</mat-form-field>
|
||||
<mat-form-field appearance="fill" class="full-width">
|
||||
<mat-label>Netmask</mat-label>
|
||||
<input matInput [(ngModel)]="netmask" placeholder="Netmask" required>
|
||||
</mat-form-field>
|
||||
<mat-form-field appearance="fill" class="full-width">
|
||||
<mat-label>Dirección IP</mat-label>
|
||||
<input matInput [(ngModel)]="ipAddress" placeholder="Dirección IP" required>
|
||||
</mat-form-field>
|
||||
|
||||
<!-- Parámetros Avanzados -->
|
||||
<mat-expansion-panel>
|
||||
<mat-expansion-panel-header>
|
||||
<mat-panel-title>Parámetros avanzados</mat-panel-title>
|
||||
</mat-expansion-panel-header>
|
||||
|
||||
<mat-form-field appearance="fill" class="full-width">
|
||||
<mat-label>Next Server</mat-label>
|
||||
<input matInput [(ngModel)]="nextServer" placeholder="Next Server">
|
||||
</mat-form-field>
|
||||
<mat-form-field appearance="fill" class="full-width">
|
||||
<mat-label>Boot File Name</mat-label>
|
||||
<input matInput [(ngModel)]="bootFileName" placeholder="Boot File Name">
|
||||
</mat-form-field>
|
||||
<mat-form-field appearance="fill" class="full-width">
|
||||
<mat-label>Router</mat-label>
|
||||
<input matInput [(ngModel)]="router" placeholder="Router">
|
||||
</mat-form-field>
|
||||
</mat-expansion-panel>
|
||||
</div>
|
||||
</mat-tab>
|
||||
|
||||
<mat-tab *ngIf="isEditMode" label="Clientes">
|
||||
<mat-list>
|
||||
<ng-container *ngFor="let client of clients">
|
||||
<mat-list-item>
|
||||
<div class="list-item-content">
|
||||
<mat-icon matListItemIcon>computer</mat-icon>
|
||||
<div class="text-content">
|
||||
<div matListItemTitle>{{ client.name }}</div>
|
||||
<div matListItemLine>{{ client.mac }}</div>
|
||||
</div>
|
||||
<div class="icon-container">
|
||||
<button mat-icon-button color="warn" class="right-icon" (click)="deleteClient(client)">
|
||||
<mat-icon>delete</mat-icon>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</mat-list-item>
|
||||
</ng-container>
|
||||
</mat-list>
|
||||
</mat-tab>
|
||||
</mat-tab-group>
|
||||
<mat-divider></mat-divider>
|
||||
<span class="step-title">Parámetros avanzados</span>
|
||||
<mat-form-field appearance="fill" class="full-width">
|
||||
<mat-label>Next Server</mat-label>
|
||||
<input matInput [(ngModel)]="nextServer" placeholder="Next Server">
|
||||
</mat-form-field>
|
||||
<mat-form-field appearance="fill" class="full-width">
|
||||
<mat-label>Boot File Name</mat-label>
|
||||
<input matInput [(ngModel)]="bootFileName" placeholder="Boot File Name">
|
||||
</mat-form-field>
|
||||
<mat-form-field appearance="fill" class="full-width">
|
||||
<mat-label>Router</mat-label>
|
||||
<input matInput [(ngModel)]="router" placeholder="Router">
|
||||
</mat-form-field>
|
||||
</div>
|
||||
</mat-dialog-content>
|
||||
|
||||
<mat-dialog-actions class="action-container">
|
||||
<button class="ordinary-button" (click)="onNoClick()">Cancelar</button>
|
||||
<button class="submit-button" (click)="save()" cdkFocusInitial>Guardar</button>
|
||||
</mat-dialog-actions>
|
||||
</mat-dialog-actions>
|
||||
|
|
|
@ -18,9 +18,7 @@ export class CreateSubnetComponent implements OnInit {
|
|||
nextServer: string = '';
|
||||
bootFileName: string = '';
|
||||
router: string = '';
|
||||
syncronized: boolean = false;
|
||||
serverId: number = 0;
|
||||
clients: any[] = [];
|
||||
isEditMode: boolean = false;
|
||||
|
||||
constructor(
|
||||
|
@ -46,9 +44,7 @@ export class CreateSubnetComponent implements OnInit {
|
|||
this.nextServer = this.data.nextServer;
|
||||
this.bootFileName = this.data.bootFileName;
|
||||
this.router = this.data.router;
|
||||
this.syncronized = this.data.syncronized;
|
||||
this.serverId = this.data.serverId;
|
||||
this.clients = this.data.clients
|
||||
}
|
||||
|
||||
onNoClick(): void {
|
||||
|
@ -69,12 +65,10 @@ export class CreateSubnetComponent implements OnInit {
|
|||
this.http.post(`${this.baseUrl}/subnets`, payload)
|
||||
.subscribe({
|
||||
next: (response) => {
|
||||
console.log('Success:', response);
|
||||
this.toastService.success('Configuración de red añadida exitosamente');
|
||||
this.dialogRef.close();
|
||||
},
|
||||
error: (error) => {
|
||||
console.error('Error:', error);
|
||||
this.toastService.error(error.error['hydra:description']);
|
||||
}
|
||||
});
|
||||
|
@ -82,35 +76,13 @@ export class CreateSubnetComponent implements OnInit {
|
|||
this.http.patch(`${this.baseUrl}/subnets/${this.subnetId}`, payload)
|
||||
.subscribe({
|
||||
next: (response) => {
|
||||
console.log('Success:', response);
|
||||
this.toastService.success('Configuración de red actualizada exitosamente');
|
||||
this.dialogRef.close();
|
||||
},
|
||||
error: (error) => {
|
||||
console.error('Error:', error);
|
||||
this.toastService.error(error.error['hydra:description']);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
deleteClient(client: any): void {
|
||||
const dialogRef = this.dialog.open(DeleteModalComponent, {
|
||||
width: '300px',
|
||||
data: { name: client.name }
|
||||
});
|
||||
|
||||
dialogRef.afterClosed().subscribe(result => {
|
||||
if (result) {
|
||||
this.http.delete(`${this.baseUrl}/og-dhcp/server/${this.subnetId}/delete-host/${client.uuid}`, {}).subscribe({
|
||||
next: () => {
|
||||
this.toastService.success('Cliente eliminado exitosamente');
|
||||
this.dialogRef.close();
|
||||
},
|
||||
error: (error) => {
|
||||
this.toastService.error(error.error['hydra:description']);
|
||||
}
|
||||
});
|
||||
}})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
<app-loading [isLoading]="loading"></app-loading>
|
||||
|
||||
<div class="header-container">
|
||||
<button mat-icon-button color="primary" (click)="iniciarTour()">
|
||||
<mat-icon>help</mat-icon>
|
||||
|
@ -36,13 +38,6 @@
|
|||
<mat-icon matSuffix>search</mat-icon>
|
||||
<mat-hint i18n="@@searchHint">Pulsar 'enter' para buscar</mat-hint>
|
||||
</mat-form-field>
|
||||
<mat-form-field appearance="fill" class="search-string" joyrideStep="searchBootFileStep"
|
||||
text="Busca subredes según el nombre del archivo de arranque.">
|
||||
<mat-label i18n="@@searchLabel">Buscar Boot file name</mat-label>
|
||||
<input matInput placeholder="Búsqueda" [(ngModel)]="filters['bootFileName']" i18n-placeholder="@@searchPlaceholder">
|
||||
<mat-icon matSuffix>search</mat-icon>
|
||||
<mat-hint i18n="@@searchHint">Pulsar 'enter' para buscar</mat-hint>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
|
||||
<app-loading [isLoading]="loading"></app-loading>
|
||||
|
|
|
@ -35,7 +35,7 @@ export interface Subnet {
|
|||
templateUrl: './og-dhcp-subnets.component.html',
|
||||
styleUrls: ['./og-dhcp-subnets.component.css']
|
||||
})
|
||||
export class OgDhcpSubnetsComponent {
|
||||
export class OgDhcpSubnetsComponent implements OnInit {
|
||||
baseUrl: string = import.meta.env.NG_APP_BASE_API_URL;
|
||||
displayedColumns: string[] = ['id', 'name', 'netmask', 'ipAddress', 'synchronized', 'serverId', 'clients', 'actions'];
|
||||
dataSource = new MatTableDataSource<Subnet>([]);
|
||||
|
@ -79,7 +79,7 @@ export class OgDhcpSubnetsComponent {
|
|||
this.length = response['hydra:totalItems'];
|
||||
},
|
||||
error: error => {
|
||||
console.error('Error al cargar plantillas PXE:', error);
|
||||
this.toastService.error(error.error['hydra:description']);
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -94,7 +94,6 @@ export class OgDhcpSubnetsComponent {
|
|||
this.toastService.success('Sincronización con componente DHCP exitosa');
|
||||
this.loadSubnets()
|
||||
}, error => {
|
||||
console.error('Error al sincronizar', error);
|
||||
this.toastService.error('Error al sincronizar');
|
||||
});
|
||||
}
|
||||
|
@ -214,7 +213,7 @@ export class OgDhcpSubnetsComponent {
|
|||
height: '100vh',
|
||||
maxWidth: '100vw',
|
||||
maxHeight: '100vh',
|
||||
data: { subnetId: subnet.id, subnetName: subnet.name }
|
||||
data: { subnetId: subnet.id, subnetName: subnet.name, subnetUuid: subnet.uuid }
|
||||
});
|
||||
|
||||
dialogRef.afterClosed().subscribe(result => {
|
||||
|
@ -224,7 +223,7 @@ export class OgDhcpSubnetsComponent {
|
|||
|
||||
addClientsToSubnet(subnet: Subnet) {
|
||||
const dialogRef = this.dialog.open(AddClientsToSubnetComponent, {
|
||||
width: '600px',
|
||||
width: '800px',
|
||||
data: { subnetUuid: subnet.uuid, subnetName: subnet.name }
|
||||
});
|
||||
|
||||
|
|
|
@ -1,14 +1,34 @@
|
|||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { MatDialogModule, MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog';
|
||||
import {MAT_DIALOG_DATA } from '@angular/material/dialog';
|
||||
import { OperationResultDialogComponent } from './operation-result-dialog.component';
|
||||
import {ShowClientsComponent} from "../show-clients/show-clients.component";
|
||||
import {MatExpansionModule} from "@angular/material/expansion";
|
||||
import {MatIconModule} from "@angular/material/icon";
|
||||
import {MatDividerModule} from "@angular/material/divider";
|
||||
import {MatFormFieldModule} from "@angular/material/form-field";
|
||||
import {MatSelectModule} from "@angular/material/select";
|
||||
import {MatPaginatorModule} from "@angular/material/paginator";
|
||||
import {BrowserAnimationsModule} from "@angular/platform-browser/animations";
|
||||
import {FormsModule} from "@angular/forms";
|
||||
import {MatInputModule} from "@angular/material/input";
|
||||
import {MatDialog, MatDialogModule, MatDialogRef} from "@angular/material/dialog";
|
||||
import {MatTableModule} from "@angular/material/table";
|
||||
import {TranslateModule} from "@ngx-translate/core";
|
||||
import {JoyrideModule} from "ngx-joyride";
|
||||
import {HttpClient} from "@angular/common/http";
|
||||
import {ToastrService} from "ngx-toastr";
|
||||
import {LoadingComponent} from "../../../shared/loading/loading.component";
|
||||
|
||||
describe('OperationResultDialogComponent', () => {
|
||||
let component: OperationResultDialogComponent;
|
||||
let fixture: ComponentFixture<OperationResultDialogComponent>;
|
||||
let component: ShowClientsComponent;
|
||||
let fixture: ComponentFixture<ShowClientsComponent>;
|
||||
let mockDialog: jasmine.SpyObj<MatDialog>;
|
||||
let mockHttpClient: jasmine.SpyObj<HttpClient>;
|
||||
let mockToastrService: jasmine.SpyObj<ToastrService>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [OperationResultDialogComponent],
|
||||
declarations: [OperationResultDialogComponent, LoadingComponent],
|
||||
imports: [MatDialogModule],
|
||||
providers: [
|
||||
{ provide: MatDialogRef, useValue: {} },
|
||||
|
@ -17,7 +37,36 @@ describe('OperationResultDialogComponent', () => {
|
|||
})
|
||||
.compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(OperationResultDialogComponent);
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [ShowClientsComponent],
|
||||
imports: [
|
||||
MatExpansionModule,
|
||||
MatIconModule,
|
||||
MatDividerModule,
|
||||
MatFormFieldModule,
|
||||
MatSelectModule,
|
||||
MatPaginatorModule,
|
||||
BrowserAnimationsModule,
|
||||
FormsModule,
|
||||
MatInputModule,
|
||||
MatDialogModule,
|
||||
MatTableModule,
|
||||
TranslateModule.forRoot(),
|
||||
JoyrideModule.forRoot(),
|
||||
],
|
||||
providers: [
|
||||
{ provide: MatDialog, useValue: mockDialog },
|
||||
{ provide: HttpClient, useValue: mockHttpClient },
|
||||
{ provide: ToastrService, useValue: mockToastrService },
|
||||
{
|
||||
provide: MatDialogRef,
|
||||
useValue: {}
|
||||
},
|
||||
],
|
||||
})
|
||||
.compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(ShowClientsComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
@ -25,4 +74,4 @@ describe('OperationResultDialogComponent', () => {
|
|||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -7,13 +7,6 @@ import {MAT_DIALOG_DATA, MatDialogRef} from "@angular/material/dialog";
|
|||
template: `
|
||||
<h2 mat-dialog-title>Resultado de la operación</h2>
|
||||
<mat-dialog-content>
|
||||
<div class="success-box" *ngIf="data.success.length > 0">
|
||||
<h3>Éxitos</h3>
|
||||
<ul>
|
||||
<li *ngFor="let success of data.success">{{ success.client }} ✅</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="error-box" *ngIf="data.errors.length > 0">
|
||||
<h3>Errores</h3>
|
||||
<ul>
|
||||
|
@ -22,6 +15,12 @@ import {MAT_DIALOG_DATA, MatDialogRef} from "@angular/material/dialog";
|
|||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="success-box" *ngIf="data.success.length > 0">
|
||||
<h3>Éxitos</h3>
|
||||
<ul>
|
||||
<li *ngFor="let success of data.success">{{ success.client }} ✅</li>
|
||||
</ul>
|
||||
</div>
|
||||
</mat-dialog-content>
|
||||
<mat-dialog-actions align="end">
|
||||
<button mat-button color="primary" (click)="close()">Cerrar</button>
|
||||
|
|
|
@ -40,19 +40,6 @@ form {
|
|||
gap: 1em;
|
||||
padding: 1.5em;
|
||||
}
|
||||
.header-container {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 10px 10px;
|
||||
border-bottom: 1px solid #ddd;
|
||||
}
|
||||
|
||||
.header-container-title {
|
||||
flex-grow: 1;
|
||||
text-align: left;
|
||||
margin-left: 1em;
|
||||
}
|
||||
|
||||
.lists-container {
|
||||
padding: 16px;
|
||||
|
@ -68,7 +55,12 @@ form {
|
|||
}
|
||||
|
||||
.search-string {
|
||||
flex: 2;
|
||||
flex: 1;
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
.search-select {
|
||||
flex: 1;
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<app-loading [isLoading]="loading"></app-loading>
|
||||
|
||||
<h2 mat-dialog-title>Buscar clientes en {{data.subnetName}}</h2>
|
||||
<h2 mat-dialog-title>Gestionar clientes en {{data.subnetName}}</h2>
|
||||
|
||||
<mat-dialog-content>
|
||||
<div class="search-container">
|
||||
|
@ -38,6 +38,17 @@
|
|||
</button>
|
||||
<mat-hint i18n="@@searchHint">Pulsar 'enter' para buscar</mat-hint>
|
||||
</mat-form-field>
|
||||
<mat-form-field class="form-field search-select" >
|
||||
<mat-label>Estados</mat-label>
|
||||
<mat-select [(ngModel)]="filters['status']" (selectionChange)="loadData()">
|
||||
<mat-option *ngFor="let option of status" [value]="option.value" >
|
||||
{{ option.name }}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
<button *ngIf="filters['status']" mat-icon-button matSuffix aria-label="Clear tree search" (click)="filters['status'] = ''; loadData()">
|
||||
<mat-icon>close</mat-icon>
|
||||
</button>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
|
||||
<app-loading [isLoading]="loading"></app-loading>
|
||||
|
@ -54,12 +65,25 @@
|
|||
{{ client.ogLive?.date | date }}
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngIf="column.columnDef !== 'status' && column.columnDef !== 'ogLive'">
|
||||
<ng-container *ngIf="column.columnDef === 'organizationalUnit'">
|
||||
{{ client.organizationalUnit?.path }}
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngIf="column.columnDef !== 'status' && column.columnDef !== 'ogLive' && column.columnDef !== 'organizationalUnit'">
|
||||
{{ column.cell(client) }}
|
||||
</ng-container>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="actions">
|
||||
<th mat-header-cell *matHeaderCellDef i18n="@@columnActions" style="text-align: center;">Acciones</th>
|
||||
<td mat-cell *matCellDef="let client" style="text-align: center;">
|
||||
<button mat-icon-button color="warn" (click)="deleteClient(client)">
|
||||
<mat-icon i18n="@@deleteElementTooltip">delete</mat-icon>
|
||||
</button>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
|
||||
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
|
||||
</table>
|
||||
|
@ -70,7 +94,6 @@
|
|||
(page)="onPageChange($event)">
|
||||
</mat-paginator>
|
||||
</div>
|
||||
|
||||
</mat-dialog-content>
|
||||
|
||||
<mat-dialog-actions class="action-container">
|
||||
|
|
|
@ -29,8 +29,6 @@ describe('ShowClientsComponent', () => {
|
|||
mockDialog = jasmine.createSpyObj('MatDialog', ['open']);
|
||||
mockHttpClient = jasmine.createSpyObj('HttpClient', ['get', 'post', 'put', 'delete']);
|
||||
mockToastrService = jasmine.createSpyObj('ToastrService', ['success', 'error']);
|
||||
mockHttpClient.get.and.returnValue(of({ 'hydra:member': [], 'hydra:totalItems': 0 }));
|
||||
mockHttpClient.post.and.returnValue(of({}));
|
||||
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [ShowClientsComponent, LoadingComponent],
|
||||
|
@ -67,4 +65,4 @@ describe('ShowClientsComponent', () => {
|
|||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
import { Component, Inject, OnInit } from '@angular/core';
|
||||
import { ToastrService } from "ngx-toastr";
|
||||
import { HttpClient } from "@angular/common/http";
|
||||
import { MAT_DIALOG_DATA, MatDialog, MatDialogRef } from "@angular/material/dialog";
|
||||
import {MAT_DIALOG_DATA, MatDialog, MatDialogRef} from "@angular/material/dialog";
|
||||
import { MatTableDataSource } from "@angular/material/table";
|
||||
import { Subnet } from "../og-dhcp-subnets.component";
|
||||
import { Client } from "../../groups/model/model";
|
||||
import {DeleteModalComponent} from "../../../shared/delete_modal/delete-modal/delete-modal.component";
|
||||
|
||||
@Component({
|
||||
selector: 'app-show-clients',
|
||||
|
@ -21,16 +21,27 @@ export class ShowClientsComponent implements OnInit {
|
|||
loading: boolean = false;
|
||||
filters: { [key: string]: string } = {};
|
||||
|
||||
protected status = [
|
||||
{value: 'off', name: 'Apagado'},
|
||||
{value: 'initializing', name: 'Inicializando'},
|
||||
{value: 'og-live', name: 'Og Live'},
|
||||
{value: 'linux', name: 'Linux'},
|
||||
{value: 'linux-session', name: 'Linux Session'},
|
||||
{value: 'windows', name: 'Windows'},
|
||||
{value: 'mac', name: 'Mac'},
|
||||
];
|
||||
|
||||
columns = [
|
||||
{ columnDef: 'id', header: 'ID', cell: (client: Client) => client.id },
|
||||
{ columnDef: 'status', header: 'Estado', cell: (client: Client) => client.status },
|
||||
{ columnDef: 'name', header: 'Name', cell: (client: Client) => client.name },
|
||||
{ columnDef: 'ip', header: 'Ip', cell: (client: Client) => client.ip },
|
||||
{ columnDef: 'mac', header: 'Mac', cell: (client: Client) => client.mac },
|
||||
{ columnDef: 'organizationalUnit', header: 'Ruta', cell: (client: Client) => client.organizationalUnit },
|
||||
{ columnDef: 'ogLive', header: 'OgLive', cell: (client: Client) => client.ogLive?.date },
|
||||
];
|
||||
|
||||
displayedColumns: string[] = ['id', 'status', 'name', 'ip', 'mac', 'ogLive'];
|
||||
displayedColumns: string[] = ['id', 'status', 'name', 'ip', 'mac', 'organizationalUnit', 'ogLive', 'actions'];
|
||||
|
||||
constructor(
|
||||
private toastService: ToastrService,
|
||||
|
@ -61,6 +72,26 @@ export class ShowClientsComponent implements OnInit {
|
|||
console.log(this.dataSource.data)
|
||||
}
|
||||
|
||||
deleteClient(client: any): void {
|
||||
const dialogRef = this.dialog.open(DeleteModalComponent, {
|
||||
width: '300px',
|
||||
data: { name: client.name }
|
||||
});
|
||||
|
||||
dialogRef.afterClosed().subscribe(result => {
|
||||
if (result) {
|
||||
this.http.delete(`${this.baseUrl}/og-dhcp/server/${this.data.subnetUuid}/delete-host/${client.uuid}`, {}).subscribe({
|
||||
next: () => {
|
||||
this.toastService.success('Cliente eliminado exitosamente de la red');
|
||||
this.loadData()
|
||||
},
|
||||
error: (error) => {
|
||||
this.toastService.error(error.error['hydra:description']);
|
||||
}
|
||||
});
|
||||
}})
|
||||
}
|
||||
|
||||
onNoClick(): void {
|
||||
this.dialogRef.close();
|
||||
}
|
||||
|
|
|
@ -45,4 +45,4 @@
|
|||
</button>
|
||||
</mat-menu>
|
||||
</div>
|
||||
</mat-toolbar>
|
||||
</mat-toolbar>
|
||||
|
|
|
@ -46,5 +46,5 @@ export class HeaderComponent implements OnInit {
|
|||
width: '400px',
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 778 B |
Loading…
Reference in New Issue