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-option>
|
||||||
</mat-select>
|
</mat-select>
|
||||||
</mat-form-field>
|
</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>
|
</form>
|
||||||
</mat-dialog-content>
|
</mat-dialog-content>
|
||||||
<mat-dialog-actions class="action-container">
|
<mat-dialog-actions class="action-container">
|
||||||
|
|
|
@ -24,6 +24,11 @@ export class AddUserModalComponent implements OnInit {
|
||||||
organizationalUnits: any[] = [];
|
organizationalUnits: any[] = [];
|
||||||
userId: string | null = null;
|
userId: string | null = null;
|
||||||
|
|
||||||
|
protected views = [
|
||||||
|
{value: 'card', name: 'Tarjetas'},
|
||||||
|
{value: 'list', name: 'Listado'},
|
||||||
|
];
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
public dialogRef: MatDialogRef<AddUserModalComponent>,
|
public dialogRef: MatDialogRef<AddUserModalComponent>,
|
||||||
@Inject(MAT_DIALOG_DATA) public data: any,
|
@Inject(MAT_DIALOG_DATA) public data: any,
|
||||||
|
@ -36,6 +41,7 @@ export class AddUserModalComponent implements OnInit {
|
||||||
username: ['', Validators.required],
|
username: ['', Validators.required],
|
||||||
password: ['', Validators.required],
|
password: ['', Validators.required],
|
||||||
role: ['', Validators.required],
|
role: ['', Validators.required],
|
||||||
|
groupsView: ['card', Validators.required],
|
||||||
organizationalUnits: [[]]
|
organizationalUnits: [[]]
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -55,15 +61,14 @@ export class AddUserModalComponent implements OnInit {
|
||||||
load(): void {
|
load(): void {
|
||||||
this.dataService.getUser(this.data).subscribe({
|
this.dataService.getUser(this.data).subscribe({
|
||||||
next: (response) => {
|
next: (response) => {
|
||||||
console.log(response);
|
|
||||||
|
|
||||||
const organizationalUnitIds = response.allowedOrganizationalUnits.map((unit: any) => unit['@id']);
|
const organizationalUnitIds = response.allowedOrganizationalUnits.map((unit: any) => unit['@id']);
|
||||||
|
|
||||||
// Patch the values to the form
|
|
||||||
this.userForm.patchValue({
|
this.userForm.patchValue({
|
||||||
username: response.username,
|
username: response.username,
|
||||||
role: response.userGroups[0]['@id'],
|
role: response.userGroups.length > 0 ? response.userGroups[0]['@id'] : null,
|
||||||
organizationalUnits: organizationalUnitIds
|
organizationalUnits: organizationalUnitIds,
|
||||||
|
groupsView: response.groupsView
|
||||||
});
|
});
|
||||||
|
|
||||||
this.userId = response['@id'];
|
this.userId = response['@id'];
|
||||||
|
@ -85,7 +90,8 @@ export class AddUserModalComponent implements OnInit {
|
||||||
allowedOrganizationalUnits: this.userForm.value.organizationalUnit,
|
allowedOrganizationalUnits: this.userForm.value.organizationalUnit,
|
||||||
password: this.userForm.value.password,
|
password: this.userForm.value.password,
|
||||||
enabled: true,
|
enabled: true,
|
||||||
userGroups: [this.userForm.value.role ]
|
userGroups: [this.userForm.value.role ],
|
||||||
|
groupsView: this.userForm.value.groupsView
|
||||||
};
|
};
|
||||||
|
|
||||||
if (this.userId) {
|
if (this.userId) {
|
||||||
|
|
|
@ -32,6 +32,11 @@ export class UsersComponent implements OnInit {
|
||||||
header: 'Nombre de Usuario',
|
header: 'Nombre de Usuario',
|
||||||
cell: (user: any) => `${user.username}`
|
cell: (user: any) => `${user.username}`
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
columnDef: 'groupsView',
|
||||||
|
header: 'Vista de Grupos',
|
||||||
|
cell: (user: any) => `${user.groupsView}`
|
||||||
|
},
|
||||||
{
|
{
|
||||||
columnDef: 'allowedOrganizationalUnits',
|
columnDef: 'allowedOrganizationalUnits',
|
||||||
header: 'Unidades Organizacionales Permitidas',
|
header: 'Unidades Organizacionales Permitidas',
|
||||||
|
|
|
@ -27,3 +27,16 @@ mat-dialog-actions {
|
||||||
gap: 1em;
|
gap: 1em;
|
||||||
padding: 1.5em;
|
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>
|
<h2 mat-dialog-title>Añade clientes a {{data.subnetName}}</h2>
|
||||||
|
|
||||||
<mat-dialog-content>
|
<mat-dialog-content>
|
||||||
|
@ -10,7 +12,12 @@
|
||||||
|
|
||||||
<div class="checkbox-group">
|
<div class="checkbox-group">
|
||||||
<label>Clientes</label>
|
<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"
|
<mat-checkbox *ngFor="let client of clients"
|
||||||
(change)="toggleClientSelection(client.uuid)"
|
(change)="toggleClientSelection(client.uuid)"
|
||||||
[checked]="selectedClients.includes(client.uuid)">
|
[checked]="selectedClients.includes(client.uuid)">
|
||||||
|
|
|
@ -18,6 +18,7 @@ export class AddClientsToSubnetComponent implements OnInit {
|
||||||
loading: boolean = true;
|
loading: boolean = true;
|
||||||
unitControl = new FormControl();
|
unitControl = new FormControl();
|
||||||
childUnitControl = new FormControl();
|
childUnitControl = new FormControl();
|
||||||
|
allSelected: boolean = false;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private http: HttpClient,
|
private http: HttpClient,
|
||||||
|
@ -43,7 +44,7 @@ export class AddClientsToSubnetComponent implements OnInit {
|
||||||
}
|
}
|
||||||
|
|
||||||
loadChildUnits(event: any) {
|
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 => {
|
response => {
|
||||||
this.clients = response['hydra:member'];
|
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() {
|
save() {
|
||||||
|
this.loading = true;
|
||||||
const postData = { clients: this.selectedClients.map(clientId => `/clients/${clientId}`) };
|
const postData = { clients: this.selectedClients.map(clientId => `/clients/${clientId}`) };
|
||||||
|
|
||||||
this.http.post(`${this.baseUrl}/og-dhcp/server/${this.data.subnetUuid}/post-host`, postData).subscribe(
|
this.http.post(`${this.baseUrl}/og-dhcp/server/${this.data.subnetUuid}/post-host`, postData).subscribe(
|
||||||
(response: any) => {
|
(response: any) => {
|
||||||
this.dialog.open(OperationResultDialogComponent, {
|
this.dialog.open(OperationResultDialogComponent, {
|
||||||
width: '600px',
|
width: '800px',
|
||||||
data: {
|
data: {
|
||||||
success: response.success || [],
|
success: response.success || [],
|
||||||
errors: response.errors || []
|
errors: response.errors || []
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.loading = false;
|
||||||
this.dialogRef.close(this.selectedClients);
|
this.dialogRef.close(this.selectedClients);
|
||||||
},
|
},
|
||||||
error => {
|
error => {
|
||||||
console.error(`Error al asignar el cliente:`, error);
|
|
||||||
this.toastService.error(`Error al asignar el cliente: ${error.error['hydra:description']}`);
|
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() {
|
close() {
|
||||||
this.dialogRef.close();
|
this.dialogRef.close();
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,3 +40,10 @@ form {
|
||||||
gap: 1em;
|
gap: 1em;
|
||||||
padding: 1.5em;
|
padding: 1.5em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.step-title {
|
||||||
|
font-family: 'Roboto', sans-serif;
|
||||||
|
color: #3f51b5;
|
||||||
|
margin: 40px 0 15px 0;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
<h2 mat-dialog-title>{{ isEditMode ? 'Editar' : 'Añadir' }} subred</h2>
|
<h2 mat-dialog-title>{{ isEditMode ? 'Editar' : 'Añadir' }} subred</h2>
|
||||||
|
|
||||||
<mat-dialog-content>
|
<mat-dialog-content>
|
||||||
<mat-tab-group>
|
|
||||||
<mat-tab label="Subred">
|
|
||||||
<div class="spacing-container">
|
<div class="spacing-container">
|
||||||
<mat-form-field appearance="fill" class="full-width">
|
<mat-form-field appearance="fill" class="full-width">
|
||||||
<mat-label>Nombre</mat-label>
|
<mat-label>Nombre</mat-label>
|
||||||
|
@ -17,12 +15,8 @@
|
||||||
<input matInput [(ngModel)]="ipAddress" placeholder="Dirección IP" required>
|
<input matInput [(ngModel)]="ipAddress" placeholder="Dirección IP" required>
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
|
|
||||||
<!-- Parámetros Avanzados -->
|
<mat-divider></mat-divider>
|
||||||
<mat-expansion-panel>
|
<span class="step-title">Parámetros avanzados</span>
|
||||||
<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-form-field appearance="fill" class="full-width">
|
||||||
<mat-label>Next Server</mat-label>
|
<mat-label>Next Server</mat-label>
|
||||||
<input matInput [(ngModel)]="nextServer" placeholder="Next Server">
|
<input matInput [(ngModel)]="nextServer" placeholder="Next Server">
|
||||||
|
@ -35,31 +29,7 @@
|
||||||
<mat-label>Router</mat-label>
|
<mat-label>Router</mat-label>
|
||||||
<input matInput [(ngModel)]="router" placeholder="Router">
|
<input matInput [(ngModel)]="router" placeholder="Router">
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
</mat-expansion-panel>
|
|
||||||
</div>
|
</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-dialog-content>
|
</mat-dialog-content>
|
||||||
|
|
||||||
<mat-dialog-actions class="action-container">
|
<mat-dialog-actions class="action-container">
|
||||||
|
|
|
@ -18,9 +18,7 @@ export class CreateSubnetComponent implements OnInit {
|
||||||
nextServer: string = '';
|
nextServer: string = '';
|
||||||
bootFileName: string = '';
|
bootFileName: string = '';
|
||||||
router: string = '';
|
router: string = '';
|
||||||
syncronized: boolean = false;
|
|
||||||
serverId: number = 0;
|
serverId: number = 0;
|
||||||
clients: any[] = [];
|
|
||||||
isEditMode: boolean = false;
|
isEditMode: boolean = false;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
|
@ -46,9 +44,7 @@ export class CreateSubnetComponent implements OnInit {
|
||||||
this.nextServer = this.data.nextServer;
|
this.nextServer = this.data.nextServer;
|
||||||
this.bootFileName = this.data.bootFileName;
|
this.bootFileName = this.data.bootFileName;
|
||||||
this.router = this.data.router;
|
this.router = this.data.router;
|
||||||
this.syncronized = this.data.syncronized;
|
|
||||||
this.serverId = this.data.serverId;
|
this.serverId = this.data.serverId;
|
||||||
this.clients = this.data.clients
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onNoClick(): void {
|
onNoClick(): void {
|
||||||
|
@ -69,12 +65,10 @@ export class CreateSubnetComponent implements OnInit {
|
||||||
this.http.post(`${this.baseUrl}/subnets`, payload)
|
this.http.post(`${this.baseUrl}/subnets`, payload)
|
||||||
.subscribe({
|
.subscribe({
|
||||||
next: (response) => {
|
next: (response) => {
|
||||||
console.log('Success:', response);
|
|
||||||
this.toastService.success('Configuración de red añadida exitosamente');
|
this.toastService.success('Configuración de red añadida exitosamente');
|
||||||
this.dialogRef.close();
|
this.dialogRef.close();
|
||||||
},
|
},
|
||||||
error: (error) => {
|
error: (error) => {
|
||||||
console.error('Error:', error);
|
|
||||||
this.toastService.error(error.error['hydra:description']);
|
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)
|
this.http.patch(`${this.baseUrl}/subnets/${this.subnetId}`, payload)
|
||||||
.subscribe({
|
.subscribe({
|
||||||
next: (response) => {
|
next: (response) => {
|
||||||
console.log('Success:', response);
|
|
||||||
this.toastService.success('Configuración de red actualizada exitosamente');
|
this.toastService.success('Configuración de red actualizada exitosamente');
|
||||||
this.dialogRef.close();
|
this.dialogRef.close();
|
||||||
},
|
},
|
||||||
error: (error) => {
|
error: (error) => {
|
||||||
console.error('Error:', error);
|
|
||||||
this.toastService.error(error.error['hydra:description']);
|
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">
|
<div class="header-container">
|
||||||
<button mat-icon-button color="primary" (click)="iniciarTour()">
|
<button mat-icon-button color="primary" (click)="iniciarTour()">
|
||||||
<mat-icon>help</mat-icon>
|
<mat-icon>help</mat-icon>
|
||||||
|
@ -36,13 +38,6 @@
|
||||||
<mat-icon matSuffix>search</mat-icon>
|
<mat-icon matSuffix>search</mat-icon>
|
||||||
<mat-hint i18n="@@searchHint">Pulsar 'enter' para buscar</mat-hint>
|
<mat-hint i18n="@@searchHint">Pulsar 'enter' para buscar</mat-hint>
|
||||||
</mat-form-field>
|
</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>
|
</div>
|
||||||
|
|
||||||
<app-loading [isLoading]="loading"></app-loading>
|
<app-loading [isLoading]="loading"></app-loading>
|
||||||
|
|
|
@ -35,7 +35,7 @@ export interface Subnet {
|
||||||
templateUrl: './og-dhcp-subnets.component.html',
|
templateUrl: './og-dhcp-subnets.component.html',
|
||||||
styleUrls: ['./og-dhcp-subnets.component.css']
|
styleUrls: ['./og-dhcp-subnets.component.css']
|
||||||
})
|
})
|
||||||
export class OgDhcpSubnetsComponent {
|
export class OgDhcpSubnetsComponent implements OnInit {
|
||||||
baseUrl: string = import.meta.env.NG_APP_BASE_API_URL;
|
baseUrl: string = import.meta.env.NG_APP_BASE_API_URL;
|
||||||
displayedColumns: string[] = ['id', 'name', 'netmask', 'ipAddress', 'synchronized', 'serverId', 'clients', 'actions'];
|
displayedColumns: string[] = ['id', 'name', 'netmask', 'ipAddress', 'synchronized', 'serverId', 'clients', 'actions'];
|
||||||
dataSource = new MatTableDataSource<Subnet>([]);
|
dataSource = new MatTableDataSource<Subnet>([]);
|
||||||
|
@ -79,7 +79,7 @@ export class OgDhcpSubnetsComponent {
|
||||||
this.length = response['hydra:totalItems'];
|
this.length = response['hydra:totalItems'];
|
||||||
},
|
},
|
||||||
error: error => {
|
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.toastService.success('Sincronización con componente DHCP exitosa');
|
||||||
this.loadSubnets()
|
this.loadSubnets()
|
||||||
}, error => {
|
}, error => {
|
||||||
console.error('Error al sincronizar', error);
|
|
||||||
this.toastService.error('Error al sincronizar');
|
this.toastService.error('Error al sincronizar');
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -214,7 +213,7 @@ export class OgDhcpSubnetsComponent {
|
||||||
height: '100vh',
|
height: '100vh',
|
||||||
maxWidth: '100vw',
|
maxWidth: '100vw',
|
||||||
maxHeight: '100vh',
|
maxHeight: '100vh',
|
||||||
data: { subnetId: subnet.id, subnetName: subnet.name }
|
data: { subnetId: subnet.id, subnetName: subnet.name, subnetUuid: subnet.uuid }
|
||||||
});
|
});
|
||||||
|
|
||||||
dialogRef.afterClosed().subscribe(result => {
|
dialogRef.afterClosed().subscribe(result => {
|
||||||
|
@ -224,7 +223,7 @@ export class OgDhcpSubnetsComponent {
|
||||||
|
|
||||||
addClientsToSubnet(subnet: Subnet) {
|
addClientsToSubnet(subnet: Subnet) {
|
||||||
const dialogRef = this.dialog.open(AddClientsToSubnetComponent, {
|
const dialogRef = this.dialog.open(AddClientsToSubnetComponent, {
|
||||||
width: '600px',
|
width: '800px',
|
||||||
data: { subnetUuid: subnet.uuid, subnetName: subnet.name }
|
data: { subnetUuid: subnet.uuid, subnetName: subnet.name }
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -1,14 +1,34 @@
|
||||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
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 { 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', () => {
|
describe('OperationResultDialogComponent', () => {
|
||||||
let component: OperationResultDialogComponent;
|
let component: ShowClientsComponent;
|
||||||
let fixture: ComponentFixture<OperationResultDialogComponent>;
|
let fixture: ComponentFixture<ShowClientsComponent>;
|
||||||
|
let mockDialog: jasmine.SpyObj<MatDialog>;
|
||||||
|
let mockHttpClient: jasmine.SpyObj<HttpClient>;
|
||||||
|
let mockToastrService: jasmine.SpyObj<ToastrService>;
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
await TestBed.configureTestingModule({
|
await TestBed.configureTestingModule({
|
||||||
declarations: [OperationResultDialogComponent],
|
declarations: [OperationResultDialogComponent, LoadingComponent],
|
||||||
imports: [MatDialogModule],
|
imports: [MatDialogModule],
|
||||||
providers: [
|
providers: [
|
||||||
{ provide: MatDialogRef, useValue: {} },
|
{ provide: MatDialogRef, useValue: {} },
|
||||||
|
@ -17,7 +37,36 @@ describe('OperationResultDialogComponent', () => {
|
||||||
})
|
})
|
||||||
.compileComponents();
|
.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;
|
component = fixture.componentInstance;
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
});
|
});
|
||||||
|
|
|
@ -7,13 +7,6 @@ import {MAT_DIALOG_DATA, MatDialogRef} from "@angular/material/dialog";
|
||||||
template: `
|
template: `
|
||||||
<h2 mat-dialog-title>Resultado de la operación</h2>
|
<h2 mat-dialog-title>Resultado de la operación</h2>
|
||||||
<mat-dialog-content>
|
<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">
|
<div class="error-box" *ngIf="data.errors.length > 0">
|
||||||
<h3>Errores</h3>
|
<h3>Errores</h3>
|
||||||
<ul>
|
<ul>
|
||||||
|
@ -22,6 +15,12 @@ import {MAT_DIALOG_DATA, MatDialogRef} from "@angular/material/dialog";
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</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-content>
|
||||||
<mat-dialog-actions align="end">
|
<mat-dialog-actions align="end">
|
||||||
<button mat-button color="primary" (click)="close()">Cerrar</button>
|
<button mat-button color="primary" (click)="close()">Cerrar</button>
|
||||||
|
|
|
@ -40,19 +40,6 @@ form {
|
||||||
gap: 1em;
|
gap: 1em;
|
||||||
padding: 1.5em;
|
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 {
|
.lists-container {
|
||||||
padding: 16px;
|
padding: 16px;
|
||||||
|
@ -68,7 +55,12 @@ form {
|
||||||
}
|
}
|
||||||
|
|
||||||
.search-string {
|
.search-string {
|
||||||
flex: 2;
|
flex: 1;
|
||||||
|
padding: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-select {
|
||||||
|
flex: 1;
|
||||||
padding: 5px;
|
padding: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<app-loading [isLoading]="loading"></app-loading>
|
<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>
|
<mat-dialog-content>
|
||||||
<div class="search-container">
|
<div class="search-container">
|
||||||
|
@ -38,6 +38,17 @@
|
||||||
</button>
|
</button>
|
||||||
<mat-hint i18n="@@searchHint">Pulsar 'enter' para buscar</mat-hint>
|
<mat-hint i18n="@@searchHint">Pulsar 'enter' para buscar</mat-hint>
|
||||||
</mat-form-field>
|
</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>
|
</div>
|
||||||
|
|
||||||
<app-loading [isLoading]="loading"></app-loading>
|
<app-loading [isLoading]="loading"></app-loading>
|
||||||
|
@ -54,12 +65,25 @@
|
||||||
{{ client.ogLive?.date | date }}
|
{{ client.ogLive?.date | date }}
|
||||||
</ng-container>
|
</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) }}
|
{{ column.cell(client) }}
|
||||||
</ng-container>
|
</ng-container>
|
||||||
</td>
|
</td>
|
||||||
</ng-container>
|
</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-header-row *matHeaderRowDef="displayedColumns"></tr>
|
||||||
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
|
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
|
||||||
</table>
|
</table>
|
||||||
|
@ -70,7 +94,6 @@
|
||||||
(page)="onPageChange($event)">
|
(page)="onPageChange($event)">
|
||||||
</mat-paginator>
|
</mat-paginator>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</mat-dialog-content>
|
</mat-dialog-content>
|
||||||
|
|
||||||
<mat-dialog-actions class="action-container">
|
<mat-dialog-actions class="action-container">
|
||||||
|
|
|
@ -29,8 +29,6 @@ describe('ShowClientsComponent', () => {
|
||||||
mockDialog = jasmine.createSpyObj('MatDialog', ['open']);
|
mockDialog = jasmine.createSpyObj('MatDialog', ['open']);
|
||||||
mockHttpClient = jasmine.createSpyObj('HttpClient', ['get', 'post', 'put', 'delete']);
|
mockHttpClient = jasmine.createSpyObj('HttpClient', ['get', 'post', 'put', 'delete']);
|
||||||
mockToastrService = jasmine.createSpyObj('ToastrService', ['success', 'error']);
|
mockToastrService = jasmine.createSpyObj('ToastrService', ['success', 'error']);
|
||||||
mockHttpClient.get.and.returnValue(of({ 'hydra:member': [], 'hydra:totalItems': 0 }));
|
|
||||||
mockHttpClient.post.and.returnValue(of({}));
|
|
||||||
|
|
||||||
await TestBed.configureTestingModule({
|
await TestBed.configureTestingModule({
|
||||||
declarations: [ShowClientsComponent, LoadingComponent],
|
declarations: [ShowClientsComponent, LoadingComponent],
|
||||||
|
|
|
@ -3,8 +3,8 @@ import { ToastrService } from "ngx-toastr";
|
||||||
import { HttpClient } from "@angular/common/http";
|
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 { MatTableDataSource } from "@angular/material/table";
|
||||||
import { Subnet } from "../og-dhcp-subnets.component";
|
|
||||||
import { Client } from "../../groups/model/model";
|
import { Client } from "../../groups/model/model";
|
||||||
|
import {DeleteModalComponent} from "../../../shared/delete_modal/delete-modal/delete-modal.component";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-show-clients',
|
selector: 'app-show-clients',
|
||||||
|
@ -21,16 +21,27 @@ export class ShowClientsComponent implements OnInit {
|
||||||
loading: boolean = false;
|
loading: boolean = false;
|
||||||
filters: { [key: string]: string } = {};
|
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 = [
|
columns = [
|
||||||
{ columnDef: 'id', header: 'ID', cell: (client: Client) => client.id },
|
{ columnDef: 'id', header: 'ID', cell: (client: Client) => client.id },
|
||||||
{ columnDef: 'status', header: 'Estado', cell: (client: Client) => client.status },
|
{ columnDef: 'status', header: 'Estado', cell: (client: Client) => client.status },
|
||||||
{ columnDef: 'name', header: 'Name', cell: (client: Client) => client.name },
|
{ columnDef: 'name', header: 'Name', cell: (client: Client) => client.name },
|
||||||
{ columnDef: 'ip', header: 'Ip', cell: (client: Client) => client.ip },
|
{ columnDef: 'ip', header: 'Ip', cell: (client: Client) => client.ip },
|
||||||
{ columnDef: 'mac', header: 'Mac', cell: (client: Client) => client.mac },
|
{ 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 },
|
{ 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(
|
constructor(
|
||||||
private toastService: ToastrService,
|
private toastService: ToastrService,
|
||||||
|
@ -61,6 +72,26 @@ export class ShowClientsComponent implements OnInit {
|
||||||
console.log(this.dataSource.data)
|
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 {
|
onNoClick(): void {
|
||||||
this.dialogRef.close();
|
this.dialogRef.close();
|
||||||
}
|
}
|
||||||
|
|
Binary file not shown.
After Width: | Height: | Size: 778 B |
Loading…
Reference in New Issue