[ogGui-495] Creación de filtros y vistas #6

Merged
apuente merged 14 commits from oggui/responsive into main 2024-08-12 14:18:27 +02:00
50 changed files with 1654 additions and 518 deletions

View File

@ -4,6 +4,12 @@
"newProjectRoot": "projects", "newProjectRoot": "projects",
"projects": { "projects": {
"ogWebconsole": { "ogWebconsole": {
"i18n": {
"sourceLocale": "es",
"locales": {
"en-US": "src/locale/messages.en.json"
}
},
"projectType": "application", "projectType": "application",
"schematics": { "schematics": {
"@schematics/angular:component": { "@schematics/angular:component": {
@ -23,11 +29,14 @@
"build": { "build": {
"builder": "@angular-devkit/build-angular:application", "builder": "@angular-devkit/build-angular:application",
"options": { "options": {
"localize": true,
"aot": true,
"outputPath": "dist/og-webconsole", "outputPath": "dist/og-webconsole",
"index": "src/index.html", "index": "src/index.html",
"browser": "src/main.ts", "browser": "src/main.ts",
"polyfills": [ "polyfills": [
"zone.js" "zone.js",
"@angular/localize/init"
], ],
"tsConfig": "tsconfig.app.json", "tsConfig": "tsconfig.app.json",
"assets": [ "assets": [
@ -61,6 +70,12 @@
"optimization": false, "optimization": false,
"extractLicenses": false, "extractLicenses": false,
"sourceMap": true "sourceMap": true
},
"es": {
"localize": ["es-ES"]
},
"en": {
"localize": ["en-US"]
} }
}, },
"defaultConfiguration": "production" "defaultConfiguration": "production"
@ -73,6 +88,12 @@
}, },
"development": { "development": {
"buildTarget": "ogWebconsole:build:development" "buildTarget": "ogWebconsole:build:development"
},
"es": {
"buildTarget": "ogWebconsole:build:es"
},
"en": {
"buildTarget": "ogWebconsole:build:en"
} }
}, },
"defaultConfiguration": "development" "defaultConfiguration": "development"
@ -88,7 +109,8 @@
"options": { "options": {
"polyfills": [ "polyfills": [
"zone.js", "zone.js",
"zone.js/testing" "zone.js/testing",
"@angular/localize/init"
], ],
"tsConfig": "tsconfig.spec.json", "tsConfig": "tsconfig.spec.json",
"assets": [ "assets": [

View File

@ -28,6 +28,7 @@
"@angular-devkit/build-angular": "^18.0.1", "@angular-devkit/build-angular": "^18.0.1",
"@angular/cli": "^18.0.1", "@angular/cli": "^18.0.1",
"@angular/compiler-cli": "^18.0.0", "@angular/compiler-cli": "^18.0.0",
"@angular/localize": "^18.1.0",
"@types/jasmine": "~5.1.0", "@types/jasmine": "~5.1.0",
"jasmine-core": "~5.1.0", "jasmine-core": "~5.1.0",
"karma": "~6.4.0", "karma": "~6.4.0",
@ -486,6 +487,30 @@
"rxjs": "^6.5.3 || ^7.4.0" "rxjs": "^6.5.3 || ^7.4.0"
} }
}, },
"node_modules/@angular/localize": {
"version": "18.1.0",
"resolved": "https://registry.npmjs.org/@angular/localize/-/localize-18.1.0.tgz",
"integrity": "sha512-84D06p2Th5NxoJZzsSIn4FkTJGImj7rtNnvyTrHvHdomzzUKwiBOXDB2FiCLDstND0DsCtgjD/uBJivg77z9tg==",
"dev": true,
"dependencies": {
"@babel/core": "7.24.7",
"@types/babel__core": "7.20.5",
"fast-glob": "3.3.2",
"yargs": "^17.2.1"
},
"bin": {
"localize-extract": "tools/bundles/src/extract/cli.js",
"localize-migrate": "tools/bundles/src/migrate/cli.js",
"localize-translate": "tools/bundles/src/translate/cli.js"
},
"engines": {
"node": "^18.19.1 || ^20.11.1 || >=22.0.0"
},
"peerDependencies": {
"@angular/compiler": "18.1.0",
"@angular/compiler-cli": "18.1.0"
}
},
"node_modules/@angular/material": { "node_modules/@angular/material": {
"version": "18.0.6", "version": "18.0.6",
"resolved": "https://registry.npmjs.org/@angular/material/-/material-18.0.6.tgz", "resolved": "https://registry.npmjs.org/@angular/material/-/material-18.0.6.tgz",
@ -4938,6 +4963,47 @@
"url": "https://github.com/sponsors/isaacs" "url": "https://github.com/sponsors/isaacs"
} }
}, },
"node_modules/@types/babel__core": {
"version": "7.20.5",
"resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz",
"integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==",
"dev": true,
"dependencies": {
"@babel/parser": "^7.20.7",
"@babel/types": "^7.20.7",
"@types/babel__generator": "*",
"@types/babel__template": "*",
"@types/babel__traverse": "*"
}
},
"node_modules/@types/babel__generator": {
"version": "7.6.8",
"resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.8.tgz",
"integrity": "sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw==",
"dev": true,
"dependencies": {
"@babel/types": "^7.0.0"
}
},
"node_modules/@types/babel__template": {
"version": "7.4.4",
"resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz",
"integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==",
"dev": true,
"dependencies": {
"@babel/parser": "^7.1.0",
"@babel/types": "^7.0.0"
}
},
"node_modules/@types/babel__traverse": {
"version": "7.20.6",
"resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.6.tgz",
"integrity": "sha512-r1bzfrm0tomOI8g1SzvCaQHo6Lcv6zu0EA+W2kHrt8dyrHQxGzBBL4kdkzIS+jBMV+EYcMAEAqXqYaLJq5rOZg==",
"dev": true,
"dependencies": {
"@babel/types": "^7.20.7"
}
},
"node_modules/@types/body-parser": { "node_modules/@types/body-parser": {
"version": "1.19.5", "version": "1.19.5",
"resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.5.tgz", "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.5.tgz",

View File

@ -30,6 +30,7 @@
"@angular-devkit/build-angular": "^18.0.1", "@angular-devkit/build-angular": "^18.0.1",
"@angular/cli": "^18.0.1", "@angular/cli": "^18.0.1",
"@angular/compiler-cli": "^18.0.0", "@angular/compiler-cli": "^18.0.0",
"@angular/localize": "^18.1.0",
"@types/jasmine": "~5.1.0", "@types/jasmine": "~5.1.0",
"jasmine-core": "~5.1.0", "jasmine-core": "~5.1.0",
"karma": "~6.4.0", "karma": "~6.4.0",

View File

@ -56,7 +56,7 @@ import { DeleteGroupsModalComponent } from './components/groups/delete-groups-mo
import { DragDropModule } from '@angular/cdk/drag-drop'; import { DragDropModule } from '@angular/cdk/drag-drop';
import { ToastrModule } from 'ngx-toastr'; import { ToastrModule } from 'ngx-toastr';
import { ShowOrganizationalUnitComponent } from './components/groups/organizational-units/show-organizational-unit/show-organizational-unit.component'; import { ShowOrganizationalUnitComponent } from './components/groups/organizational-units/show-organizational-unit/show-organizational-unit.component';
import { MatGridList } from "@angular/material/grid-list"; import {MatGridList, MatGridTile} from "@angular/material/grid-list";
import { TreeViewComponent } from './components/groups/tree-view/tree-view.component'; import { TreeViewComponent } from './components/groups/tree-view/tree-view.component';
import { import {
MatNestedTreeNode, MatNestedTreeNode,
@ -68,6 +68,9 @@ import {
} from "@angular/material/tree"; } from "@angular/material/tree";
import { LegendComponent } from './components/groups/legend/legend.component'; import { LegendComponent } from './components/groups/legend/legend.component';
import { ClassroomViewDialogComponent } from './components/groups/classroom-view/classroom-view-modal'; import { ClassroomViewDialogComponent } from './components/groups/classroom-view/classroom-view-modal';
import {MatPaginator} from "@angular/material/paginator";
import { SaveFiltersDialogComponent } from './components/groups/save-filters-dialog/save-filters-dialog.component';
import { AcctionsModalComponent } from './components/groups/acctions-modal/acctions-modal.component';
@NgModule({ @NgModule({
declarations: [ declarations: [
@ -99,7 +102,9 @@ import { ClassroomViewDialogComponent } from './components/groups/classroom-view
ShowOrganizationalUnitComponent, ShowOrganizationalUnitComponent,
TreeViewComponent, TreeViewComponent,
LegendComponent, LegendComponent,
ClassroomViewDialogComponent ClassroomViewDialogComponent,
SaveFiltersDialogComponent,
AcctionsModalComponent
], ],
bootstrap: [AppComponent], bootstrap: [AppComponent],
imports: [BrowserModule, imports: [BrowserModule,
@ -132,7 +137,7 @@ import { ClassroomViewDialogComponent } from './components/groups/classroom-view
progressAnimation: 'increasing', progressAnimation: 'increasing',
closeButton: true closeButton: true
} }
), MatGridList, MatTree, MatTreeNode, MatNestedTreeNode, MatTreeNodeToggle, MatTreeNodeDef, MatTreeNodePadding, MatTreeNodeOutlet ), MatGridList, MatTree, MatTreeNode, MatNestedTreeNode, MatTreeNodeToggle, MatTreeNodeDef, MatTreeNodePadding, MatTreeNodeOutlet, MatPaginator, MatGridTile
], ],
schemas: [ schemas: [
CUSTOM_ELEMENTS_SCHEMA, CUSTOM_ELEMENTS_SCHEMA,

View File

@ -1 +1 @@
<p>dashboard works!</p> <p>dashboard works!</p>

View File

@ -0,0 +1,20 @@
.button-column {
display: flex;
flex-direction: column;
align-items: center;
background-color: #fff;
padding: 20px;
border-radius: 10px;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); /* Sombra ligera */
}
.button-column button {
margin: 10px 0; /* Espaciado entre los botones */
width: 200px; /* Ancho uniforme para todos los botones */
font-size: 16px; /* Tamaño de fuente consistente */
}
.button-column button.mat-flat-button {
border-radius: 5px; /* Bordes ligeramente redondeados */
}

View File

@ -0,0 +1,9 @@
<h1 mat-dialog-title i18n="@@actions-modal-title">Acciones</h1>
<div class="button-column">
<button mat-flat-button color="primary" class="button-action button-encender" i18n="@@power-on-button" (click)="onSend()">Encender</button>
<button mat-flat-button color="accent" class="button-action button-apagar" i18n="@@power-off-button" (click)="onSend()">Apagar</button>
<button mat-flat-button color="warn" class="button-action button-resetear" i18n="@@reset-button">Resetear</button>
<button mat-flat-button class="button-action button-otros-1" i18n="@@other-actions-1">Otras acciones 1</button>
<button mat-flat-button class="button-action button-otros-2" i18n="@@other-actions-2">Otras acciones 2</button>
<button mat-flat-button class="button-action button-otros-3" i18n="@@other-actions-3">Otras acciones 3</button>
</div>

View File

@ -0,0 +1,23 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { AcctionsModalComponent } from './acctions-modal.component';
describe('AcctionsModalComponent', () => {
let component: AcctionsModalComponent;
let fixture: ComponentFixture<AcctionsModalComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [AcctionsModalComponent]
})
.compileComponents();
fixture = TestBed.createComponent(AcctionsModalComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,29 @@
// componente
import { Component, Inject } from '@angular/core';
import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog';
import { ToastrService } from 'ngx-toastr';
@Component({
selector: 'app-acctions-modal',
templateUrl: './acctions-modal.component.html',
styleUrls: ['./acctions-modal.component.css']
})
export class AcctionsModalComponent {
selectedElements: any;
constructor(
private toastService: ToastrService,
public dialogRef: MatDialogRef<AcctionsModalComponent>,
@Inject(MAT_DIALOG_DATA) public data: any
) {
this.selectedElements = data.selectedElements;
}
onCancel(): void {
this.dialogRef.close(null);
}
onSend(): void {
this.toastService.success(' Acción enviada a: ' + this.selectedElements);
}
}

View File

@ -41,12 +41,12 @@ mat-card {
background-color: rgba(0, 0, 0, 0); background-color: rgba(0, 0, 0, 0);
color: black; color: black;
text-align: center; text-align: center;
padding: 10px; padding: 15px;
box-sizing: border-box; box-sizing: border-box;
} }
.client-name { .client-name {
font-size: medium; font-size: small;
font-weight: bold; font-weight: bold;
} }

View File

@ -1,9 +1,8 @@
<div class="classroom"> <div class="classroom">
<mat-card *ngFor="let group of groupedClients" class="classroom-group"> <mat-card *ngFor="let group of groupedClients" class="classroom-group">
<div class="misc-clients"> <div class="misc-clients">
<div class="classroom-board" cdkDrag cdkDragBoundary=".classroom">Pizarra digital</div> <div class="classroom-board" cdkDrag cdkDragBoundary=".classroom" i18n="@@digital-board">Pizarra digital</div>
<img mat-card-image src="assets/images/proyector.png" alt="Proyector" class="proyector-image" cdkDrag cdkDragBoundary=".classroom"/> <img mat-card-image src="assets/images/proyector.png" alt="Proyector" class="proyector-image" cdkDrag cdkDragBoundary=".classroom" i18n-alt="@@projector-alt"/>
</div> </div>
<div *ngFor="let row of group.clientRows" class="client-row"> <div *ngFor="let row of group.clientRows" class="client-row">
<div class="client-container" *ngFor="let client of row" <div class="client-container" *ngFor="let client of row"
@ -11,12 +10,12 @@
<div class="client-box" (dblclick)="handleClientClick(client)"> <div class="client-box" (dblclick)="handleClientClick(client)">
<mat-card appearance="outlined"> <mat-card appearance="outlined">
<div class="client-image-container"> <div class="client-image-container">
<img mat-card-image src="assets/images/client.png" alt="Client" class="client-image"/> <img mat-card-image src="assets/images/client.png" alt="Client" class="client-image" i18n-alt="@@client-image-alt"/>
<div class="client-info"> <div class="client-info">
<div class="client-name">{{ client.name }}</div> <div class="client-name">{{ client.name }}</div>
<div class="client-details"> <!-- <div class="client-details">
<span>{{ client.ip }}</span> <span>{{ client.ip }}</span>
</div> </div> -->
</div> </div>
</div> </div>
</mat-card> </mat-card>
@ -25,4 +24,4 @@
</div> </div>
</mat-card> </mat-card>
</div> </div>
<button mat-flat-button class="saveDisposition-btn" color="primary" (click)="saveDisposition()">Guardar disposición</button> <button mat-flat-button class="saveDisposition-btn" color="primary" (click)="saveDisposition()" i18n="@@save-disposition-button">Guardar disposición</button>

View File

@ -1,14 +1,15 @@
<h1 mat-dialog-title>Propiedades cliente</h1> <h1 mat-dialog-title i18n="@@client-properties-title">Propiedades cliente</h1>
<mat-dialog-content> <mat-dialog-content>
<mat-tab-group dynamicHeight> <mat-tab-group dynamicHeight>
<mat-tab label="Datos generales"> <mat-tab label="Datos generales">
<table mat-table [dataSource]="generalData" class="mat-elevation-z8"> <table mat-table [dataSource]="generalData" class="mat-elevation-z8">
<ng-container matColumnDef="property"> <ng-container matColumnDef="property">
<th mat-header-cell *matHeaderCellDef class="fixed-column"> Propiedad </th> <th mat-header-cell *matHeaderCellDef class="fixed-column" i18n="@@property-header">Propiedad</th>
<td mat-cell *matCellDef="let element" class="fixed-column"> {{element.property}} </td> <td mat-cell *matCellDef="let element" class="fixed-column"> {{element.property}} </td>
</ng-container> </ng-container>
<ng-container matColumnDef="value"> <ng-container matColumnDef="value">
<th mat-header-cell *matHeaderCellDef> Valor </th> <th mat-header-cell *matHeaderCellDef i18n="@@value-header">Valor</th>
<td mat-cell *matCellDef="let element"> {{element.value}} </td> <td mat-cell *matCellDef="let element"> {{element.value}} </td>
</ng-container> </ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr> <tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
@ -18,11 +19,11 @@
<mat-tab label="Propiedades de red"> <mat-tab label="Propiedades de red">
<table mat-table [dataSource]="networkData" class="mat-elevation-z8"> <table mat-table [dataSource]="networkData" class="mat-elevation-z8">
<ng-container matColumnDef="property"> <ng-container matColumnDef="property">
<th mat-header-cell *matHeaderCellDef class="fixed-column"> Propiedad </th> <th mat-header-cell *matHeaderCellDef class="fixed-column" i18n="@@property-header">Propiedad</th>
<td mat-cell *matCellDef="let element" class="fixed-column"> {{element.property}} </td> <td mat-cell *matCellDef="let element" class="fixed-column"> {{element.property}} </td>
</ng-container> </ng-container>
<ng-container matColumnDef="value"> <ng-container matColumnDef="value">
<th mat-header-cell *matHeaderCellDef> Valor </th> <th mat-header-cell *matHeaderCellDef i18n="@@value-header">Valor</th>
<td mat-cell *matCellDef="let element"> {{element.value}} </td> <td mat-cell *matCellDef="let element"> {{element.value}} </td>
</ng-container> </ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr> <tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
@ -32,11 +33,11 @@
<mat-tab label="Propiedades del aula"> <mat-tab label="Propiedades del aula">
<table mat-table [dataSource]="classroomData" class="mat-elevation-z8"> <table mat-table [dataSource]="classroomData" class="mat-elevation-z8">
<ng-container matColumnDef="property"> <ng-container matColumnDef="property">
<th mat-header-cell *matHeaderCellDef class="fixed-column"> Propiedad </th> <th mat-header-cell *matHeaderCellDef class="fixed-column" i18n="@@property-header">Propiedad</th>
<td mat-cell *matCellDef="let element" class="fixed-column"> {{element.property}} </td> <td mat-cell *matCellDef="let element" class="fixed-column"> {{element.property}} </td>
</ng-container> </ng-container>
<ng-container matColumnDef="value"> <ng-container matColumnDef="value">
<th mat-header-cell *matHeaderCellDef> Valor </th> <th mat-header-cell *matHeaderCellDef i18n="@@value-header">Valor</th>
<td mat-cell *matCellDef="let element"> {{element.value}} </td> <td mat-cell *matCellDef="let element"> {{element.value}} </td>
</ng-container> </ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr> <tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
@ -45,12 +46,12 @@
</mat-tab> </mat-tab>
<mat-tab label="Acciones"> <mat-tab label="Acciones">
<div class="button-column"> <div class="button-column">
<button mat-flat-button color="primary" class="button-action button-encender">Encender</button> <button mat-flat-button color="primary" class="button-action button-encender" i18n="@@power-on-button">Encender</button>
<button mat-flat-button color="accent" class="button-action button-apagar">Apagar</button> <button mat-flat-button color="accent" class="button-action button-apagar" i18n="@@power-off-button">Apagar</button>
<button mat-flat-button color="warn" class="button-action button-resetear">Resetear</button> <button mat-flat-button color="warn" class="button-action button-resetear" i18n="@@reset-button">Resetear</button>
<button mat-flat-button class="button-action button-otros-1">Otras acciones 1</button> <button mat-flat-button class="button-action button-otros-1" i18n="@@other-actions-1">Otras acciones 1</button>
<button mat-flat-button class="button-action button-otros-2">Otras acciones 2</button> <button mat-flat-button class="button-action button-otros-2" i18n="@@other-actions-2">Otras acciones 2</button>
<button mat-flat-button class="button-action button-otros-3">Otras acciones 3</button> <button mat-flat-button class="button-action button-otros-3" i18n="@@other-actions-3">Otras acciones 3</button>
</div> </div>
</mat-tab> </mat-tab>
<mat-tab label="Particiones"> <mat-tab label="Particiones">
@ -58,5 +59,5 @@
</mat-tab-group> </mat-tab-group>
</mat-dialog-content> </mat-dialog-content>
<mat-dialog-actions> <mat-dialog-actions>
<button mat-button mat-dialog-close (click)="onNoClick()">Cerrar</button> <button mat-button mat-dialog-close (click)="onNoClick()" i18n="@@close-button">Cerrar</button>
</mat-dialog-actions> </mat-dialog-actions>

View File

@ -1,69 +1,71 @@
<div class="create-client-container"> <div class="create-client-container">
<h1 mat-dialog-title>Añadir Cliente</h1> <h1 mat-dialog-title i18n="@@add-client-dialog-title">Añadir Cliente</h1>
<div class="mat-dialog-content" [ngClass]="{'loading': loading}"> <div class="mat-dialog-content" [ngClass]="{'loading': loading}">
<mat-spinner class="loading-spinner" *ngIf="loading"></mat-spinner> <mat-spinner class="loading-spinner" *ngIf="loading"></mat-spinner>
<form [formGroup]="clientForm" class="client-form" *ngIf="!loading"> <form [formGroup]="clientForm" class="client-form" *ngIf="!loading">
<mat-form-field class="form-field"> <mat-form-field class="form-field">
<mat-label>Padre</mat-label> <mat-label i18n="@@organizational-unit-label">Padre</mat-label>
<mat-select formControlName="organizationalUnit"> <mat-select formControlName="organizationalUnit">
<mat-option *ngFor="let unit of parentUnits" [value]="unit['@id']"> <mat-option *ngFor="let unit of parentUnits" [value]="unit['@id']">
<div class="unit-name">{{ unit.name }}</div> <div class="unit-name">{{ unit.name }}</div>
<div class="unit-path">{{ unit.path }}</div> <div class="unit-path">{{ unit.path }}</div>
</mat-option> </mat-option>
</mat-select> </mat-select>
</mat-form-field> </mat-form-field>
<mat-form-field class="form-field"> <mat-form-field class="form-field">
<mat-label>Nombre</mat-label> <mat-label i18n="@@name-label">Nombre</mat-label>
<input matInput formControlName="name" > <input matInput formControlName="name">
</mat-form-field> </mat-form-field>
<mat-form-field class="form-field"> <mat-form-field class="form-field">
<mat-label>Número de Serie</mat-label> <mat-label i18n="@@serial-number-label">Número de Serie</mat-label>
<input matInput formControlName="serialNumber" > <input matInput formControlName="serialNumber">
</mat-form-field> </mat-form-field>
<mat-form-field class="form-field"> <mat-form-field class="form-field">
<mat-label>Interfaz de red</mat-label> <mat-label i18n="@@netiface-label">Interfaz de red</mat-label>
<mat-select formControlName="netiface" > <mat-select formControlName="netiface">
<mat-option *ngFor="let type of netifaceTypes" value="{{ type.value }}"> <mat-option *ngFor="let type of netifaceTypes" [value]="type.value">
{{ type.name }} {{ type.name }}
</mat-option> </mat-option>
</mat-select> </mat-select>
</mat-form-field> </mat-form-field>
<mat-form-field class="form-field"> <mat-form-field class="form-field">
<mat-label>Controlador de red</mat-label> <mat-label i18n="@@net-driver-label">Controlador de red</mat-label>
<mat-select formControlName="netDriver" > <mat-select formControlName="netDriver">
<mat-option *ngFor="let type of netDriverTypes" value="{{ type.value }}"> <mat-option *ngFor="let type of netDriverTypes" [value]="type.value">
{{ type.name }} {{ type.name }}
</mat-option> </mat-option>
</mat-select> </mat-select>
</mat-form-field> </mat-form-field>
<mat-form-field class="form-field"> <mat-form-field class="form-field">
<mat-label>MAC</mat-label> <mat-label i18n="@@mac-label">MAC</mat-label>
<mat-hint>Ejemplo: 00:11:22:33:44:55</mat-hint> <mat-hint i18n="@@mac-hint">Ejemplo: 00:11:22:33:44:55</mat-hint>
<input matInput formControlName="mac" > <input matInput formControlName="mac">
<mat-error>Formato de MAC inválido. Ejemplo válido: 00:11:22:33:44:55</mat-error> <mat-error i18n="@@mac-error">Formato de MAC inválido. Ejemplo válido: 00:11:22:33:44:55</mat-error>
</mat-form-field> </mat-form-field>
<mat-form-field class="form-field"> <mat-form-field class="form-field">
<mat-label>Dirección IP</mat-label> <mat-label i18n="@@ip-label">Dirección IP</mat-label>
<mat-hint>Ejemplo: 127.0.0.1</mat-hint> <mat-hint i18n="@@ip-hint">Ejemplo: 127.0.0.1</mat-hint>
<input matInput formControlName="ip"> <input matInput formControlName="ip">
<mat-error>Formato de dirección IP inválido. Ejemplo válido: 127.0.0.1</mat-error> <mat-error i18n="@@ip-error">Formato de dirección IP inválido. Ejemplo válido: 127.0.0.1</mat-error>
</mat-form-field> </mat-form-field>
<mat-form-field class="form-field"> <mat-form-field class="form-field">
<mat-label>Menú URL</mat-label> <mat-label i18n="@@menu-url-label">Menú URL</mat-label>
<input matInput formControlName="menu" type="url"> <input matInput formControlName="menu" type="url">
<mat-error>Formato de URL inválido.</mat-error> <mat-error i18n="@@menu-url-error">Formato de URL inválido.</mat-error>
</mat-form-field> </mat-form-field>
<mat-form-field class="form-field"> <mat-form-field class="form-field">
<mat-label>Perfil de Hardware</mat-label> <mat-label i18n="@@hardware-profile-label">Perfil de Hardware</mat-label>
<mat-select formControlName="hardwareProfile"> <mat-select formControlName="hardwareProfile">
<mat-option *ngFor="let unit of hardwareProfiles" [value]="unit['@id']">{{ unit.description }} </mat-option> <mat-option *ngFor="let unit of hardwareProfiles" [value]="unit['@id']">
</mat-select> {{ unit.description }}
<mat-error>Formato de URL inválido.</mat-error> </mat-option>
</mat-form-field> </mat-select>
</form> <mat-error i18n="@@hardware-profile-error">Formato de URL inválido.</mat-error>
</div> </mat-form-field>
<div mat-dialog-actions> </form>
<button mat-button (click)="onNoClick()">Cancelar</button> </div>
<button mat-button [disabled]="!clientForm.valid" (click)="onSubmit()">Añadir</button> <div mat-dialog-actions>
</div> <button mat-button (click)="onNoClick()" i18n="@@cancel-button">Cancelar</button>
<button mat-button [disabled]="!clientForm.valid" (click)="onSubmit()" i18n="@@add-button">Añadir</button>
</div>
</div> </div>

View File

@ -1,23 +1,25 @@
<h1 mat-dialog-title>Editar Cliente</h1> <h1 mat-dialog-title i18n="@@edit-client-dialog-title">Editar Cliente</h1>
<div class="mat-dialog-content" [ngClass]="{'loading': loading}"> <div class="mat-dialog-content" [ngClass]="{'loading': loading}">
<mat-spinner class="loading-spinner" *ngIf="loading"></mat-spinner> <mat-spinner class="loading-spinner" *ngIf="loading"></mat-spinner>
<form [formGroup]="clientForm" class="client-form" *ngIf="!loading"> <form [formGroup]="clientForm" class="client-form" *ngIf="!loading">
<mat-form-field class="form-field"> <mat-form-field class="form-field">
<mat-label>Padre</mat-label> <mat-label i18n="@@organizational-unit-label">Padre</mat-label>
<mat-select formControlName="organizationalUnit"> <mat-select formControlName="organizationalUnit">
<mat-option *ngFor="let unit of parentUnits" [value]="unit['@id']">{{ unit.name }}</mat-option> <mat-option *ngFor="let unit of parentUnits" [value]="unit['@id']">
{{ unit.name }}
</mat-option>
</mat-select> </mat-select>
</mat-form-field> </mat-form-field>
<mat-form-field class="form-field"> <mat-form-field class="form-field">
<mat-label>Nombre</mat-label> <mat-label i18n="@@name-label">Nombre</mat-label>
<input matInput formControlName="name"> <input matInput formControlName="name">
</mat-form-field> </mat-form-field>
<mat-form-field class="form-field"> <mat-form-field class="form-field">
<mat-label>Número de Serie</mat-label> <mat-label i18n="@@serial-number-label">Número de Serie</mat-label>
<input matInput formControlName="serialNumber"> <input matInput formControlName="serialNumber">
</mat-form-field> </mat-form-field>
<mat-form-field class="form-field"> <mat-form-field class="form-field">
<mat-label>Interfaz de red</mat-label> <mat-label i18n="@@netiface-label">Interfaz de red</mat-label>
<mat-select formControlName="netiface"> <mat-select formControlName="netiface">
<mat-option *ngFor="let type of netifaceTypes" [value]="type.value"> <mat-option *ngFor="let type of netifaceTypes" [value]="type.value">
{{ type.name }} {{ type.name }}
@ -25,7 +27,7 @@
</mat-select> </mat-select>
</mat-form-field> </mat-form-field>
<mat-form-field class="form-field"> <mat-form-field class="form-field">
<mat-label>Controlador de red</mat-label> <mat-label i18n="@@net-driver-label">Controlador de red</mat-label>
<mat-select formControlName="netDriver"> <mat-select formControlName="netDriver">
<mat-option *ngFor="let type of netDriverTypes" [value]="type.value"> <mat-option *ngFor="let type of netDriverTypes" [value]="type.value">
{{ type.name }} {{ type.name }}
@ -33,30 +35,34 @@
</mat-select> </mat-select>
</mat-form-field> </mat-form-field>
<mat-form-field class="form-field"> <mat-form-field class="form-field">
<mat-label>MAC</mat-label> <mat-label i18n="@@mac-label">MAC</mat-label>
<input matInput formControlName="mac"> <input matInput formControlName="mac">
<mat-error>Formato de MAC inválido. Ejemplo válido: 00:11:22:33:44:55</mat-error> <mat-error i18n="@@mac-error">Formato de MAC inválido. Ejemplo válido: 00:11:22:33:44:55</mat-error>
</mat-form-field> </mat-form-field>
<mat-form-field class="form-field"> <mat-form-field class="form-field">
<mat-label>Dirección IP</mat-label> <mat-label i18n="@@ip-label">Dirección IP</mat-label>
<input matInput formControlName="ip"> <input matInput formControlName="ip">
<mat-error>Formato de dirección IP inválido. Ejemplo válido: 127.0.0.1</mat-error> <mat-error i18n="@@ip-error">Formato de dirección IP inválido. Ejemplo válido: 127.0.0.1</mat-error>
</mat-form-field> </mat-form-field>
<mat-form-field class="form-field"> <mat-form-field class="form-field">
<mat-label>Menú URL</mat-label> <mat-label i18n="@@menu-url-label">Menú URL</mat-label>
<input matInput formControlName="menu" type="url"> <input matInput formControlName="menu" type="url">
<mat-error>Formato de URL inválido.</mat-error> <mat-error i18n="@@menu-url-error">Formato de URL inválido.</mat-error>
</mat-form-field> </mat-form-field>
<mat-form-field class="form-field"> <mat-form-field class="form-field">
<mat-label>Perfil de Hardware</mat-label> <mat-label i18n="@@hardware-profile-label">Perfil de Hardware</mat-label>
<mat-select formControlName="hardwareProfile"> <mat-select formControlName="hardwareProfile">
<mat-option *ngFor="let unit of hardwareProfiles" [value]="unit['@id']">{{ unit.description }} </mat-option> <mat-option *ngFor="let unit of hardwareProfiles" [value]="unit['@id']">
{{ unit.description }}
</mat-option>
</mat-select> </mat-select>
<mat-error>Formato de URL inválido.</mat-error> <mat-error i18n="@@hardware-profile-error">Formato de URL inválido.</mat-error>
</mat-form-field> </mat-form-field>
</form> </form>
</div> </div>
<div mat-dialog-actions> <div mat-dialog-actions>
<button mat-button (click)="onNoClick()">Cancelar</button> <button mat-button (click)="onNoClick()" i18n="@@cancel-button">Cancelar</button>
<button mat-button [disabled]="!clientForm.valid" (click)="onSubmit()">{{ !isEditMode ? 'Añadir' : 'Guardar' }}</button> <button mat-button [disabled]="!clientForm.valid" (click)="onSubmit()">
{{ !isEditMode ? 'Añadir' : 'Guardar' }}
</button>
</div> </div>

View File

@ -1,5 +1,5 @@
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http'; import {HttpClient, HttpParams} from '@angular/common/http';
import { Observable, throwError } from 'rxjs'; import { Observable, throwError } from 'rxjs';
import { catchError, map } from 'rxjs/operators'; import { catchError, map } from 'rxjs/operators';
import { UnidadOrganizativa } from './model'; import { UnidadOrganizativa } from './model';
@ -10,7 +10,7 @@ import { UnidadOrganizativa } from './model';
export class DataService { export class DataService {
private apiUrl = 'http://127.0.0.1:8080/organizational-units?page=1&itemsPerPage=1000'; private apiUrl = 'http://127.0.0.1:8080/organizational-units?page=1&itemsPerPage=1000';
private clientsUrl = 'http://127.0.0.1:8080/clients?page=1&itemsPerPage=30'; private clientsUrl = 'http://127.0.0.1:8080/clients?page=1&itemsPerPage=1000';
constructor(private http: HttpClient) {} constructor(private http: HttpClient) {}
@ -107,5 +107,72 @@ export class DataService {
); );
} }
getFilteredResults(filter1: string, filter2: string, filterName: string, page: number, pageSize: number): Observable<any> {
let params = new HttpParams();
if (filter2 && filter2 !== 'none') {
params = params.set('type', filter2);
}
if (filterName) {
params = params.set('name', filterName);
}
params = params.set('page', page.toString());
params = params.set('itemsPerPage', pageSize.toString());
const url = filter1 === 'client' ? this.clientsUrl : this.apiUrl;
return this.http.get<any>(url, { params }).pipe(
map(response => {
if (response['hydra:member'] && Array.isArray(response['hydra:member'])) {
return {
results: response['hydra:member'],
total: response['hydra:totalItems'] || response['hydra:member'].length
};
} else {
throw new Error('Unexpected response format');
}
}),
catchError(error => {
console.error('Error fetching data', error);
return throwError(error);
})
);
}
getFilters(): Observable<any> {
return this.http.get<any>('http://127.0.0.1:8080/views?page=1&itemsPerPage=30').pipe(
map(response => {
if (response['hydra:member'] && Array.isArray(response['hydra:member'])) {
return response['hydra:member'];
} else {
throw new Error('Unexpected response format');
}
}),
catchError(error => {
console.error('Error fetching filters', error);
return throwError(error);
})
);
}
getFilter(id: string): Observable<any> {
return this.http.get<any>('http://127.0.0.1:8080/views/' + id).pipe(
map(response => {
if (response.name && response.filters) {
return response;
} else {
throw new Error('Unexpected response format');
}
}),
catchError(error => {
console.error('Error fetching filters', error);
return throwError(error);
})
);
}
} }

View File

@ -4,14 +4,16 @@ import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog';
@Component({ @Component({
selector: 'app-delete-confirm-dialog', selector: 'app-delete-confirm-dialog',
template: ` template: `
<h1 mat-dialog-title>Eliminar</h1> <h1 mat-dialog-title i18n="@@delete-dialog-title">Eliminar</h1>
<div mat-dialog-content> <div mat-dialog-content>
<p>¿Quiere borrar los clientes situados en {{data.name}} o quiere resituarlos en el nivel superior?</p> <p i18n="@@delete-dialog-content">¿Quiere borrar los clientes situados en {{data.name}} o quiere resituarlos en el nivel superior?</p>
</div> </div>
<div mat-dialog-actions> <div mat-dialog-actions>
<button mat-button (click)="deleteClick()">Borrar todos los clientes</button> <button mat-button (click)="deleteClick()" i18n="@@delete-all-clients-button">Borrar todos los clientes</button>
<button mat-button (click)="changeClick()">Resituar </button> <button mat-button (click)="changeClick()" i18n="@@reposition-clients-button">Resituar</button>
</div> </div>
` `
}) })
export class DeleteGroupsModalComponent { export class DeleteGroupsModalComponent {

View File

@ -4,14 +4,15 @@ import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog';
@Component({ @Component({
selector: 'app-delete-confirm-dialog', selector: 'app-delete-confirm-dialog',
template: ` template: `
<h1 mat-dialog-title>Eliminar</h1> <h1 mat-dialog-title i18n="@@deleteDialogTitle">Eliminar</h1>
<div mat-dialog-content> <div mat-dialog-content>
<p>¿Estás seguro que deseas eliminar {{data.name}}?</p> <p i18n="@@deleteConfirmationMessage">¿Estás seguro que deseas eliminar {{data.name}}?</p>
</div> </div>
<div mat-dialog-actions> <div mat-dialog-actions>
<button mat-button (click)="onNoClick()">Cancelar</button> <button mat-button (click)="onNoClick()" i18n="@@cancelButton">Cancelar</button>
<button mat-button (click)="onYesClick()">Eliminar</button> <button mat-button (click)="onYesClick()" i18n="@@confirmButton">Eliminar</button>
</div> </div>
` `
}) })
export class DeleteModalComponent { export class DeleteModalComponent {

View File

@ -122,12 +122,85 @@ mat-spinner {
align-self: center; align-self: center;
} }
.container {
.container { /* Asegúrate de que esta clase sea la del contenedor del botón */
display: flex; display: flex;
justify-content: flex-end; justify-content: flex-end;
} }
.classroomBtn-container {
.roomMap-btn { display: flex;
justify-content: flex-end;
width: 100%;
padding-right: 20px;
} }
.roomMap-btn{
}
.container {
display: flex;
flex-direction: column;
}
.header {
display: flex;
align-items: center;
gap: 10px;
padding: 20px;
}
.header mat-form-field {
width: 300px;
}
.main-content {
display: flex;
}
.filters {
padding: 20px;
display: flex;
flex-direction: column;
width: 300px;
}
.saved-filter {
display: flex;
flex-direction: column;
width: 300px;
margin-bottom: 10px;
padding: 10px;
}
.results {
width: 100%;
}
.results-container {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 16px;
margin-bottom: 16px;
}
.result-card {
width: 100%;
max-width: 250px;
height: 250px; /* Fijo para mantener la forma cuadrada */
}
.paginator-container {
display: flex;
justify-content: center;
margin-bottom: 30px;
}
.divider {
margin: 20px 0;
}
mat-card {
margin-bottom: 20px;
}
.temp_filter{color: red;
}

View File

@ -1,151 +1,295 @@
<div class="header-container"> <mat-tab-group>
<h2 class="title">Administrar grupos</h2> <mat-tab label="General">
<div class="groups-button-row"> <div class="header-container">
<button mat-flat-button color="primary" (click)="addOU($event)">Nueva Unidad Organizativa</button> <h2 class="title" i18n="@@adminGroupsTitle">Administrar grupos</h2>
<button mat-flat-button color="primary" (click)="addClient($event)">Nuevo Cliente</button> <div class="groups-button-row">
<button mat-raised-button (click)="openBottomSheet()">Leyenda</button> <button mat-flat-button color="primary" (click)="addOU($event)" i18n="@@newOrganizationalUnitButton">Nueva Unidad Organizativa</button>
<button mat-flat-button color="primary" (click)="addClient($event)" i18n="@@newClientButton">Nuevo Cliente</button>
<button mat-raised-button (click)="openBottomSheet()" i18n="@@legendButton">Leyenda</button>
</div>
<div class="container">
<button mat-flat-button class="roomMap-btn" color="accent" (click)="roomMap()" *ngIf="selectedDetail && selectedDetail.type === 'classroom'">Plano de aula</button>
</div>
</div>
<div class="search-container">
<mat-form-field appearance="fill">
<mat-label>Búsqueda</mat-label>
<input matInput placeholder="Búsqueda" [(ngModel)]="searchTerm" (keyup.enter)="search()">
<mat-icon matSuffix>search</mat-icon>
<mat-hint>Pulsar 'enter' para buscar entre las unidades organizativas</mat-hint>
</mat-form-field>
</div>
<div class="groupLists-container">
<mat-card class="card unidad-card">
<mat-card-title>Unidad organizativa</mat-card-title>
<mat-card-content>
<mat-spinner *ngIf="loading"></mat-spinner>
<mat-list *ngIf="!loading">
<mat-list-item *ngFor="let unidad of organizationalUnits"
[ngClass]="{'selected-item': unidad === selectedUnidad, 'clickable-item': true}" (click)="onSelectUnidad(unidad)">
<div class="item-content">
<mat-icon>apartment</mat-icon>
{{ unidad.name }}
<span class="actions">
<mat-icon mat-button [matMenuTriggerFor]="menu" (click)="$event.stopPropagation()">menu</mat-icon>
<mat-menu #menu="matMenu">
<button mat-menu-item (click)="onTreeClick($event, unidad)">
<mat-icon
class="edit-icon"
#tooltip="matTooltip"
matTooltip="Visualizar en forma de arbol"
matTooltipHideDelay="0">account_tree
</mat-icon>
Ver organigrama
</button>
<button mat-menu-item (click)="onEditClick($event, unidad.type, unidad.uuid)">
<mat-icon
class="edit-icon"
#tooltip="matTooltip"
matTooltip="Editar unidad organizativa"
matTooltipHideDelay="0">edit
</mat-icon>
Editar
</button>
<button mat-menu-item (click)="onShowClick($event, unidad)">
<mat-icon
class="edit-icon"
#tooltip="matTooltip"
matTooltip="Visualizar unidad organizativa"
matTooltipHideDelay="0">visibility
</mat-icon>
Visualizar datos
</button>
<button mat-menu-item (click)="addOU($event, unidad)">
<mat-icon
class="edit-icon"
#tooltip="matTooltip"
matTooltip="Crear unidad organizativa interna"
matTooltipHideDelay="0">add_home_work
</mat-icon>
Añadir unidad organizativa
</button>
<button mat-menu-item (click)="addClient($event, unidad)">
<mat-icon
class="edit-icon"
#tooltip="matTooltip"
matTooltip="Crear cliente en esta unidad organizativa"
matTooltipHideDelay="0">devices
</mat-icon>
Crear cliente
</button>
</mat-menu>
</span>
</div>
</mat-list-item>
</mat-list>
</mat-card-content>
</mat-card>
<mat-card class="card elements-card">
<mat-card-title>
<div class="title-with-breadcrumb">
<span>Elementos internos</span>
<mat-card-subtitle>
<ng-container *ngFor="let crumb of breadcrumb; let i = index">
<a (click)="navigateToBreadcrumb(i)">{{ crumb }}</a>
<span *ngIf="i < breadcrumb.length - 1"> > </span>
</ng-container>
</mat-card-subtitle>
</div> </div>
</mat-card-title> <div class="classroomBtn-container">
<mat-card-content class="element-content"> <button mat-flat-button class="roomMap-btn" color="accent" (click)="roomMap()" *ngIf="selectedDetail && selectedDetail.type === 'classroom'" i18n="@@classroomMapButton">Plano de aula</button>
<mat-spinner *ngIf="loadingChildren"></mat-spinner> </div>
<mat-list *ngIf="!loadingChildren"> </div>
<div *ngIf="children.length === 0" class="empty-list"> <div class="search-container">
<mat-icon>info</mat-icon> <mat-form-field appearance="fill">
<span>No hay elementos internos</span> <mat-label i18n="@@searchLabel">Búsqueda</mat-label>
</div> <input matInput placeholder="Búsqueda" [(ngModel)]="searchTerm" (keyup.enter)="search()" i18n-placeholder="@@searchPlaceholder">
<mat-list-item *ngFor="let child of children" [ngClass]="{'selected-item': child === selectedUnidad, 'clickable-item': true}" (click)="onSelectChild(child)"> <mat-icon matSuffix>search</mat-icon>
<div class="item-content"> <mat-hint i18n="@@searchHint">Pulsar 'enter' para buscar entre las unidades organizativas</mat-hint>
<mat-icon [ngSwitch]="child.type"> </mat-form-field>
<ng-container *ngSwitchCase="'organizational-unit'">apartment</ng-container> </div>
<ng-container *ngSwitchCase="'classrooms-group'">meeting_room</ng-container> <div class="groupLists-container">
<ng-container *ngSwitchCase="'classroom'">school</ng-container> <mat-card class="card unidad-card">
<ng-container *ngSwitchCase="'client'">computer</ng-container> <mat-card-title i18n="@@organizationalUnitTitle">Unidad organizativa</mat-card-title>
<ng-container *ngSwitchCase="'clients-group'">lan</ng-container> <mat-card-content>
<ng-container *ngSwitchDefault>help_outline</ng-container> <mat-spinner *ngIf="loading"></mat-spinner>
</mat-icon> <mat-list *ngIf="!loading">
{{child.name}} <mat-list-item *ngFor="let unidad of organizationalUnits"
<span class="actions"> [ngClass]="{'selected-item': unidad === selectedUnidad, 'clickable-item': true}" (click)="onSelectUnidad(unidad)">
<mat-icon mat-button [matMenuTriggerFor]="menu" (click)="$event.stopPropagation()">menu</mat-icon> <div class="item-content">
<mat-menu #menu="matMenu"> <mat-icon>apartment</mat-icon>
<button mat-menu-item (click)="onEditClick($event, child.type, child.uuid)"> {{ unidad.name }}
<mat-icon class="edit-icon" #tooltip="matTooltip" matTooltip="Editar elemento" matTooltipHideDelay="0">edit</mat-icon> <span class="actions">
Editar <mat-icon mat-button [matMenuTriggerFor]="menu" (click)="$event.stopPropagation()">menu</mat-icon>
</button> <mat-menu #menu="matMenu">
<button *ngIf="child.type !== 'client'" mat-menu-item (click)="onShowClick($event, child)"> <button mat-menu-item (click)="onTreeClick($event, unidad)">
<mat-icon class="edit-icon" #tooltip="matTooltip" matTooltip="Visualizar unidad organizativa" matTooltipHideDelay="0">visibility</mat-icon> <mat-icon
Visualizar datos class="edit-icon"
</button> #tooltip="matTooltip"
<button *ngIf="child.type !== 'client'" mat-menu-item (click)="addOU($event, child)"> matTooltip="Visualizar en forma de arbol"
<mat-icon class="edit-icon" #tooltip="matTooltip" matTooltip="Crear unidad organizativa interna" matTooltipHideDelay="0">add_home_work</mat-icon> matTooltipHideDelay="0"
Añadir unidad organizativa i18n="@@viewTreeTooltip">account_tree
</button> </mat-icon>
<button *ngIf="child.type !== 'client'" mat-menu-item (click)="addClient($event, child)"> <span i18n="@@viewTreeMenu">Ver organigrama</span>
<mat-icon class="edit-icon" #tooltip="matTooltip" matTooltip="Crear cliente en esta unidad organizativa" matTooltipHideDelay="0">devices</mat-icon> </button>
Crear cliente <button mat-menu-item (click)="onEditClick($event, unidad.type, unidad.uuid)">
</button> <mat-icon
<button mat-menu-item (click)="onDeleteClick($event, child.uuid, child.name, child.type)"> class="edit-icon"
<mat-icon class="delete-icon" #tooltip="matTooltip" matTooltip="Borrar elemento" matTooltipHideDelay="0">delete</mat-icon> #tooltip="matTooltip"
Borrar elemento matTooltip="Editar unidad organizativa"
</button> matTooltipHideDelay="0"
</mat-menu> i18n="@@editUnitTooltip">edit
</span> </mat-icon>
<span i18n="@@editUnitMenu">Editar</span>
</button>
<button mat-menu-item (click)="onShowClick($event, unidad)">
<mat-icon
class="edit-icon"
#tooltip="matTooltip"
matTooltip="Visualizar unidad organizativa"
matTooltipHideDelay="0"
i18n="@@viewUnitTool">visibility
</mat-icon>
<span i18n="@@viewUnitMenu">Visualizar datos</span>
</button>
<button mat-menu-item (click)="addOU($event, unidad)">
<mat-icon
class="edit-icon"
#tooltip="matTooltip"
matTooltip="Crear unidad organizativa interna"
matTooltipHideDelay="0"
i18n="@@addInternalUnitTool">add_home_work
</mat-icon>
<span i18n="@@addInternalUnitMenu">Añadir unidad organizativa</span>
</button>
<button mat-menu-item (click)="addClient($event, unidad)">
<mat-icon
class="edit-icon"
#tooltip="matTooltip"
matTooltip="Crear cliente en esta unidad organizativa"
matTooltipHideDelay="0"
i18n="@@addClientDevice">devices
</mat-icon>
<span i18n="@@addClientMenu">Crear cliente</span>
</button>
</mat-menu>
</span>
</div>
</mat-list-item>
</mat-list>
</mat-card-content>
</mat-card>
<mat-card class="card elements-card">
<mat-card-title>
<div class="title-with-breadcrumb">
<span i18n="@@internalElementsTitle">Elementos internos</span>
<mat-card-subtitle>
<ng-container *ngFor="let crumb of breadcrumb; let i = index">
<a (click)="navigateToBreadcrumb(i)">{{ crumb }}</a>
<span *ngIf="i < breadcrumb.length - 1"> > </span>
</ng-container>
</mat-card-subtitle>
</div> </div>
</mat-list-item> </mat-card-title>
</mat-list> <mat-card-content class="element-content">
</mat-card-content> <mat-spinner *ngIf="loadingChildren"></mat-spinner>
</mat-card> <mat-list *ngIf="!loadingChildren">
<div *ngIf="children.length === 0" class="empty-list">
<mat-icon>info</mat-icon>
<span i18n="@@noInternalElementsMessage">No hay elementos internos</span>
</div>
<mat-list-item *ngFor="let child of children" [ngClass]="{'selected-item': child === selectedUnidad, 'clickable-item': true}" (click)="onSelectChild(child)">
<div class="item-content">
<mat-icon [ngSwitch]="child.type">
<ng-container *ngSwitchCase="'organizational-unit'">apartment</ng-container>
<ng-container *ngSwitchCase="'classrooms-group'">meeting_room</ng-container>
<ng-container *ngSwitchCase="'classroom'">school</ng-container>
<ng-container *ngSwitchCase="'client'">computer</ng-container>
<ng-container *ngSwitchCase="'clients-group'">lan</ng-container>
<ng-container *ngSwitchDefault>help_outline</ng-container>
</mat-icon>
{{child.name}}
<span class="actions">
<mat-icon mat-button [matMenuTriggerFor]="menu" (click)="$event.stopPropagation()">menu</mat-icon>
<mat-menu #menu="matMenu">
<button mat-menu-item (click)="onEditClick($event, child.type, child.uuid)">
<mat-icon class="edit-icon" #tooltip="matTooltip" matTooltip="Editar elemento" matTooltipHideDelay="0" i18n="@@editElementTooltip">edit</mat-icon>
<span i18n="@@editElementMenu">Editar</span>
</button>
<button *ngIf="child.type !== 'client'" mat-menu-item (click)="onShowClick($event, child)">
<mat-icon class="edit-icon" #tooltip="matTooltip" matTooltip="Visualizar unidad organizativa" matTooltipHideDelay="0" i18n="@@viewUnitTooltip">visibility</mat-icon>
<span i18n="@@viewUnitMenu">Visualizar datos</span>
</button>
<button *ngIf="child.type !== 'client'" mat-menu-item (click)="addOU($event, child)">
<mat-icon class="edit-icon" #tooltip="matTooltip" matTooltip="Crear unidad organizativa interna" matTooltipHideDelay="0" i18n="@@addInternalUnitTooltip">add_home_work</mat-icon>
<span i18n="@@addInternalUnitMenu">Añadir unidad organizativa</span>
</button>
<button *ngIf="child.type !== 'client'" mat-menu-item (click)="addClient($event, child)">
<mat-icon class="edit-icon" #tooltip="matTooltip" matTooltip="Crear cliente en esta unidad organizativa" matTooltipHideDelay="0" i18n="@@addClientTooltip">devices</mat-icon>
<span i18n="@@addClientMenu">Crear cliente</span>
</button>
<button mat-menu-item (click)="onDeleteClick($event, child.uuid, child.name, child.type)">
<mat-icon class="delete-icon" #tooltip="matTooltip" matTooltip="Borrar elemento" matTooltipHideDelay="0" i18n="@@deleteElementTooltip">delete</mat-icon>
<span i18n="@@deleteElementMenu">Borrar elemento</span>
</button>
</mat-menu>
</span>
</div>
</mat-list-item>
</mat-list>
</mat-card-content>
</mat-card>
</div>
</mat-tab>
<mat-tab i18n-label label="Búsqueda avanzada" >
<h2 class="title" i18n="@@searchTitle">Búsqueda</h2>
<div class="container">
<div class="header">
<mat-form-field>
<mat-label i18n="@@selectFilterLabel">Seleccione filtro</mat-label>
<mat-select (selectionChange)="loadSelectedFilter($event.value)">
<mat-option *ngFor="let savedFilter of savedFilterNames" [value]="savedFilter">
{{ savedFilter[0] }}
</mat-option>
</mat-select>
</mat-form-field>
</div>
<mat-divider class="divider"></mat-divider>
<div class="main-content">
<div class="filters">
<mat-form-field>
<mat-label i18n="@@selectOptionLabel">Selecciona una opción</mat-label>
<mat-select [(value)]="selectedFilter1" (selectionChange)="applyFilter()">
<mat-option value="ou" i18n="@@organizationalUnitsOption">Unidades organizativas</mat-option>
<mat-option value="client" i18n="@@clientsOption">Clientes</mat-option>
</mat-select>
</mat-form-field>
<mat-form-field class="example-full-width">
<mat-label i18n="@@nameLabel">Nombre</mat-label>
<input matInput placeholder="Unidad organizativa" (input)="applyFilter()" [(ngModel)]="filterName" i18n-placeholder="@@namePlaceholder">
</mat-form-field>
<!-- <app-classroom-view class="card classroom-view" [clients]="clientsData" [pcInTable]="5"></app-classroom-view> -->
</div>
<!-- FILTROS UNIDAD ORGANIZATIVA-->
<ng-container *ngIf="selectedFilter1 === 'ou'">
<mat-form-field [disabled]="selectedFilter1 === 'ou'">
<mat-label i18n="@@unitTypeLabel">Tipo de unidad</mat-label>
<mat-select [(value)]="selectedFilter2" (selectionChange)="applyFilter()">
<mat-option value="organizational-unit" i18n="@@organizationalUnitOption">Unidad organizativa</mat-option>
<mat-option value="classroom-group" i18n="@@classroomsGroupOption">Grupos de aulas</mat-option>
<mat-option value="classroom" i18n="@@classroomOption">Aulas</mat-option>
<mat-option value="client-group" i18n="@@clientGroupOption">Grupos de clientes</mat-option>
</mat-select>
</mat-form-field>
<mat-form-field>
<mat-label i18n="@@floorLabel" class="temp_filter">Planta</mat-label>
<mat-select [(value)]="selectedFilter1">
<mat-option value="none" i18n="@@noneOption">Ninguno</mat-option>
<mat-option value="option1" i18n="@@option1">Planta 1</mat-option>
<mat-option value="option2" i18n="@@option2">Planta 2</mat-option>
<mat-option value="option3" i18n="@@option3">Planta 3</mat-option>
</mat-select>
</mat-form-field>
</ng-container>
<!-- FILTROS CLIENTES -->
<ng-container *ngIf="selectedFilter1 === 'client'">
<mat-form-field>
<mat-label i18n="@@selectAnotherOptionLabel" class="temp_filter">Sistema Operativo</mat-label>
<mat-select multiple [(value)]="selectedFilterOS" >
<mat-option value="none" i18n="@@noneOption">Ninguno</mat-option>
<mat-option value="Windows 10 Education 1803 64 bits">Windows 10 Education 1803 64 bits</mat-option>
<mat-option value="Ubuntu 18.04.1 LTS 64 bits">Ubuntu 18.04.1 LTS 64 bits</mat-option>
<mat-option value="Ubuntu 16.04.4 LTS 64 bits">Ubuntu 16.04.4 LTS 64 bits</mat-option>
<mat-option value="DATA">RESTO DE OPCIONES TBI</mat-option>
</mat-select>
</mat-form-field>
<mat-form-field>
<mat-label i18n="@@selectStateLabel" class="temp_filter">Estado</mat-label>
<mat-select multiple [(value)]="selectedFilterStatus">
<mat-option value="off" i18n="@@offOption">off</mat-option>
<mat-option value="initializing" i18n="@@initializingOption">initializing</mat-option>
<mat-option value="oglive" i18n="@@ogliveOption">oglive</mat-option>
<mat-option value="busy" i18n="@@busyOption">busy</mat-option>
<mat-option value="linux" i18n="@@linuxOption">linux</mat-option>
<mat-option value="linux_session" i18n="@@linuxSessionOption">linux_session</mat-option>
<mat-option value="macos" i18n="@@macosOption">macos</mat-option>
<mat-option value="windows" i18n="@@windowsOption">windows</mat-option>
<mat-option value="windows_session" i18n="@@windowsSessionOption">windows_session</mat-option>
</mat-select>
</mat-form-field>
<mat-form-field class="example-full-width">
<mat-label class="temp_filter">IP</mat-label>
<input matInput placeholder="Dírección IP" i18n [(ngModel)]="filterIP">
</mat-form-field>
<mat-form-field class="example-full-width" >
<mat-label class="temp_filter">MAC</mat-label>
<input matInput placeholder="Dírección IP" i18n [(ngModel)]="filterMAC">
</mat-form-field>
</ng-container>
<button mat-raised-button color="primary" (click)="toggleSelectAll()">Seleccionar/Deseleccionar Todos</button>
<button mat-raised-button color="primary" (click)="saveFilters()" i18n="@@saveFiltersButton">Guardar Filtros</button>
<button mat-raised-button color="accent" (click)="sendActions()" i18n="@@sendFiltersButton" [disabled]="selectedElements.length === 0">Enviar Acción</button>
</div>
<div class="results">
<ng-container *ngIf="filteredResults && filteredResults.length > 0; else noResults">
<mat-grid-list cols="4" rowHeight="1:1">
<mat-grid-tile *ngFor="let result of filteredResults">
<mat-card class="result-card">
<mat-checkbox
[checked]="isSelected(result.name)"
(change)="onCheckboxChange($event, result.name)">
</mat-checkbox>
<mat-card-title>{{ result.name }}</mat-card-title>
<mat-card-content>
<p>{{ result.type }}</p>
<p *ngIf="result.type !== 'client'" i18n="@@internalUnits">
Unidades internas: {{ result.type !== 'client' ? result.children.length : 0 }}
</p>
<p *ngIf="result.type !== 'client'" i18n="@@clients">
Clientes: {{ result.type !== 'client' ? result.clients.length : 0 }}
</p>
</mat-card-content>
</mat-card>
</mat-grid-tile>
</mat-grid-list>
<div class="paginator-container">
<mat-paginator [length]="length"
[pageSize]="itemsPerPage"
[pageIndex]="page"
[pageSizeOptions]="pageSizeOptions"
(page)="onPageChange($event)">
</mat-paginator>
</div>
</ng-container>
<ng-template #noResults>
<p i18n="@@noResultsMessage">No hay resultados para mostrar.</p>
</ng-template>
</div>
</div>
</div>
</mat-tab>
</mat-tab-group>

View File

@ -13,8 +13,11 @@ import {ToastrService} from "ngx-toastr";
import {TreeViewComponent} from "./tree-view/tree-view.component"; import {TreeViewComponent} from "./tree-view/tree-view.component";
import {MatBottomSheet} from "@angular/material/bottom-sheet"; import {MatBottomSheet} from "@angular/material/bottom-sheet";
import {LegendComponent} from "./legend/legend.component"; import {LegendComponent} from "./legend/legend.component";
import { ClassroomViewComponent } from './classroom-view/classroom-view.component';
import { ClassroomViewDialogComponent } from './classroom-view/classroom-view-modal'; import { ClassroomViewDialogComponent } from './classroom-view/classroom-view-modal';
import {HttpClient} from "@angular/common/http";
import {PageEvent} from "@angular/material/paginator";
import { SaveFiltersDialogComponent } from './save-filters-dialog/save-filters-dialog.component';
import { AcctionsModalComponent } from './acctions-modal/acctions-modal.component';
@Component({ @Component({
selector: 'app-groups', selector: 'app-groups',
@ -24,23 +27,55 @@ import { ClassroomViewDialogComponent } from './classroom-view/classroom-view-mo
export class GroupsComponent implements OnInit { export class GroupsComponent implements OnInit {
organizationalUnits: UnidadOrganizativa[] = []; organizationalUnits: UnidadOrganizativa[] = [];
selectedUnidad: UnidadOrganizativa | null = null; selectedUnidad: UnidadOrganizativa | null = null;
selectedDetail: any | null = null; // Nueva variable para el detalle del elemento seleccionado selectedDetail: any | null = null;
children: any[] = []; children: any[] = [];
breadcrumb: string[] = []; breadcrumb: string[] = [];
clientsData: any[] = []; // Nueva variable para almacenar los datos de clients clientsData: any[] = [];
breadcrumbData: any[] = []; // Almacenar datos de breadcrumb para navegar breadcrumbData: any[] = [];
loading:boolean = false; loading:boolean = false;
loadingChildren:boolean = false; loadingChildren:boolean = false;
searchTerm: string = ''; searchTerm: string = '';
constructor( selectedFilter1: string = 'none';
selectedFilter2: string = 'none';
selectedFilterOS: string[] = [];
selectedFilterStatus: string[] = [];
filterIP: string = '';
filterMAC: string = '';
filterName: string = '';
filteredResults: any[] = [];
savedFilterNames: any[] = [];
length: number = 0;
itemsPerPage: number = 10;
page: number = 1;
pageSizeOptions: number[] = [5, 10, 25, 100];
selectedElements: string[] = [];
isAllSelected: boolean = false;
constructor(
private dataService: DataService, private dataService: DataService,
public dialog: MatDialog, public dialog: MatDialog,
private toastService: ToastrService, private toastService: ToastrService,
private _bottomSheet: MatBottomSheet private _bottomSheet: MatBottomSheet,
private http: HttpClient
) {} ) {}
ngOnInit(): void { ngOnInit(): void {
this.search(); this.search();
this.getFilters();
}
getFilters(): void {
this.dataService.getFilters().subscribe(
data => {
this.savedFilterNames = data.map((filter: any) => [filter.name, filter.uuid]);
},
error => {
console.error('Error fetching filters:', error);
}
);
} }
search(): void { search(): void {
@ -48,11 +83,11 @@ constructor(
this.dataService.getOrganizationalUnits(this.searchTerm).subscribe( this.dataService.getOrganizationalUnits(this.searchTerm).subscribe(
data => { data => {
this.organizationalUnits = data; this.organizationalUnits = data;
this.loading = false; // Desactivar el spinner después de obtener los datos this.loading = false;
}, },
error => { error => {
console.error('Error fetching unidades organizativas', error); console.error('Error fetching unidades organizativas', error);
this.loading = false; // Desactivar el spinner en caso de error this.loading = false;
} }
); );
} }
@ -60,14 +95,14 @@ constructor(
onSelectUnidad(unidad: UnidadOrganizativa): void { onSelectUnidad(unidad: UnidadOrganizativa): void {
this.selectedUnidad = unidad; this.selectedUnidad = unidad;
this.selectedDetail = unidad; // Mostrar detalles de la unidad seleccionada this.selectedDetail = unidad;
this.breadcrumb = [unidad.name]; this.breadcrumb = [unidad.name];
this.breadcrumbData = [unidad]; this.breadcrumbData = [unidad];
this.loadChildrenAndClients(unidad.id); this.loadChildrenAndClients(unidad.id);
} }
onSelectChild(child: any): void { onSelectChild(child: any): void {
this.selectedDetail = child; // Mostrar detalles del niño seleccionado this.selectedDetail = child;
if (child.type !== 'client' && child.uuid && child.id) { if (child.type !== 'client' && child.uuid && child.id) {
this.breadcrumb.push(child.name || child.name); this.breadcrumb.push(child.name || child.name);
this.breadcrumbData.push(child); this.breadcrumbData.push(child);
@ -93,27 +128,27 @@ constructor(
console.log('Children data:', childrenData); console.log('Children data:', childrenData);
this.dataService.getClients(id).subscribe( this.dataService.getClients(id).subscribe(
clientsData => { clientsData => {
this.clientsData = clientsData; // Almacenar clientsData para pasarlo al componente hijo this.clientsData = clientsData;
const newChildren = [...childrenData, ...clientsData]; const newChildren = [...childrenData, ...clientsData];
if (newChildren.length > 0) { if (newChildren.length > 0) {
this.children = newChildren; this.children = newChildren;
} else { } else {
this.children = []; // Limpiar card2 cuando no hay elementos this.children = [];
} }
this.loadingChildren = false this.loadingChildren = false
}, },
error => { error => {
console.error('Error fetching clients', error); console.error('Error fetching clients', error);
this.clientsData = []; // Limpiar clientsData en caso de error this.clientsData = [];
this.children = []; // Limpiar card2 en caso de error this.children = [];
this.loadingChildren = false this.loadingChildren = false
} }
); );
}, },
error => { error => {
console.error('Error fetching children', error); console.error('Error fetching children', error);
this.children = []; // Limpiar card2 en caso de error this.children = [];
this.loadingChildren = false this.loadingChildren = false
} }
); );
@ -138,7 +173,6 @@ constructor(
const dialogRef = this.dialog.open(CreateClientComponent, { data: { organizationalUnit }, width: '700px'}); const dialogRef = this.dialog.open(CreateClientComponent, { data: { organizationalUnit }, width: '700px'});
// Subscribirse al evento unitAdded del componente de creación después de cerrar el diálogo
dialogRef.afterClosed().subscribe(() => { dialogRef.afterClosed().subscribe(() => {
this.dataService.getOrganizationalUnits().subscribe( this.dataService.getOrganizationalUnits().subscribe(
data => { data => {
@ -267,4 +301,117 @@ constructor(
}); });
} }
} }
applyFilter() {
this.dataService.getFilteredResults(this.selectedFilter1, this.selectedFilter2, this.filterName, this.page, this.itemsPerPage)
.subscribe(
response => {
this.filteredResults = response.results;
this.length = response.total;
},
error => {
console.error('Error al obtener los resultados filtrados', error);
this.filteredResults = [];
}
);
}
onPageChange(event: PageEvent) {
this.page = event.pageIndex;
this.itemsPerPage = event.pageSize;
this.applyFilter();
}
saveFilters() {
const dialogRef = this.dialog.open(SaveFiltersDialogComponent);
dialogRef.afterClosed().subscribe(result => {
if (result) {
const filters = {
name: result,
favourite: true,
filters: {
filter0: this.filterName,
filter1: this.selectedFilter1,
filter2: this.selectedFilter2,
filter3: this.selectedFilterOS,
filter4: this.selectedFilterStatus,
filter5: this.filterIP,
filter6: this.filterMAC,
}
};
this.http.post('http://127.0.0.1:8080/views', filters).subscribe(response => {
console.log('Response from server:', response);
this.toastService.success('Se ha guardado el filtro correctamente');
}, error => {
console.error('Error:', error);
this.toastService.error(error);
});
}
});
}
loadSelectedFilter(savedFilter: any) {
const url = 'http://127.0.0.1:8080/views/' + savedFilter[1];
console.log('llamando a:', url);
this.dataService.getFilter(savedFilter[1]).subscribe(response => {
console.log('Response from server:', response.filters);
if (response) {
console.log('Filter1:', response.filters);
this.filterName = response.filters.filter0 || '';
this.selectedFilter1 = response.filters.filter1 || null;
this.selectedFilter2 = response.filters.filter2 || '';
this.selectedFilterOS = response.filters.filter3 || [];
this.selectedFilterStatus = response.filters.filter4 || [];
this.filterIP = response.filters.filter5 || '';
this.filterMAC = response.filters.filter6 || '';
this.applyFilter();
}
}, error => {
console.error('Error:', error);
});
}
onCheckboxChange(event: any, name: string) {
if (event.checked) {
this.selectedElements.push(name);
} else {
const index = this.selectedElements.indexOf(name);
if (index > -1) {
this.selectedElements.splice(index, 1);
}
}
this.isAllSelected = this.selectedElements.length === this.filteredResults.length;
console.log(this.selectedElements);
}
toggleSelectAll() {
this.isAllSelected = !this.isAllSelected;
if (this.isAllSelected) {
this.selectedElements = this.filteredResults.map(result => result.name);
} else {
this.selectedElements = [];
}
console.log(this.selectedElements);
}
isSelected(name: string): boolean {
return this.selectedElements.includes(name);
}
sendActions() {
const dialogRef = this.dialog.open(AcctionsModalComponent, { data: { selectedElements: this.selectedElements }, width: '700px'});
}
} }

View File

@ -1,22 +1,22 @@
<mat-list> <mat-list>
<mat-list-item> <mat-list-item>
<mat-icon matListItemIcon>apartment</mat-icon> <mat-icon matListItemIcon>apartment</mat-icon>
<div matListItemTitle>Unidad organizativa</div> <div matListItemTitle i18n="@@orgUnitTitle">Unidad organizativa</div>
</mat-list-item> </mat-list-item>
<mat-list-item> <mat-list-item>
<mat-icon matListItemIcon>meeting_room</mat-icon> <mat-icon matListItemIcon>meeting_room</mat-icon>
<div matListItemTitle>Grupos de aula</div> <div matListItemTitle i18n="@@classroomGroupsTitle">Grupos de aula</div>
</mat-list-item> </mat-list-item>
<mat-list-item> <mat-list-item>
<mat-icon matListItemIcon>school</mat-icon> <mat-icon matListItemIcon>school</mat-icon>
<div matListItemTitle>Aula</div> <div matListItemTitle i18n="@@classroomTitle">Aula</div>
</mat-list-item> </mat-list-item>
<mat-list-item> <mat-list-item>
<mat-icon matListItemIcon>lan</mat-icon> <mat-icon matListItemIcon>lan</mat-icon>
<div matListItemTitle>Grupos de clientes</div> <div matListItemTitle i18n="@@clientGroupsTitle">Grupos de clientes</div>
</mat-list-item> </mat-list-item>
<mat-list-item> <mat-list-item>
<mat-icon matListItemIcon>computer</mat-icon> <mat-icon matListItemIcon>computer</mat-icon>
<div matListItemTitle>Cliente</div> <div matListItemTitle i18n="@@clientTitle">Cliente</div>
</mat-list-item> </mat-list-item>
</mat-list> </mat-list>

View File

@ -1,13 +1,13 @@
<h1 mat-dialog-title>Añadir Unidad Organizativa</h1> <h1 mat-dialog-title i18n="@@addOrgUnitTitle">Añadir Unidad Organizativa</h1>
<div mat-dialog-content> <div mat-dialog-content>
<mat-stepper orientation="vertical" [linear]="isLinear"> <mat-stepper orientation="vertical" [linear]="isLinear">
<!-- Step 1: General --> <!-- Step 1: General -->
<mat-step [stepControl]="generalFormGroup"> <mat-step [stepControl]="generalFormGroup">
<form [formGroup]="generalFormGroup"> <form [formGroup]="generalFormGroup">
<ng-template matStepLabel>General</ng-template> <ng-template matStepLabel i18n="@@generalStepLabel">General</ng-template>
<mat-form-field class="form-field"> <mat-form-field class="form-field">
<mat-label>Tipo</mat-label> <mat-label i18n="@@typeLabel">Tipo</mat-label>
<mat-select formControlName="type" required> <mat-select formControlName="type" required>
<mat-option *ngFor="let type of types" [value]="type"> <mat-option *ngFor="let type of types" [value]="type">
{{ typeTranslations[type] }} {{ typeTranslations[type] }}
@ -15,22 +15,22 @@
</mat-select> </mat-select>
</mat-form-field> </mat-form-field>
<mat-form-field class="form-field"> <mat-form-field class="form-field">
<mat-label>Nombre</mat-label> <mat-label i18n="@@nameLabel">Nombre</mat-label>
<input matInput formControlName="name" required> <input matInput formControlName="name" required>
</mat-form-field> </mat-form-field>
<mat-form-field class="form-field"> <mat-form-field class="form-field">
<mat-label>Unidad organizativa padre</mat-label> <mat-label i18n="@@createOrgUnitparentLabel">Unidad organizativa padre</mat-label>
<mat-select formControlName="parent"> <mat-select formControlName="parent">
<mat-option>--</mat-option> <mat-option i18n="@@noParentOption">--</mat-option>
<mat-option *ngFor="let unit of parentUnits" [value]="unit['@id']">{{ unit.name }}</mat-option> <mat-option *ngFor="let unit of parentUnits" [value]="unit['@id']">{{ unit.name }}</mat-option>
</mat-select> </mat-select>
</mat-form-field> </mat-form-field>
<mat-form-field class="form-field"> <mat-form-field class="form-field">
<mat-label>Descripción</mat-label> <mat-label i18n="@@descriptionLabel">Descripción</mat-label>
<textarea matInput formControlName="description"></textarea> <textarea matInput formControlName="description"></textarea>
</mat-form-field> </mat-form-field>
<div> <div>
<button mat-button matStepperNext>Siguiente</button> <button mat-button matStepperNext i18n="@@nextButton">Siguiente</button>
</div> </div>
</form> </form>
</mat-step> </mat-step>
@ -38,20 +38,20 @@
<!-- Step 2: Classroom Info --> <!-- Step 2: Classroom Info -->
<mat-step *ngIf="generalFormGroup.value.type === 'classroom'" [stepControl]="classroomInfoFormGroup"> <mat-step *ngIf="generalFormGroup.value.type === 'classroom'" [stepControl]="classroomInfoFormGroup">
<form [formGroup]="classroomInfoFormGroup"> <form [formGroup]="classroomInfoFormGroup">
<ng-template matStepLabel>Información del Aula</ng-template> <ng-template matStepLabel i18n="@@classroomInfoStepLabel">Información del Aula</ng-template>
<mat-form-field class="form-field"> <mat-form-field class="form-field">
<mat-label>Ubicación</mat-label> <mat-label i18n="@@locationLabel">Ubicación</mat-label>
<input matInput formControlName="location"> <input matInput formControlName="location">
</mat-form-field> </mat-form-field>
<mat-slide-toggle formControlName="projector">Proyector</mat-slide-toggle> <mat-slide-toggle formControlName="projector" i18n="@@projectorToggle">Proyector</mat-slide-toggle>
<mat-slide-toggle formControlName="board">Pizarra</mat-slide-toggle> <mat-slide-toggle formControlName="board" i18n="@@boardToggle">Pizarra</mat-slide-toggle>
<mat-form-field class="form-field"> <mat-form-field class="form-field">
<mat-label>Aforo</mat-label> <mat-label i18n="@@capacityLabel">Aforo</mat-label>
<input matInput formControlName="capacity" type="number"> <input matInput formControlName="capacity" type="number">
</mat-form-field> </mat-form-field>
<div> <div>
<button mat-button matStepperPrevious>Atrás</button> <button mat-button matStepperPrevious i18n="@@backButton">Atrás</button>
<button mat-button matStepperNext>Siguiente</button> <button mat-button matStepperNext i18n="@@nextButton">Siguiente</button>
</div> </div>
</form> </form>
</mat-step> </mat-step>
@ -59,14 +59,14 @@
<!-- Step 3: Información Adicional --> <!-- Step 3: Información Adicional -->
<mat-step [stepControl]="additionalInfoFormGroup"> <mat-step [stepControl]="additionalInfoFormGroup">
<form [formGroup]="additionalInfoFormGroup"> <form [formGroup]="additionalInfoFormGroup">
<ng-template matStepLabel>Información Adicional</ng-template> <ng-template matStepLabel i18n="@@additionalInfoStepLabel">Información Adicional</ng-template>
<mat-form-field class="form-field"> <mat-form-field class="form-field">
<mat-label>Comentarios</mat-label> <mat-label i18n="@@commentsLabel">Comentarios</mat-label>
<textarea matInput formControlName="comments"></textarea> <textarea matInput formControlName="comments"></textarea>
</mat-form-field> </mat-form-field>
<div> <div>
<button mat-button matStepperPrevious>Atrás</button> <button mat-button matStepperPrevious i18n="@@backButton">Atrás</button>
<button mat-button matStepperNext>Siguiente</button> <button mat-button matStepperNext i18n="@@nextButton">Siguiente</button>
</div> </div>
</form> </form>
</mat-step> </mat-step>
@ -74,82 +74,82 @@
<!-- Step 4: Configuración de Red --> <!-- Step 4: Configuración de Red -->
<mat-step [stepControl]="networkSettingsFormGroup"> <mat-step [stepControl]="networkSettingsFormGroup">
<form [formGroup]="networkSettingsFormGroup"> <form [formGroup]="networkSettingsFormGroup">
<ng-template matStepLabel>Configuración de Red</ng-template> <ng-template matStepLabel i18n="@@networkSettingsStepLabel">Configuración de Red</ng-template>
<mat-form-field class="form-field"> <mat-form-field class="form-field">
<mat-label>Url servidor Proxy</mat-label> <mat-label i18n="@@proxyUrlLabel">Url servidor Proxy</mat-label>
<input matInput formControlName="proxy"> <input matInput formControlName="proxy">
</mat-form-field> </mat-form-field>
<mat-form-field class="form-field"> <mat-form-field class="form-field">
<mat-label>IP servidor DNS</mat-label> <mat-label i18n="@@dnsIpLabel">IP servidor DNS</mat-label>
<input matInput formControlName="dns"> <input matInput formControlName="dns">
</mat-form-field> </mat-form-field>
<mat-form-field class="form-field"> <mat-form-field class="form-field">
<mat-label>Máscara de Red</mat-label> <mat-label i18n="@@netmaskLabel">Máscara de Red</mat-label>
<input matInput formControlName="netmask"> <input matInput formControlName="netmask">
</mat-form-field> </mat-form-field>
<mat-form-field class="form-field"> <mat-form-field class="form-field">
<mat-label>Router</mat-label> <mat-label i18n="@@routerLabel">Router</mat-label>
<input matInput formControlName="router"> <input matInput formControlName="router">
</mat-form-field> </mat-form-field>
<mat-form-field class="form-field"> <mat-form-field class="form-field">
<mat-label>IP servidor NTP</mat-label> <mat-label i18n="@@ntpIpLabel">IP servidor NTP</mat-label>
<input matInput formControlName="ntp"> <input matInput formControlName="ntp">
</mat-form-field> </mat-form-field>
<mat-form-field class="form-field"> <mat-form-field class="form-field">
<mat-label>Modo P2P</mat-label> <mat-label i18n="@@p2pModeLabel">Modo P2P</mat-label>
<mat-select formControlName="p2pMode"> <mat-select formControlName="p2pMode">
<mat-option <mat-option
*ngFor="let option of p2pModeOptions" *ngFor="let option of p2pModeOptions"
value="{{ option.value }}"> [value]="option.value">
{{ option.name }} {{ option.name }}
</mat-option> </mat-option>
</mat-select> </mat-select>
</mat-form-field> </mat-form-field>
<mat-form-field class="form-field"> <mat-form-field class="form-field">
<mat-label>Tiempo P2P</mat-label> <mat-label i18n="@@p2pTimeLabel">Tiempo P2P</mat-label>
<input matInput formControlName="p2pTime" type="number"> <input matInput formControlName="p2pTime" type="number">
</mat-form-field> </mat-form-field>
<mat-form-field class="form-field"> <mat-form-field class="form-field">
<mat-label>IP Multicast</mat-label> <mat-label i18n="@@mcastIpLabel">IP Multicast</mat-label>
<input matInput formControlName="mcastIp"> <input matInput formControlName="mcastIp">
</mat-form-field> </mat-form-field>
<mat-form-field class="form-field"> <mat-form-field class="form-field">
<mat-label>Velocidad Multicast</mat-label> <mat-label i18n="@@mcastSpeedLabel">Velocidad Multicast</mat-label>
<input matInput formControlName="mcastSpeed" type="number"> <input matInput formControlName="mcastSpeed" type="number">
</mat-form-field> </mat-form-field>
<mat-form-field class="form-field"> <mat-form-field class="form-field">
<mat-label>Puerto Multicast</mat-label> <mat-label i18n="@@mcastPortLabel">Puerto Multicast</mat-label>
<input matInput formControlName="mcastPort" type="number"> <input matInput formControlName="mcastPort" type="number">
</mat-form-field> </mat-form-field>
<mat-form-field class="form-field"> <mat-form-field class="form-field">
<mat-label>Modo Multicast</mat-label> <mat-label i18n="@@mcastModeLabel">Modo Multicast</mat-label>
<mat-select formControlName="mcastMode"> <mat-select formControlName="mcastMode">
<mat-option <mat-option
*ngFor="let option of multicastModeOptions" *ngFor="let option of multicastModeOptions"
value="{{ option.value }}"> [value]="option.value">
{{ option.name }} {{ option.name }}
</mat-option> </mat-option>
</mat-select> </mat-select>
</mat-form-field> </mat-form-field>
<mat-form-field class="form-field"> <mat-form-field class="form-field">
<mat-label>Menú URL</mat-label> <mat-label i18n="@@menuUrlLabel">Menú URL</mat-label>
<input matInput formControlName="menu" type="url"> <input matInput formControlName="menu" type="url">
</mat-form-field> </mat-form-field>
<mat-form-field class="form-field"> <mat-form-field class="form-field">
<mat-label>Perfil de Hardware</mat-label> <mat-label i18n="@@hardwareProfileLabel">Perfil de Hardware</mat-label>
<mat-select formControlName="hardwareProfile"> <mat-select formControlName="hardwareProfile">
<mat-option *ngFor="let unit of hardwareProfiles" [value]="unit['@id']">{{ unit.description }} </mat-option> <mat-option *ngFor="let unit of hardwareProfiles" [value]="unit['@id']">{{ unit.description }} </mat-option>
</mat-select> </mat-select>
<mat-error>Formato de URL inválido.</mat-error> <mat-error i18n="@@urlFormatError">Formato de URL inválido.</mat-error>
</mat-form-field> </mat-form-field>
<div> <div>
<button mat-button matStepperPrevious>Atrás</button> <button mat-button matStepperPrevious i18n="@@backButton">Atrás</button>
<button mat-button (click)="onSubmit()" [disabled]="!networkSettingsFormGroup.valid">Añadir</button> <button mat-button (click)="onSubmit()" [disabled]="!networkSettingsFormGroup.valid" i18n="@@submitButton">Añadir</button>
</div> </div>
</form> </form>
</mat-step> </mat-step>
</mat-stepper> </mat-stepper>
</div> </div>
<div mat-dialog-actions> <div mat-dialog-actions>
<button mat-button (click)="onNoClick()">Cancelar</button> <button mat-button (click)="onNoClick()" i18n="@@cancelButton">Cancelar</button>
</div> </div>

View File

@ -1,32 +1,32 @@
<h1 mat-dialog-title>Editar Unidad Organizativa</h1> <h1 mat-dialog-title i18n="@@editOrgUnitTitle">Editar Unidad Organizativa</h1>
<div mat-dialog-content> <div mat-dialog-content>
<mat-stepper orientation="vertical" [linear]="isLinear"> <mat-stepper orientation="vertical" [linear]="isLinear">
<!-- Step 1: General --> <!-- Step 1: General -->
<mat-step [stepControl]="generalFormGroup"> <mat-step [stepControl]="generalFormGroup">
<form [formGroup]="generalFormGroup"> <form [formGroup]="generalFormGroup">
<ng-template matStepLabel>General</ng-template> <ng-template matStepLabel i18n="@@generalStepLabel">General</ng-template>
<mat-form-field class="form-field"> <mat-form-field class="form-field">
<mat-label>Tipo</mat-label> <mat-label i18n="@@typeLabel">Tipo</mat-label>
<mat-select formControlName="type" required> <mat-select formControlName="type" required>
<mat-option *ngFor="let type of types" [value]="type">{{ type }}</mat-option> <mat-option *ngFor="let type of types" [value]="type">{{ type }}</mat-option>
</mat-select> </mat-select>
</mat-form-field> </mat-form-field>
<mat-form-field class="form-field"> <mat-form-field class="form-field">
<mat-label>Nombre</mat-label> <mat-label i18n="@@nameLabel">Nombre</mat-label>
<input matInput formControlName="name" required> <input matInput formControlName="name" required>
</mat-form-field> </mat-form-field>
<mat-form-field class="form-field"> <mat-form-field class="form-field">
<mat-label>Padre</mat-label> <mat-label i18n="@@editOrgUnitParentLabel">Padre</mat-label>
<mat-select formControlName="parent"> <mat-select formControlName="parent">
<mat-option *ngFor="let unit of parentUnits" [value]="unit['@id']">{{ unit.name }}</mat-option> <mat-option *ngFor="let unit of parentUnits" [value]="unit['@id']">{{ unit.name }}</mat-option>
</mat-select> </mat-select>
</mat-form-field> </mat-form-field>
<mat-form-field class="form-field"> <mat-form-field class="form-field">
<mat-label>Descripción</mat-label> <mat-label i18n="@@descriptionLabel">Descripción</mat-label>
<textarea matInput formControlName="description"></textarea> <textarea matInput formControlName="description"></textarea>
</mat-form-field> </mat-form-field>
<div> <div>
<button mat-button matStepperNext>Siguiente</button> <button mat-button matStepperNext i18n="@@nextButton">Siguiente</button>
</div> </div>
</form> </form>
</mat-step> </mat-step>
@ -34,20 +34,20 @@
<!-- Step 2: Classroom Info --> <!-- Step 2: Classroom Info -->
<mat-step *ngIf="generalFormGroup.value.type === 'classroom'" [stepControl]="classroomInfoFormGroup"> <mat-step *ngIf="generalFormGroup.value.type === 'classroom'" [stepControl]="classroomInfoFormGroup">
<form [formGroup]="classroomInfoFormGroup"> <form [formGroup]="classroomInfoFormGroup">
<ng-template matStepLabel>Información del Aula</ng-template> <ng-template matStepLabel i18n="@@classroomInfoStepLabel">Información del Aula</ng-template>
<mat-form-field class="form-field"> <mat-form-field class="form-field">
<mat-label>Ubicación</mat-label> <mat-label i18n="@@locationLabel">Ubicación</mat-label>
<input matInput formControlName="location"> <input matInput formControlName="location">
</mat-form-field> </mat-form-field>
<mat-slide-toggle formControlName="projector">Proyector</mat-slide-toggle> <mat-slide-toggle formControlName="projector" i18n="@@projectorToggle">Proyector</mat-slide-toggle>
<mat-slide-toggle formControlName="board">Pizarra</mat-slide-toggle> <mat-slide-toggle formControlName="board" i18n="@@boardToggle">Pizarra</mat-slide-toggle>
<mat-form-field class="form-field"> <mat-form-field class="form-field">
<mat-label>Aforo</mat-label> <mat-label i18n="@@capacityLabel">Aforo</mat-label>
<input matInput formControlName="capacity" type="number"> <input matInput formControlName="capacity" type="number">
</mat-form-field> </mat-form-field>
<div> <div>
<button mat-button matStepperPrevious>Atrás</button> <button mat-button matStepperPrevious i18n="@@backButton">Atrás</button>
<button mat-button matStepperNext>Siguiente</button> <button mat-button matStepperNext i18n="@@nextButton">Siguiente</button>
</div> </div>
</form> </form>
</mat-step> </mat-step>
@ -55,14 +55,14 @@
<!-- Step 3: Información Adicional --> <!-- Step 3: Información Adicional -->
<mat-step [stepControl]="additionalInfoFormGroup"> <mat-step [stepControl]="additionalInfoFormGroup">
<form [formGroup]="additionalInfoFormGroup"> <form [formGroup]="additionalInfoFormGroup">
<ng-template matStepLabel>Información Adicional</ng-template> <ng-template matStepLabel i18n="@@additionalInfoStepLabel">Información Adicional</ng-template>
<mat-form-field class="form-field"> <mat-form-field class="form-field">
<mat-label>Comentarios</mat-label> <mat-label i18n="@@commentsLabel">Comentarios</mat-label>
<textarea matInput formControlName="comments"></textarea> <textarea matInput formControlName="comments"></textarea>
</mat-form-field> </mat-form-field>
<div> <div>
<button mat-button matStepperPrevious>Atrás</button> <button mat-button matStepperPrevious i18n="@@backButton">Atrás</button>
<button mat-button matStepperNext>Siguiente</button> <button mat-button matStepperNext i18n="@@nextButton">Siguiente</button>
</div> </div>
</form> </form>
</mat-step> </mat-step>
@ -70,83 +70,83 @@
<!-- Step 4: Configuración de Red --> <!-- Step 4: Configuración de Red -->
<mat-step [stepControl]="networkSettingsFormGroup"> <mat-step [stepControl]="networkSettingsFormGroup">
<form [formGroup]="networkSettingsFormGroup"> <form [formGroup]="networkSettingsFormGroup">
<ng-template matStepLabel>Configuración de Red</ng-template> <ng-template matStepLabel i18n="@@networkSettingsStepLabel">Configuración de Red</ng-template>
<mat-form-field class="form-field"> <mat-form-field class="form-field">
<mat-label>Url servidor Proxy</mat-label> <mat-label i18n="@@proxyUrlLabel">Url servidor Proxy</mat-label>
<input matInput formControlName="proxy"> <input matInput formControlName="proxy">
</mat-form-field> </mat-form-field>
<mat-form-field class="form-field"> <mat-form-field class="form-field">
<mat-label>IP servidor DNS</mat-label> <mat-label i18n="@@dnsIpLabel">IP servidor DNS</mat-label>
<input matInput formControlName="dns"> <input matInput formControlName="dns">
</mat-form-field> </mat-form-field>
<mat-form-field class="form-field"> <mat-form-field class="form-field">
<mat-label>Máscara de Red</mat-label> <mat-label i18n="@@netmaskLabel">Máscara de Red</mat-label>
<input matInput formControlName="netmask"> <input matInput formControlName="netmask">
</mat-form-field> </mat-form-field>
<mat-form-field class="form-field"> <mat-form-field class="form-field">
<mat-label>Router</mat-label> <mat-label i18n="@@routerLabel">Router</mat-label>
<input matInput formControlName="router"> <input matInput formControlName="router">
</mat-form-field> </mat-form-field>
<mat-form-field class="form-field"> <mat-form-field class="form-field">
<mat-label>IP servidor NTP</mat-label> <mat-label i18n="@@ntpIpLabel">IP servidor NTP</mat-label>
<input matInput formControlName="ntp"> <input matInput formControlName="ntp">
</mat-form-field> </mat-form-field>
<mat-form-field class="form-field"> <mat-form-field class="form-field">
<mat-label>Modo P2P</mat-label> <mat-label i18n="@@p2pModeLabel">Modo P2P</mat-label>
<mat-select formControlName="p2pMode"> <mat-select formControlName="p2pMode">
<mat-option <mat-option
*ngFor="let option of p2pModeOptions" *ngFor="let option of p2pModeOptions"
value="{{ option.value }}"> [value]="option.value">
{{ option.name }} {{ option.name }}
</mat-option> </mat-option>
</mat-select> </mat-select>
</mat-form-field> </mat-form-field>
<mat-form-field class="form-field"> <mat-form-field class="form-field">
<mat-label>Tiempo P2P</mat-label> <mat-label i18n="@@p2pTimeLabel">Tiempo P2P</mat-label>
<input matInput formControlName="p2pTime" type="number"> <input matInput formControlName="p2pTime" type="number">
</mat-form-field> </mat-form-field>
<mat-form-field class="form-field"> <mat-form-field class="form-field">
<mat-label>IP Multicast</mat-label> <mat-label i18n="@@mcastIpLabel">IP Multicast</mat-label>
<input matInput formControlName="mcastIp"> <input matInput formControlName="mcastIp">
</mat-form-field> </mat-form-field>
<mat-form-field class="form-field"> <mat-form-field class="form-field">
<mat-label>Velocidad Multicast</mat-label> <mat-label i18n="@@mcastSpeedLabel">Velocidad Multicast</mat-label>
<input matInput formControlName="mcastSpeed" type="number"> <input matInput formControlName="mcastSpeed" type="number">
</mat-form-field> </mat-form-field>
<mat-form-field class="form-field"> <mat-form-field class="form-field">
<mat-label>Puerto Multicast</mat-label> <mat-label i18n="@@mcastPortLabel">Puerto Multicast</mat-label>
<input matInput formControlName="mcastPort" type="number"> <input matInput formControlName="mcastPort" type="number">
</mat-form-field> </mat-form-field>
<mat-form-field class="form-field"> <mat-form-field class="form-field">
<mat-label>Modo Multicast</mat-label> <mat-label i18n="@@mcastModeLabel">Modo Multicast</mat-label>
<mat-select formControlName="mcastMode"> <mat-select formControlName="mcastMode">
<mat-option <mat-option
*ngFor="let option of multicastModeOptions" *ngFor="let option of multicastModeOptions"
value="{{ option.value }}"> [value]="option.value">
{{ option.name }} {{ option.name }}
</mat-option> </mat-option>
</mat-select> </mat-select>
</mat-form-field> </mat-form-field>
<mat-form-field class="form-field"> <mat-form-field class="form-field">
<mat-label>Menú URL</mat-label> <mat-label i18n="@@menuUrlLabel">Menú URL</mat-label>
<input matInput formControlName="menu" type="url"> <input matInput formControlName="menu" type="url">
</mat-form-field> </mat-form-field>
<mat-form-field class="form-field"> <mat-form-field class="form-field">
<mat-label>Perfil de Hardware</mat-label> <mat-label i18n="@@hardwareProfileLabel">Perfil de Hardware</mat-label>
<mat-select formControlName="hardwareProfile"> <mat-select formControlName="hardwareProfile">
<mat-option *ngFor="let unit of hardwareProfiles" [value]="unit['@id']">{{ unit.description }} </mat-option> <mat-option *ngFor="let unit of hardwareProfiles" [value]="unit['@id']">{{ unit.description }} </mat-option>
</mat-select> </mat-select>
<mat-error>Formato de URL inválido.</mat-error> <mat-error i18n="@@urlFormatError">Formato de URL inválido.</mat-error>
</mat-form-field> </mat-form-field>
<mat-slide-toggle formControlName="validation">Validación</mat-slide-toggle> <mat-slide-toggle formControlName="validation" i18n="@@validationToggle">Validación</mat-slide-toggle>
<div> <div>
<button mat-button matStepperPrevious>Atrás</button> <button mat-button matStepperPrevious i18n="@@backButton">Atrás</button>
<button mat-button (click)="onSubmit()" [disabled]="!networkSettingsFormGroup.valid">Añadir</button> <button mat-button (click)="onSubmit()" [disabled]="!networkSettingsFormGroup.valid" i18n="@@submitButton">Añadir</button>
</div> </div>
</form> </form>
</mat-step> </mat-step>
</mat-stepper> </mat-stepper>
</div> </div>
<div mat-dialog-actions> <div mat-dialog-actions>
<button mat-button (click)="onNoClick()">Cancelar</button> <button mat-button (click)="onNoClick()" i18n="@@cancelButton">Cancelar</button>
</div> </div>

View File

@ -1,42 +1,42 @@
<h1 mat-dialog-title>Propiedades unidad organizativa</h1> <h1 mat-dialog-title i18n="@@orgUnitPropertiesTitle">Propiedades unidad organizativa</h1>
<div mat-dialog-content> <div mat-dialog-content>
<mat-tab-group dynamicHeight> <mat-tab-group dynamicHeight>
<mat-tab label="Datos generales"> <mat-tab label="Datos generales" i18n-label="@@generalDataTab">
<table mat-table [dataSource]="generalData" class="mat-elevation-z8"> <table mat-table [dataSource]="generalData" class="mat-elevation-z8">
<ng-container matColumnDef="property"> <ng-container matColumnDef="property">
<th mat-header-cell *matHeaderCellDef> Propiedad </th> <th mat-header-cell *matHeaderCellDef i18n-header="@@propertyHeader"> Propiedad </th>
<td mat-cell *matCellDef="let element"> {{ element.property }} </td> <td mat-cell *matCellDef="let element"> {{ element.property }} </td>
</ng-container> </ng-container>
<ng-container matColumnDef="value"> <ng-container matColumnDef="value">
<th mat-header-cell *matHeaderCellDef> Valor </th> <th mat-header-cell *matHeaderCellDef i18n-header="@@valueHeader"> Valor </th>
<td mat-cell *matCellDef="let element"> {{ element.value }} </td> <td mat-cell *matCellDef="let element"> {{ element.value }} </td>
</ng-container> </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>
</mat-tab> </mat-tab>
<mat-tab [disabled]="data.data.type !== 'classroom'" label="Propiedades aula y de red"> <mat-tab [disabled]="data.data.type !== 'classroom'" label="Propiedades aula y de red" i18n-label="@@classroomNetworkPropertiesTab">
<table mat-table [dataSource]="networkData" class="mat-elevation-z8"> <table mat-table [dataSource]="networkData" class="mat-elevation-z8">
<ng-container matColumnDef="property"> <ng-container matColumnDef="property">
<th mat-header-cell *matHeaderCellDef> Propiedad </th> <th mat-header-cell *matHeaderCellDef i18n-header="@@propertyHeader"> Propiedad </th>
<td mat-cell *matCellDef="let element"> {{ element.property }} </td> <td mat-cell *matCellDef="let element"> {{ element.property }} </td>
</ng-container> </ng-container>
<ng-container matColumnDef="value"> <ng-container matColumnDef="value">
<th mat-header-cell *matHeaderCellDef> Valor </th> <th mat-header-cell *matHeaderCellDef i18n-header="@@valueHeader"> Valor </th>
<td mat-cell *matCellDef="let element"> {{ element.value }} </td> <td mat-cell *matCellDef="let element"> {{ element.value }} </td>
</ng-container> </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>
</mat-tab> </mat-tab>
<mat-tab disabled label="Acciones"> <mat-tab disabled label="Acciones" i18n-label="@@actionsTab">
<div class="button-column"> <div class="button-column">
<button mat-flat-button color="primary" class="button-encender">Encender</button> <button mat-flat-button color="primary" class="button-encender" i18n>Encender</button>
<button mat-flat-button color="accent" class="button-apagar">Apagar</button> <button mat-flat-button color="accent" class="button-apagar" i18n>Apagar</button>
<button mat-flat-button color="warn" class="button-resetear">Resetear</button> <button mat-flat-button color="warn" class="button-resetear" i18n>Resetear</button>
<button mat-flat-button class="button-otros-1">Otras acciones 1</button> <button mat-flat-button class="button-otros-1" i18n>Otras acciones 1</button>
<button mat-flat-button class="button-otros-2">Otras acciones 2</button> <button mat-flat-button class="button-otros-2" i18n>Otras acciones 2</button>
<button mat-flat-button class="button-otros-3">Otras acciones 3</button> <button mat-flat-button class="button-otros-3" i18n>Otras acciones 3</button>
</div> </div>
</mat-tab> </mat-tab>
</mat-tab-group> </mat-tab-group>

View File

@ -0,0 +1 @@
<p>save-filters-dialog works!</p>

View File

@ -0,0 +1,23 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { SaveFiltersDialogComponent } from './save-filters-dialog.component';
describe('SaveFiltersDialogComponent', () => {
let component: SaveFiltersDialogComponent;
let fixture: ComponentFixture<SaveFiltersDialogComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [SaveFiltersDialogComponent]
})
.compileComponents();
fixture = TestBed.createComponent(SaveFiltersDialogComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,38 @@
import { Component } from '@angular/core';
import { MatDialogRef } from '@angular/material/dialog';
import { FormControl, Validators } from '@angular/forms';
@Component({
selector: 'app-save-filters-dialog',
template: `
<h1 mat-dialog-title>Guardar filtros</h1>
<div mat-dialog-content>
<mat-form-field>
<mat-label>Nombre del filtro</mat-label>
<input matInput [formControl]="filterNameControl" placeholder="Nombre del filtro">
<mat-error *ngIf="filterNameControl.hasError('required')">
El nombre es obligatorio
</mat-error>
</mat-form-field>
</div>
<div mat-dialog-actions>
<button mat-button (click)="onCancel()">Cancelar</button>
<button mat-button [disabled]="filterNameControl.invalid" (click)="onSave()">Guardar</button>
</div>
`
})
export class SaveFiltersDialogComponent {
filterNameControl = new FormControl('', [Validators.required]);
constructor(public dialogRef: MatDialogRef<SaveFiltersDialogComponent>) {}
onCancel(): void {
this.dialogRef.close(null);
}
onSave(): void {
if (this.filterNameControl.valid) {
this.dialogRef.close(this.filterNameControl.value);
}
}
}

View File

@ -1,4 +1,4 @@
<h1 mat-dialog-title>Visualizar arbol unidad Organizativa</h1> <h1 mat-dialog-title i18n="@@viewTreeTitle">Visualizar árbol unidad Organizativa</h1>
<mat-dialog-content> <mat-dialog-content>
<mat-tree [dataSource]="dataSource" [treeControl]="treeControl" class="tree"> <mat-tree [dataSource]="dataSource" [treeControl]="treeControl" class="tree">
@ -17,7 +17,8 @@
<mat-nested-tree-node *matTreeNodeDef="let node; when: hasChild"> <mat-nested-tree-node *matTreeNodeDef="let node; when: hasChild">
<div class="mat-tree-node"> <div class="mat-tree-node">
<button mat-icon-button matTreeNodeToggle <button mat-icon-button matTreeNodeToggle
[attr.aria-label]="'Toggle ' + node.name"> [attr.aria-label]="'Toggle ' + node.name"
i18n-aria-label="@@toggleNodeAriaLabel">
<mat-icon class="mat-icon-rtl-mirror"> <mat-icon class="mat-icon-rtl-mirror">
{{treeControl.isExpanded(node) ? 'expand_more' : 'chevron_right'}} {{treeControl.isExpanded(node) ? 'expand_more' : 'chevron_right'}}
</mat-icon> </mat-icon>
@ -51,5 +52,5 @@
</mat-tree> </mat-tree>
</mat-dialog-content> </mat-dialog-content>
<mat-dialog-actions> <mat-dialog-actions>
<button mat-button (click)="close()">Cerrar</button> <button mat-button (click)="close()" i18n="@@closeButton">Cerrar</button>
</mat-dialog-actions> </mat-dialog-actions>

View File

@ -1,12 +1,12 @@
<mat-toolbar> <mat-toolbar>
<span class="navbar-tittle" routerLink="/dashboard">Opengnsys webconsole</span> <span class="navbar-title" routerLink="/dashboard" i18n="@@webConsoleTitle">Opengnsys webconsole</span>
<div class="navbar-button-row"> <div class="navbar-button-row">
<button class="admin-button" *ngIf="isSuperAdmin" mat-button [matMenuTriggerFor]="menu">Administracion</button> <button class="admin-button" *ngIf="isSuperAdmin" mat-button [matMenuTriggerFor]="menu" i18n="@@admin">Administración</button>
<button class="user-button" mat-button *ngIf="!isSuperAdmin" (click)="editUser()">Editar usuario</button> <button class="user-button" mat-button *ngIf="!isSuperAdmin" (click)="editUser()" i18n="@@editUser">Editar usuario</button>
<mat-menu #menu="matMenu"> <mat-menu #menu="matMenu">
<button mat-menu-item routerLink="/users">Usuarios</button> <button mat-menu-item routerLink="/users" i18n="@@usersMenuItem">Usuarios</button>
<button mat-menu-item routerLink="/user-groups">Roles</button> <button mat-menu-item routerLink="/user-groups" i18n="@@rolesMenuItem">Roles</button>
</mat-menu> </mat-menu>
<button mat-flat-button color="warn" routerLink="/auth/login">Salir</button> <button mat-flat-button color="warn" routerLink="/auth/login" i18n="@@logout">Salir</button>
</div> </div>
</mat-toolbar> </mat-toolbar>

View File

@ -30,7 +30,6 @@ export class HeaderComponent implements OnInit {
this.decodedToken = jwtDecode(token); this.decodedToken = jwtDecode(token);
this.isSuperAdmin = this.decodedToken.roles.includes('ROLE_SUPER_ADMIN'); this.isSuperAdmin = this.decodedToken.roles.includes('ROLE_SUPER_ADMIN');
localStorage.setItem('isSuperAdmin', String(this.isSuperAdmin)); localStorage.setItem('isSuperAdmin', String(this.isSuperAdmin));
console.log('isSuperAdmin:', this.isSuperAdmin);
this.username = this.decodedToken.username; this.username = this.decodedToken.username;
} catch (error) { } catch (error) {
console.error('Error decoding JWT:', error); console.error('Error decoding JWT:', error);
@ -51,4 +50,5 @@ export class HeaderComponent implements OnInit {
console.log("User edited successfully!") console.log("User edited successfully!")
}); */ }); */
} }
} }

View File

@ -37,3 +37,8 @@ mat-icon {
margin-top: auto; margin-top: auto;
} }
@media (max-width: 680px) {
mat-nav-list {
width: 0px;
}
}

View File

@ -1,7 +1,7 @@
<mat-nav-list> <mat-nav-list>
<mat-list-item disabled> <mat-list-item disabled>
<span class="user-logged"> <span class="user-logged">
<span>Bienvenido {{username}}</span> <span i18n="@@welcomeUser">Bienvenido {{username}}</span>
</span> </span>
</mat-list-item> </mat-list-item>
@ -10,49 +10,49 @@
<mat-list-item routerLink="/groups"> <mat-list-item routerLink="/groups">
<span class="entry"> <span class="entry">
<mat-icon class="icon">apartment</mat-icon> <mat-icon class="icon">apartment</mat-icon>
<span>Grupos</span> <span i18n="@@groups">Grupos</span>
</span> </span>
</mat-list-item> </mat-list-item>
<mat-list-item> <mat-list-item>
<span class="entry"> <span class="entry">
<mat-icon class="icon">chevron_right</mat-icon> <mat-icon class="icon">chevron_right</mat-icon>
<span>Acciones</span> <span i18n="@@actions">Acciones</span>
</span> </span>
</mat-list-item> </mat-list-item>
<mat-list-item> <mat-list-item>
<span class="entry"> <span class="entry">
<mat-icon class="icon">desktop_windows</mat-icon> <mat-icon class="icon">desktop_windows</mat-icon>
<span>Imágenes</span> <span i18n="@@images">Imágenes</span>
</span> </span>
</mat-list-item> </mat-list-item>
<mat-list-item> <mat-list-item>
<span class="entry"> <span class="entry">
<mat-icon class="icon">settings_input_component</mat-icon> <mat-icon class="icon">settings_input_component</mat-icon>
<span>Componentes</span> <span i18n="@@components">Componentes</span>
</span> </span>
</mat-list-item> </mat-list-item>
<mat-list-item> <mat-list-item>
<span class="entry"> <span class="entry">
<mat-icon class="icon">warehouse</mat-icon> <mat-icon class="icon">warehouse</mat-icon>
<span>Repositorios</span> <span i18n="@@repositories">Repositorios</span>
</span> </span>
</mat-list-item> </mat-list-item>
<mat-list-item> <mat-list-item>
<span class="entry"> <span class="entry">
<mat-icon class="icon">list</mat-icon> <mat-icon class="icon">list</mat-icon>
<span>Menús</span> <span i18n="@@menus">Menús</span>
</span> </span>
</mat-list-item> </mat-list-item>
<mat-list-item> <mat-list-item>
<span class="entry"> <span class="entry">
<mat-icon class="icon">search</mat-icon> <mat-icon class="icon">search</mat-icon>
<span>Buscar</span> <span i18n="@@search">Buscar</span>
</span> </span>
</mat-list-item> </mat-list-item>
<mat-list-item> <mat-list-item>
<span class="entry"> <span class="entry">
<mat-icon class="icon">calendar_month</mat-icon> <mat-icon class="icon">calendar_month</mat-icon>
<span>Calendarios</span> <span i18n="@@calendars">Calendarios</span>
</span> </span>
</mat-list-item> </mat-list-item>
</mat-nav-list> </mat-nav-list>

View File

@ -23,7 +23,6 @@ export class SidebarComponent {
this.decodedToken = jwtDecode(token); this.decodedToken = jwtDecode(token);
this.isSuperAdmin = this.decodedToken.roles.includes('ROLE_SUPER_ADMIN'); this.isSuperAdmin = this.decodedToken.roles.includes('ROLE_SUPER_ADMIN');
localStorage.setItem('isSuperAdmin', String(this.isSuperAdmin)); localStorage.setItem('isSuperAdmin', String(this.isSuperAdmin));
console.log('isSuperAdmin:', this.isSuperAdmin);
this.username = this.decodedToken.username; this.username = this.decodedToken.username;
} catch (error) { } catch (error) {
console.error('Error decoding JWT:', error); console.error('Error decoding JWT:', error);

View File

@ -1,27 +1,33 @@
<div> <div>
<form class="login" (ngSubmit)="onLogin()" #loginForm="ngForm"> <form class="login" (ngSubmit)="onLogin()" #loginForm="ngForm">
<img src="assets/images/logo.png" alt="Opengnsys" <img src="assets/images/logo.png" alt="Opengnsys"
class="login-logo" [class.rotating]="isLoading"> class="login-logo" [class.rotating]="isLoading">
<h2>Opengnsys</h2> <h2 i18n="@@headerOpengnsys">Opengnsys</h2>
<mat-form-field> <mat-form-field>
<mat-label>Introducte tu usuario</mat-label> <mat-label i18n="@@loginlabelUsername">Introduce tu usuario</mat-label>
<input matInput [(ngModel)]="loginObj.username" name="username" required #usernameInput="ngModel" [ngClass]="{'invalid': !usernameInput.valid && usernameInput.touched}" /> <input matInput [(ngModel)]="loginObj.username" name="username" required #usernameInput="ngModel" [ngClass]="{'invalid': !usernameInput.valid && usernameInput.touched}" />
</mat-form-field> </mat-form-field>
<mat-form-field> <mat-form-field>
<mat-label>Introduce tu contraseña</mat-label> <mat-label i18n="@@loginlabelPassword">Introduce tu contraseña</mat-label>
<input matInput [type]="hide() ? 'password' : 'text'" required [(ngModel)]="loginObj.password" name="password"/> <input matInput [type]="hide() ? 'password' : 'text'" required [(ngModel)]="loginObj.password" name="password"/>
<button <button
mat-icon-button mat-icon-button
matSuffix matSuffix
(click)="clickEvent($event)" (click)="clickEvent($event)"
[attr.aria-label]="'Ocultar contraseña'" [attr.aria-label]="'Ocultar contraseña'"
[attr.aria-pressed]="hide()" [attr.aria-pressed]="hide()"
> >
<mat-icon>{{hide() ? 'visibility_off' : 'visibility'}}</mat-icon> <mat-icon>{{hide() ? 'visibility_off' : 'visibility'}}</mat-icon>
</button> </button>
</mat-form-field> </mat-form-field>
<div class="button-row"> <div class="button-row">
<button mat-flat-button color="primary" type="submit" (keydown.enter)="$event.preventDefault()" [disabled]="!loginObj.username || !loginObj.password">Iniciar sesión</button> <button mat-flat-button color="primary" type="submit" (keydown.enter)="$event.preventDefault()" [disabled]="!loginObj.username || !loginObj.password" i18n="@@buttonLogin">Iniciar sesión</button>
</div> </div>
</form>
</form>
</div> </div>
<!-- BORRAR DESPUES DE LA DEMO -->
<button mat-flat-button (click)="redirectToUrl1()">Español</button>
<!-- Botón para redirigir a http://localhost:4200/auth/login -->
<button mat-flat-button (click)="redirectToUrl2()">Inglés</button>

View File

@ -74,4 +74,14 @@ export class LoginComponent {
} else } else
this.toastService.success(message, 'Éxito'); this.toastService.success(message, 'Éxito');
} }
//SOLO PARA LA DEMO BORRAR EN PRODUCCION
redirectToUrl1() {
window.location.href = 'http://localhost:4200/auth/login';
}
redirectToUrl2() {
window.location.href = 'http://localhost:4201/auth/login';
}
} }

View File

@ -1,10 +1,10 @@
<div class="container"> <div class="container">
<button mat-fab color="primary" class="fab-button" routerLink="/users"> <button mat-fab color="primary" class="fab-button" routerLink="/users">
<mat-icon>group</mat-icon> <mat-icon>group</mat-icon>
<span>Usuarios</span> <span i18n="@@labelUsers">Usuarios</span>
</button> </button>
<button mat-fab color="primary" class="fab-button" routerLink="/user-groups"> <button mat-fab color="primary" class="fab-button" routerLink="/user-groups">
<mat-icon>admin_panel_settings</mat-icon> <mat-icon>admin_panel_settings</mat-icon>
<span>Roles</span> <span i18n="@@labelRoles">Roles</span>
</button> </button>
</div> </div>

View File

@ -1,25 +1,24 @@
<h1 mat-dialog-title>Añadir Rol (TBD)</h1> <h1 mat-dialog-title i18n="@@dialogTitleAddRole">Añadir Rol (TBD)</h1>
<div mat-dialog-content> <div mat-dialog-content>
<form class="role-form"> <form class="role-form">
<mat-form-field class="form-field"> <mat-form-field class="form-field">
<mat-label>Nombre</mat-label> <mat-label i18n="@@labelRoleName">Nombre</mat-label>
<input matInput formControlName="rolename" required> <input matInput formControlName="rolename" required>
</mat-form-field> </mat-form-field>
<section class="example-section"> <section class="example-section">
<h4>Permisos:</h4> <h4 i18n="@@sectionTitlePermissions">Permisos:</h4>
<p><mat-checkbox >Gestionar los usuarios</mat-checkbox></p> <p><mat-checkbox i18n="@@checkboxManageUsers">Gestionar los usuarios</mat-checkbox></p>
<p><mat-checkbox >Configuración PXE</mat-checkbox></p> <p><mat-checkbox i18n="@@checkboxPXEConfig">Configuración PXE</mat-checkbox></p>
<p><mat-checkbox >Imágenes de la consola web</mat-checkbox></p> <p><mat-checkbox i18n="@@checkboxConsoleImages">Imágenes de la consola web</mat-checkbox></p>
<p><mat-checkbox >Gestionar los distintos componentes</mat-checkbox></p> <p><mat-checkbox i18n="@@checkboxManageComponents">Gestionar los distintos componentes</mat-checkbox></p>
<p><mat-checkbox >Crear imágenes</mat-checkbox></p> <p><mat-checkbox i18n="@@checkboxCreateImages">Crear imágenes</mat-checkbox></p>
<p><mat-checkbox >script de configuración del servidor</mat-checkbox></p> <p><mat-checkbox i18n="@@checkboxServerConfigScript">script de configuración del servidor</mat-checkbox></p>
<p><mat-checkbox >...</mat-checkbox></p> <p><mat-checkbox i18n="@@checkboxOther">...</mat-checkbox></p>
</section> </section>
</form> </form>
</div> </div>
<div mat-dialog-actions> <div mat-dialog-actions>
<button mat-button (click)="onNoClick()">Cancelar</button> <button mat-button (click)="onNoClick()" i18n="@@buttonCancel">Cancelar</button>
<button mat-button>Añadir</button> <button mat-button i18n="@@buttonAdd">Añadir</button>
</div> </div>

View File

@ -1,8 +1,8 @@
<h1 mat-dialog-title>Eliminar Rol</h1> <h1 mat-dialog-title i18n="@@dialogTitleDeleteRole">Eliminar Rol</h1>
<div mat-dialog-content> <div mat-dialog-content>
<p>¿Estás seguro que deseas eliminar el rol {{ data.name }}?</p> <p i18n="@@dialogContentDeleteRole">¿Estás seguro que deseas eliminar el rol {{ data.name }}?</p>
</div> </div>
<div mat-dialog-actions> <div mat-dialog-actions>
<button mat-button (click)="onNoClick()">Cancelar</button> <button mat-button (click)="onNoClick()" i18n="@@buttonCancel">Cancelar</button>
<button mat-button (click)="onYesClick()">Eliminar</button> <button mat-button (click)="onYesClick()" i18n="@@buttonDelete">Eliminar</button>
</div> </div>

View File

@ -1,6 +1,6 @@
<div class="header-container"> <div class="header-container">
<h1>Gestión de roles</h1> <h1 i18n="@@headerRoleManagement">Gestión de roles</h1>
<button mat-flat-button color="primary" (click)="addUser()">+ Añadir</button> <button mat-flat-button color="primary" (click)="addUser()" i18n="@@buttonAddRole">+ Añadir</button>
</div> </div>
<table mat-table [dataSource]="dataSource" class="mat-elevation-z8"> <table mat-table [dataSource]="dataSource" class="mat-elevation-z8">
@ -9,15 +9,12 @@
<td mat-cell *matCellDef="let role"> {{ column.cell(role) }} </td> <td mat-cell *matCellDef="let role"> {{ column.cell(role) }} </td>
</ng-container> </ng-container>
<!-- Botones Column -->
<ng-container matColumnDef="actions"> <ng-container matColumnDef="actions">
<th mat-header-cell *matHeaderCellDef> Acciones </th> <th mat-header-cell *matHeaderCellDef i18n="@@headerActions">Acciones</th>
<td mat-cell *matCellDef="let role"> <td mat-cell *matCellDef="let role">
<button mat-button color="warn" [disabled]="role.name=== 'Super Admin' " (click)="deleteRole(role)">Eliminar</button> <button mat-button color="warn" [disabled]="role.name === 'Super Admin'" (click)="deleteRole(role)" i18n="@@buttonDelete">Eliminar</button>
</td> </td>
</ng-container> </ng-container>
<!-- Row definition -->
<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>

View File

@ -1,17 +1,17 @@
<h1 mat-dialog-title>Añadir Usuario</h1> <h1 mat-dialog-title i18n="@@dialogTitleAddUser">Añadir Usuario</h1>
<div mat-dialog-content> <div mat-dialog-content>
<form [formGroup]="userForm" class="user-form"> <form [formGroup]="userForm" class="user-form">
<mat-form-field class="form-field"> <mat-form-field class="form-field">
<mat-label>Nombre de usuario</mat-label> <mat-label i18n="@@addUserlabelUsername">Nombre de usuario</mat-label>
<input matInput formControlName="username" required> <input matInput formControlName="username" required>
</mat-form-field> </mat-form-field>
<mat-form-field class="form-field"> <mat-form-field class="form-field">
<mat-label>Contraseña</mat-label> <mat-label i18n="@@addUserlabelPassword">Contraseña</mat-label>
<input matInput formControlName="password" type="password" required> <input matInput formControlName="password" type="password" required>
</mat-form-field> </mat-form-field>
<mat-form-field class="form-field"> <mat-form-field class="form-field">
<mat-label>Rol</mat-label> <mat-label i18n="@@labelRole">Rol</mat-label>
<mat-select formControlName="role"> <mat-select formControlName="role">
<mat-option *ngFor="let group of userGroups" [value]="group['@id']"> <mat-option *ngFor="let group of userGroups" [value]="group['@id']">
{{ group.name }} {{ group.name }}
@ -20,18 +20,16 @@
</mat-form-field> </mat-form-field>
<mat-form-field class="form-field"> <mat-form-field class="form-field">
<mat-label>Unidad organiativa</mat-label> <mat-label i18n="@@labelOrganizationalUnit">Unidad organiativa</mat-label>
<mat-select multiple formControlName="organizationalUnit"> <mat-select multiple formControlName="organizationalUnit">
<mat-option *ngFor="let unit of organizationalUnits" [value]="unit['@id']"> <mat-option *ngFor="let unit of organizationalUnits" [value]="unit['@id']">
{{unit.name}} {{unit.name}}
</mat-option> </mat-option>
</mat-select> </mat-select>
</mat-form-field> </mat-form-field>
</form> </form>
</div> </div>
<div mat-dialog-actions> <div mat-dialog-actions>
<button mat-button (click)="onNoClick()">Cancelar</button> <button mat-button (click)="onNoClick()" i18n="@@buttonCancel">Cancelar</button>
<button mat-button [disabled]="!userForm.valid" (click)="onSubmit()">Añadir</button> <button mat-button [disabled]="!userForm.valid" (click)="onSubmit()" i18n="@@buttonAdd">Añadir</button>
</div> </div>

View File

@ -1,33 +1,31 @@
<h1 mat-dialog-title>Editar Usuario</h1> <h1 mat-dialog-title i18n="@@dialogTitleEditUser">Editar Usuario</h1>
<div mat-dialog-content> <div mat-dialog-content>
<form [formGroup]="userForm" class="user-form"> <form [formGroup]="userForm" class="user-form">
<mat-form-field class="form-field"> <mat-form-field class="form-field">
<mat-label>Contraseña actual</mat-label> <mat-label i18n="@@labelCurrentPassword">Contraseña actual</mat-label>
<input matInput formControlName="currentPassword" type="currentPassword"> <input matInput formControlName="currentPassword" type="password">
</mat-form-field> </mat-form-field>
<mat-form-field class="form-field"> <mat-form-field class="form-field">
<mat-label>Nueva contraseña</mat-label> <mat-label i18n="@@labelNewPassword">Nueva contraseña</mat-label>
<input matInput formControlName="newPassword" type="password"> <input matInput formControlName="newPassword" type="password">
</mat-form-field> </mat-form-field>
<mat-form-field class="form-field"> <mat-form-field class="form-field">
<mat-label>Repite la contraseña</mat-label> <mat-label i18n="@@labelRepeatPassword">Repite la contraseña</mat-label>
<input matInput formControlName="repeatNewPassword" type="password"> <input matInput formControlName="repeatNewPassword" type="password">
</mat-form-field> </mat-form-field>
@if (loading){ <mat-spinner *ngIf="loading"></mat-spinner>
<mat-spinner></mat-spinner>
}
@if (passwordMismatch) { <div class="error-message" *ngIf="passwordMismatch" i18n="@@errorPasswordMismatch">
<div class="error-message">Las contraseñas no coinciden</div> Las contraseñas no coinciden
} </div>
@if (updateError) { <div class="error-message" *ngIf="updateError" i18n="@@errorUpdate">
<div class="error-message">{{resetPasswordError}}</div> {{ resetPasswordError }}
} </div>
</form> </form>
</div> </div>
<div mat-dialog-actions> <div mat-dialog-actions>
<button mat-button (click)="onNoClick()">Cancelar</button> <button mat-button (click)="onNoClick()" i18n="@@buttonCancel">Cancelar</button>
<button mat-button (click)="onSubmit()" [disabled]="loading">Editar</button> <button mat-button (click)="onSubmit()" [disabled]="loading" i18n="@@buttonEdit">Editar</button>
</div> </div>

View File

@ -1,8 +1,8 @@
<h1 mat-dialog-title>Eliminar Usuario</h1> <h1 mat-dialog-title i18n="@@dialogTitleDeleteUser">Eliminar Usuario</h1>
<div mat-dialog-content> <div mat-dialog-content>
<p>¿Estás seguro que deseas eliminar a {{ data.username }}?</p> <p i18n="@@dialogContentDeleteUser">¿Estás seguro que deseas eliminar a {{ data.username }}?</p>
</div> </div>
<div mat-dialog-actions> <div mat-dialog-actions>
<button mat-button (click)="onNoClick()">Cancelar</button> <button mat-button (click)="onNoClick()" i18n="@@buttonCancel">Cancelar</button>
<button mat-button (click)="onYesClick()">Eliminar</button> <button mat-button (click)="onYesClick()" i18n="@@buttonDelete">Eliminar</button>
</div> </div>

View File

@ -1,17 +1,17 @@
<h1 mat-dialog-title>Editar Usuario</h1> <h1 mat-dialog-title i18n="@@dialogTitleEditUser">Editar Usuario</h1>
<mat-spinner *ngIf="loading" class="loading-container"></mat-spinner> <mat-spinner *ngIf="loading" class="loading-container"></mat-spinner>
<div *ngIf="!loading" mat-dialog-content> <div *ngIf="!loading" mat-dialog-content>
<form [formGroup]="userForm" class="user-form"> <form [formGroup]="userForm" class="user-form">
<mat-form-field class="form-field"> <mat-form-field class="form-field">
<mat-label>Nombre de usuario</mat-label> <mat-label i18n="@@editUserlabelUsername">Nombre de usuario</mat-label>
<input matInput formControlName="username"> <input matInput formControlName="username">
</mat-form-field> </mat-form-field>
<mat-form-field class="form-field"> <mat-form-field class="form-field">
<mat-label>Contraseña</mat-label> <mat-label i18n="@@editUserlabelPassword">Contraseña</mat-label>
<input matInput formControlName="password" type="password"> <input matInput formControlName="password" type="password">
</mat-form-field> </mat-form-field>
<mat-form-field class="form-field"> <mat-form-field class="form-field">
<mat-label>Rol</mat-label> <mat-label i18n="@@labelRole">Rol</mat-label>
<mat-select multiple formControlName="userGroups"> <mat-select multiple formControlName="userGroups">
<mat-option *ngFor="let group of userGroups" [value]="group['@id']"> <mat-option *ngFor="let group of userGroups" [value]="group['@id']">
{{ group.name }} {{ group.name }}
@ -20,17 +20,16 @@
</mat-form-field> </mat-form-field>
<mat-form-field class="form-field"> <mat-form-field class="form-field">
<mat-label>Unidad organiativa</mat-label> <mat-label i18n="@@labelOrgUnit">Unidad organizativa</mat-label>
<mat-select multiple formControlName="allowedOrganizationalUnits"> <mat-select multiple formControlName="allowedOrganizationalUnits">
<mat-option *ngFor="let unit of organizationalUnits" [value]="unit['@id']"> <mat-option *ngFor="let unit of organizationalUnits" [value]="unit['@id']">
{{unit.name}} {{unit.name}}
</mat-option> </mat-option>
</mat-select> </mat-select>
</mat-form-field> </mat-form-field>
</form> </form>
</div> </div>
<div mat-dialog-actions> <div mat-dialog-actions>
<button mat-button (click)="onNoClick()">Cancelar</button> <button mat-button (click)="onNoClick()" i18n="@@buttonCancel">Cancelar</button>
<button mat-button (click)="onSubmit()">Editar</button> <button mat-button (click)="onSubmit()" i18n="@@buttonEdit">Editar</button>
</div> </div>

View File

@ -1,6 +1,6 @@
<div class="header-container"> <div class="header-container">
<h1>Gestión de usuarios</h1> <h1 i18n="@@headerUserManagement">Gestión de usuarios</h1>
<button mat-flat-button color="primary" (click)="addUser()">+ Añadir</button> <button mat-flat-button color="primary" (click)="addUser()" i18n="@@buttonAddUser">+ Añadir</button>
</div> </div>
<table mat-table [dataSource]="dataSource" class="mat-elevation-z8"> <table mat-table [dataSource]="dataSource" class="mat-elevation-z8">
@ -9,16 +9,14 @@
<td mat-cell *matCellDef="let user"> {{ column.cell(user) }} </td> <td mat-cell *matCellDef="let user"> {{ column.cell(user) }} </td>
</ng-container> </ng-container>
<!-- Botones Column -->
<ng-container matColumnDef="actions"> <ng-container matColumnDef="actions">
<th mat-header-cell *matHeaderCellDef> Acciones </th> <th mat-header-cell *matHeaderCellDef i18n="@@columnActions">Acciones</th>
<td mat-cell *matCellDef="let user"> <td mat-cell *matCellDef="let user">
<button mat-button color="primary" (click)="editUser(user)">Editar</button> <button mat-button color="primary" (click)="editUser(user)" i18n="@@buttonEditUser">Editar</button>
<button mat-button color="warn" (click)="deleteUser(user)">Eliminar</button> <button mat-button color="warn" (click)="deleteUser(user)" i18n="@@buttonDeleteUser">Eliminar</button>
</td> </td>
</ng-container> </ng-container>
<!-- Row definition -->
<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>

View File

@ -0,0 +1,221 @@
{
"locale": "en",
"translations": {
"actions-modal-title": "Actions",
"power-on-button": "Power On",
"power-off-button": "Power Off",
"reset-button": "Reset",
"other-actions-1": "Other Actions 1",
"other-actions-2": "Other Actions 2",
"other-actions-3": "Other Actions 3",
"digital-board": "Digital Board",
"projector-alt": "Projector",
"client-image-alt": "Client",
"save-disposition-button": "Save Disposition",
"client-properties-title": "Client Properties",
"property-header": "Property",
"value-header": "Value",
"close-button": "Close",
"add-client-dialog-title": "Add Client",
"organizational-unit-label": "Parent",
"name-label": "Name",
"serial-number-label": "Serial Number",
"netiface-label": "Network Interface",
"net-driver-label": "Network Driver",
"mac-label": "MAC",
"mac-hint": "Example: 00:11:22:33:44:55",
"mac-error": "Invalid MAC format. Valid example: 00:11:22:33:44:55",
"ip-label": "IP Address",
"ip-hint": "Example: 127.0.0.1",
"ip-error": "Invalid IP address format. Valid example: 127.0.0.1",
"menu-url-label": "Menu URL",
"menu-url-error": "Invalid URL format.",
"hardware-profile-label": "Hardware Profile",
"hardware-profile-error": "Invalid URL format.",
"cancel-button": "Cancel",
"add-button": "Add",
"edit-client-dialog-title": "Edit Client",
"delete-dialog-title": "Delete",
"delete-dialog-content": "Do you want to delete the clients located in {$INTERPOLATION} or do you want to relocate them to the higher level?",
"delete-all-clients-button": "Delete all clients",
"reposition-clients-button": "Relocate",
"deleteDialogTitle": "Delete",
"deleteConfirmationMessage": "Are you sure you want to delete {$INTERPOLATION}?",
"cancelButton": "Cancel",
"confirmButton": "Delete",
"adminGroupsTitle": "Manage Groups",
"newOrganizationalUnitButton": "New Organizational Unit",
"newClientButton": "New Client",
"legendButton": "Legend",
"classroomMapButton": "Classroom Map",
"searchLabel": "Search",
"searchPlaceholder": "Search",
"searchHint": "Press 'enter' to search among organizational units",
"organizationalUnitTitle": "Organizational Unit",
"viewTreeTooltip": "account_tree ",
"viewTreeMenu": "View Organizational Chart",
"editUnitTooltip": "edit ",
"editUnitMenu": "Edit",
"viewUnitTool": "visibility ",
"viewUnitMenu": "View Data",
"addInternalUnitTool": "add_home_work ",
"addInternalUnitMenu": "Add Organizational Unit",
"addClientDevice": "devices ",
"addClientMenu": "Create Client",
"internalElementsTitle": "Internal Elements",
"noInternalElementsMessage": "No internal elements",
"editElementTooltip": "edit",
"editElementMenu": "Edit",
"viewUnitTooltip": "visibility",
"addInternalUnitTooltip": "add_home_work",
"addClientTooltip": "devices",
"deleteElementTooltip": "delete",
"deleteElementMenu": "Delete Element",
"7122753603772512402": "Advanced Search",
"searchTitle": "Search",
"selectFilterLabel": "Select Filter",
"selectOptionLabel": "Select an Option",
"organizationalUnitsOption": "Organizational Units",
"clientsOption": "Clients",
"nameLabel": "Name",
"namePlaceholder": "Organizational Unit",
"unitTypeLabel": "Unit Type",
"organizationalUnitOption": "Organizational Unit",
"classroomsGroupOption": "Classroom Groups",
"classroomOption": "Classrooms",
"clientGroupOption": "Client Groups",
"floorLabel": "Floor",
"noneOption": "None",
"option1": "Floor 1",
"option2": "Floor 2",
"option3": "Floor 3",
"selectAnotherOptionLabel": "Operating System",
"selectStateLabel": "State",
"offOption": "off",
"initializingOption": "initializing",
"ogliveOption": "oglive",
"busyOption": "busy",
"linuxOption": "linux",
"linuxSessionOption": "linux_session",
"macosOption": "macos",
"windowsOption": "windows",
"windowsSessionOption": "windows_session",
"saveFiltersButton": "Save Filters",
"sendFiltersButton": "Send Action",
"internalUnits": "Internal units: {$INTERPOLATION}",
"clients": "Clients: {$INTERPOLATION}",
"noResultsMessage": "No results to display.",
"orgUnitTitle": "Organizational Unit",
"classroomGroupsTitle": "Classroom Groups",
"classroomTitle": "Classroom",
"clientGroupsTitle": "Client Groups",
"clientTitle": "Client",
"addOrgUnitTitle": "Add Organizational Unit",
"generalStepLabel": "General",
"typeLabel": "Type",
"createOrgUnitparentLabel": "Parent Organizational Unit",
"noParentOption": "--",
"descriptionLabel": "Description",
"nextButton": "Next",
"classroomInfoStepLabel": "Classroom Information",
"locationLabel": "Location",
"projectorToggle": "Projector",
"boardToggle": "Board",
"capacityLabel": "Capacity",
"backButton": "Back",
"additionalInfoStepLabel": "Additional Information",
"commentsLabel": "Comments",
"networkSettingsStepLabel": "Network Settings",
"proxyUrlLabel": "Proxy Server URL",
"dnsIpLabel": "DNS Server IP",
"netmaskLabel": "Netmask",
"routerLabel": "Router",
"ntpIpLabel": "NTP Server IP",
"p2pModeLabel": "P2P Mode",
"p2pTimeLabel": "P2P Time",
"mcastIpLabel": "Multicast IP",
"mcastSpeedLabel": "Multicast Speed",
"mcastPortLabel": "Multicast Port",
"mcastModeLabel": "Multicast Mode",
"menuUrlLabel": "Menu URL",
"hardwareProfileLabel": "Hardware Profile",
"urlFormatError": "Invalid URL format.",
"submitButton": "Add",
"editOrgUnitTitle": "Edit Organizational Unit",
"editOrgUnitParentLabel": "Parent",
"validationToggle": "Validation",
"orgUnitPropertiesTitle": "Organizational Unit Properties",
"generalDataTab": "General Data",
"classroomNetworkPropertiesTab": "Classroom and Network Properties",
"actionsTab": "Actions",
"2366056895545879062": "Power On",
"7368908909686115507": "Power Off",
"7760171369336053154": "Reset",
"6799187990933478083": "Other Actions 1",
"8971534271481971645": "Other Actions 2",
"3300614831699539964": "Other Actions 3",
"viewTreeTitle": "View Organizational Unit Tree",
"closeButton": "Close",
"webConsoleTitle": "Opengnsys Webconsole",
"admin": "Administration",
"editUser": "Edit User",
"usersMenuItem": "Users",
"rolesMenuItem": "Roles",
"logout": "Logout",
"welcomeUser": "Welcome {$INTERPOLATION}",
"groups": "Groups",
"actions": "Actions",
"images": "Images",
"components": "Components",
"repositories": "Repositories",
"menus": "Menus",
"search": "Search",
"calendars": "Calendars",
"headerOpengnsys": "Opengnsys",
"loginlabelUsername": "Enter your username",
"loginlabelPassword": "Enter your password",
"buttonLogin": "Login",
"labelUsers": "Users",
"labelRoles": "Roles",
"dialogTitleAddRole": "Add Role (TBD)",
"labelRoleName": "Name",
"sectionTitlePermissions": "Permissions:",
"checkboxManageUsers": "Manage Users",
"checkboxPXEConfig": "PXE Configuration",
"checkboxConsoleImages": "Web Console Images",
"checkboxManageComponents": "Manage Different Components",
"checkboxCreateImages": "Create Images",
"checkboxServerConfigScript": "Server Configuration Script",
"checkboxOther": "...",
"buttonCancel": "Cancel",
"buttonAdd": "Add",
"dialogTitleDeleteRole": "Delete Role",
"dialogContentDeleteRole": "Are you sure you want to delete the role {$INTERPOLATION}?",
"buttonDelete": "Delete",
"headerRoleManagement": "Role Management",
"buttonAddRole": "+ Add",
"headerActions": "Actions",
"dialogTitleAddUser": "Add User",
"addUserlabelUsername": "Username",
"addUserlabelPassword": "Password",
"labelRole": "Role",
"labelOrganizationalUnit": "Organizational Unit",
"dialogTitleEditUser": "Edit User",
"labelCurrentPassword": "Current Password",
"labelNewPassword": "New Password",
"labelRepeatPassword": "Repeat Password",
"errorPasswordMismatch": " Passwords do not match ",
"errorUpdate": " {$INTERPOLATION} ",
"buttonEdit": "Edit",
"dialogTitleDeleteUser": "Delete User",
"dialogContentDeleteUser": "Are you sure you want to delete {$INTERPOLATION}?",
"editUserlabelUsername": "Username",
"editUserlabelPassword": "Password",
"labelOrgUnit": "Organizational Unit",
"headerUserManagement": "User Management",
"buttonAddUser": "+ Add",
"columnActions": "Actions",
"buttonEditUser": "Edit",
"buttonDeleteUser": "Delete"
}
}

View File

@ -0,0 +1,221 @@
{
"locale": "es",
"translations": {
"actions-modal-title": "Acciones",
"power-on-button": "Encender",
"power-off-button": "Apagar",
"reset-button": "Resetear",
"other-actions-1": "Otras acciones 1",
"other-actions-2": "Otras acciones 2",
"other-actions-3": "Otras acciones 3",
"digital-board": "Pizarra digital",
"projector-alt": "Proyector",
"client-image-alt": "Client",
"save-disposition-button": "Guardar disposición",
"client-properties-title": "Propiedades cliente",
"property-header": "Propiedad",
"value-header": "Valor",
"close-button": "Cerrar",
"add-client-dialog-title": "Añadir Cliente",
"organizational-unit-label": "Padre",
"name-label": "Nombre",
"serial-number-label": "Número de Serie",
"netiface-label": "Interfaz de red",
"net-driver-label": "Controlador de red",
"mac-label": "MAC",
"mac-hint": "Ejemplo: 00:11:22:33:44:55",
"mac-error": "Formato de MAC inválido. Ejemplo válido: 00:11:22:33:44:55",
"ip-label": "Dirección IP",
"ip-hint": "Ejemplo: 127.0.0.1",
"ip-error": "Formato de dirección IP inválido. Ejemplo válido: 127.0.0.1",
"menu-url-label": "Menú URL",
"menu-url-error": "Formato de URL inválido.",
"hardware-profile-label": "Perfil de Hardware",
"hardware-profile-error": "Formato de URL inválido.",
"cancel-button": "Cancelar",
"add-button": "Añadir",
"edit-client-dialog-title": "Editar Cliente",
"delete-dialog-title": "Eliminar",
"delete-dialog-content": "¿Quiere borrar los clientes situados en {$INTERPOLATION} o quiere resituarlos en el nivel superior?",
"delete-all-clients-button": "Borrar todos los clientes",
"reposition-clients-button": "Resituar",
"deleteDialogTitle": "Eliminar",
"deleteConfirmationMessage": "¿Estás seguro que deseas eliminar {$INTERPOLATION}?",
"cancelButton": "Cancelar",
"confirmButton": "Eliminar",
"adminGroupsTitle": "Administrar grupos",
"newOrganizationalUnitButton": "Nueva Unidad Organizativa",
"newClientButton": "Nuevo Cliente",
"legendButton": "Leyenda",
"classroomMapButton": "Plano de aula",
"searchLabel": "Búsqueda",
"searchPlaceholder": "Búsqueda",
"searchHint": "Pulsar 'enter' para buscar entre las unidades organizativas",
"organizationalUnitTitle": "Unidad organizativa",
"viewTreeTooltip": "account_tree ",
"viewTreeMenu": "Ver organigrama",
"editUnitTooltip": "edit ",
"editUnitMenu": "Editar",
"viewUnitTool": "visibility ",
"viewUnitMenu": "Visualizar datos",
"addInternalUnitTool": "add_home_work ",
"addInternalUnitMenu": "Añadir unidad organizativa",
"addClientDevice": "devices ",
"addClientMenu": "Crear cliente",
"internalElementsTitle": "Elementos internos",
"noInternalElementsMessage": "No hay elementos internos",
"editElementTooltip": "edit",
"editElementMenu": "Editar",
"viewUnitTooltip": "visibility",
"addInternalUnitTooltip": "add_home_work",
"addClientTooltip": "devices",
"deleteElementTooltip": "delete",
"deleteElementMenu": "Borrar elemento",
"7122753603772512402": "Búsqueda avanzada",
"searchTitle": "Búsqueda",
"selectFilterLabel": "Seleccione filtro",
"selectOptionLabel": "Selecciona una opción",
"organizationalUnitsOption": "Unidades organizativas",
"clientsOption": "Clientes",
"nameLabel": "Nombre",
"namePlaceholder": "Unidad organizativa",
"unitTypeLabel": "Tipo de unidad",
"organizationalUnitOption": "Unidad organizativa",
"classroomsGroupOption": "Grupos de aulas",
"classroomOption": "Aulas",
"clientGroupOption": "Grupos de clientes",
"floorLabel": "Planta",
"noneOption": "Ninguno",
"option1": "Planta 1",
"option2": "Planta 2",
"option3": "Planta 3",
"selectAnotherOptionLabel": "Sistema Operativo",
"selectStateLabel": "Estado",
"offOption": "off",
"initializingOption": "initializing",
"ogliveOption": "oglive",
"busyOption": "busy",
"linuxOption": "linux",
"linuxSessionOption": "linux_session",
"macosOption": "macos",
"windowsOption": "windows",
"windowsSessionOption": "windows_session",
"saveFiltersButton": "Guardar Filtros",
"sendFiltersButton": "Enviar Acción",
"internalUnits": "Unidades internas: {$INTERPOLATION}",
"clients": "Clientes: {$INTERPOLATION}",
"noResultsMessage": "No hay resultados para mostrar.",
"orgUnitTitle": "Unidad organizativa",
"classroomGroupsTitle": "Grupos de aula",
"classroomTitle": "Aula",
"clientGroupsTitle": "Grupos de clientes",
"clientTitle": "Cliente",
"addOrgUnitTitle": "Añadir Unidad Organizativa",
"generalStepLabel": "General",
"typeLabel": "Tipo",
"createOrgUnitparentLabel": "Unidad organizativa padre",
"noParentOption": "--",
"descriptionLabel": "Descripción",
"nextButton": "Siguiente",
"classroomInfoStepLabel": "Información del Aula",
"locationLabel": "Ubicación",
"projectorToggle": "Proyector",
"boardToggle": "Pizarra",
"capacityLabel": "Aforo",
"backButton": "Atrás",
"additionalInfoStepLabel": "Información Adicional",
"commentsLabel": "Comentarios",
"networkSettingsStepLabel": "Configuración de Red",
"proxyUrlLabel": "Url servidor Proxy",
"dnsIpLabel": "IP servidor DNS",
"netmaskLabel": "Máscara de Red",
"routerLabel": "Router",
"ntpIpLabel": "IP servidor NTP",
"p2pModeLabel": "Modo P2P",
"p2pTimeLabel": "Tiempo P2P",
"mcastIpLabel": "IP Multicast",
"mcastSpeedLabel": "Velocidad Multicast",
"mcastPortLabel": "Puerto Multicast",
"mcastModeLabel": "Modo Multicast",
"menuUrlLabel": "Menú URL",
"hardwareProfileLabel": "Perfil de Hardware",
"urlFormatError": "Formato de URL inválido.",
"submitButton": "Añadir",
"editOrgUnitTitle": "Editar Unidad Organizativa",
"editOrgUnitParentLabel": "Padre",
"validationToggle": "Validación",
"orgUnitPropertiesTitle": "Propiedades unidad organizativa",
"generalDataTab": "Datos generales",
"classroomNetworkPropertiesTab": "Propiedades aula y de red",
"actionsTab": "Acciones",
"2366056895545879062": "Encender",
"7368908909686115507": "Apagar",
"7760171369336053154": "Resetear",
"6799187990933478083": "Otras acciones 1",
"8971534271481971645": "Otras acciones 2",
"3300614831699539964": "Otras acciones 3",
"viewTreeTitle": "Visualizar árbol unidad Organizativa",
"closeButton": "Cerrar",
"webConsoleTitle": "Opengnsys webconsole",
"admin": "Administración",
"editUser": "Editar usuario",
"usersMenuItem": "Usuarios",
"rolesMenuItem": "Roles",
"logout": "Salir",
"welcomeUser": "Bienvenido {$INTERPOLATION}",
"groups": "Grupos",
"actions": "Acciones",
"images": "Imágenes",
"components": "Componentes",
"repositories": "Repositorios",
"menus": "Menús",
"search": "Buscar",
"calendars": "Calendarios",
"headerOpengnsys": "Opengnsys",
"loginlabelUsername": "Introduce tu usuario",
"loginlabelPassword": "Introduce tu contraseña",
"buttonLogin": "Iniciar sesión",
"labelUsers": "Usuarios",
"labelRoles": "Roles",
"dialogTitleAddRole": "Añadir Rol (TBD)",
"labelRoleName": "Nombre",
"sectionTitlePermissions": "Permisos:",
"checkboxManageUsers": "Gestionar los usuarios",
"checkboxPXEConfig": "Configuración PXE",
"checkboxConsoleImages": "Imágenes de la consola web",
"checkboxManageComponents": "Gestionar los distintos componentes",
"checkboxCreateImages": "Crear imágenes",
"checkboxServerConfigScript": "script de configuración del servidor",
"checkboxOther": "...",
"buttonCancel": "Cancelar",
"buttonAdd": "Añadir",
"dialogTitleDeleteRole": "Eliminar Rol",
"dialogContentDeleteRole": "¿Estás seguro que deseas eliminar el rol {$INTERPOLATION}?",
"buttonDelete": "Eliminar",
"headerRoleManagement": "Gestión de roles",
"buttonAddRole": "+ Añadir",
"headerActions": "Acciones",
"dialogTitleAddUser": "Añadir Usuario",
"addUserlabelUsername": "Nombre de usuario",
"addUserlabelPassword": "Contraseña",
"labelRole": "Rol",
"labelOrganizationalUnit": "Unidad organiativa",
"dialogTitleEditUser": "Editar Usuario",
"labelCurrentPassword": "Contraseña actual",
"labelNewPassword": "Nueva contraseña",
"labelRepeatPassword": "Repite la contraseña",
"errorPasswordMismatch": " Las contraseñas no coinciden ",
"errorUpdate": " {$INTERPOLATION} ",
"buttonEdit": "Editar",
"dialogTitleDeleteUser": "Eliminar Usuario",
"dialogContentDeleteUser": "¿Estás seguro que deseas eliminar a {$INTERPOLATION}?",
"editUserlabelUsername": "Nombre de usuario",
"editUserlabelPassword": "Contraseña",
"labelOrgUnit": "Unidad organizativa",
"headerUserManagement": "Gestión de usuarios",
"buttonAddUser": "+ Añadir",
"columnActions": "Acciones",
"buttonEditUser": "Editar",
"buttonDeleteUser": "Eliminar"
}
}

View File

@ -1,3 +1,5 @@
/// <reference types="@angular/localize" />
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppModule } from './app/app.module'; import { AppModule } from './app/app.module';

View File

@ -3,7 +3,9 @@
"extends": "./tsconfig.json", "extends": "./tsconfig.json",
"compilerOptions": { "compilerOptions": {
"outDir": "./out-tsc/app", "outDir": "./out-tsc/app",
"types": [] "types": [
"@angular/localize"
]
}, },
"files": [ "files": [
"src/main.ts" "src/main.ts"

View File

@ -4,7 +4,8 @@
"compilerOptions": { "compilerOptions": {
"outDir": "./out-tsc/spec", "outDir": "./out-tsc/spec",
"types": [ "types": [
"jasmine" "jasmine",
"@angular/localize"
] ]
}, },
"include": [ "include": [