refs #2098. Move clients to different OU
parent
4e6dbde59c
commit
1ce50857ac
|
@ -153,6 +153,7 @@ import { OutputDialogComponent } from './components/task-logs/output-dialog/outp
|
||||||
import { ClientTaskLogsComponent } from './components/task-logs/client-task-logs/client-task-logs.component';
|
import { ClientTaskLogsComponent } from './components/task-logs/client-task-logs/client-task-logs.component';
|
||||||
import { BootSoPartitionComponent } from './components/commands/main-commands/execute-command/boot-so-partition/boot-so-partition.component';
|
import { BootSoPartitionComponent } from './components/commands/main-commands/execute-command/boot-so-partition/boot-so-partition.component';
|
||||||
import { RemoveCacheImageComponent } from './components/commands/main-commands/execute-command/remove-cache-image/remove-cache-image.component';
|
import { RemoveCacheImageComponent } from './components/commands/main-commands/execute-command/remove-cache-image/remove-cache-image.component';
|
||||||
|
import { ChangeParentComponent } from './components/groups/shared/change-parent/change-parent.component';
|
||||||
|
|
||||||
export function HttpLoaderFactory(http: HttpClient) {
|
export function HttpLoaderFactory(http: HttpClient) {
|
||||||
return new TranslateHttpLoader(http, './locale/', '.json');
|
return new TranslateHttpLoader(http, './locale/', '.json');
|
||||||
|
@ -263,7 +264,8 @@ registerLocaleData(localeEs, 'es-ES');
|
||||||
OutputDialogComponent,
|
OutputDialogComponent,
|
||||||
ClientTaskLogsComponent,
|
ClientTaskLogsComponent,
|
||||||
BootSoPartitionComponent,
|
BootSoPartitionComponent,
|
||||||
RemoveCacheImageComponent
|
RemoveCacheImageComponent,
|
||||||
|
ChangeParentComponent
|
||||||
],
|
],
|
||||||
bootstrap: [AppComponent],
|
bootstrap: [AppComponent],
|
||||||
imports: [BrowserModule,
|
imports: [BrowserModule,
|
||||||
|
|
|
@ -33,15 +33,6 @@
|
||||||
<ng-container *ngIf="column.columnDef !== 'commands'">
|
<ng-container *ngIf="column.columnDef !== 'commands'">
|
||||||
{{ column.cell(commandGroup) }}
|
{{ column.cell(commandGroup) }}
|
||||||
</ng-container>
|
</ng-container>
|
||||||
|
|
||||||
<ng-container *ngIf="column.columnDef === 'commands'" joyrideStep="viewCommandsStep" text="{{ 'viewCommandsStepText' | translate }}">
|
|
||||||
<button class="action-button" [matMenuTriggerFor]="menu">{{ 'viewCommands' | translate }}</button>
|
|
||||||
<mat-menu #menu="matMenu">
|
|
||||||
<button mat-menu-item *ngFor="let command of commandGroup.commands">
|
|
||||||
{{ command.name }}
|
|
||||||
</button>
|
|
||||||
</mat-menu>
|
|
||||||
</ng-container>
|
|
||||||
</td>
|
</td>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
|
|
||||||
|
|
|
@ -224,11 +224,16 @@
|
||||||
<strong>{{ selectedNode?.name }}</strong>
|
<strong>{{ selectedNode?.name }}</strong>
|
||||||
</span>
|
</span>
|
||||||
<div class="view-type-container">
|
<div class="view-type-container">
|
||||||
|
<button class="action-button" [disabled]="selection.selected.length === 0" (click)="changeParent($event)"
|
||||||
|
matTooltip="{{ 'moveClientsTooltip' | translate }}" matTooltipShowDelay="1000">
|
||||||
|
{{ 'changeOU' | translate }}
|
||||||
|
</button>
|
||||||
<div joyrideStep="executeCommandStep" text="{{ 'executeCommandStepText' | translate }}">
|
<div joyrideStep="executeCommandStep" text="{{ 'executeCommandStepText' | translate }}">
|
||||||
<app-execute-command [clientData]="selection.selected" [buttonType]="'text'"
|
<app-execute-command [clientData]="selection.selected" [buttonType]="'text'"
|
||||||
[buttonText]="'ejecutarComandos' | translate" [disabled]="selection.selected.length === 0"
|
[buttonText]="'ejecutarComandos' | translate" [disabled]="selection.selected.length === 0"
|
||||||
[runScriptContext]="getRunScriptContext(selection.selected)"></app-execute-command>
|
[runScriptContext]="getRunScriptContext(selection.selected)"></app-execute-command>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<mat-button-toggle-group name="viewType" aria-label="View Type" [hideSingleSelectionIndicator]="true"
|
<mat-button-toggle-group name="viewType" aria-label="View Type" [hideSingleSelectionIndicator]="true"
|
||||||
(change)="toggleView($event.value)" joyrideStep="tabsStep" text="{{ 'tabsStepText' | translate }}">
|
(change)="toggleView($event.value)" joyrideStep="tabsStep" text="{{ 'tabsStepText' | translate }}">
|
||||||
<mat-button-toggle value="list" [disabled]="currentView === 'list'">
|
<mat-button-toggle value="list" [disabled]="currentView === 'list'">
|
||||||
|
|
|
@ -29,6 +29,7 @@ import { MatMenuTrigger } from '@angular/material/menu';
|
||||||
import { ClientDetailsComponent } from './shared/client-details/client-details.component';
|
import { ClientDetailsComponent } from './shared/client-details/client-details.component';
|
||||||
import { PartitionTypeOrganizatorComponent } from './shared/partition-type-organizator/partition-type-organizator.component';
|
import { PartitionTypeOrganizatorComponent } from './shared/partition-type-organizator/partition-type-organizator.component';
|
||||||
import { ClientTaskLogsComponent } from '../task-logs/client-task-logs/client-task-logs.component';
|
import { ClientTaskLogsComponent } from '../task-logs/client-task-logs/client-task-logs.component';
|
||||||
|
import {ChangeParentComponent} from "./shared/change-parent/change-parent.component";
|
||||||
|
|
||||||
enum NodeType {
|
enum NodeType {
|
||||||
OrganizationalUnit = 'organizational-unit',
|
OrganizationalUnit = 'organizational-unit',
|
||||||
|
@ -864,6 +865,21 @@ export class GroupsComponent implements OnInit, OnDestroy {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
changeParent(event: MouseEvent, ): void {
|
||||||
|
event.stopPropagation();
|
||||||
|
|
||||||
|
const dialogRef = this.dialog.open(ChangeParentComponent, {
|
||||||
|
data: { clients: this.selection.selected },
|
||||||
|
width: '700px',
|
||||||
|
});
|
||||||
|
|
||||||
|
dialogRef.afterClosed().subscribe((result) => {
|
||||||
|
if (result) {
|
||||||
|
this.refreshData();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
openClientTaskLogs(event: MouseEvent, client: Client): void {
|
openClientTaskLogs(event: MouseEvent, client: Client): void {
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,39 @@
|
||||||
|
.loading-container {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
height: 100px;
|
||||||
|
}
|
||||||
|
|
||||||
|
mat-form-field {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
mat-dialog-actions {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
}
|
||||||
|
|
||||||
|
.checkbox-group {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.selected-list ul {
|
||||||
|
list-style: none;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.selected-item {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between; /* Alinea texto a la izquierda y botón a la derecha */
|
||||||
|
align-items: center; /* Centra verticalmente */
|
||||||
|
padding: 8px;
|
||||||
|
border-bottom: 1px solid #ccc;
|
||||||
|
}
|
||||||
|
|
||||||
|
.selected-item button {
|
||||||
|
margin-left: 10px;
|
||||||
|
}
|
|
@ -0,0 +1,15 @@
|
||||||
|
<h2 mat-dialog-title>Mover clientes a:</h2>
|
||||||
|
|
||||||
|
<mat-dialog-content>
|
||||||
|
<mat-form-field appearance="fill" class="full-width">
|
||||||
|
<mat-label>Seleccione aula</mat-label>
|
||||||
|
<mat-select [(ngModel)]="newOU">
|
||||||
|
<mat-option *ngFor="let unit of units" [value]="unit">{{ unit.name }}</mat-option>
|
||||||
|
</mat-select>
|
||||||
|
</mat-form-field>
|
||||||
|
</mat-dialog-content>
|
||||||
|
|
||||||
|
<div class="action-container">
|
||||||
|
<button class="ordinary-button" (click)="close()">Cancelar</button>
|
||||||
|
<button class="submit-button" (click)="save()" [disabled]="!newOU">Continuar</button>
|
||||||
|
</div>
|
|
@ -0,0 +1,23 @@
|
||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { ChangeParentComponent } from './change-parent.component';
|
||||||
|
|
||||||
|
describe('ChangeParentComponent', () => {
|
||||||
|
let component: ChangeParentComponent;
|
||||||
|
let fixture: ComponentFixture<ChangeParentComponent>;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
declarations: [ChangeParentComponent]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
|
||||||
|
fixture = TestBed.createComponent(ChangeParentComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,63 @@
|
||||||
|
import {Component, Inject, OnInit} from '@angular/core';
|
||||||
|
import {HttpClient} from "@angular/common/http";
|
||||||
|
import {MAT_DIALOG_DATA, MatDialogRef} from "@angular/material/dialog";
|
||||||
|
import {ToastrService} from "ngx-toastr";
|
||||||
|
import {Router} from "@angular/router";
|
||||||
|
import {ConfigService} from "@services/config.service";
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-change-parent',
|
||||||
|
templateUrl: './change-parent.component.html',
|
||||||
|
styleUrl: './change-parent.component.css'
|
||||||
|
})
|
||||||
|
export class ChangeParentComponent implements OnInit {
|
||||||
|
baseUrl: string;
|
||||||
|
loading: boolean = true;
|
||||||
|
units: any[] = [];
|
||||||
|
newOU: any;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private http: HttpClient,
|
||||||
|
public dialogRef: MatDialogRef<ChangeParentComponent>,
|
||||||
|
private toastService: ToastrService,
|
||||||
|
private router: Router,
|
||||||
|
private configService: ConfigService,
|
||||||
|
@Inject(MAT_DIALOG_DATA) public data: { clients: any}
|
||||||
|
) {
|
||||||
|
this.baseUrl = this.configService.apiUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
this.loading = true;
|
||||||
|
this.loadUnits();
|
||||||
|
}
|
||||||
|
|
||||||
|
loadUnits() {
|
||||||
|
this.http.get<any>(`${this.baseUrl}/organizational-units?page=1&itemsPerPage=500`).subscribe(
|
||||||
|
response => {
|
||||||
|
this.units = response['hydra:member'];
|
||||||
|
this.loading = false;
|
||||||
|
},
|
||||||
|
error => console.error('Error fetching organizational units:', error)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
save() {
|
||||||
|
this.http.post<any>(`${this.baseUrl}/clients/change-organizational-unit`, {
|
||||||
|
clients: this.data.clients.map((client: any) => client['@id']),
|
||||||
|
organizationalUnit: this.newOU['@id']
|
||||||
|
}).subscribe({
|
||||||
|
next: (response) => {
|
||||||
|
this.toastService.success('Parent changed successfully');
|
||||||
|
this.dialogRef.close(true);
|
||||||
|
},
|
||||||
|
error: error => {
|
||||||
|
this.toastService.error(error.error['hydra:description']);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
close() {
|
||||||
|
this.dialogRef.close();
|
||||||
|
}
|
||||||
|
}
|
|
@ -517,6 +517,8 @@
|
||||||
"hardwareInventory": "Hardware Inventory",
|
"hardwareInventory": "Hardware Inventory",
|
||||||
"runScript": "Run Script"
|
"runScript": "Run Script"
|
||||||
},
|
},
|
||||||
|
"changeOU": "Change Organizational Unit",
|
||||||
|
"moveClientsTooltip": "Move clients to another organizational unit",
|
||||||
"remoteAccess": "Remote access available",
|
"remoteAccess": "Remote access available",
|
||||||
"noRemoteAccess": "Remote access not available",
|
"noRemoteAccess": "Remote access not available",
|
||||||
"capacityWarning": "The capacity cannot be negative",
|
"capacityWarning": "The capacity cannot be negative",
|
||||||
|
|
|
@ -518,6 +518,8 @@
|
||||||
"hardwareInventory": "Inventario Hardware",
|
"hardwareInventory": "Inventario Hardware",
|
||||||
"runScript": "Ejecutar script"
|
"runScript": "Ejecutar script"
|
||||||
},
|
},
|
||||||
|
"changeOU": "Mover clientes",
|
||||||
|
"moveClientsTooltip": "Mover clientes a otra unidad organizativa",
|
||||||
"remoteAccess": "Disponible acceso remoto",
|
"remoteAccess": "Disponible acceso remoto",
|
||||||
"noRemoteAccess": "No disponible acceso remoto",
|
"noRemoteAccess": "No disponible acceso remoto",
|
||||||
"capacityWarning": "El aforo no puede ser",
|
"capacityWarning": "El aforo no puede ser",
|
||||||
|
|
Loading…
Reference in New Issue