diff options
author | jm.bardallo <juanmanuel.bardallo@sic.uhu.es> | 2019-05-02 15:03:30 +0200 |
---|---|---|
committer | jm.bardallo <juanmanuel.bardallo@sic.uhu.es> | 2019-05-02 15:03:30 +0200 |
commit | 2272900dfa23f1c5b7c0926e24ab9c435a3d1b5d (patch) | |
tree | 1f2b9fc986115cb7ed0852f9c1ccc6179a7aa5a8 | |
parent | 20fc050be9508646e857ac1e086ebc72181587be (diff) |
Posibilidad de añadir clientes mediante fichero dhcp
Añadido perfil software
Añadidos comandos:
- Ejecutar script
- Crear imagen
- Deploy de imagen
- Iniciar sesion
Añadidos los menus
68 files changed, 3180 insertions, 742 deletions
diff --git a/admin/WebConsole3/frontend/src/app/api/command.service.ts b/admin/WebConsole3/frontend/src/app/api/command.service.ts index fe77bda3..28b18520 100644 --- a/admin/WebConsole3/frontend/src/app/api/command.service.ts +++ b/admin/WebConsole3/frontend/src/app/api/command.service.ts @@ -1,26 +1,26 @@ -import { Injectable } from '@angular/core';
-import { HttpClient} from '@angular/common/http';
-
-import { environment } from '../../environments/environment';
-import { Command } from '../model/command';
-import { CommandSerializer } from '../serializer/command.serializer';
-
-import {ResourceService} from 'globunet-angular/core/providers/api/resource.service';
-import {Observable} from 'rxjs';
-
-
-@Injectable({
- providedIn: 'root'
-})
-export class CommandService extends ResourceService<Command> {
-
- constructor(http: HttpClient) {
- super(http, environment.API_URL, 'commands', new CommandSerializer());
- }
-
- execute(params): Observable<any> {
- const url = this.url + 'executes.json';
- return this.httpClient.post(url, params);
- }
-
-}
+import {Injectable} from '@angular/core'; +import {HttpClient} from '@angular/common/http'; + +import {environment} from '../../environments/environment'; +import {Command} from '../model/command'; +import {CommandSerializer} from '../serializer/command.serializer'; + +import {ResourceService} from 'globunet-angular/core/providers/api/resource.service'; +import {Observable} from 'rxjs'; + + +@Injectable({ + providedIn: 'root' +}) +export class CommandService extends ResourceService<Command> { + + constructor(http: HttpClient) { + super(http, environment.API_URL, 'commands', new CommandSerializer()); + } + + execute(params): Observable<any> { + const url = this.url + '/commands/executes.json'; + return this.httpClient.post(url, params); + } + +} diff --git a/admin/WebConsole3/frontend/src/app/api/software-component.service.ts b/admin/WebConsole3/frontend/src/app/api/software-component.service.ts index 6b794109..b154d41a 100644 --- a/admin/WebConsole3/frontend/src/app/api/software-component.service.ts +++ b/admin/WebConsole3/frontend/src/app/api/software-component.service.ts @@ -1,20 +1,20 @@ -import { Injectable } from '@angular/core';
-import { HttpClient} from '@angular/common/http';
-
-import { environment } from '../../environments/environment';
-import { SoftwareComponent } from "../model/software-component";
-import { SoftwareComponentSerializer } from "../serializer/software-component.serializer";
-
-import {ResourceService} from "globunet-angular/core/providers/api/resource.service";
-
-
-@Injectable({
- providedIn: 'root'
-})
-export class SoftwareComponentService extends ResourceService<SoftwareComponent> {
-
- constructor(http: HttpClient){
- super(http, environment.API_URL,"softwareComponents", new SoftwareComponentSerializer());
- }
-
-}
+import { Injectable } from '@angular/core'; +import { HttpClient} from '@angular/common/http'; + +import { environment } from '../../environments/environment'; +import { SoftwareComponent } from "../model/software-component"; +import { SoftwareComponentSerializer } from "../serializer/software-component.serializer"; + +import {ResourceService} from "globunet-angular/core/providers/api/resource.service"; + + +@Injectable({ + providedIn: 'root' +}) +export class SoftwareComponentService extends ResourceService<SoftwareComponent> { + + constructor(http: HttpClient){ + super(http, environment.API_URL,"softwarecomponents", new SoftwareComponentSerializer()); + } + +} diff --git a/admin/WebConsole3/frontend/src/app/api/software-profile.service.ts b/admin/WebConsole3/frontend/src/app/api/software-profile.service.ts index 442d97a7..92b09e23 100644 --- a/admin/WebConsole3/frontend/src/app/api/software-profile.service.ts +++ b/admin/WebConsole3/frontend/src/app/api/software-profile.service.ts @@ -1,20 +1,20 @@ -import { Injectable } from '@angular/core';
-import { HttpClient} from '@angular/common/http';
-
-import { environment } from '../../environments/environment';
-import { SoftwareProfile } from "../model/software-profile";
-import { SoftwareProfileSerializer } from "../serializer/software-profile.serializer";
-
-import {ResourceService} from "globunet-angular/core/providers/api/resource.service";
-
-
-@Injectable({
- providedIn: 'root'
-})
-export class SoftwareProfileService extends ResourceService<SoftwareProfile> {
-
- constructor(http: HttpClient){
- super(http, environment.API_URL,"softwareProfiles", new SoftwareProfileSerializer());
- }
-
-}
+import { Injectable } from '@angular/core'; +import { HttpClient} from '@angular/common/http'; + +import { environment } from '../../environments/environment'; +import { SoftwareProfile } from "../model/software-profile"; +import { SoftwareProfileSerializer } from "../serializer/software-profile.serializer"; + +import {ResourceService} from "globunet-angular/core/providers/api/resource.service"; + + +@Injectable({ + providedIn: 'root' +}) +export class SoftwareProfileService extends ResourceService<SoftwareProfile> { + + constructor(http: HttpClient){ + super(http, environment.API_URL,"softwareprofiles", new SoftwareProfileSerializer()); + } + +} diff --git a/admin/WebConsole3/frontend/src/app/api/software-type.service.ts b/admin/WebConsole3/frontend/src/app/api/software-type.service.ts index aa2e457e..ccc6eb8f 100644 --- a/admin/WebConsole3/frontend/src/app/api/software-type.service.ts +++ b/admin/WebConsole3/frontend/src/app/api/software-type.service.ts @@ -1,20 +1,20 @@ -import { Injectable } from '@angular/core';
-import { HttpClient} from '@angular/common/http';
-
-import { environment } from '../../environments/environment';
-import { SoftwareType } from "../model/software-type";
-import { SoftwareTypeSerializer } from "../serializer/software-type.serializer";
-
-import {ResourceService} from "globunet-angular/core/providers/api/resource.service";
-
-
-@Injectable({
- providedIn: 'root'
-})
-export class SoftwareTypeService extends ResourceService<SoftwareType> {
-
- constructor(http: HttpClient){
- super(http, environment.API_URL,"softwareTypes", new SoftwareTypeSerializer());
- }
-
-}
+import { Injectable } from '@angular/core'; +import { HttpClient} from '@angular/common/http'; + +import { environment } from '../../environments/environment'; +import { SoftwareType } from "../model/software-type"; +import { SoftwareTypeSerializer } from "../serializer/software-type.serializer"; + +import {ResourceService} from "globunet-angular/core/providers/api/resource.service"; + + +@Injectable({ + providedIn: 'root' +}) +export class SoftwareTypeService extends ResourceService<SoftwareType> { + + constructor(http: HttpClient){ + super(http, environment.API_URL,"softwaretypes", new SoftwareTypeSerializer()); + } + +} diff --git a/admin/WebConsole3/frontend/src/app/app-routing.module.ts b/admin/WebConsole3/frontend/src/app/app-routing.module.ts index 7e5c4c63..80d357fa 100644 --- a/admin/WebConsole3/frontend/src/app/app-routing.module.ts +++ b/admin/WebConsole3/frontend/src/app/app-routing.module.ts @@ -17,6 +17,16 @@ import {ImageEditComponent} from './pages/image/edit/image-edit.component'; import {ProfileComponent} from './pages/profile/profile.component'; import {OrganizationalUnitEditComponent} from './pages/organizational-unit/edit/organizational-unit-edit.component'; import {ClientComponent} from './pages/client/client.component'; +import {ClientDhcpComponent} from './pages/client/dhcp/client-dhcp.component'; +import {DeployImageCommandComponent} from './pages/command/deploy-image-command/deploy-image-command.component'; +import {MenuComponent} from './pages/menu/menu.component'; +import {MenuEditComponent} from './pages/menu/edit/menu-edit.component'; +import {SoftwareProfileComponent} from './pages/software-profile/software-profile.component'; +import {SoftwareComponentComponent} from './pages/software-component/software-component.component'; +import {SoftwareComponent} from './pages/software/software.component'; +import {LoginCommandComponent} from './pages/command/login-command/login-command.component'; +import {ExecuteCommandComponent} from './pages/command/execute-command/execute-command.component'; +import {CreateImageCommandComponent} from './pages/command/create-image-command/create-image-command.component'; const routes: Routes = [ @@ -59,14 +69,18 @@ const routes: Routes = [ }, { path: 'clients/dhcp', - component: ClientComponent + component: ClientDhcpComponent }, { path: 'images', component: ImageComponent }, { - path: 'images/create', + path: 'images/create/monolithic', + component: ImageEditComponent + }, + { + path: 'images/create/basic', component: ImageEditComponent }, { @@ -94,10 +108,50 @@ const routes: Routes = [ component: HardwareProfileComponent }, { + path: 'software', + component: SoftwareComponent, + }, + { + path: 'software/profile/create', + component: SoftwareProfileComponent + }, + { + path: 'software/component/create', + component: SoftwareComponentComponent + }, + { + path: 'software/profile/:id', + component: SoftwareProfileComponent + }, + { + path: 'menus', + component: MenuComponent + }, + { + path: 'menus/create', + component: MenuEditComponent + }, + { path: 'commands', component: CommandComponent }, { + path: 'commands/deploy_image', + component: DeployImageCommandComponent + }, + { + path: 'commands/login', + component: LoginCommandComponent + }, + { + path: 'commands/execute', + component: ExecuteCommandComponent + }, + { + path: 'commands/create_image', + component: CreateImageCommandComponent + }, + { path: 'commands/:id', component: EditCommandComponent }, diff --git a/admin/WebConsole3/frontend/src/app/app.module.ts b/admin/WebConsole3/frontend/src/app/app.module.ts index 3dd55fe6..5f861c65 100644 --- a/admin/WebConsole3/frontend/src/app/app.module.ts +++ b/admin/WebConsole3/frontend/src/app/app.module.ts @@ -26,8 +26,8 @@ import { HardwareComponent } from './pages/hardware/hardware.component'; import { HardwareComponentsComponent } from './pages/hardware/hardware-components/hardware-components.component'; import { HardwareProfilesComponent } from './pages/hardware/hardware-profiles/hardware-profiles.component'; import { HardwareTypesComponent } from './pages/hardware/hardware-types/hardware-types.component'; -import {ProfilesTableComponent} from './pages/hardware/hardware-profiles/profiles-table/profiles-table.component'; -import {ProfilesGroupComponent} from './pages/hardware/hardware-profiles/profiles-group/profiles-group.component'; +import {HardwareProfilesTableComponent} from './pages/hardware/hardware-profiles/profiles-table/hardware-profiles-table.component'; +import {HardwareProfilesGroupComponent} from './pages/hardware/hardware-profiles/profiles-group/hardware-profiles-group.component'; import {HardwareComponentsTableComponent} from './pages/hardware/hardware-components/hardware-components-table/hardware-components-table.component'; import {HardwareComponentsGroupComponent} from './pages/hardware/hardware-components/hardware-components-group/hardware-components-group.component'; import {HardwareProfileComponent} from './pages/hardware-profile/hardware-profile.component'; @@ -58,6 +58,23 @@ import {OrganizationalUnitEditComponent} from './pages/organizational-unit/edit/ import {platformBrowserDynamic} from '@angular/platform-browser-dynamic'; import {ClientComponent} from './pages/client/client.component'; import {ChartsModule} from 'ng2-charts'; +import {ClientDhcpComponent} from './pages/client/dhcp/client-dhcp.component'; +import {DeployImageCommandComponent} from './pages/command/deploy-image-command/deploy-image-command.component'; +import {MenuComponent} from './pages/menu/menu.component'; +import {MenuEditComponent} from './pages/menu/edit/menu-edit.component'; +import {SoftwareComponentComponent} from './pages/software-component/software-component.component'; +import {SoftwareComponent} from './pages/software/software.component'; +import {SoftwareComponentsComponent} from './pages/software/software-components/software-components.component'; +import {SoftwareProfilesComponent} from './pages/software/software-profiles/software-profiles.component'; +import {SoftwareProfileComponent} from './pages/software-profile/software-profile.component'; +import {SoftwareTypesComponent} from './pages/software/software-types/software-types.component'; +import {SoftwareProfilesTableComponent} from './pages/software/software-profiles/software-profiles-table/software-profiles-table.component'; +import {SoftwareProfilesGroupComponent} from './pages/software/software-profiles/software-profiles-group/software-profiles-group.component'; +import {SoftwareComponentsTableComponent} from './pages/software/software-components/software-components-table/software-components-table.component'; +import {SoftwareComponentsGroupComponent} from './pages/software/software-components/software-components-group/software-components-group.component'; +import {LoginCommandComponent} from './pages/command/login-command/login-command.component'; +import {ExecuteCommandComponent} from './pages/command/execute-command/execute-command.component'; +import {CreateImageCommandComponent} from './pages/command/create-image-command/create-image-command.component'; @@ -67,6 +84,8 @@ import {ChartsModule} from 'ng2-charts'; LoginComponent, ImageComponent, ImageEditComponent, + MenuComponent, + MenuEditComponent, DashboardComponent, RepositoryComponent, OrganizationalUnitComponent, @@ -79,14 +98,29 @@ import {ChartsModule} from 'ng2-charts'; HardwareProfilesComponent, HardwareProfileComponent, HardwareTypesComponent, - ProfilesTableComponent, - ProfilesGroupComponent, + HardwareProfilesTableComponent, + HardwareProfilesGroupComponent, HardwareComponentsTableComponent, HardwareComponentsGroupComponent, + SoftwareComponentComponent, + SoftwareComponent, + SoftwareComponentsComponent, + SoftwareProfilesComponent, + SoftwareProfileComponent, + SoftwareTypesComponent, + SoftwareProfilesTableComponent, + SoftwareProfilesGroupComponent, + SoftwareComponentsTableComponent, + SoftwareComponentsGroupComponent, OuGroupComponent, OuClientComponent, ClientComponent, + ClientDhcpComponent, CommandComponent, + DeployImageCommandComponent, + LoginCommandComponent, + ExecuteCommandComponent, + CreateImageCommandComponent, EditCommandComponent, IcheckDirective, FixedToolboxBarDirective, @@ -110,17 +144,28 @@ import {ChartsModule} from 'ng2-charts'; LoginComponent, ImageComponent, ImageEditComponent, + MenuComponent, + MenuEditComponent, OrganizationalUnitComponent, OrganizationalUnitEditComponent, Ng2TableActionComponent, - ProfilesTableComponent, - ProfilesGroupComponent, + HardwareProfilesTableComponent, + HardwareProfilesGroupComponent, HardwareComponentsTableComponent, HardwareComponentsGroupComponent, + SoftwareProfilesTableComponent, + SoftwareProfilesGroupComponent, + SoftwareComponentsTableComponent, + SoftwareComponentsGroupComponent, OuGroupComponent, OuClientComponent, ClientComponent, + ClientDhcpComponent, CommandComponent, + DeployImageCommandComponent, + LoginCommandComponent, + ExecuteCommandComponent, + CreateImageCommandComponent, EditCommandComponent, OgOuGeneralOptionsComponent, TraceComponent, diff --git a/admin/WebConsole3/frontend/src/app/form-type/menu.form-type.ts b/admin/WebConsole3/frontend/src/app/form-type/menu.form-type.ts new file mode 100644 index 00000000..94a8d97b --- /dev/null +++ b/admin/WebConsole3/frontend/src/app/form-type/menu.form-type.ts @@ -0,0 +1,12 @@ +import {GlobunetFormType} from './globunet.form-type'; +import {Menu} from '../model/menu'; + + +export class MenuFormType extends GlobunetFormType { + getForm() { + const form: any[] = GlobunetFormType.getForm(new Menu()); + this.setFieldType(form, 'description', 'textarea'); + this.setFieldType(form, 'resolution', 'select'); + return form; + } +} diff --git a/admin/WebConsole3/frontend/src/app/model/command.ts b/admin/WebConsole3/frontend/src/app/model/command.ts index 2f3639ba..2c5697aa 100644 --- a/admin/WebConsole3/frontend/src/app/model/command.ts +++ b/admin/WebConsole3/frontend/src/app/model/command.ts @@ -1,8 +1,14 @@ -import { Resource } from 'globunet-angular/core/models/api/resource';
-
-export class Command extends Resource {
- public title = '';
- public script = '';
- public parameters = false;
-
-}
+import { Resource } from 'globunet-angular/core/models/api/resource'; + +export class Excecution { + script = ''; + clients = ''; + type = ''; +} + +export class Command extends Resource { + public title = ''; + public script = ''; + public parameters = false; + +} diff --git a/admin/WebConsole3/frontend/src/app/model/image.ts b/admin/WebConsole3/frontend/src/app/model/image.ts index 2a85299f..2d52cf63 100644 --- a/admin/WebConsole3/frontend/src/app/model/image.ts +++ b/admin/WebConsole3/frontend/src/app/model/image.ts @@ -1,20 +1,24 @@ -import { Resource } from 'globunet-angular/core/models/api/resource';
-import {Repository} from './repository';
-
-export class PartitionInfo {
- numDisk: number;
- numPartition: number;
- partitionCode: string;
- filesystem: string;
- osName: string;
-}
-
-export class Image extends Resource {
- public canonicalName: string = '';
- public repository: Repository = new Repository();
- public description: string = '';
- public comments: string = '';
- public revision: string;
- public createdAt: Date;
- public partitionInfo: PartitionInfo;
-}
+import { Resource } from 'globunet-angular/core/models/api/resource'; +import {Repository} from './repository'; +import {Client} from './client'; +import {SoftwareProfile} from './software-profile'; + +export class PartitionInfo { + numDisk: number; + numPartition: number; + partitionCode: string; + filesystem: string; + osName: string; +} + +export class Image extends Resource { + public canonicalName = ''; + public repository: Repository = new Repository(); + public description = ''; + public comments = ''; + public revision: string; + public createdAt: Date; + public softwareProfile: SoftwareProfile; + public partitionInfo: PartitionInfo; + public client?: Client; +} diff --git a/admin/WebConsole3/frontend/src/app/model/menu.ts b/admin/WebConsole3/frontend/src/app/model/menu.ts index e8928976..1d19bd44 100644 --- a/admin/WebConsole3/frontend/src/app/model/menu.ts +++ b/admin/WebConsole3/frontend/src/app/model/menu.ts @@ -1,12 +1,12 @@ -import { Resource } from 'globunet-angular/core/models/api/resource';
-
-export class Menu extends Resource {
- public title: string;
- public resolution: string;
- public description: string;
- public comments: string;
- public publicColumns: number;
- public publicUrl: string;
- public privateColumns: number;
- public privateUrl: string;
-}
+import { Resource } from 'globunet-angular/core/models/api/resource'; + +export class Menu extends Resource { + public title = ''; + public resolution = ''; + public description = ''; + public comments = ''; + public publicUrl = '' + public privateUrl = ''; + public publicColumns: number; + public privateColumns: number; +} diff --git a/admin/WebConsole3/frontend/src/app/pages/client/dhcp/client-dhcp.component.html b/admin/WebConsole3/frontend/src/app/pages/client/dhcp/client-dhcp.component.html new file mode 100644 index 00000000..c21f5c8d --- /dev/null +++ b/admin/WebConsole3/frontend/src/app/pages/client/dhcp/client-dhcp.component.html @@ -0,0 +1,139 @@ +<section class="content-header"> + <h1 translate="dhcp_clients"> + </h1> + <ol class="breadcrumb"> + <li><a [routerLink]="'app/dashboard'"><i class="fa fa-dashboard"></i> {{'dashboard'|translate}}</a></li> + <li><a [routerLink]="'app/ous'" ><i class="fa fa-th"></i> {{'ous'|translate}}</a></li> + <li class="active" translate="dhcp_clients"></li> + </ol> +</section> +<section fixed-toolboxbar class="toolboxbar"> + <div> + <div class="col-md-12"> + <div class="box-tools pull-right"> + <button class="btn btn-primary" translate="save" (click)="save()"></button> + </div> + </div> + </div> +</section> +<section class="content"> + <div class="row"> + <div class="col-md-12"> + <div class="box box-primary"> + <div class="box-header with-border"> + <h3 class="box-title" translate="load_clients_from_dhcp"></h3> + <div *ngIf="clients.length == 0" class="btn-group pull-right"> + <button type="button" name="search" id="search-btn" class="btn btn-flat" (click)="downloadFromServer()"> + <i class="fa fa-download"></i> + <span translate="download_from_server"></span> + </button> + <button class="btn btn-primary" (click)="proccessDhcp()" translate="proccess_dhcp"></button> + </div> + <div *ngIf="clients.length > 0" class="pull-right"> + <button class="btn btn-danger" (click)="clients = []" translate="back"></button> + </div> + </div> + <div *ngIf="clients.length == 0" class="box-body"> + <div class="row"> + <div class="col-md-12"> + <textarea [(ngModel)]="dhcpText" class="og-instructions"> + + </textarea> + </div> + </div> + </div> + <div class="box-body" *ngIf="clients.length > 0"> + <div class="row"> + <div class="col-md-12"> + <div class="box box-default"> + <div class="box-header with-border"> + <h3 class="box-title" translate="common_options"></h3> + </div> + <div class="box-body"> + <div class="row"> + <div class="col-xs-2"> + <div class="form-group"> + <label class="control-label" for="repository" translate="repository"></label> + <select name="repository" class="form-control" [(ngModel)]="commonProperties.repository"> + <option *ngFor="let repository of repositories" [value]="repository.id">{{repository.name}}</option> + </select> + </div> + </div> + <div class="col-xs-2"> + <div class="form-group"> + <label class="control-label" for="hardwareProfile" translate="hardware_profile"></label> + <select name="hardwareProfile" class="form-control" [(ngModel)]="commonProperties.hardwareProfile"> + <option *ngFor="let profile of hardwareProfiles" [value]="profile.id"> + {{profile.description}} + </option> + </select> + </div> + </div> + <div class="col-xs-1"> + <div class="form-group"> + <label class="control-label" for="netiface" translate="netiface"></label> + <input type="text" name="netiface" class="form-control" [(ngModel)]="commonProperties.netiface" /> + </div> + </div> + <div class="col-xs-2"> + <div class="form-group"> + <label class="control-label" for="netdriver" translate="netdriver"></label> + <input type="text" name="netdriver" class="form-control" [(ngModel)]="commonProperties.netdriver" /> + </div> + </div> + <div class="form-group col-md-3"> + <label for="oglive" translate="oglive"> + <span class="symbol required ng-scope"></span> + </label> + <select class="form-control" required="true" [(ngModel)]="commonProperties.oglive" name="oglive"> + <option *ngFor="let item of constants.ogliveinfo" [value]="item.directory"> + {{item.directory}} + </option> + </select> + </div> + <div class="form-group col-md-2"> + <label for="netboot" translate="netboot"> + <span class="symbol required ng-scope"></span> + </label> + <select class="form-control" required="true" [(ngModel)]="commonProperties.netboot" name="netboot"> + <option *ngFor="let item of netboots" [value]="item.id">{{item.name}}</option> + </select> + </div> + </div> + </div> + <!-- /.box-body --> + </div> + </div> + <div class="col-md-12"> + <table class="table table-striped"> + <thead> + <tr> + <th> + <input icheck checkbox-class="icheckbox_square-blue" radio-class="iradio_square-blue" type="checkbox" class="selection-checkbox" (change)="selectedUnselectAll()" [(ngModel)]="selectAll" /> + <span translate="select"></span> + </th> + <th translate="name"></th> + <th translate="ip"></th> + <th translate="mac"></th> + </tr> + </thead> + <tbody> + <tr *ngFor="let client of clients"> + <td> + <input icheck checkbox-class="icheckbox_square-blue" radio-class="iradio_square-blue" type="checkbox" class="selection-checkbox" [(ngModel)]="client.$$selected" /> + </td> + <td>{{client.name}}</td> + <td>{{client.ip}}</td> + <td>{{client.mac}}</td> + </tr> + </tbody> + </table> + </div> + </div> + </div> + <div class="box-footer"> + </div> + </div> + </div> + </div> +</section> diff --git a/admin/WebConsole3/frontend/src/app/pages/client/dhcp/client-dhcp.component.scss b/admin/WebConsole3/frontend/src/app/pages/client/dhcp/client-dhcp.component.scss new file mode 100644 index 00000000..0bbea7e4 --- /dev/null +++ b/admin/WebConsole3/frontend/src/app/pages/client/dhcp/client-dhcp.component.scss @@ -0,0 +1,5 @@ +::ng-deep app-client { + ::ng-deep .box-title { + width: 100%; + } +} diff --git a/admin/WebConsole3/frontend/src/app/pages/client/dhcp/client-dhcp.component.ts b/admin/WebConsole3/frontend/src/app/pages/client/dhcp/client-dhcp.component.ts new file mode 100644 index 00000000..70394ba4 --- /dev/null +++ b/admin/WebConsole3/frontend/src/app/pages/client/dhcp/client-dhcp.component.ts @@ -0,0 +1,223 @@ +import {Component, OnInit} from '@angular/core'; + +import {ClientService} from 'src/app/api/client.service'; +import {ActivatedRoute, ParamMap, Router} from '@angular/router'; +import {forkJoin, Observable} from 'rxjs'; +import {NetbootService} from '../../../api/netboot.service'; +import {ToasterService} from '../../../service/toaster.service'; +import {RepositoryService} from '../../../api/repository.service'; +import {HardwareProfileService} from '../../../api/hardware-profile.service'; +import {Repository} from '../../../model/repository'; +import {HardwareProfile} from '../../../model/hardware-profile'; +import {OgCommonService} from '../../../service/og-common.service'; +import {ClientFormType} from '../../../form-type/client.form-type'; +import {TranslateService} from '@ngx-translate/core'; + +@Component({ + selector: 'app-client-dhcp', + templateUrl: './client-dhcp.component.html', + styleUrls: ['./client-dhcp.component.scss'] +}) +export class ClientDhcpComponent implements OnInit { + public netboots: any = []; + public repositories: Repository[] = []; + public hardwareProfiles: HardwareProfile[] = []; + public oglives: any[] = []; + private formType: ClientFormType; + public form; + public constants = {}; + private dhcpFile: string; + public commonProperties: any; + public dhcpText: string; + public clients: any[]; + public selectAll: boolean; + + // this tells the tabs component which Pages + // should be each tab's root Page + constructor(private router: Router, + private activatedRouter: ActivatedRoute, + private clientService: ClientService, + private netbootService: NetbootService, + private translate: TranslateService, + private toaster: ToasterService, + private repositoryService: RepositoryService, + private hardwareProfileService: HardwareProfileService, + private ogCommonService: OgCommonService) { + + this.commonProperties = {}; + this.clients = []; + + } + + ngOnInit() { + this.ogCommonService.loadEngineConfig().subscribe( + data => { + this.constants = data.constants; + } + ); + this.dhcpFile = '/etc/dhcp/dhcpd.conf'; + this.loadNetboots(); + // Los repositorios vienen cargados ya desde config.router + this.repositoryService.list().subscribe( + (repositories) => { + this.repositories = repositories; + this.commonProperties.repository = this.repositories[0].id; + if (!this.hardwareProfiles) { + this.hardwareProfileService.list().subscribe( + (response) => { + this.hardwareProfiles = response; + this.commonProperties.hardwareProfile = this.hardwareProfiles[0].id; + }, + (error) => { + alert(error); + } + ); + } else { + this.hardwareProfiles = this.hardwareProfiles; + } + }, + (error) => { + this.toaster.pop({type: 'error', title: 'error', body: error}); + } + ); + + } + + loadNetboots() { + this.netbootService.list().subscribe( + (result) => { + this.netboots = result; + this.commonProperties.netboot = this.netboots[0]; + }, + (error) => { + this.toaster.pop({type: 'error', title: 'error', body: error}); + } + ); + } + + + downloadFromServer() { + this.dhcpText = 'ddns-update-style none;\n' + + 'option domain-name "example.org";\n' + + 'log-facility local7;\n' + + 'not-authoritative;\n' + + '\n' + + 'subnet 172.16.140.0 netmask 255.255.255.0 {\n' + + ' option domain-name-servers 172.16.3.1;\n' + + ' option routers 172.16.140.254;\n' + + ' option broadcast-address 172.16.140.255;\n' + + ' default-lease-time 600;\n' + + ' max-lease-time 7200;\n' + + ' next-server 172.16.140.210;\n' + + ' filename "grldr";\n' + + ' use-host-decl-names on;\n' + + '\n' + + '# host HOSTNAME1 {\n' + + '# hardware ethernet HOSTMAC1;\n' + + '# fixed-address HOSTIP1;\n' + + '# }\n' + + '\n' + + ' host pc-pruebas {\n' + + ' hardware ethernet 00:1B:21:1F:EE:9D;\n' + + ' fixed-address 172.16.140.213;\n' + + ' }\n' + + ' host pc-virtualbox {\n' + + ' hardware ethernet 20:CF:30:BF:9A:39;\n' + + ' fixed-address 172.16.140.214;\n' + + ' }\n' + + '\n' + + '\n' + + '}\n'; + /* + ServerDchpResource.getDhcp().then( + function(response) { + this.dhcpText = response.text; + this.toaster.pop({type: 'success', title: 'success', body: this.translate.instant('successfully_loaded')}); + }, + function(error) { + this.toaster.pop({type: 'error', title: 'error', body: error}); + } + ); + /**/ + } + + proccessDhcp() { + if (typeof this.dhcpText !== 'undefined' && this.dhcpText !== '') { + const lines = this.dhcpText.split('\n'); + this.clients = []; + for (let i = 0; i < lines.length; i++) { + // Comprobar si la línea actual contiene la palabra "host" sin ninguna # delante que sería comentario + if (/^host/.test(lines[i].trim())) { + // Unimos las siguientes líneas hasta encontrar "}" + let line = ''; + while(lines[i].indexOf("}") === -1 && i < lines.length){ + line += lines[i]; + i++; + } + // procesar la linea + // host pc53-151 { hardware ethernet 00:1E:33:61:49:B8; fixed-address 172.16.53.151; } + let parts = line.split('{'); + const hostname = parts[0].trim().split(' ')[1]; + + // Las siguientes partes pueden estar en la linea actual o las siguientes + parts = parts[1].trim().split(";"); + const mac = parts[0].trim().split('ethernet')[1]; + // lo mismo puede ocurrir con fixed-address puede estar en lineas diferentes + parts = parts[1].trim().split('fixed-address'); + const ip = parts[1]; + this.clients.push( + { + name: hostname, + ip: ip, + mac: mac, + $$selected: true + } + ); + } + } + } else { + this.toaster.pop({type: 'error', title: 'error', body: this.translate.instant('nothing_to_proccess')}); + } + } + + selectedUnselectAll() { + for (let c = 0; c < this.clients.length; c++) { + this.clients[c].$$selected = this.selectAll; + } + } + + save() { + const promises = []; + let ou = ''; + this.activatedRouter.queryParams.subscribe( + query => { + ou = query.ou; + } + ); + for (let c = 0; c < this.clients.length; c++) { + if (this.clients[c].$$selected === true) { + const client = Object.assign({}, this.clients[c]); + + // Si se indicó un padre en la url, se añade dicha propiedad + client.organizationalUnit = ou; + client.idproautoexec = 0; + client.netdriver = this.commonProperties.netdriver; + client.netiface = this.commonProperties.netiface; + // Propiedades comunes + // client.repository = this.commonProperties.repository; + // client.hardwareProfile = this.commonProperties.hardwareProfile; + promises.push(this.clientService.create(client)); + } + } + forkJoin(promises).subscribe( + (response) => { + this.toaster.pop({type: 'success', title: 'success', body: 'Successfully saved'}); + this.router.navigate(['/app/ous']); + }, + (error) => { + this.toaster.pop({type: 'error', title: 'error', body: error}); + } + ); + } + +} diff --git a/admin/WebConsole3/frontend/src/app/pages/command/create-image-command/create-image-command.component.html b/admin/WebConsole3/frontend/src/app/pages/command/create-image-command/create-image-command.component.html new file mode 100644 index 00000000..9534718c --- /dev/null +++ b/admin/WebConsole3/frontend/src/app/pages/command/create-image-command/create-image-command.component.html @@ -0,0 +1,98 @@ +<section class="content-header"> + <h1 translate="create_image"> + </h1> + <ol class="breadcrumb"> + <li><a [routerLink]="'/app/dashboard'"><i class="fa fa-dashboard"></i>{{'dashboard'|translate}}</a></li> + <li><a [routerLink]="'/app/ous'"><i class="fa fa-th"></i>{{'ous'|translate}}</a></li> + <li class="active" translate="create_image"></li> + </ol> +</section> +<section fixed-toolboxbar class="toolboxbar"> + <div> + <div class="col-md-12"> + <div class="box-tools pull-right"> + <button class="btn btn-primary" translate="execute" (click)="sendCommand()"></button> + </div> + </div> + </div> +</section> +<section style="padding: 0 30px;"> + <h3 translate="selected_clients"></h3> + <app-og-selected-clients></app-og-selected-clients> +</section> +<!-- Main content --> +<section class="content"> + <div class="row"> + <div class="col-md-12"> + <div class="box box-primary"> + <div class="box-header with-border"> + </div> + <div class="box-body"> + <form role="form" name="Form"> + <div class="form-group"> + <label> + <span translate="client"></span> + {{client.name}} + </label> + </div> + <div class="form-group" ng-class="{'has-error':Form.images.$dirty && Form.images.$invalid, 'has-success':Form.images.$valid}"> + <label for="images"> + <span translate="images"></span> + </label> + <select (change)="setCanonicalName()" class="form-control" type="text" [(ngModel)]="command.image" name="images"> + <option [ngValue]="null" translate="----"></option> + <option *ngFor="let image of images" [ngValue]="image">{{image.canonicalName}}</option> + </select> + </div> + <div class="form-group" ng-class="{'has-error':Form.canonicalName.$dirty && Form.canonicalName.$invalid, 'has-success':Form.canonicalName.$valid}"> + <label for="canonicalName"> + <span translate="canonicalName"></span> + <span class="symbol required"></span> + </label> + <input type="text" class="form-control" type="text" required="true" [(ngModel)]="command.canonicalName" name="canonicalName"> + </div> + <div> + <table class="table"> + <thead> + <tr> + <th translate="select"> + </th> + <th translate="disk"> + </th> + <th translate="partition"> + </th> + <th translate="filesystem"> + </th> + <th translate="osname"> + </th> + </tr> + </thead> + <tbody> + <ng-container *ngFor="let partition of client.partitions; let index = index;"> + <tr *ngIf="isClonable(partition)"> + <td> + <input icheck type="radio" [name]="'partition_'+partition.numPartition" checkbox-class="icheckbox_square-blue" radio-class="iradio_square-blue" class="selection-checkbox" [(ngModel)]="selectedPartition" [value]="index" /> + </td> + <td> + {{partition.numDisk}} + </td> + <td> + {{partition.numPartition}} + </td> + <td> + {{partition.filesystem}} + </td> + <td> + {{partition.osName}} + </td> + </tr> + </ng-container> + </tbody> + </table> + </div> + </form> + </div> + </div> + </div> + </div> +</section> diff --git a/admin/WebConsole3/frontend/src/app/pages/command/create-image-command/create-image-command.component.scss b/admin/WebConsole3/frontend/src/app/pages/command/create-image-command/create-image-command.component.scss new file mode 100644 index 00000000..08b1082b --- /dev/null +++ b/admin/WebConsole3/frontend/src/app/pages/command/create-image-command/create-image-command.component.scss @@ -0,0 +1,3 @@ +app-execute-command { + +} diff --git a/admin/WebConsole3/frontend/src/app/pages/command/create-image-command/create-image-command.component.ts b/admin/WebConsole3/frontend/src/app/pages/command/create-image-command/create-image-command.component.ts new file mode 100644 index 00000000..8f018e33 --- /dev/null +++ b/admin/WebConsole3/frontend/src/app/pages/command/create-image-command/create-image-command.component.ts @@ -0,0 +1,188 @@ +import {Component, OnInit} from '@angular/core'; + +import {ToasterService} from '../../../service/toaster.service'; +import {ActivatedRoute, Router} from '@angular/router'; +import {TranslateService} from '@ngx-translate/core'; +import {OgCommonService} from '../../../service/og-common.service'; +import {OgSweetAlertService} from '../../../service/og-sweet-alert.service'; +import {AuthModule} from 'globunet-angular/core'; +import {User} from '../../../model/user'; +import {OGCommandsService} from '../../../service/og-commands.service'; +import {CommandService} from '../../../api/command.service'; +import {Image} from '../../../model/image'; +import {Command, Excecution} from '../../../model/command'; +import {Client, Partition} from '../../../model/client'; +import {Repository} from '../../../model/repository'; +import {RepositoryService} from '../../../api/repository.service'; +import {ImageService} from '../../../api/image.service'; +import {forkJoin} from 'rxjs'; + +@Component({ + selector: 'app-create-image-command', + templateUrl: './create-image-command.component.html', + styleUrls: [ './create-image-command.component.scss' ] +}) +export class CreateImageCommandComponent implements OnInit { + private readonly user: User; + private constants: any; + public repositories: Repository[]; + public execution = new Excecution(); + public commands: Command[] = []; + public client: Client; + public images = []; + public command = {canonicalName: '', image: new Image()}; + public selectedPartition: number; + + + // this tells the tabs component which Pages + // should be each tab's root Page + constructor(public ogCommandsService: OGCommandsService, + private authModule: AuthModule, + private router: Router, + private activatedRoute: ActivatedRoute, + private ogCommonService: OgCommonService, + private commandService: CommandService, + private imageService: ImageService, + private repositoryService: RepositoryService, + private ogSweetAlert: OgSweetAlertService, + private toaster: ToasterService, + private translate: TranslateService) { + this.user = this.authModule.getLoggedUser(); + } + + + + ngOnInit() { + if (this.user && this.ogCommonService.selectedClients) { + const clientId = Object.keys(this.ogCommonService.selectedClients)[0]; + this.client = this.ogCommonService.selectedClients[clientId]; + this.execution.clients = clientId; + this.ogCommonService.loadEngineConfig().subscribe( + data => { + this.constants = data.constants; + } + ); + this.loadRepositories(); + this.loadImages(); + } else { + // TODO - dar error? + this.ogSweetAlert.error(this.translate.instant('opengnsys_error'), this.translate.instant('not_clients_selected')); + this.router.navigate(['app.ous']); + } + } + + + sendCommand() { + if (!this.selectedPartition) { + this.toaster.pop({type: 'error', title: 'error', body: this.translate.instant('you_must_select_partition')}); + } else { + const disk = this.client.partitions[this.selectedPartition].numDisk; + const partition = this.client.partitions[this.selectedPartition].numPartition; + // Al crear la imagen, le asociamos un perfil software + // @ts-ignore + this.execution.script = this.constants.commands.SOFTWARE_INVENTORY + ' ' + disk + ' ' + partition + '\n'; + this.execution.script += this.constants.commands.CREATE_IMAGE + ' ' + disk + ' ' + partition + ' ' + this.command.canonicalName + ' REPO '; + // @ts-ignore + this.execution.script = this.execution.script.replace(/\"/g, '\\"').replace(/\$/g, '\\\$'); + + let image: Image = this.command.image; + let newImage = false; + + let result = true; + // Crear la imagen si no existe + if (!image) { + newImage = true; + // Comprobar que exista el repositorio, sino no podemos crear la nueva imagen + if (!this.repositories) { + result = false; + this.toaster.pop({type: 'error', title: 'error', body: this.translate.instant('no_repository_exist')}); + } else { + // Usar el repositorio por defecto + const repository = this.repositories[0]; + image = new Image(); + image.canonicalName = this.command.canonicalName; + image.description = this.translate.instant('image_created_automatically'); + image.repository = repository; + } + } + + // Asignar a la imagen los atributos del sistema operativo elegido + image.client = this.client; + + // Si no hubo ningun error se guardan todas las pgms + if (result === true) { + const promises = []; + if (newImage === true) { + promises.push(this.imageService.create(image)); + } else { + const imageCopy = Object.assign({}, image); + delete imageCopy.id; + delete imageCopy.softwareProfile; + promises.push(this.imageService.update(imageCopy)); + } + this.execution.type = 'CREATE_IMAGE'; + promises.push(this.commandService.execute(this.execution)); + forkJoin(promises).subscribe( + (response) => { + this.toaster.pop({type: 'success', title: 'success', body: this.translate.instant('successfully_executed')}); + this.router.navigate(['app.ous']); + }, + (error) => { + this.toaster.pop({type: 'error', title: 'error', body: error}); + } + ); + } + } + } + + setCanonicalName() { + if (this.command.image !== null) { + this.command.canonicalName = this.command.image.canonicalName; + } else { + this.command.canonicalName = ''; + } + } + + private loadImages() { + this.imageService.list().subscribe( + (response) => { + this.images = response; + }, + (error) => { + this.toaster.pop({type: 'error', title: 'error', body: error}); + } + ); + } + private loadRepositories() { + this.repositoryService.list().subscribe( + (response) => { + this.repositories = response; + }, + (error) => { + this.toaster.pop({type: 'error', title: 'error', body: error}); + } + ); + } + + isClonable(partition) { + let clonable = false; + let index = 0; + const code = partition.partitionCode; + + if (partition.numPartition !== 0) { + // Buscar el codigo entre las constantes + while (index < this.constants.partitiontable.length && !clonable) { + // para cada tabla de particiones, buscamos el codigo de la particion + const elements = this.constants.partitiontable[index].partitions.filter(function(part) { + return (part.id === partition.partitionCode.padStart(2, '0')); + } + ); + clonable = (elements.length > 0 && elements[0].clonable === true); + index++; + } + } + + return clonable; + } + +} diff --git a/admin/WebConsole3/frontend/src/app/pages/command/deploy-image-command/deploy-image-command.component.html b/admin/WebConsole3/frontend/src/app/pages/command/deploy-image-command/deploy-image-command.component.html new file mode 100644 index 00000000..7dc55c29 --- /dev/null +++ b/admin/WebConsole3/frontend/src/app/pages/command/deploy-image-command/deploy-image-command.component.html @@ -0,0 +1,146 @@ +<section class="content-header"> + <h1 translate="deploy_image"></h1> + <ol class="breadcrumb"> + <li><a [routerLink]="'/app/dashboard'"><i class="fa fa-dashboard"></i> {{'dashboard'|translate}}</a></li> + <li><a [routerLink]="'/app/ous'" ><i class="fa fa-th"></i> {{'ous'|translate}}</a></li> + <li class="active" translate="deploy_image"></li> + </ol> +</section> +<section style="padding: 0 30px;"> + <h3 translate="selected_clients"></h3> + <app-og-selected-clients></app-og-selected-clients> +</section> +<section class="content padding-top-30" style="padding-top: 30px"> + <div class="box box-default box-solid"> + <div class="box-header with-border"> + </div> + <!-- /.box-header --> + <div class="box-body"> + <form role="form" name="Form"> + <div class="row"> + <div class="form-group col-md-3" > + <div class="checkbox clip-check check-primary checkbox-inline"> + <input id="deployImageParameters" name="deployImage" icheck checkbox-class="iradio_square-blue" radio-class="iradio_square-blue" type="radio" class="selection-checkbox" value="true" [(ngModel)]="deployImage" (change)="updateDeployOptions()" /> + </div> + <label for="deployImage"> + <span translate="deploy_image_update_restore"></span> + </label> + </div> + <div class="form-group col-md-3"> + <div class="checkbox clip-check check-primary checkbox-inline"> + <input id="parameters" name="updateCache" icheck checkbox-class="iradio_square-blue" radio-class="iradio_square-blue" type="radio" class="selection-checkbox" value="false" [(ngModel)]="deployImage" (change)="updateDeployOptions()" /> + </div> + <label for="updateCache"> + <span translate="update_cache_only_download"></span> + </label> + </div> + </div> + <div class="row"> + <div class="form-group col-md-4"> + <div class="form-group" ng-class="{'has-error':Form.images.$dirty && Form.images.$invalid, 'has-success':Form.images.$valid}"> + <label> + <span translate="images"></span> + </label> + <select (change)="setCanonicalName()" class="form-control" type="text" [(ngModel)]="image" name="images"> + <option *ngFor="let image of images" [ngValue]="image">{{image.canonicalName}}</option> + </select> + </div> + </div> + <div class="form-group col-md-2"> + <label for="disk" translate="disk"> + </label> + <input name="disk" type="number" min="1" [(ngModel)]="disk" class="form-control"> + + </div> + <div class="form-group col-md-2"> + <label for="partition" translate="partition"> + </label> + <input name="partition" type="number" min="1" [(ngModel)]="partition" class="form-control"> + </div> + <div class="form-group col-md-4"> + <label for="deployMethod" translate="deploy_method"> + </label> + <select class="form-control" name="deployMethod" [(ngModel)]="deployMethod"> + <option *ngFor="let deployMethod of deployMethods" [value]="deployMethod">{{deployMethod}}</option> + </select> + </div> + </div> + <div *ngIf="deployMethod == 'MULTICAST' || deployMethod == 'MULTICAST-DIRECT'"> + <div class="row"> + <div class="form-group col-md-4"> + <label for="port" translate="port"> + </label> + <input class="form-control" type="text" name="port" [(ngModel)]="multicast.port"/> + </div> + <div class="form-group col-md-4"> + <label for="address" translate="address"> + </label> + <input class="form-control" type="text" name="address" [(ngModel)]="multicast.address"/> + </div> + <div class="form-group col-md-4"> + <label for="multicastMode" translate="mode"> + </label> + <input class="form-control" type="text" name="multicastMode" [(ngModel)]="multicast.mode"/> + </div> + </div> + <div class="row"> + <div class="form-group col-md-4"> + <label for="speed" translate="speed"> + </label> + <input class="form-control" type="text" name="speed" [(ngModel)]="multicast.speed"/> + </div> + <div class="form-group col-md-4"> + <label for="maxClients" translate="max_clients"> + </label> + <input class="form-control" type="text" name="maxClients" [(ngModel)]="multicast.maxClients"/> + </div> + <div class="form-group col-md-4"> + <label for="maxWaitTime" translate="max_wait_time"> + </label> + <input class="form-control" type="text" name="maxWaitTime" [(ngModel)]="multicast.maxWaitTime"/> + </div> + </div> + </div> + <div class="row" *ngIf="deployMethod == 'TORRENT'"> + <div class="form-group col-md-6"> + <label for="torrentMode" translate="mode"> + </label> + <input class="form-control" type="text" name="torrentMode" [(ngModel)]="torrent.mode"/> + </div> + <div class="form-group col-md-6"> + <label for="seedTime" translate="seed_time"> + + </label> + <input class="form-control" type="text" name="seedTime" [(ngModel)]="torrent.seedTime"/> + </div> + </div> + </form> + + </div> + <!-- /.box-body --> + <div class="box-footer"> + <div class="row"> + <div class="col-md-12"> + <div class="btn-group pull-left"> + <button class="btn btn-primary"(click)="generateOgInstruction()"><span translate="generate_og_instruction"></span></button> + <button [class]="editInstructions == false ? 'btn btn-default':'btn btn-success'" *ngIf="ogCommandsService.ogInstructions != ''" (click)="editInstructions = !editInstructions"><span translate="{{editInstructions == false?'edit':'done'}}"></span></button> + </div> + <div class="btn-group pull-right"> + <app-og-execute-command-options></app-og-execute-command-options> + </div> + </div> + </div> + <div class="row"> + <div class="col-md-12"> + <div class="box"> + <div class="box-header"></div> + <div class="box-body" > + <div *ngIf="editInstructions == false" [innerHTML]="ogCommandsService.ogInstructions|ogCommands"></div> + <textarea *ngIf="editInstructions == true" class="og-instructions" [(ngModel)]="ogCommandsService.ogInstructions"></textarea> + </div> + </div> + </div> + </div> + </div> + </div> +</section> diff --git a/admin/WebConsole3/frontend/src/app/pages/command/deploy-image-command/deploy-image-command.component.scss b/admin/WebConsole3/frontend/src/app/pages/command/deploy-image-command/deploy-image-command.component.scss new file mode 100644 index 00000000..ccb34440 --- /dev/null +++ b/admin/WebConsole3/frontend/src/app/pages/command/deploy-image-command/deploy-image-command.component.scss @@ -0,0 +1,3 @@ +command { + +} diff --git a/admin/WebConsole3/frontend/src/app/pages/command/deploy-image-command/deploy-image-command.component.ts b/admin/WebConsole3/frontend/src/app/pages/command/deploy-image-command/deploy-image-command.component.ts new file mode 100644 index 00000000..b8312964 --- /dev/null +++ b/admin/WebConsole3/frontend/src/app/pages/command/deploy-image-command/deploy-image-command.component.ts @@ -0,0 +1,137 @@ +import {Component, OnInit} from '@angular/core'; + +import {ToasterService} from '../../../service/toaster.service'; +import {ActivatedRoute, Router} from '@angular/router'; +import {TranslateService} from '@ngx-translate/core'; +import {OgCommonService} from '../../../service/og-common.service'; +import {OgSweetAlertService} from '../../../service/og-sweet-alert.service'; +import {AuthModule} from 'globunet-angular/core'; +import {User} from '../../../model/user'; +import {ImageService} from '../../../api/image.service'; +import {OGCommandsService} from '../../../service/og-commands.service'; + +@Component({ + selector: 'app-deploy-image-command', + templateUrl: './deploy-image-command.component.html', + styleUrls: [ './deploy-image-command.component.scss' ] +}) +export class DeployImageCommandComponent implements OnInit { + torrent = { + mode: 'peer', + seedTime: '60' + }; + multicast = { + port: '9000', + address: '239.194.16.140', + mode: 'full-duplex', + speed: 90, + maxClients: 50, + maxWaitTime: 60 + }; + disk = 1; + partition = 1; + + images = []; + deployMethods = []; + deployMethod = 'MULTICAST'; + private deployImage: string; + private user: User; + private constants: any; + public image: any; + public editInstructions = false; + + + // this tells the tabs component which Pages + // should be each tab's root Page + constructor(public ogCommandsService: OGCommandsService, + private authModule: AuthModule, + private router: Router, + private activatedRoute: ActivatedRoute, + private ogCommonService: OgCommonService, + private imageService: ImageService, + private ogSweetAlert: OgSweetAlertService, + private toaster: ToasterService, + private translate: TranslateService) { + this.user = this.authModule.getLoggedUser(); + } + + + ngOnInit() { + this.deployImage = 'true'; + this.updateDeployOptions(); + if (this.user) { + // Comprobar la selección de clientes + if (this.ogCommonService.getSelectionSize() > 0) { + this.imageService.list().subscribe( + (response) => { + this.images = response; + }, + (error) => { + this.images = []; + + } + ); + + } else { + // TODO - dar error? + this.toaster.pop({type: 'error', body: this.translate.instant('not_clients_selected'), title: this.translate.instant('opengnsys_error')}); + this.router.navigate(['app.ous']); + } + } + } + + updateDeployOptions() { + this.ogCommonService.loadEngineConfig().subscribe( + data => { + this.constants = data.constants; + if (this.deployImage === 'true') { + this.deployMethods = this.constants.deployMethods.deployImage; + } else { + // Si es updateCache, se quitan las opciones de deploy direct + this.deployMethods = this.constants.deployMethods.updateCache; + } + } + ); + + } + + /**/ + generateOgInstruction() { + let script = ''; + const disk = this.disk; + const partition = this.partition; + // Capturar ip del repositorio de la imagen elegida + let ip = '172.16.140.210'; + let imgName = this.image.canonicalName; + let target = ' ' + disk + ' ' + partition; + let log = 'ogEcho log session "[0] $MSG_SCRIPTS_TASK_START '; + + // Modo deploy + if (this.deployImage === 'true') { + script = 'deployImage '; + } else { + script = 'updateCache '; + ip = 'REPO'; + imgName += '.img'; + target = ''; + } + script += ip + ' /' + imgName + target + ' ' + this.deployMethod; + log += script + '"\n'; + script = log + script; + + // Modo + let params = ''; + if (this.deployMethod === 'MULTICAST' || this.deployMethod === 'MULTICAST-DIRECT') { + params = this.multicast.port + ':' + this.multicast.mode + ':' + this.multicast.address + ':' + this.multicast.speed + 'M:' + this.multicast.maxClients + ':' + this.multicast.maxWaitTime; + } else if (this.deployMethod === 'TORRENT') { + params = this.torrent.mode + ':' + this.torrent.seedTime; + } + script += ' ' + params; + + this.ogCommandsService.ogInstructions = script; + } + + setCanonicalName() { + //this.command.canonicalName = this.command.image.canonicalName; + } +} diff --git a/admin/WebConsole3/frontend/src/app/pages/command/execute-command/execute-command.component.html b/admin/WebConsole3/frontend/src/app/pages/command/execute-command/execute-command.component.html new file mode 100644 index 00000000..37d7f8e2 --- /dev/null +++ b/admin/WebConsole3/frontend/src/app/pages/command/execute-command/execute-command.component.html @@ -0,0 +1,95 @@ +<section class="content-header"> + <h1 translate="new_command"> + </h1> + <ol class="breadcrumb"> + <li><a [routerLink]="'/app/dashboard'"><i class="fa fa-dashboard"></i> {{'dashboard'|translate}}</a></li> + <li><a [routerLink]="'/app/commands'"><i class="fa fa-terminal"></i> {{'commands'|translate}}</a></li> + <li class="active" translate="command"></li> + </ol> +</section> +<section style="padding: 0 30px;"> + <h3 translate="selected_clients"></h3> + <app-og-selected-clients></app-og-selected-clients> +</section> +<section fixed-toolboxbar class="toolboxbar"> + <div> + <div class="col-md-12"> + <app-og-execute-command-options></app-og-execute-command-options> + </div> + </div> +</section> +<!-- Main content --> +<section class="content"> + <div class="row"> + <div class="col-md-12"> + <div class="box box-primary"> + <div class="box-header with-border"> + <div class="form-inline"> + <div class="form-group" ng-class="{'has-error':Form.newCommand.$dirty && Form.newCommand.$invalid, 'has-success':Form.newCommand.$valid}"> + <div class="checkbox clip-check check-primary checkbox-inline"> + <input id="parameters" name="newCommand" icheck checkbox-class="iradio_square-blue" radio-class="iradio_square-blue" type="radio" class="selection-checkbox" value="true" [(ngModel)]="newCommand" /> + </div> + <label for="newCommand"> + <span translate="new_command"></span> + </label> + </div> + <div class="form-group" ng-class="{'has-error':Form.savedCommand.$dirty && Form.savedCommand.$invalid, 'has-success':Form.savedCommand.$valid}"> + <div class="checkbox clip-check check-primary checkbox-inline"> + <input id="parameters" name="savedCommand" icheck checkbox-class="iradio_square-blue" radio-class="iradio_square-blue" type="radio" class="selection-checkbox" value="false" [(ngModel)]="newCommand" /> + </div> + <label for="savedCommand"> + <span translate="saved_command"></span> + </label> + </div> + </div> + </div> + <div class="box-body"> + <form role="form" name="Form" *ngIf="newCommand == 'true'"> + <div class="form-group" ng-class="{'has-error':Form.script.$dirty && Form.script.$invalid, 'has-success':Form.script.$valid}"> + <label for="script"> + <span translate="script"></span> + <span *ngIf="required == 'true'" class="symbol required"></span> + </label> + <textarea class="form-control" class="og-instructions" type="text" required="true" [(ngModel)]="ogCommandsService.ogInstructions" name="script"></textarea> + </div> + </form> + <form role="form" name="Form" *ngIf="newCommand == 'false'"> + <div class="row"> + <div class="col-md-12"> + <div class="form-group"> + <label translate="commands"></label> + <select class="form-control" name="command" [(ngModel)]="selectedCommand" (change)="updateSelectedCommand()"> + <option *ngFor="let command of commands" [ngValue]="command">{{command.title}}</option> + </select> + </div> + <div class="form-group" *ngIf="selectedCommand.parameters == true"> + <label translate="parameters"></label> + <p class="help-block"><span translate="detected_params"></span> <span style="font-weight: bold" ng-bind-html="selectedCommand.inputs.length"></span></p> + <div class="row"> + <div class="col-md-2" *ngFor="let input of selectedCommand.inputs; let index = index"> + <label for="param{{index}}"> + <span translate="parameter"></span> {{index+1}} + </label> + <input type="text" name="param{{index}}" [value]="selectedCommand.inputs[index]" (change)="updateScript(index, $event)"> + </div> + </div> + </div> + </div> + </div> + <div class="row"> + <div class="col-md-12"> + <div class="box"> + <div class="box-header"></div> + <div class="box-body" > + <div *ngIf="editInstructions == false" [innerHTML]="ogCommandsService.ogInstructions|ogCommands"></div> + <textarea *ngIf="editInstructions == true" class="og-instructions" [(ngModel)]="ogCommandsService.ogInstructions"></textarea> + </div> + </div> + </div> + </div> + </form> + </div> + </div> + </div> + </div> +</section> diff --git a/admin/WebConsole3/frontend/src/app/pages/command/execute-command/execute-command.component.scss b/admin/WebConsole3/frontend/src/app/pages/command/execute-command/execute-command.component.scss new file mode 100644 index 00000000..08b1082b --- /dev/null +++ b/admin/WebConsole3/frontend/src/app/pages/command/execute-command/execute-command.component.scss @@ -0,0 +1,3 @@ +app-execute-command { + +} diff --git a/admin/WebConsole3/frontend/src/app/pages/command/execute-command/execute-command.component.ts b/admin/WebConsole3/frontend/src/app/pages/command/execute-command/execute-command.component.ts new file mode 100644 index 00000000..9560258a --- /dev/null +++ b/admin/WebConsole3/frontend/src/app/pages/command/execute-command/execute-command.component.ts @@ -0,0 +1,142 @@ +import {Component, OnInit} from '@angular/core'; + +import {ToasterService} from '../../../service/toaster.service'; +import {ActivatedRoute, Router} from '@angular/router'; +import {TranslateService} from '@ngx-translate/core'; +import {OgCommonService} from '../../../service/og-common.service'; +import {OgSweetAlertService} from '../../../service/og-sweet-alert.service'; +import {AuthModule} from 'globunet-angular/core'; +import {User} from '../../../model/user'; +import {OGCommandsService} from '../../../service/og-commands.service'; +import {CommandService} from '../../../api/command.service'; +import {CommandFormType} from '../../../form-type/command.form-type'; +import {Command} from '../../../model/command'; + +@Component({ + selector: 'app-execute-command', + templateUrl: './execute-command.component.html', + styleUrls: [ './execute-command.component.scss' ] +}) +export class ExecuteCommandComponent implements OnInit { + execution = {script: '', clients: ''}; + selectedCommand = { + inputs: [], + script: '' + }; + newCommand = 'true'; + private user: User; + private selectedClients = []; + private form = []; + private formType: CommandFormType; + public commands: Command[] = []; + editInstructions = false; + + + // this tells the tabs component which Pages + // should be each tab's root Page + constructor(public ogCommandsService: OGCommandsService, + private authModule: AuthModule, + private router: Router, + private activatedRoute: ActivatedRoute, + private ogCommonService: OgCommonService, + private commandService: CommandService, + private ogSweetAlert: OgSweetAlertService, + private toaster: ToasterService, + private translate: TranslateService) { + this.user = this.authModule.getLoggedUser(); + } + + + + + + + ngOnInit(): void { + this.selectedClients = this.ogCommonService.selectedClients; + if (this.user && this.selectedClients) { + this.loadFormOptions(); + this.loadCommands(); + } else { + // TODO - dar error? + this.ogSweetAlert.error(this.translate.instant('opengnsys_error'), this.translate.instant('not_clients_selected')); + this.router.navigate(['/app/ous']); + } + } + + sendCommand() { + let result = true; + + if (!this.execution.script) { + result = false; + this.toaster.pop({type: 'error', title: 'error', body: this.translate.instant('command_not_valid')}); + } else if (!this.execution.clients) { + result = false; + this.toaster.pop({type: 'error', title: 'error', body: this.translate.instant('not_clients_selected')}); + } + // Si no hubo ningun error + if (result === true) { + this.execution.script = this.execution.script.replace(/\"/g, '\\"').replace(/\$/g, '\\\$'); + // Resetar las instrucciones del script opengnsys almacenadas. + this.ogCommandsService.ogInstructions = ''; + this.commandService.execute(this.execution).subscribe( + (response) => { + this.toaster.pop({type: 'success', title: 'success', body: 'Successfully saved'}); + this.router.navigate(['/app/ous']); + }, + function(error) { + this.toaster.pop({type: 'error', title: 'error', body: error}); + } + ); + } + } + + loadFormOptions() { + this.formType = new CommandFormType(); + this.form = this.formType.getForm(); + } + + loadCommands() { + this.commandService.list().subscribe( + (result) => { + this.commands = result; + } + ); + } + + + executeSelectedCommand() { + // Ejecuta el contenido de ogInstructions + this.ogCommandsService.execute('RUN_SCRIPT'); + } + + updateSelectedCommand() { + this.getParamsNumber(this.selectedCommand); + this.ogCommandsService.ogInstructions = this.selectedCommand.script; + } + + + updateScript(i, value) { + this.selectedCommand.inputs[i] = value.target.value; + let script = this.selectedCommand.script; + for (let index = 0; index < this.selectedCommand.inputs.length; index++) { + script = script.replace('@' + (index + 1), this.selectedCommand.inputs[index]); + } + this.ogCommandsService.ogInstructions = script; + + } + + getParamsNumber(command) { + const params = []; + if (command.parameters === true) { + const allparams = command.script.match(/@[1-9]+/g)||[]; + for (let index = 0; index < allparams.length; index++) { + if (params.indexOf(allparams[index]) === -1) { + params.push(allparams[index]); + } + } + this.selectedCommand.inputs = params; + } + return params.length; + } + +} diff --git a/admin/WebConsole3/frontend/src/app/pages/command/login-command/login-command.component.html b/admin/WebConsole3/frontend/src/app/pages/command/login-command/login-command.component.html new file mode 100644 index 00000000..e8bcdbc5 --- /dev/null +++ b/admin/WebConsole3/frontend/src/app/pages/command/login-command/login-command.component.html @@ -0,0 +1,81 @@ +<section class="content-header"> + <h1 translate="login_command"> + </h1> + <ol class="breadcrumb"> + <li><a [routerLink]="'/app/dashboard'"><i class="fa fa-dashboard"></i>{{'dashboard'|translate}}</a></li> + <li><a [routerLink]="'/app/ous'"><i class="fa fa-th"></i>{{'ous'|translate}}</a></li> + <li class="active" translate="login_command"></li> + </ol> +</section> +<section fixed-toolboxbar class="toolboxbar"> + <div> + <div class="col-md-12"> + <div class="box-tools pull-right"> + <button class="btn btn-primary" translate="execute" (click)="sendCommand()"></button> + </div> + </div> + </div> +</section> +<section style="padding: 0 30px;"> + <h3 translate="selected_clients"></h3> + <app-og-selected-clients></app-og-selected-clients> +</section> +<!-- Main content --> +<section class="content"> + <div class="row"> + <div class="col-md-12"> + <div class="box box-primary"> + <div class="box-header with-border"> + </div> + <div class="box-body"> + <form role="form" name="vm.Form"> + <div *ngFor="let client of selectedClients"> + <table class="table" *ngIf="client && client.id" > + <thead> + <tr> + <th colspan="5"> + {{client.name}} + </th> + </tr> + <tr> + <th translate="select"> + </th> + <th translate="disk"> + </th> + <th translate="partition"> + </th> + <th translate="filesystem"> + </th> + <th translate="osname"> + </th> + </tr> + </thead> + <tbody> + <ng-container *ngFor="let partition of client.partitions"> + <tr *ngIf="canLogin(partition)"> + <td> + <input icheck type="radio" name="partition" checkbox-class="icheckbox_square-blue" radio-class="iradio_square-blue" class="selection-checkbox" [(ngModel)]="selectedPartition" [value]="partition" /> + </td> + <td> + {{partition.numDisk}} + </td> + <td> + {{partition.numPartition}} + </td> + <td> + {{partition.filesystem}} + </td> + <td> + {{partition.osName}} + </td> + </tr> + </ng-container> + </tbody> + </table> + </div> + </form> + </div> + </div> + </div> + </div> +</section> diff --git a/admin/WebConsole3/frontend/src/app/pages/command/login-command/login-command.component.scss b/admin/WebConsole3/frontend/src/app/pages/command/login-command/login-command.component.scss new file mode 100644 index 00000000..ccb34440 --- /dev/null +++ b/admin/WebConsole3/frontend/src/app/pages/command/login-command/login-command.component.scss @@ -0,0 +1,3 @@ +command { + +} diff --git a/admin/WebConsole3/frontend/src/app/pages/command/login-command/login-command.component.ts b/admin/WebConsole3/frontend/src/app/pages/command/login-command/login-command.component.ts new file mode 100644 index 00000000..af234984 --- /dev/null +++ b/admin/WebConsole3/frontend/src/app/pages/command/login-command/login-command.component.ts @@ -0,0 +1,80 @@ +import {Component, OnInit} from '@angular/core'; + +import {ToasterService} from '../../../service/toaster.service'; +import {ActivatedRoute, Router} from '@angular/router'; +import {TranslateService} from '@ngx-translate/core'; +import {OgCommonService} from '../../../service/og-common.service'; +import {OgSweetAlertService} from '../../../service/og-sweet-alert.service'; +import {AuthModule} from 'globunet-angular/core'; +import {User} from '../../../model/user'; +import {ImageService} from '../../../api/image.service'; +import {OGCommandsService} from '../../../service/og-commands.service'; +import {Client} from '../../../model/client'; +import {CommandService} from '../../../api/command.service'; + +@Component({ + selector: 'app-login-command', + templateUrl: './login-command.component.html', + styleUrls: [ './login-command.component.scss' ] +}) +export class LoginCommandComponent implements OnInit { + execution = {clients: '', script: '', type: ''}; + command = {}; + user: User; + selectedClients: Client[]; + selectedPartition: any; + client: Client; + + // this tells the tabs component which Pages + // should be each tab's root Page + constructor(public ogCommandsService: OGCommandsService, + private authModule: AuthModule, + private router: Router, + private activatedRoute: ActivatedRoute, + private ogCommonService: OgCommonService, + private commandService: CommandService, + private ogSweetAlert: OgSweetAlertService, + private toaster: ToasterService, + private translate: TranslateService) { + this.user = this.authModule.getLoggedUser(); + } + + + + ngOnInit() { + this.selectedClients = this.ogCommonService.selectedClients; + if (this.user && this.selectedClients) { + this.execution.clients = Object.keys(this.selectedClients).join(','); + } + } + + + sendCommand() { + if (!this.selectedPartition) { + this.toaster.pop({type: 'error', title: 'error', body: this.translate.instant('you_must_select_partition')}); + } else { + const disk = this.selectedPartition.numDisk; + const partition = this.selectedPartition.numPartition; + + this.execution.script = 'bootOs ' + disk + ' ' + partition + ' &'; + this.execution.script = this.execution.script.replace(/\"/g, '\\"').replace(/\$/g, '\\\$'); + this.execution.type = 'RUN_SCRIPT'; + + this.commandService.execute(this.execution).subscribe( + (response) => { + this.toaster.pop({type: 'success', title: 'success', body: this.translate.instant('successfully_executed')}); + this.router.navigate(['app.ous']); + }, + (error) => { + this.toaster.pop({type: 'error', title: 'error', body: error}); + } + ); + } + } + + + canLogin(partition) { + return partition.osName !== '' && partition.osName !== 'DATA'; + } + +} diff --git a/admin/WebConsole3/frontend/src/app/pages/common/og-options/og-commands-options/og-commands-options.component.html b/admin/WebConsole3/frontend/src/app/pages/common/og-options/og-commands-options/og-commands-options.component.html index 7f114997..c008d3a1 100644 --- a/admin/WebConsole3/frontend/src/app/pages/common/og-options/og-commands-options/og-commands-options.component.html +++ b/admin/WebConsole3/frontend/src/app/pages/common/og-options/og-commands-options/og-commands-options.component.html @@ -6,14 +6,14 @@ <li role="presentation" class="{{ogCommonService.getSelectionSize() < 1?'disable-links':''}}"><a role="menuitem" tabindex="-1" href="javascript:void(0)"(click)="ogCommandsService.execute('POWER_OFF')" translate="power_off"></a></li> <li role="presentation" class="{{ogCommonService.getSelectionSize() < 1?'disable-links':''}}"><a role="menuitem" tabindex="-1" href="javascript:void(0)"(click)="ogCommandsService.execute('POWER_ON')" translate="power_on"></a></li> <li role="presentation" class="{{ogCommonService.getSelectionSize() < 1?'disable-links':''}}"><a role="menuitem" tabindex="-1" href="javascript:void(0)"(click)="ogCommandsService.execute('REBOOT')" translate="reboot"></a></li> - <li role="presentation" class="{{ogCommonService.getSelectionSize() < 1?'disable-links':''}}"><a role="menuitem" tabindex="-1" [routerLink]="'app/commands/login'" translate="login_command"></a></li> + <li role="presentation" class="{{ogCommonService.getSelectionSize() < 1?'disable-links':''}}"><a role="menuitem" tabindex="-1" [routerLink]="'/app/commands/login'" translate="login_command"></a></li> <li role="presentation" class="divider"></li> - <li role="presentation" class="{{ogCommonService.getSelectionSize() < 1?'disable-links':''}}"><a role="menuitem" tabindex="-1" [routerLink]="'app/commands/execute'" translate="execute_command"></a></li> - <li role="presentation" class="{{ogCommonService.getSelectionSize() != 1?'disable-links':''}}"><a role="menuitem" tabindex="-1" [routerLink]="'app/commands/create_image'" translate="create_image"></a></li> - <li role="presentation" class="{{ogCommonService.getSelectionSize() < 1?'disable-links':''}}"><a role="menuitem" tabindex="-1" href="javascript:void(0)" [routerLink]="'app/commands/deploy_image'" translate="deploy_image"></a></li> - <li role="presentation" class="{{ogCommonService.getSelectionSize() < 1?'disable-links':''}}"><a role="menuitem" tabindex="-1" href="javascript:void(0)" [routerLink]="'app/commands/delete_cache_image'" translate="delete_cache_image"></a></li> - <li role="presentation" class="{{ogCommonService.getSelectionSize() < 1?'disable-links':''}}"><a role="menuitem" tabindex="-1" [routerLink]="'app/commands/partition_format'" translate="partition_format"></a></li> - <li role="presentation" class="{{ogCommonService.getSelectionSize() < 1?'disable-links':''}}"><a role="menuitem" tabindex="-1" [routerLink]="'app/commands/format'" translate="format"></a></li> + <li role="presentation" class="{{ogCommonService.getSelectionSize() < 1?'disable-links':''}}"><a role="menuitem" tabindex="-1" [routerLink]="'/app/commands/execute'" translate="execute_command"></a></li> + <li role="presentation" class="{{ogCommonService.getSelectionSize() != 1?'disable-links':''}}"><a role="menuitem" tabindex="-1" [routerLink]="'/app/commands/create_image'" translate="create_image"></a></li> + <li role="presentation" class="{{ogCommonService.getSelectionSize() < 1?'disable-links':''}}"><a role="menuitem" tabindex="-1" href="javascript:void(0)" [routerLink]="'/app/commands/deploy_image'" translate="deploy_image"></a></li> + <li role="presentation" class="{{ogCommonService.getSelectionSize() < 1?'disable-links':''}}"><a role="menuitem" tabindex="-1" href="javascript:void(0)" [routerLink]="'/app/commands/delete_cache_image'" translate="delete_cache_image"></a></li> + <li role="presentation" class="{{ogCommonService.getSelectionSize() < 1?'disable-links':''}}"><a role="menuitem" tabindex="-1" [routerLink]="'/app/commands/partition_format'" translate="partition_format"></a></li> + <li role="presentation" class="{{ogCommonService.getSelectionSize() < 1?'disable-links':''}}"><a role="menuitem" tabindex="-1" [routerLink]="'/app/commands/format'" translate="format"></a></li> <li role="presentation" class="divider"></li> <li role="presentation" class="{{ogCommonService.getSelectionSize() != 1?'disable-links':''}}"><a role="menuitem" tabindex="-1" href="javascript:void(0)"(click)="ogCommandsService.execute('SOFTWARE_INVENTORY')" translate="software_inventary"></a></li> <li role="presentation" class="{{ogCommonService.getSelectionSize() != 1?'disable-links':''}}"><a role="menuitem" tabindex="-1" href="javascript:void(0)"(click)="ogCommandsService.execute('HARDWARE_INVENTORY')" translate="hardware_inventary"></a></li> diff --git a/admin/WebConsole3/frontend/src/app/pages/common/og-options/og-execute-command-options/og-execute-command-options.component.html b/admin/WebConsole3/frontend/src/app/pages/common/og-options/og-execute-command-options/og-execute-command-options.component.html index efaabd65..2bc015f9 100644 --- a/admin/WebConsole3/frontend/src/app/pages/common/og-options/og-execute-command-options/og-execute-command-options.component.html +++ b/admin/WebConsole3/frontend/src/app/pages/common/og-options/og-execute-command-options/og-execute-command-options.component.html @@ -1,3 +1,8 @@ -<p> - og-execute-command-options works! -</p> +<div class="btn-group"> + <button class="btn btn-default"(click)="ogCommandsService.execute('RUN_SCRIPT',{script: ogCommandsService.ogInstructions})"> + <span translate="execute"></span> + </button> + <button class="btn btn-primary"(click)="ogCommandsService.execute('RUN_SCRIPT',{script: ogCommandsService.ogInstructions, save: true})"> + <span translate="save"></span> + </button> +</div> diff --git a/admin/WebConsole3/frontend/src/app/pages/common/og-options/og-execute-command-options/og-execute-command-options.component.ts b/admin/WebConsole3/frontend/src/app/pages/common/og-options/og-execute-command-options/og-execute-command-options.component.ts index 55da5e36..86ccbf53 100644 --- a/admin/WebConsole3/frontend/src/app/pages/common/og-options/og-execute-command-options/og-execute-command-options.component.ts +++ b/admin/WebConsole3/frontend/src/app/pages/common/og-options/og-execute-command-options/og-execute-command-options.component.ts @@ -1,4 +1,5 @@ import { Component, OnInit } from '@angular/core'; +import {OGCommandsService} from '../../../../service/og-commands.service'; @Component({ selector: 'app-og-execute-command-options', @@ -7,7 +8,7 @@ import { Component, OnInit } from '@angular/core'; }) export class OgExecuteCommandOptionsComponent implements OnInit { - constructor() { } + constructor(public ogCommandsService: OGCommandsService) { } ngOnInit() { } diff --git a/admin/WebConsole3/frontend/src/app/pages/common/og-options/og-selected-clients/og-selected-clients.component.html b/admin/WebConsole3/frontend/src/app/pages/common/og-options/og-selected-clients/og-selected-clients.component.html index e87b931a..ebb52d60 100644 --- a/admin/WebConsole3/frontend/src/app/pages/common/og-options/og-selected-clients/og-selected-clients.component.html +++ b/admin/WebConsole3/frontend/src/app/pages/common/og-options/og-selected-clients/og-selected-clients.component.html @@ -1,3 +1,21 @@ -<p> - og-selected-clients works! -</p> +<div class="row"> + <div *ngFor="let client of selectedClients" class="col-md-2 col-xs-6 padding-5"> + <div class="info-box client" *ngIf="client && client.id"> + <span style="position: absolute;"> + <input icheck checkbox-class="icheckbox_square-blue" radio-class="iradio_square-blue" type="checkbox" + class="selection-checkbox" [(ngModel)]="client.selected" + (change)="ogCommonService.selectClient(client, client.parent)"/> + </span> + <span class="info-box-icon"> + <i class="fa fa-desktop"> + </i> + </span> + <div class="info-box-content"> + <span class="info-box-text">{{client.name}}</span> + <span class="info-box-text">{{client.ip}}</span> + <span class="info-box-text">{{client.mac}}</span> + </div> + <!-- /.info-box-content --> + </div> + </div> +</div> diff --git a/admin/WebConsole3/frontend/src/app/pages/common/og-options/og-selected-clients/og-selected-clients.component.ts b/admin/WebConsole3/frontend/src/app/pages/common/og-options/og-selected-clients/og-selected-clients.component.ts index 9c6f1c4e..a6c7a606 100644 --- a/admin/WebConsole3/frontend/src/app/pages/common/og-options/og-selected-clients/og-selected-clients.component.ts +++ b/admin/WebConsole3/frontend/src/app/pages/common/og-options/og-selected-clients/og-selected-clients.component.ts @@ -1,4 +1,6 @@ import { Component, OnInit } from '@angular/core'; +import {OgCommonService} from '../../../../service/og-common.service'; +import {Client} from '../../../../model/client'; @Component({ selector: 'app-og-selected-clients', @@ -6,10 +8,17 @@ import { Component, OnInit } from '@angular/core'; styleUrls: ['./og-selected-clients.component.css'] }) export class OgSelectedClientsComponent implements OnInit { + public selectedClients: Client[]; - constructor() { } + constructor(public ogCommonService: OgCommonService) { + this.selectedClients = []; + } ngOnInit() { + this.selectedClients = this.ogCommonService.selectedClients; } + getClientInfo(c: Client) { + console.log(c); + } } diff --git a/admin/WebConsole3/frontend/src/app/pages/hardware/hardware-profiles/profiles-group/profiles-group.component.html b/admin/WebConsole3/frontend/src/app/pages/hardware/hardware-profiles/profiles-group/hardware-profiles-group.component.html index 365ceebe..d7a73e89 100644 --- a/admin/WebConsole3/frontend/src/app/pages/hardware/hardware-profiles/profiles-group/profiles-group.component.html +++ b/admin/WebConsole3/frontend/src/app/pages/hardware/hardware-profiles/profiles-group/hardware-profiles-group.component.html @@ -1,47 +1,47 @@ -<mk-box boxColor="warning" headerBorder="true" isCollapsable="true" [isRemovable]="false">
- <mk-box-header class="box-header with-border">
- <i class="fa fa-folder-open-o"></i>
- <h3 class="box-title">
- <div class="btn-group" *ngIf="!content.editing">
- <div mk-dropdown class="btn-group" [isWrapper]="false" >
- <mk-dropdown-toggle>
- <button #toggleElement type="button" class="btn btn-default dropdown-toggle">
- {{content.name}}
- <span class="fa fa-caret-down"></span>
- </button>
- </mk-dropdown-toggle>
- <mk-dropdown-menu>
- <li >
- <a role="menuitem" tabindex="-1" href="#" translate="add_group"></a>
- </li>
- <li >
- <a role="menuitem" tabindex="-1" href="#" translate="add_profile" [routerLink]="'/app/hardware/profile/create/' + content.id "></a>
- </li>
- <li class="divider"></li>
- <li>
- <a class="" href="javascript:void(0)" translate="edit" (click)="content.$$tmpName = content.name; content.editing = true"></a>
- </li>
- <li role="presentation" class="divider"></li>
- <li role="presentation" class="delete-option">
- <a class="" href="javascript:void(0)" translate="delete" (click)="deleteGroup(content.id)"></a>
- </li>
- </mk-dropdown-menu>
- </div>
- </div>
- <div *ngIf="content.editing" class="col-xs-6">
- <input type="text" class="form-control" [(ngModel)]="content.$$tmpName">
- <span class="input-group-btn">
- <button type="button" class="btn btn-default btn-flat" translate="done" (click)="changeGroupName(content)"></button>
- <button type="button" class="btn btn-info btn-flat" translate="cancel" (click)="content.editing = false"></button>
- </span>
- </div>
- </h3>
- <!-- /.box-tools -->
- </mk-box-header>
- <!-- /.box-header -->
- <mk-box-content class="box-body folders" style="display: block;">
- <app-profiles-group *ngFor="let content of content.groups" [content]="content">
- </app-profiles-group>
- <app-profiles-table *ngIf="content.profiles" [profiles]="content.profiles"></app-profiles-table>
- </mk-box-content>
-</mk-box>
+<mk-box boxColor="warning" headerBorder="true" isCollapsable="true" [isRemovable]="false"> + <mk-box-header class="box-header with-border"> + <i class="fa fa-folder-open-o"></i> + <h3 class="box-title"> + <div class="btn-group" *ngIf="!content.editing"> + <div mk-dropdown class="btn-group" [isWrapper]="false" > + <mk-dropdown-toggle> + <button #toggleElement type="button" class="btn btn-default dropdown-toggle"> + {{content.name}} + <span class="fa fa-caret-down"></span> + </button> + </mk-dropdown-toggle> + <mk-dropdown-menu> + <li > + <a role="menuitem" tabindex="-1" href="#" translate="add_group"></a> + </li> + <li > + <a role="menuitem" tabindex="-1" href="#" translate="add_profile" [routerLink]="'/app/hardware/profile/create/' + content.id "></a> + </li> + <li class="divider"></li> + <li> + <a class="" href="javascript:void(0)" translate="edit" (click)="content.$$tmpName = content.name; content.editing = true"></a> + </li> + <li role="presentation" class="divider"></li> + <li role="presentation" class="delete-option"> + <a class="" href="javascript:void(0)" translate="delete" (click)="deleteGroup(content.id)"></a> + </li> + </mk-dropdown-menu> + </div> + </div> + <div *ngIf="content.editing" class="col-xs-6"> + <input type="text" class="form-control" [(ngModel)]="content.$$tmpName"> + <span class="input-group-btn"> + <button type="button" class="btn btn-default btn-flat" translate="done" (click)="changeGroupName(content)"></button> + <button type="button" class="btn btn-info btn-flat" translate="cancel" (click)="content.editing = false"></button> + </span> + </div> + </h3> + <!-- /.box-tools --> + </mk-box-header> + <!-- /.box-header --> + <mk-box-content class="box-body folders" style="display: block;"> + <app-profiles-group *ngFor="let content of content.groups" [content]="content"> + </app-profiles-group> + <app-profiles-table *ngIf="content.profiles" [profiles]="content.profiles"></app-profiles-table> + </mk-box-content> +</mk-box> diff --git a/admin/WebConsole3/frontend/src/app/pages/hardware/hardware-profiles/profiles-group/profiles-group.component.ts b/admin/WebConsole3/frontend/src/app/pages/hardware/hardware-profiles/profiles-group/hardware-profiles-group.component.ts index f9dbd868..884bb680 100644 --- a/admin/WebConsole3/frontend/src/app/pages/hardware/hardware-profiles/profiles-group/profiles-group.component.ts +++ b/admin/WebConsole3/frontend/src/app/pages/hardware/hardware-profiles/profiles-group/hardware-profiles-group.component.ts @@ -1,14 +1,14 @@ -import {ComponentMetadata} from 'codelyzer/angular/metadata';
-import {Component, Input} from '@angular/core';
-
-@Component({
- selector: 'app-profiles-group',
- templateUrl: 'profiles-group.component.html'
-})
-export class ProfilesGroupComponent {
- @Input() content;
-
- constructor() {
- console.log(this.content);
- }
-}
+import {ComponentMetadata} from 'codelyzer/angular/metadata'; +import {Component, Input} from '@angular/core'; + +@Component({ + selector: 'app-profiles-group', + templateUrl: 'hardware-profiles-group.component.html' +}) +export class HardwareProfilesGroupComponent { + @Input() content; + + constructor() { + console.log(this.content); + } +} diff --git a/admin/WebConsole3/frontend/src/app/pages/hardware/hardware-profiles/profiles-table/profiles-table.component.html b/admin/WebConsole3/frontend/src/app/pages/hardware/hardware-profiles/profiles-table/hardware-profiles-table.component.html index 45f17240..70bd2fd1 100644 --- a/admin/WebConsole3/frontend/src/app/pages/hardware/hardware-profiles/profiles-table/profiles-table.component.html +++ b/admin/WebConsole3/frontend/src/app/pages/hardware/hardware-profiles/profiles-table/hardware-profiles-table.component.html @@ -1,61 +1,61 @@ -<table class="table table-hover">
- <tbody>
- <tr>
- <th translate="description"></th>
- <th translate="windowsboot"></th>
- <th translate="options"></th>
- </tr>
- <tr *ngFor="let profile of profiles; let index = index" class="{{(index%2 == 0)?'odd':'even'}}">
- <td>
- <span *ngIf="profile.$$editing">
- <input type="text" class="form-control" [(ngModel)]="profile.$$tmpDescription">
- </span>
- <span *ngIf="!profile.$$editing">
- {{profile.description}}
- </span>
- </td>
- <td>
- <span *ngIf="profile.$$editing">
- <select class="form-control"[(ngModel)]="profile.$$tmpWindowsboot">
- <option [value]="item" *ngFor="let item of windowsboots"> {{item}}</option>
- </select>
- </span>
- <span *ngIf="!profile.$$editing">
- {{profile.windowsboot}}
- </span>
- </td>
- <td class="right">
- <ng-container *ngIf="profile.$$editing">
- <div class="btn-group ">
- <button class="btn btn-primary " translate="ok" (click)="saveHardwareProfile(profile)"></button>
- <button class="btn btn-default " translate="cancel" (click)="profile.$$editing = false"></button>
- </div>
- </ng-container>
- <ng-container *ngIf="!profile.$$editing">
- <app-table-action [rowData]="profile" [options]="tableOptions" (edit)="editHardwareProfile($event)" (delete)="deleteHardwareProfile($event)"></app-table-action>
-<!--
- <div class="btn-group visible-md visible-lg hidden-sm hidden-xs">
- <button class="btn btn-default" translate="edit" (click)="editHardwareProfile(profile)"></button>
- <button class="btn btn-default" href="javascript:void(0)" translate="config" (click)="goToEditProfile(profile)"></button>
- <button class="btn btn-danger " translate="delete" (click)="deleteHardwareProfile(profile)"></button>
- </div>
- <div class="btn-group hidden-md hidden-lg">
- <button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown">
- <i class="fa fa-gear"></i>
- <span class="caret"></span>
- <span class="sr-only">Toggle Dropdown</span>
- </button>
- <ul class="dropdown-menu" role="menu">
- <li class="btn-group-vertical">
- <button class="btn btn-default" translate="edit" (click)="editHardwareProfile(profile)"></button>
- <button class="btn btn-default" href="javascript:void(0)" translate="config" ui-sref="goToEditProfile(profile)"></button>
- <button class="btn btn-danger" href="javascript:void(0)" translate="delete" (click)="deleteHardwareProfile(profile)"></button>
- </li>
- </ul>
- </div>
--->
- </ng-container>
- </td>
- </tr>
- </tbody>
- </table>
+<table class="table table-hover"> + <tbody> + <tr> + <th translate="description"></th> + <th translate="windowsboot"></th> + <th translate="options"></th> + </tr> + <tr *ngFor="let profile of profiles; let index = index" class="{{(index%2 == 0)?'odd':'even'}}"> + <td> + <span *ngIf="profile.$$editing"> + <input type="text" class="form-control" [(ngModel)]="profile.$$tmpDescription"> + </span> + <span *ngIf="!profile.$$editing"> + {{profile.description}} + </span> + </td> + <td> + <span *ngIf="profile.$$editing"> + <select class="form-control"[(ngModel)]="profile.$$tmpWindowsboot"> + <option [value]="item" *ngFor="let item of windowsboots"> {{item}}</option> + </select> + </span> + <span *ngIf="!profile.$$editing"> + {{profile.windowsboot}} + </span> + </td> + <td class="right"> + <ng-container *ngIf="profile.$$editing"> + <div class="btn-group "> + <button class="btn btn-primary " translate="ok" (click)="saveHardwareProfile(profile)"></button> + <button class="btn btn-default " translate="cancel" (click)="profile.$$editing = false"></button> + </div> + </ng-container> + <ng-container *ngIf="!profile.$$editing"> + <app-table-action [rowData]="profile" [options]="tableOptions" (edit)="editHardwareProfile($event)" (delete)="deleteHardwareProfile($event)"></app-table-action> +<!-- + <div class="btn-group visible-md visible-lg hidden-sm hidden-xs"> + <button class="btn btn-default" translate="edit" (click)="editHardwareProfile(profile)"></button> + <button class="btn btn-default" href="javascript:void(0)" translate="config" (click)="goToEditProfile(profile)"></button> + <button class="btn btn-danger " translate="delete" (click)="deleteHardwareProfile(profile)"></button> + </div> + <div class="btn-group hidden-md hidden-lg"> + <button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown"> + <i class="fa fa-gear"></i> + <span class="caret"></span> + <span class="sr-only">Toggle Dropdown</span> + </button> + <ul class="dropdown-menu" role="menu"> + <li class="btn-group-vertical"> + <button class="btn btn-default" translate="edit" (click)="editHardwareProfile(profile)"></button> + <button class="btn btn-default" href="javascript:void(0)" translate="config" ui-sref="goToEditProfile(profile)"></button> + <button class="btn btn-danger" href="javascript:void(0)" translate="delete" (click)="deleteHardwareProfile(profile)"></button> + </li> + </ul> + </div> +--> + </ng-container> + </td> + </tr> + </tbody> + </table> diff --git a/admin/WebConsole3/frontend/src/app/pages/hardware/hardware-profiles/profiles-table/profiles-table.component.ts b/admin/WebConsole3/frontend/src/app/pages/hardware/hardware-profiles/profiles-table/hardware-profiles-table.component.ts index c1a155ff..76db2008 100644 --- a/admin/WebConsole3/frontend/src/app/pages/hardware/hardware-profiles/profiles-table/profiles-table.component.ts +++ b/admin/WebConsole3/frontend/src/app/pages/hardware/hardware-profiles/profiles-table/hardware-profiles-table.component.ts @@ -1,101 +1,101 @@ -import {Component, EventEmitter, Input, OnInit, Output} from '@angular/core';
-import {HardwareProfile} from '../../../../model/hardware-profile';
-import {HardwareProfileService} from '../../../../api/hardware-profile.service';
-import {ToasterService} from '../../../../service/toaster.service';
-import {TranslateService} from '@ngx-translate/core';
-import {OgSweetAlertService} from '../../../../service/og-sweet-alert.service';
-import {Router} from '@angular/router';
-import {environment} from '../../../../../environments/environment';
-import {PartitionInfo} from '../../../../model/image';
-import {Ng2TableActionComponent} from '../../../common/table-action/ng2-table-action.component';
-
-@Component({
- selector: 'app-profiles-table',
- templateUrl: 'profiles-table.component.html'
-})
-export class ProfilesTableComponent implements OnInit {
- @Input() profiles;
- windowsboots: any;
- tableOptions: any;
-
- public constructor(private router: Router, private hardwareProfileService: HardwareProfileService, private ogSweetAlert: OgSweetAlertService, private toaster: ToasterService, private translate: TranslateService) {
-
- }
- ngOnInit(): void {
- this.windowsboots = environment.windowsboots;
- this.tableOptions = {
- override: false,
- buttons: [
- {
- action: 'edit'
- },
- {
- label: 'configure',
- handler: (profile) => this.goToEditProfile(profile),
- classes: 'btn-default'
- },
- {
- action: 'delete'
- }
- ]
- };
- }
-
- editHardwareProfile(hardwareProfile) {
- hardwareProfile.$$editing = true;
- hardwareProfile.$$tmpName = hardwareProfile.name;
- hardwareProfile.$$tmpDescription = hardwareProfile.description;
- hardwareProfile.$$tmpWindowsboot = hardwareProfile.windowsboot;
- }
-
- saveHardwareProfile(hardwareProfile) {
- hardwareProfile.$$editing = false;
- hardwareProfile.name = hardwareProfile.$$tmpName;
- hardwareProfile.description = hardwareProfile.$$tmpDescription;
- hardwareProfile.windowsboot = hardwareProfile.$$tmpWindowsboot;
- const hpCopy = Object.assign({}, hardwareProfile);
- // TODO - Llamar al servidor para guardar el cambio
- this.hardwareProfileService.update(hpCopy).subscribe(
- (response) => {
- this.toaster.pop({type: 'success', title: 'success', body: this.translate.instant('successfully_saved')});
- },
- (error) => {
- this.toaster.pop({type: 'error', title: 'error', body: error});
- }
- );
- }
-
- deleteHardwareProfile(hardwareProfile) {
- const self = this;
-
- this.ogSweetAlert.question(this.translate.instant('sure_to_delete') + '?', this.translate.instant('action_cannot_be_undone'),
- function(result) {
- if (result.value === true) {
- self.hardwareProfileService.delete(hardwareProfile.id).subscribe(
- (response) => {
- self.toaster.pop({type: 'success', title: self.translate.instant('success'), body: self.translate.instant('successfully_deleted')});
- const index = self.profiles.indexOf(hardwareProfile);
- if (index !== -1) {
- self.profiles.splice(index, 1);
- }
- },
- (error) => {
- self.toaster.pop({type: 'error', title: self.translate.instant('error'), body: error});
- }
- );
- }
- }
- );
- }
-
- goToEditProfile(profile: HardwareProfile) {
- this.router.navigate(['/app/hardware/profile', profile.id]).then(
- success => {
- console.log(success);
- },
- error => {
- console.log(error);
- }
- );
- }
-}
+import {Component, EventEmitter, Input, OnInit, Output} from '@angular/core'; +import {HardwareProfile} from '../../../../model/hardware-profile'; +import {HardwareProfileService} from '../../../../api/hardware-profile.service'; +import {ToasterService} from '../../../../service/toaster.service'; +import {TranslateService} from '@ngx-translate/core'; +import {OgSweetAlertService} from '../../../../service/og-sweet-alert.service'; +import {Router} from '@angular/router'; +import {environment} from '../../../../../environments/environment'; +import {PartitionInfo} from '../../../../model/image'; +import {Ng2TableActionComponent} from '../../../common/table-action/ng2-table-action.component'; + +@Component({ + selector: 'app-profiles-table', + templateUrl: 'hardware-profiles-table.component.html' +}) +export class HardwareProfilesTableComponent implements OnInit { + @Input() profiles; + windowsboots: any; + tableOptions: any; + + public constructor(private router: Router, private hardwareProfileService: HardwareProfileService, private ogSweetAlert: OgSweetAlertService, private toaster: ToasterService, private translate: TranslateService) { + + } + ngOnInit(): void { + this.windowsboots = environment.windowsboots; + this.tableOptions = { + override: false, + buttons: [ + { + action: 'edit' + }, + { + label: 'configure', + handler: (profile) => this.goToEditProfile(profile), + classes: 'btn-default' + }, + { + action: 'delete' + } + ] + }; + } + + editHardwareProfile(hardwareProfile) { + hardwareProfile.$$editing = true; + hardwareProfile.$$tmpName = hardwareProfile.name; + hardwareProfile.$$tmpDescription = hardwareProfile.description; + hardwareProfile.$$tmpWindowsboot = hardwareProfile.windowsboot; + } + + saveHardwareProfile(hardwareProfile) { + hardwareProfile.$$editing = false; + hardwareProfile.name = hardwareProfile.$$tmpName; + hardwareProfile.description = hardwareProfile.$$tmpDescription; + hardwareProfile.windowsboot = hardwareProfile.$$tmpWindowsboot; + const hpCopy = Object.assign({}, hardwareProfile); + // TODO - Llamar al servidor para guardar el cambio + this.hardwareProfileService.update(hpCopy).subscribe( + (response) => { + this.toaster.pop({type: 'success', title: 'success', body: this.translate.instant('successfully_saved')}); + }, + (error) => { + this.toaster.pop({type: 'error', title: 'error', body: error}); + } + ); + } + + deleteHardwareProfile(hardwareProfile) { + const self = this; + + this.ogSweetAlert.question(this.translate.instant('sure_to_delete') + '?', this.translate.instant('action_cannot_be_undone'), + function(result) { + if (result.value === true) { + self.hardwareProfileService.delete(hardwareProfile.id).subscribe( + (response) => { + self.toaster.pop({type: 'success', title: self.translate.instant('success'), body: self.translate.instant('successfully_deleted')}); + const index = self.profiles.indexOf(hardwareProfile); + if (index !== -1) { + self.profiles.splice(index, 1); + } + }, + (error) => { + self.toaster.pop({type: 'error', title: self.translate.instant('error'), body: error}); + } + ); + } + } + ); + } + + goToEditProfile(profile: HardwareProfile) { + this.router.navigate(['/app/hardware/profile', profile.id]).then( + success => { + console.log(success); + }, + error => { + console.log(error); + } + ); + } +} diff --git a/admin/WebConsole3/frontend/src/app/pages/image/edit/image-edit.component.ts b/admin/WebConsole3/frontend/src/app/pages/image/edit/image-edit.component.ts index 1117762b..8bc33f44 100644 --- a/admin/WebConsole3/frontend/src/app/pages/image/edit/image-edit.component.ts +++ b/admin/WebConsole3/frontend/src/app/pages/image/edit/image-edit.component.ts @@ -1,76 +1,100 @@ -import {Component, OnInit} from '@angular/core';
-
-import { ImageService } from 'src/app/api/image.service';
-import {Image, PartitionInfo} from 'src/app/model/image';
-
-import {ActivatedRoute, Router} from '@angular/router';
-import {ToasterService} from '../../../service/toaster.service';
-import {TranslateService} from '@ngx-translate/core';
-import {ImageFormType} from '../../../form-type/image.form-type';
-import {RepositoryService} from '../../../api/repository.service';
-
-@Component({
- selector: 'app-image',
- templateUrl: './image-edit.component.html',
- styleUrls: [ './image-edit.component.scss' ]
-})
-export class ImageEditComponent implements OnInit {
- image: Image;
- constants: any;
- private formType = new ImageFormType();
- public form: any;
-
- // this tells the tabs component which Pages
- // should be each tab's root Page
- constructor(private router: Router, private activatedRouter: ActivatedRoute, private imageService: ImageService, private repositoryService: RepositoryService, private translate: TranslateService, private toaster: ToasterService) {
- this.form = this.formType.getForm();
- }
-
- ngOnInit(): void {
- this.image = new Image();
- this.activatedRouter.paramMap.subscribe(
- (data: any) => {
- if (data.params.id) {
- this.imageService.read(data.params.id).subscribe(
- image => {
- this.image = image;
- },
- error => {
- this.toaster.pop({type: 'error', title: 'error', body: error});
- }
- );
- }
- }
- );
- this.repositoryService.list().subscribe(
- data => {
- this.formType.getField(this.form, 'repository').options = {
- items: data,
- label: 'name',
- value: 'id'
- }
- }
- )
- }
-
- getImageFileSystem(image) {
- const result = '';
- if (typeof image.partitionInfo === 'string') {
- image.partitionInfo = JSON.parse(image.partitionInfo);
- } else if (!image.partitionInfo) {
- image.partitionInfo = {};
- }
- return image.partitionInfo.filesystem;
- }
-
-
- getPartitionType(partition) {
- // buscar la particion en el array global
- let result = this.constants.partitionTypes.filter(function (obj) {
- return obj.id === partition.id;
- });
- result = result[0];
- return result.type;
- }
-
-}
+import {Component, OnInit} from '@angular/core'; + +import { ImageService } from 'src/app/api/image.service'; +import {Image, PartitionInfo} from 'src/app/model/image'; + +import {ActivatedRoute, Router} from '@angular/router'; +import {ToasterService} from '../../../service/toaster.service'; +import {TranslateService} from '@ngx-translate/core'; +import {ImageFormType} from '../../../form-type/image.form-type'; +import {RepositoryService} from '../../../api/repository.service'; +import {Observable} from 'rxjs'; + +@Component({ + selector: 'app-image', + templateUrl: './image-edit.component.html', + styleUrls: [ './image-edit.component.scss' ] +}) +export class ImageEditComponent implements OnInit { + image: Image; + constants: any; + private formType = new ImageFormType(); + public form: any; + + // this tells the tabs component which Pages + // should be each tab's root Page + constructor(private router: Router, private activatedRouter: ActivatedRoute, private imageService: ImageService, private repositoryService: RepositoryService, private translate: TranslateService, private toaster: ToasterService) { + this.form = this.formType.getForm(); + } + + ngOnInit(): void { + this.image = new Image(); + this.activatedRouter.paramMap.subscribe( + (data: any) => { + if (data.params.id) { + this.imageService.read(data.params.id).subscribe( + image => { + this.image = image; + if (typeof this.image.partitionInfo === 'string') { + this.image.partitionInfo = JSON.parse(this.image.partitionInfo); + } else if (!this.image.partitionInfo) { + this.image.partitionInfo = new PartitionInfo(); + } + }, + error => { + this.toaster.pop({type: 'error', title: 'error', body: error}); + } + ); + } + } + ); + this.repositoryService.list().subscribe( + data => { + this.formType.getField(this.form, 'repository').options = { + items: data, + label: 'name', + value: 'id' + }; + } + ); + } + + getImageFileSystem(image) { + const result = ''; + if (typeof image.partitionInfo === 'string') { + image.partitionInfo = JSON.parse(image.partitionInfo); + } else if (!image.partitionInfo) { + image.partitionInfo = {}; + } + return image.partitionInfo.filesystem; + } + + + getPartitionType(partition) { + // buscar la particion en el array global + let result = this.constants.partitionTypes.filter(function (obj) { + return obj.id === partition.id; + }); + result = result[0]; + return result.type; + } + + save() { + let request: Observable<any>; + if (this.image.id !== 0) { + request = this.imageService.update(this.image); + } else { + request = this.imageService.create(this.image); + } + request.subscribe( + (response) => { + this.toaster.pop({type: 'success', title: this.translate.instant('success'), body: this.translate.instant('successfully_saved')}); + this.router.navigate(['/app/images']); + + }, + (error) => { + this.toaster.pop({type: 'error', title: 'error', body: error}); + } + ); + } +} diff --git a/admin/WebConsole3/frontend/src/app/pages/image/image.component.html b/admin/WebConsole3/frontend/src/app/pages/image/image.component.html index 09ba6036..a5b700ac 100644 --- a/admin/WebConsole3/frontend/src/app/pages/image/image.component.html +++ b/admin/WebConsole3/frontend/src/app/pages/image/image.component.html @@ -9,16 +9,16 @@ </section> <section fixed-toolboxbar class="toolboxbar"> <div class="row"> - <div class="col-10"> + <div class="col-md-10 col-10"> <div class="input-group"> - <input type="text" name="q" class="form-control" placeholder="{{'search'|translate}}..." ng-model="vm.ngTableSearch.text"> + <input type="text" name="q" class="form-control" placeholder="{{'search'|translate}}..." > <span class="input-group-btn"> <button type="button" name="search" id="search-btn" class="btn btn-flat btn-default"><i class="fa fa-search"></i> </button> </span> </div> </div> - <div class="col-2" style="margin-top: 5px;margin-bottom: 5px;"> + <div class="col-md-2 col-2" style="margin-top: 5px;margin-bottom: 5px;"> <div class="box-tools"> <mk-dropdown class="btn-group" [isWrapper]="false" > <mk-dropdown-toggle> diff --git a/admin/WebConsole3/frontend/src/app/pages/menu/edit/menu-edit.component.html b/admin/WebConsole3/frontend/src/app/pages/menu/edit/menu-edit.component.html new file mode 100644 index 00000000..9d96cde9 --- /dev/null +++ b/admin/WebConsole3/frontend/src/app/pages/menu/edit/menu-edit.component.html @@ -0,0 +1,34 @@ +<section class="content-header"> + <h1 translate="new_image"> + </h1> + <ol class="breadcrumb"> + <li><a [routerLink]="'/app/dashboard'"><i class="fa fa-dashboard"></i> {{'dashboard'|translate}}</a></li> + <li><a [routerLink]="'/app/images'"><i class="fa fa-cubes"></i> {{'images'|translate}}</a></li> + <li class="active" translate="edit_image"></li> + </ol> +</section> +<section fixed-toolboxbar class="toolboxbar"> + <div> + <div class="col-md-12"> + <div class="box-tools pull-right"> + <button class="btn btn-primary" translate="save" (click)="save()"></button> + </div> + </div> + </div> +</section> +<!-- Main content --> +<section class="content"> + <div class="row"> + <div class="col-md-12"> + <div class="box box-primary"> + <div class="box-header with-border"> + </div> + <div class="box-body"> + <form role="form" gbn-auto-form name="Form" ng-submit="saveImage(Form)" form-options="formOptions" form-model="image"> + <app-form-input [model]="menu" [cols]="1" [formType]="form"></app-form-input> + </form> + </div> + </div> + </div> + </div> +</section> diff --git a/admin/WebConsole3/frontend/src/app/pages/menu/edit/menu-edit.component.scss b/admin/WebConsole3/frontend/src/app/pages/menu/edit/menu-edit.component.scss new file mode 100644 index 00000000..1382f194 --- /dev/null +++ b/admin/WebConsole3/frontend/src/app/pages/menu/edit/menu-edit.component.scss @@ -0,0 +1,3 @@ +image { + +} diff --git a/admin/WebConsole3/frontend/src/app/pages/menu/edit/menu-edit.component.ts b/admin/WebConsole3/frontend/src/app/pages/menu/edit/menu-edit.component.ts new file mode 100644 index 00000000..d52f53ad --- /dev/null +++ b/admin/WebConsole3/frontend/src/app/pages/menu/edit/menu-edit.component.ts @@ -0,0 +1,77 @@ +import {Component, OnInit} from '@angular/core'; + + +import {ActivatedRoute, Router} from '@angular/router'; +import {ToasterService} from '../../../service/toaster.service'; +import {TranslateService} from '@ngx-translate/core'; +import {MenuFormType} from '../../../form-type/menu.form-type'; +import {RepositoryService} from '../../../api/repository.service'; +import {Observable} from 'rxjs'; +import {MenuService} from '../../../api/menu.service'; +import {Menu} from '../../../model/menu'; +import {OgCommonService} from '../../../service/og-common.service'; + +@Component({ + selector: 'app-menu', + templateUrl: './menu-edit.component.html', + styleUrls: [ './menu-edit.component.scss' ] +}) +export class MenuEditComponent implements OnInit { + menu: Menu; + constants: any; + private formType = new MenuFormType(); + public form: any; + + // this tells the tabs component which Pages + // should be each tab's root Page + constructor(private router: Router, private activatedRouter: ActivatedRoute, private ogCommonService: OgCommonService, private menuService: MenuService, private translate: TranslateService, private toaster: ToasterService) { + this.form = this.formType.getForm(); + } + + ngOnInit(): void { + this.menu = new Menu(); + this.ogCommonService.loadEngineConfig().subscribe( + data => { + this.formType.getField(this.form, 'resolution').options = { + items: data.constants.menus.resolutions, + label: 'text', + value: 'id' + }; + } + ); + this.activatedRouter.paramMap.subscribe( + (data: any) => { + if (data.params.id) { + this.menuService.read(data.params.id).subscribe( + menu => { + this.menu = menu; + }, + error => { + this.toaster.pop({type: 'error', title: 'error', body: error}); + } + ); + } + } + ); + } + + + save() { + let request: Observable<any>; + if (this.menu.id !== 0) { + request = this.menuService.update(this.menu); + } else { + request = this.menuService.create(this.menu); + } + request.subscribe( + (response) => { + this.toaster.pop({type: 'success', title: this.translate.instant('success'), body: this.translate.instant('successfully_saved')}); + this.router.navigate(['/app/menus']); + + }, + (error) => { + this.toaster.pop({type: 'error', title: 'error', body: error}); + } + ); + } +} diff --git a/admin/WebConsole3/frontend/src/app/pages/menu/menu.component.html b/admin/WebConsole3/frontend/src/app/pages/menu/menu.component.html index 93bab7ab..bc65667b 100644 --- a/admin/WebConsole3/frontend/src/app/pages/menu/menu.component.html +++ b/admin/WebConsole3/frontend/src/app/pages/menu/menu.component.html @@ -1 +1,51 @@ -<div>Html template for class Menu</div>
\ No newline at end of file +<div ui-view> + <section class="content-header"> + <h1 translate="menus"> + </h1> + <ol class="breadcrumb"> + <li><a [routerLink]="'app/dashboard'"><i class="fa fa-dashboard"></i> {{'dashboard'|translate}}</a></li> + <li class="active" translate="menus"></li> + </ol> + </section> + <section fixed-toolboxbar class="toolboxbar"> + <div > + <div class="col-md-12"> + <div class="input-group"> + <input type="text" name="q" class="form-control" placeholder="{{'search'|translate}}..." ng-model="vm.ngTableSearch.text"> + <span class="input-group-btn"> + <button type="button" name="search" id="search-btn" class="btn btn-flat"><i class="fa fa-search"></i> + </button> + </span> + </div> + </div> + <div class="col-md-12" style="margin-top: 5px;margin-bottom: 5px;"> + + <div class="box-tools pull-right"> + <a [routerLink]="'/app/menus/create'" type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown" aria-expanded="false"> + <span translate="new"></span> + </a> + </div> + </div> + </div> + </section> + <!-- Main content --> + <section class="content"> + <div class="row"> + <div class="col-md-12"> + <!-- Info boxes --> + <div class="box box-primary"> + <div class="box-header with-border"> + <h3 class="box-title" translate="image_list"></h3> + </div> + <div class="box-body"> + <ng2-smart-table [source]="menus" [settings]="tableSettings"></ng2-smart-table> + </div> + <div class="box-footer"> + </div> + <!-- /.col --> + </div> + </div> + </div> + <!-- /.row --> + </section> +</div> diff --git a/admin/WebConsole3/frontend/src/app/pages/menu/menu.component.ts b/admin/WebConsole3/frontend/src/app/pages/menu/menu.component.ts index a5cecb4e..4c47eb73 100644 --- a/admin/WebConsole3/frontend/src/app/pages/menu/menu.component.ts +++ b/admin/WebConsole3/frontend/src/app/pages/menu/menu.component.ts @@ -1,17 +1,104 @@ -import { Component } from '@angular/core';
-
-import { MenuService } from 'src/app/api/menu.service';
-import { Menu } from 'src/app/model/menu';
-
-@Component({
- selector: 'menu',
- templateUrl: './menu.component.html',
- styleUrls: [ './menu.component.scss' ]
-})
-export class MenuComponent {
- // this tells the tabs component which Pages
- // should be each tab's root Page
- constructor(public menuService: MenuService) {
- }
-
-}
+import {Component, OnInit} from '@angular/core'; + +import { MenuService } from 'src/app/api/menu.service'; +import { Menu } from 'src/app/model/menu'; +import {PartitionInfo} from '../../model/image'; +import {Ng2TableActionComponent} from '../common/table-action/ng2-table-action.component'; +import {TranslateService} from '@ngx-translate/core'; +import {Router} from '@angular/router'; +import {OgSweetAlertService} from '../../service/og-sweet-alert.service'; + +@Component({ + selector: 'app-menu', + templateUrl: './menu.component.html', + styleUrls: [ './menu.component.scss' ] +}) +export class MenuComponent implements OnInit { + public menus: Menu[]; + private tableSettings: any; + // this tells the tabs component which Pages + // should be each tab's root Page + constructor(public menuService: MenuService, private router: Router, private ogSweetAlert: OgSweetAlertService, private translate: TranslateService) { + } + + ngOnInit(): void { + this.menuService.list().subscribe( + data => { + this.menus = data; + }, + error => { + + } + ); + const self = this; + this.tableSettings = { + columns: { + title: { + title: this.translate.instant('title') + }, + description: { + title: this.translate.instant('description') + }, + comments: { + title: this.translate.instant('comments'), + }, + resolution: { + title: this.translate.instant('resolution') + }, + options: { + title: 'Options', + filter: false, + sort: false, + type: 'custom', + renderComponent: Ng2TableActionComponent, + onComponentInitFunction(instance) { + instance.edit.subscribe(row => { + self.router.navigate(['/app/menus/edit/', row.id]); + }); + instance.delete.subscribe(row => { + self.deleteMenu(row); + }); + } + }, + }, + actions: { + position: 'right', + add: false, + edit: false, + delete: false + } + }; + } + + deleteMenu(menu) { + const self = this; + this.ogSweetAlert.swal({ + title: this.translate.instant('sure_to_delete') + '?', + message: this.translate.instant('action_cannot_be_undone'), + type: 'warning', + showCancelButton: true, + confirmButtonColor: '#3c8dbc', + confirmButtonText: this.translate.instant('yes_delete'), + closeOnConfirm: true + }).then( + function(result) { + if (result === true) { + + this.menuService.delete(menu.id).then( + function(response) { + this.toaster.pop({type: 'success', title: 'success', body: this.translate.instant('successfully_deleted')}); + // Buscar el elemento en el array y borrarlo + const index = this.images.indexOf(menu); + if (index !== -1) { + this.images.splice(menu, 1); + } + }, + function(error) { + this.toaster.pop({type: 'error', title: 'error', body: error}); + } + ); + } + }); + } + +} diff --git a/admin/WebConsole3/frontend/src/app/pages/organizational-unit/ou-clients/ou-client.component.html b/admin/WebConsole3/frontend/src/app/pages/organizational-unit/ou-clients/ou-client.component.html index 86508a31..32b0a4db 100644 --- a/admin/WebConsole3/frontend/src/app/pages/organizational-unit/ou-clients/ou-client.component.html +++ b/admin/WebConsole3/frontend/src/app/pages/organizational-unit/ou-clients/ou-client.component.html @@ -24,7 +24,7 @@ </td> <td class="right"> <div class="btn-group visible-md visible-lg hidden-sm hidden-xs"> - <button class="btn btn-default " translate="edit" [routerLink]="'app/client.edit({ou: content.id, clientId: client.id})'"></button> + <button class="btn btn-default " translate="edit" [routerLink]="'/app/clients/edit/'+client.id"></button> <button class="btn btn-danger " translate="delete" (click)="deleteClient(client)"></button> </div> <div class="btn-group hidden-md hidden-lg"> @@ -35,7 +35,7 @@ </button> <ul class="dropdown-menu" role="menu"> <li class="btn-group-vertical"> - <button class="btn btn-default" href="javascript:void(0)" translate="edit" [routerLink]="'app/client.edit({ou: content.id, clientId: client.id})'"></button> + <button class="btn btn-default" href="javascript:void(0)" translate="edit" [routerLink]="'/app/clients/edit/'+client.id"></button> <button class="btn btn-danger" href="javascript:void(0)" translate="delete" (click)="deleteClient(client)"></button> </li> </ul> diff --git a/admin/WebConsole3/frontend/src/app/pages/organizational-unit/ou-clients/ou-client.component.ts b/admin/WebConsole3/frontend/src/app/pages/organizational-unit/ou-clients/ou-client.component.ts index b65b2ffa..743ba965 100644 --- a/admin/WebConsole3/frontend/src/app/pages/organizational-unit/ou-clients/ou-client.component.ts +++ b/admin/WebConsole3/frontend/src/app/pages/organizational-unit/ou-clients/ou-client.component.ts @@ -41,6 +41,7 @@ export class OuClientComponent { } deleteClient(client) { + const self = this; this.ogSweetAlert.swal( { title: this.translate.instant('sure_to_delete') + '?', @@ -52,18 +53,18 @@ export class OuClientComponent { }).then( function(response) { - if (response === true) { - this.clientService.delete(client.id).then( - function(success) { + if (response.value === true) { + self.clientService.delete(client.id).subscribe( + (success) => { // Lo borramos de la unidad organizativa - const index = this.ou.clients.indexOf(client); + const index = self.ou.clients.indexOf(client); if (index !== -1) { - this.ou.clients.splice(index, 1); + self.ou.clients.splice(index, 1); } - this.toaster.pop({type: 'success', title: 'success', body: 'Successfully deleted'}); + self.toaster.pop({type: 'success', title: 'success', body: 'Successfully deleted'}); }, - function(error) { - this.toaster.pop({type: 'error', title: 'error', body: error}); + (error) => { + self.toaster.pop({type: 'error', title: 'error', body: error}); } ); } diff --git a/admin/WebConsole3/frontend/src/app/pages/software/software-components/software-components-group/software-components-group.component.html b/admin/WebConsole3/frontend/src/app/pages/software/software-components/software-components-group/software-components-group.component.html new file mode 100644 index 00000000..65c3cacb --- /dev/null +++ b/admin/WebConsole3/frontend/src/app/pages/software/software-components/software-components-group/software-components-group.component.html @@ -0,0 +1,45 @@ +<mk-box [boxColor]="'warning'" [isRemovable]="false"> + <mk-box-header class="box-header with-border"> + <i class="fa fa-folder-open-o"></i> + <h3 class="box-title"> + <div mk-dropdown class="btn-group" *ngIf="!content.$$editing"> + <mk-dropdown-toggle> + <button #toggleElement type="button" class="btn btn-default dropdown-toggle" > + {{content.name}} + <span class="fa fa-caret-down"></span> + </button> + </mk-dropdown-toggle> + <mk-dropdown-menu> + <li role="presentation"> + <a role="menuitem" tabindex="-1" href="#" translate="add_group"></a> + </li> + <li role="presentation"> + <a role="menuitem" tabindex="-1" href="#" translate="add_software_component"></a> + </li> + <li role="presentation" class="divider"></li> + <li> + <a class="" href="javascript:void(0)" translate="edit" (click)="content.$$tmpDescription = content.description; content.$$editing = true"></a> + </li> + <li role="presentation" class="divider"></li> + <li role="presentation" class="delete-option"> + <a class="" href="javascript:void(0)" translate="delete" (click)="vm.deleteGroup(content.id)"></a> + </li> + </mk-dropdown-menu> + </div> + <div *ngIf="content.$$editing" class="col-xs-6"> + <input type="text" class="form-control" [(ngModel)]="content.$$tmpDescription"> + <span class="input-group-btn"> + <button type="button" class="btn btn-default btn-flat" translate="done" (click)="changeGroupName(content)"></button> + <button type="button" class="btn btn-info btn-flat" translate="cancel" (click)="content.$$editing = false"></button> + </span> + </div> + </h3> + <!-- /.box-tools --> + </mk-box-header> + <!-- /.box-header --> + <mk-box-content class="box-body folders" style="display: block;"> + <app-software-component-group *ngFor="let content of content.groups" [content]="content" [softwareTypes]="softwareTypes"> + </app-software-component-group> + <app-software-components-table *ngIf="content.components" [components]="content.components" [softwareTypes]="softwareTypes"></app-software-components-table> + </mk-box-content> +</mk-box> diff --git a/admin/WebConsole3/frontend/src/app/pages/software/software-components/software-components-group/software-components-group.component.ts b/admin/WebConsole3/frontend/src/app/pages/software/software-components/software-components-group/software-components-group.component.ts new file mode 100644 index 00000000..d27504a4 --- /dev/null +++ b/admin/WebConsole3/frontend/src/app/pages/software/software-components/software-components-group/software-components-group.component.ts @@ -0,0 +1,10 @@ +import {Component, Input} from '@angular/core'; + +@Component({ + selector: 'app-software-component-group', + templateUrl: 'software-components-group.component.html' +}) +export class SoftwareComponentsGroupComponent { + @Input() content; + @Input() softwareTypes; +} diff --git a/admin/WebConsole3/frontend/src/app/pages/software/software-components/software-components-table/software-components-table.component.html b/admin/WebConsole3/frontend/src/app/pages/software/software-components/software-components-table/software-components-table.component.html new file mode 100644 index 00000000..fb4bdbd2 --- /dev/null +++ b/admin/WebConsole3/frontend/src/app/pages/software/software-components/software-components-table/software-components-table.component.html @@ -0,0 +1,43 @@ +<table class="table table-hover"> + <tbody> + <tr> + <th translate="description"></th> + <th translate="type"></th> + <!--th translate="imageUrl"></th--> + <th translate="options"></th> + </tr> + <tr *ngFor="let softwareComponent of components; let index = index" class="{{(index%2 == 0)?'odd':'even'}}"> + <td> + <span *ngIf="softwareComponent.$$editing"> + <input type="text" class="form-control" [(ngModel)]="softwareComponent.$$tmpDescription"> + </span> + <span *ngIf="!softwareComponent.$$editing"> + {{softwareComponent.description}} + </span> + </td> + <td> + <span *ngIf="softwareComponent.$$editing"> + <select class="form-control" [(ngModel)]="softwareComponent.$$tmpType"> + <option [value]="softwareType.nemonic" *ngFor="let softwareType of softwareTypes">{{softwareType.name}}</option> + </select> + </span> + <span *ngIf="!softwareComponent.$$editing"> + <select disabled="disabled" class="form-control" [(ngModel)]="softwareComponent.type"> + <option [value]="softwareType.nemonic" *ngFor="let softwareType of softwareTypes">{{softwareType.name}}</option> + </select> + </span> + </td> + <td class="right"> + <span *ngIf="softwareComponent.$$editing"> + <div class="btn-group "> + <button class="btn btn-primary " translate="ok" (click)="saveSoftwareComponent(softwareComponent)"></button> + <button class="btn btn-default " translate="cancel" (click)="softwareComponent.$$editing = false"></button> + </div> + </span> + <span *ngIf="!softwareComponent.$$editing"> + <app-table-action [rowData]="softwareComponent" [options]="tableOptions" (edit)="editSoftwareComponent($event)" (delete)="deleteSoftwareComponent($event)"></app-table-action> + </span> + </td> + </tr> + </tbody> +</table> diff --git a/admin/WebConsole3/frontend/src/app/pages/software/software-components/software-components-table/software-components-table.component.ts b/admin/WebConsole3/frontend/src/app/pages/software/software-components/software-components-table/software-components-table.component.ts new file mode 100644 index 00000000..30341c92 --- /dev/null +++ b/admin/WebConsole3/frontend/src/app/pages/software/software-components/software-components-table/software-components-table.component.ts @@ -0,0 +1,84 @@ +import {Component, Input, OnInit} from '@angular/core'; +import {ToasterService} from '../../../../service/toaster.service'; +import {TranslateService} from '@ngx-translate/core'; +import {OgSweetAlertService} from '../../../../service/og-sweet-alert.service'; +import {Router} from '@angular/router'; +import {SoftwareComponent} from '../../../../model/software-component'; +import {SoftwareComponentService} from '../../../../api/software-component.service'; +import {environment} from '../../../../../environments/environment'; + +@Component({ + selector: 'app-software-components-table', + templateUrl: 'software-components-table.component.html' +}) +export class SoftwareComponentsTableComponent implements OnInit { + @Input() components; + @Input() softwareTypes; + public tableOptions: { buttons: ({ action: string } | { handler: (profile) => any; classes: string; label: string })[]; override: boolean }; + + public constructor(private router: Router, private softwareComponentService: SoftwareComponentService, private ogSweetAlert: OgSweetAlertService, private toaster: ToasterService, private translate: TranslateService) { + } + + ngOnInit(): void { + this.tableOptions = { + override: false, + buttons: [ + { + action: 'edit' + }, + { + action: 'delete' + } + ] + }; + } + + editSoftwareComponent(softwareComponent) { + softwareComponent.$$editing = true; + softwareComponent.$$tmpDescription = softwareComponent.description; + softwareComponent.$$tmpType = softwareComponent.type; + } + saveSoftwareComponent(softwareComponent: any) { + softwareComponent.$$editing = false; + softwareComponent.description = softwareComponent.$$tmpDescription; + softwareComponent.type = softwareComponent.$$tmpType; + const hcCopy = Object.assign({}, softwareComponent); + + // TODO - Llamar al servidor para guardar el cambio + this.softwareComponentService.update(hcCopy).subscribe( + (response) => { + this.toaster.pop({type: 'success', title: this.translate.instant('success'), body: this.translate.instant('successfully_saved')}); + }, + (error) => { + this.toaster.pop({type: 'error', title: this.translate.instant('error'), body: error}); + } + ); + } + + deleteSoftwareComponent(softwareComponent: SoftwareComponent) { + this.ogSweetAlert.swal({ + title: this.translate.instant('sure_to_delete') + '?', + text: this.translate.instant('action_cannot_be_undone'), + type: 'warning', + showCancelButton: true, + confirmButtonColor: '#3c8dbc', + confirmButtonText: this.translate.instant('yes_delete'), + closeOnConfirm: true}).then( + function(result) { + if (result === true) { + this.softwareComponentService.delete(softwareComponent.id).subscribe( + (response) => { + this.toaster.pop({type: 'success', title: this.translate.instant('success'), body: this.translate.instant('successfully_deleted')}); + const index = this.softwareComponentsGroups[0].components.indexOf(softwareComponent); + if (index !== -1) { + this.softwareComponentsGroups[0].components.splice(index, 1); + } + }, + (error) => { + this.toaster.pop({type: 'error', title: this.translate.instant('error'), body: error}); + } + ); + } + }); + } +} diff --git a/admin/WebConsole3/frontend/src/app/pages/software/software-components/software-components.component.css b/admin/WebConsole3/frontend/src/app/pages/software/software-components/software-components.component.css new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/admin/WebConsole3/frontend/src/app/pages/software/software-components/software-components.component.css diff --git a/admin/WebConsole3/frontend/src/app/pages/software/software-components/software-components.component.html b/admin/WebConsole3/frontend/src/app/pages/software/software-components/software-components.component.html new file mode 100644 index 00000000..043210de --- /dev/null +++ b/admin/WebConsole3/frontend/src/app/pages/software/software-components/software-components.component.html @@ -0,0 +1 @@ +<app-software-component-group *ngFor="let content of softwareComponentsGroups" [content]="content" [softwareTypes]="softwareTypes"></app-software-component-group> diff --git a/admin/WebConsole3/frontend/src/app/pages/software/software-components/software-components.component.ts b/admin/WebConsole3/frontend/src/app/pages/software/software-components/software-components.component.ts new file mode 100644 index 00000000..78e80784 --- /dev/null +++ b/admin/WebConsole3/frontend/src/app/pages/software/software-components/software-components.component.ts @@ -0,0 +1,17 @@ +import {Component, Input, OnInit} from '@angular/core'; + +@Component({ + selector: 'app-software-components', + templateUrl: './software-components.component.html', + styleUrls: ['./software-components.component.css'] +}) +export class SoftwareComponentsComponent implements OnInit { + @Input() softwareTypes; + @Input() softwareComponentsGroups; + constructor() { } + + ngOnInit() { + console.log(this.softwareComponentsGroups); + } + +} diff --git a/admin/WebConsole3/frontend/src/app/pages/software/software-profiles/software-profiles-group/software-profiles-group.component.html b/admin/WebConsole3/frontend/src/app/pages/software/software-profiles/software-profiles-group/software-profiles-group.component.html new file mode 100644 index 00000000..95b2879a --- /dev/null +++ b/admin/WebConsole3/frontend/src/app/pages/software/software-profiles/software-profiles-group/software-profiles-group.component.html @@ -0,0 +1,47 @@ +<mk-box boxColor="warning" headerBorder="true" isCollapsable="true" [isRemovable]="false"> + <mk-box-header class="box-header with-border"> + <i class="fa fa-folder-open-o"></i> + <h3 class="box-title"> + <div class="btn-group" *ngIf="!content.editing"> + <div mk-dropdown class="btn-group" [isWrapper]="false" > + <mk-dropdown-toggle> + <button #toggleElement type="button" class="btn btn-default dropdown-toggle"> + {{content.name}} + <span class="fa fa-caret-down"></span> + </button> + </mk-dropdown-toggle> + <mk-dropdown-menu> + <li > + <a role="menuitem" tabindex="-1" href="#" translate="add_group"></a> + </li> + <li > + <a role="menuitem" tabindex="-1" href="#" translate="add_profile" [routerLink]="'/app/software/profile/create/' + content.id "></a> + </li> + <li class="divider"></li> + <li> + <a class="" href="javascript:void(0)" translate="edit" (click)="content.$$tmpName = content.name; content.editing = true"></a> + </li> + <li role="presentation" class="divider"></li> + <li role="presentation" class="delete-option"> + <a class="" href="javascript:void(0)" translate="delete" (click)="deleteGroup(content.id)"></a> + </li> + </mk-dropdown-menu> + </div> + </div> + <div *ngIf="content.editing" class="col-xs-6"> + <input type="text" class="form-control" [(ngModel)]="content.$$tmpName"> + <span class="input-group-btn"> + <button type="button" class="btn btn-default btn-flat" translate="done" (click)="changeGroupName(content)"></button> + <button type="button" class="btn btn-info btn-flat" translate="cancel" (click)="content.editing = false"></button> + </span> + </div> + </h3> + <!-- /.box-tools --> + </mk-box-header> + <!-- /.box-header --> + <mk-box-content class="box-body folders" style="display: block;"> + <app-software-profiles-group *ngFor="let content of content.groups" [content]="content"> + </app-software-profiles-group> + <app-software-profiles-table *ngIf="content.profiles" [profiles]="content.profiles"></app-software-profiles-table> + </mk-box-content> +</mk-box> diff --git a/admin/WebConsole3/frontend/src/app/pages/software/software-profiles/software-profiles-group/software-profiles-group.component.ts b/admin/WebConsole3/frontend/src/app/pages/software/software-profiles/software-profiles-group/software-profiles-group.component.ts new file mode 100644 index 00000000..e3e65420 --- /dev/null +++ b/admin/WebConsole3/frontend/src/app/pages/software/software-profiles/software-profiles-group/software-profiles-group.component.ts @@ -0,0 +1,14 @@ +import {ComponentMetadata} from 'codelyzer/angular/metadata'; +import {Component, Input} from '@angular/core'; + +@Component({ + selector: 'app-software-profiles-group', + templateUrl: 'software-profiles-group.component.html' +}) +export class SoftwareProfilesGroupComponent { + @Input() content; + + constructor() { + console.log(this.content); + } +} diff --git a/admin/WebConsole3/frontend/src/app/pages/software/software-profiles/software-profiles-table/software-profiles-table.component.html b/admin/WebConsole3/frontend/src/app/pages/software/software-profiles/software-profiles-table/software-profiles-table.component.html new file mode 100644 index 00000000..6f362fa9 --- /dev/null +++ b/admin/WebConsole3/frontend/src/app/pages/software/software-profiles/software-profiles-table/software-profiles-table.component.html @@ -0,0 +1,61 @@ +<table class="table table-hover"> + <tbody> + <tr> + <th translate="description"></th> + <th translate="windowsboot"></th> + <th translate="options"></th> + </tr> + <tr *ngFor="let profile of profiles; let index = index" class="{{(index%2 == 0)?'odd':'even'}}"> + <td> + <span *ngIf="profile.$$editing"> + <input type="text" class="form-control" [(ngModel)]="profile.$$tmpDescription"> + </span> + <span *ngIf="!profile.$$editing"> + {{profile.description}} + </span> + </td> + <td> + <span *ngIf="profile.$$editing"> + <select class="form-control"[(ngModel)]="profile.$$tmpWindowsboot"> + <option [value]="item" *ngFor="let item of windowsboots"> {{item}}</option> + </select> + </span> + <span *ngIf="!profile.$$editing"> + {{profile.windowsboot}} + </span> + </td> + <td class="right"> + <ng-container *ngIf="profile.$$editing"> + <div class="btn-group "> + <button class="btn btn-primary " translate="ok" (click)="saveSoftwareProfile(profile)"></button> + <button class="btn btn-default " translate="cancel" (click)="profile.$$editing = false"></button> + </div> + </ng-container> + <ng-container *ngIf="!profile.$$editing"> + <app-table-action [rowData]="profile" [options]="tableOptions" (edit)="editSoftwareProfile($event)" (delete)="deleteSoftwareProfile($event)"></app-table-action> +<!-- + <div class="btn-group visible-md visible-lg hidden-sm hidden-xs"> + <button class="btn btn-default" translate="edit" (click)="editSoftwareProfile(profile)"></button> + <button class="btn btn-default" href="javascript:void(0)" translate="config" (click)="goToEditProfile(profile)"></button> + <button class="btn btn-danger " translate="delete" (click)="deleteSoftwareProfile(profile)"></button> + </div> + <div class="btn-group hidden-md hidden-lg"> + <button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown"> + <i class="fa fa-gear"></i> + <span class="caret"></span> + <span class="sr-only">Toggle Dropdown</span> + </button> + <ul class="dropdown-menu" role="menu"> + <li class="btn-group-vertical"> + <button class="btn btn-default" translate="edit" (click)="editSoftwareProfile(profile)"></button> + <button class="btn btn-default" href="javascript:void(0)" translate="config" ui-sref="goToEditProfile(profile)"></button> + <button class="btn btn-danger" href="javascript:void(0)" translate="delete" (click)="deleteSoftwareProfile(profile)"></button> + </li> + </ul> + </div> +--> + </ng-container> + </td> + </tr> + </tbody> + </table> diff --git a/admin/WebConsole3/frontend/src/app/pages/software/software-profiles/software-profiles-table/software-profiles-table.component.ts b/admin/WebConsole3/frontend/src/app/pages/software/software-profiles/software-profiles-table/software-profiles-table.component.ts new file mode 100644 index 00000000..9ea76af2 --- /dev/null +++ b/admin/WebConsole3/frontend/src/app/pages/software/software-profiles/software-profiles-table/software-profiles-table.component.ts @@ -0,0 +1,100 @@ +import {Component, EventEmitter, Input, OnInit, Output} from '@angular/core'; +import {SoftwareProfile} from '../../../../model/software-profile'; +import {SoftwareProfileService} from '../../../../api/software-profile.service'; +import {ToasterService} from '../../../../service/toaster.service'; +import {TranslateService} from '@ngx-translate/core'; +import {OgSweetAlertService} from '../../../../service/og-sweet-alert.service'; +import {Router} from '@angular/router'; +import {environment} from '../../../../../environments/environment'; + + +@Component({ + selector: 'app-software-profiles-table', + templateUrl: 'software-profiles-table.component.html' +}) +export class SoftwareProfilesTableComponent implements OnInit { + @Input() profiles; + windowsboots: any; + tableOptions: any; + + public constructor(private router: Router, private softwareProfileService: SoftwareProfileService, private ogSweetAlert: OgSweetAlertService, private toaster: ToasterService, private translate: TranslateService) { + + } + ngOnInit(): void { + this.windowsboots = environment.windowsboots; + this.tableOptions = { + override: false, + buttons: [ + { + action: 'edit' + }, + { + label: 'configure', + handler: (profile) => this.goToEditProfile(profile), + classes: 'btn-default' + }, + { + action: 'delete' + } + ] + }; + } + + editSoftwareProfile(softwareProfile) { + softwareProfile.$$editing = true; + softwareProfile.$$tmpName = softwareProfile.name; + softwareProfile.$$tmpDescription = softwareProfile.description; + softwareProfile.$$tmpWindowsboot = softwareProfile.windowsboot; + } + + saveSoftwareProfile(softwareProfile) { + softwareProfile.$$editing = false; + softwareProfile.name = softwareProfile.$$tmpName; + softwareProfile.description = softwareProfile.$$tmpDescription; + softwareProfile.windowsboot = softwareProfile.$$tmpWindowsboot; + const hpCopy = Object.assign({}, softwareProfile); + // TODO - Llamar al servidor para guardar el cambio + this.softwareProfileService.update(hpCopy).subscribe( + (response) => { + this.toaster.pop({type: 'success', title: 'success', body: this.translate.instant('successfully_saved')}); + }, + (error) => { + this.toaster.pop({type: 'error', title: 'error', body: error}); + } + ); + } + + deleteSoftwareProfile(softwareProfile) { + const self = this; + + this.ogSweetAlert.question(this.translate.instant('sure_to_delete') + '?', this.translate.instant('action_cannot_be_undone'), + function(result) { + if (result.value === true) { + self.softwareProfileService.delete(softwareProfile.id).subscribe( + (response) => { + self.toaster.pop({type: 'success', title: self.translate.instant('success'), body: self.translate.instant('successfully_deleted')}); + const index = self.profiles.indexOf(softwareProfile); + if (index !== -1) { + self.profiles.splice(index, 1); + } + }, + (error) => { + self.toaster.pop({type: 'error', title: self.translate.instant('error'), body: error}); + } + ); + } + } + ); + } + + goToEditProfile(profile: SoftwareProfile) { + this.router.navigate(['/app/software/profile', profile.id]).then( + success => { + console.log(success); + }, + error => { + console.log(error); + } + ); + } +} diff --git a/admin/WebConsole3/frontend/src/app/pages/software/software-profiles/software-profiles.component.css b/admin/WebConsole3/frontend/src/app/pages/software/software-profiles/software-profiles.component.css new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/admin/WebConsole3/frontend/src/app/pages/software/software-profiles/software-profiles.component.css diff --git a/admin/WebConsole3/frontend/src/app/pages/software/software-profiles/software-profiles.component.html b/admin/WebConsole3/frontend/src/app/pages/software/software-profiles/software-profiles.component.html new file mode 100644 index 00000000..adf2e70b --- /dev/null +++ b/admin/WebConsole3/frontend/src/app/pages/software/software-profiles/software-profiles.component.html @@ -0,0 +1,3 @@ +<!-- Nested node template --> + +<app-software-profiles-group *ngFor="let content of softwareProfileGroups" [content]="content"></app-software-profiles-group> diff --git a/admin/WebConsole3/frontend/src/app/pages/software/software-profiles/software-profiles.component.ts b/admin/WebConsole3/frontend/src/app/pages/software/software-profiles/software-profiles.component.ts new file mode 100644 index 00000000..d7d3987d --- /dev/null +++ b/admin/WebConsole3/frontend/src/app/pages/software/software-profiles/software-profiles.component.ts @@ -0,0 +1,19 @@ +import {Component, Input, OnInit} from '@angular/core'; + +@Component({ + selector: 'app-software-profiles', + templateUrl: './software-profiles.component.html', + styleUrls: ['./software-profiles.component.css'] +}) +export class SoftwareProfilesComponent implements OnInit { + + @Input() softwareProfileGroups; + + constructor() { + } + + ngOnInit() { + console.log(this.softwareProfileGroups); + } + +} diff --git a/admin/WebConsole3/frontend/src/app/pages/software/software-types/software-types.component.css b/admin/WebConsole3/frontend/src/app/pages/software/software-types/software-types.component.css new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/admin/WebConsole3/frontend/src/app/pages/software/software-types/software-types.component.css diff --git a/admin/WebConsole3/frontend/src/app/pages/software/software-types/software-types.component.html b/admin/WebConsole3/frontend/src/app/pages/software/software-types/software-types.component.html new file mode 100644 index 00000000..ceda7046 --- /dev/null +++ b/admin/WebConsole3/frontend/src/app/pages/software/software-types/software-types.component.html @@ -0,0 +1,66 @@ +<div class="box box-warning" > + <div class="box-header with-border"> + <i class="fa fa-folder-open-o"></i> + <h3 class="box-title"> + <div class="btn-group"> + <div> + <a href="javascript:void(0)" data-toggle="dropdown" class="dropdown-toggle" translate="software_types"> + </a> + <ul class="dropdown-menu"> + <li role="presentation"> + <a role="menuitem" tabindex="-1" href="#" translate="add_software_type"></a> + </li> + </ul> + </div> + </div> + </h3> + <div class="box-tools pull-right"> + <button type="button" class="btn btn-box-tool" data-widget="collapse"><i class="fa fa-minus"></i> + </button> + </div> + <!-- /.box-tools --> + </div> + <!-- /.box-header --> + <div class="box-body folders" style="display: block;"> + <table class="table table-hover"> + <tbody><tr> + <th translate="name"></th> + <th translate="options"></th> + </tr> + <tr *ngFor="let softwareType of softwareTypes; let index = index;" class="{{( index%2 == 0)?'odd':'even'}}"> + <td> + <span *ngIf="!softwareType.$$editing">{{softwareType.name}}</span> + <span *ngIf="softwareType.$$editing"><input type="text" class="form-control" [(ngModel)]="softwareType.$$tmpName" /></span> + </td> + <td class="right"> + <span *ngIf="softwareType.$$editing"> + <div class="btn-group "> + <button class="btn btn-primary " translate="ok" (click)="saveSoftwareType(softwareType)"></button> + <button class="btn btn-default " translate="cancel" (click)="softwareType.$$editing = false"></button> + </div> + </span> + <span *ngIf="!softwareType.$$editing"> + <div class="btn-group visible-md visible-lg hidden-sm hidden-xs"> + <button class="btn btn-default " translate="edit" (click)="editSoftwareType(softwareType)"></button> + <button class="btn btn-danger " translate="delete" (click)="deleteClient(client.id)"></button> + </div> + <div class="btn-group hidden-md hidden-lg"> + <button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown"> + <i class="fa fa-gear"></i> + <span class="caret"></span> + <span class="sr-only">Toggle Dropdown</span> + </button> + <ul class="dropdown-menu" role="menu"> + <li class="btn-group-vertical"> + <button class="btn btn-default" href="javascript:void(0)" translate="edit" (click)="editSoftwareType(softwareType)"></button> + <button class="btn btn-danger" href="javascript:void(0)" translate="delete" (click)="deleteClient(client.id)"></button> + </li> + </ul> + </div> + </span> + </td> + </tr> + </tbody> + </table> + </div> +</div> diff --git a/admin/WebConsole3/frontend/src/app/pages/software/software-types/software-types.component.ts b/admin/WebConsole3/frontend/src/app/pages/software/software-types/software-types.component.ts new file mode 100644 index 00000000..a5e62b2f --- /dev/null +++ b/admin/WebConsole3/frontend/src/app/pages/software/software-types/software-types.component.ts @@ -0,0 +1,26 @@ +import {Component, Input, OnInit} from '@angular/core'; + +@Component({ + selector: 'app-software-types', + templateUrl: './software-types.component.html', + styleUrls: ['./software-types.component.css'] +}) +export class SoftwareTypesComponent implements OnInit { + @Input() softwareTypes; + + constructor() { } + + ngOnInit() { + } + + editSoftwareType(softwareType) { + softwareType.$$editing = true; + softwareType.$$tmpName = softwareType.name; + } + saveSoftwareType(softwareType) { + softwareType.$$editing = false; + softwareType.name = softwareType.$$tmpName; + // TODO - Llamar al servidor para guardar el cambio + } + +} diff --git a/admin/WebConsole3/frontend/src/app/pages/software/software.component.css b/admin/WebConsole3/frontend/src/app/pages/software/software.component.css new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/admin/WebConsole3/frontend/src/app/pages/software/software.component.css diff --git a/admin/WebConsole3/frontend/src/app/pages/software/software.component.html b/admin/WebConsole3/frontend/src/app/pages/software/software.component.html index adb7ae48..fadb8848 100644 --- a/admin/WebConsole3/frontend/src/app/pages/software/software.component.html +++ b/admin/WebConsole3/frontend/src/app/pages/software/software.component.html @@ -1 +1,65 @@ -<div>Html template for class Software</div>
\ No newline at end of file +<ng-container> + <section class="content-header"> + <h1 translate="software"> + </h1> + <ol class="breadcrumb"> + <li><a [routerLink]="'/app/dashboard'"><i class="fa fa-dashboard"></i> {{'dashboard'|translate}}</a></li> + <li class="active" translate="software"></li> + </ol> + </section> + <section fixed-toolboxbar class="toolboxbar"> + <div > + <div class="col-md-12"> + <div class="input-group"> + <input type="text" name="q" class="form-control" placeholder="{{'search'|translate}}..." ng-model="vm.searchText"> + <span class="input-group-btn"> + <button type="button" name="search" id="search-btn" class="btn btn-flat"><i class="fa fa-search"></i> + </button> + </span> + </div> + </div> + <div class="col-md-12" style="margin-top: 5px;margin-bottom: 5px;"> + <div class="box-tools pull-right"> + <mk-dropdown class="btn-group"> + <mk-dropdown-toggle> + <span translate="new"></span><span class="caret"></span> + </mk-dropdown-toggle> + <mk-dropdown-menu> + <li role="presentation"><a role="menuitem" tabindex="-1" [routerLink]="'/app/software/profile/create'" translate="profile"></a></li> + <li role="presentation"><a role="menuitem" tabindex="-1" [routerLink]="'/app/software/component/create'" translate="component"></a></li> + <!--li role="presentation"><a role="menuitem" tabindex="-1" [routerLink]="app/software.type.new" translate="software_type"></a></li--> + </mk-dropdown-menu> + </mk-dropdown> + </div> + </div> + </div> + </section> + <section class="content"> + <div class="row"> + <span style="padding: 0 10px"></span> + <div class="col-md-12"> + <mk-tabs> + <mk-tab> + <mk-tab-header><span translate="software_profiles"></span></mk-tab-header> + <mk-tab-content> + <app-software-profiles [softwareProfileGroups]="softwareProfileGroups"></app-software-profiles> + </mk-tab-content> + </mk-tab> + <mk-tab> + <mk-tab-header><span translate="software_components"></span></mk-tab-header> + <mk-tab-content> + <app-software-components [softwareComponentsGroups]="softwareComponentsGroups" [softwareTypes]="softwareTypes"></app-software-components> + </mk-tab-content> + </mk-tab> + <mk-tab> + <mk-tab-header><span translate="software_types"></span></mk-tab-header> + <mk-tab-content> + <app-software-types [softwareTypes]="softwareTypes" ></app-software-types> + </mk-tab-content> + </mk-tab> + </mk-tabs> + <!-- /.tab-content --> + </div> + </div> + </section> +</ng-container> diff --git a/admin/WebConsole3/frontend/src/app/pages/software/software.component.scss b/admin/WebConsole3/frontend/src/app/pages/software/software.component.scss deleted file mode 100644 index b936796b..00000000 --- a/admin/WebConsole3/frontend/src/app/pages/software/software.component.scss +++ /dev/null @@ -1,3 +0,0 @@ -software {
-
-}
diff --git a/admin/WebConsole3/frontend/src/app/pages/software/software.component.ts b/admin/WebConsole3/frontend/src/app/pages/software/software.component.ts index ef75722b..a51d9560 100644 --- a/admin/WebConsole3/frontend/src/app/pages/software/software.component.ts +++ b/admin/WebConsole3/frontend/src/app/pages/software/software.component.ts @@ -1,17 +1,67 @@ -import { Component } from '@angular/core';
-
-import { SoftwareService } from 'src/app/api/software.service';
-import { Software } from 'src/app/model/software';
-
-@Component({
- selector: 'software',
- templateUrl: './software.component.html',
- styleUrls: [ './software.component.scss' ]
-})
-export class SoftwareComponent {
- // this tells the tabs component which Pages
- // should be each tab's root Page
- constructor(public softwareService: SoftwareService) {
- }
-
-}
+import { Component, OnInit } from '@angular/core'; +import {AuthModule} from 'globunet-angular/core'; +import {SoftwareProfileService} from '../../api/software-profile.service'; +import {OgCommonService} from '../../service/og-common.service'; +import {TranslateService} from '@ngx-translate/core'; +import {SoftwareComponentService} from '../../api/software-component.service'; +import {OgSweetAlertService} from '../../service/og-sweet-alert.service'; +import {ToasterService} from '../../service/toaster.service'; +import {SoftwareTypeService} from '../../api/software-type.service'; + +@Component({ + selector: 'app-software', + templateUrl: './software.component.html', + styleUrls: ['./software.component.css'] +}) +export class SoftwareComponent implements OnInit { + public softwareProfileGroups: any[] = []; + public softwareComponentsGroups: any[][]; + public softwareComponents: any[] = []; + public softwareTypes: any[] = []; + + constructor(private authModule: AuthModule, + private ogSweetAlert: OgSweetAlertService, + private toaster: ToasterService, + private softwareComponentService: SoftwareComponentService, + private softwareTypeService: SoftwareTypeService, + private softwareProfileService: SoftwareProfileService, + private OGCommonService: OgCommonService, + private translate: TranslateService) { } + + ngOnInit() { + if (this.authModule.getLoggedUser().id !== 0) { + this.softwareProfileService.list().subscribe( + (response) => { + this.softwareProfileGroups = [ + this.OGCommonService.createGroups(response, 'profiles') + ]; + this.softwareProfileGroups[0].name = this.translate.instant('software_profiles'); + }, + (error) => { + alert(error); + } + ); + this.softwareTypeService.list().subscribe( + data => { + this.softwareTypes = data; + }, + (error) => { + alert(error); + } + ); + this.softwareComponentService.list().subscribe( + data => { + this.softwareComponents = data; + this.softwareComponentsGroups = [ + this.OGCommonService.createGroups(this.softwareComponents, 'components') + ]; + // @ts-ignore + this.softwareComponentsGroups[0].name = this.translate.instant('software_components'); + }, + error => { + alert(error); + } + ); + } + } +} diff --git a/admin/WebConsole3/frontend/src/app/serializer/image.serializer.ts b/admin/WebConsole3/frontend/src/app/serializer/image.serializer.ts index f6004e6a..c2043805 100644 --- a/admin/WebConsole3/frontend/src/app/serializer/image.serializer.ts +++ b/admin/WebConsole3/frontend/src/app/serializer/image.serializer.ts @@ -1,5 +1,16 @@ -import { Serializer } from "globunet-angular/core/providers/api/serializer";
-
-export class ImageSerializer extends Serializer {
-
-}
\ No newline at end of file +import { Serializer } from 'globunet-angular/core/providers/api/serializer'; +import {Image} from '../model/image'; + +export class ImageSerializer extends Serializer { + + toJson(resource: Image): any { + const image: any = Object.assign({}, resource); + if (image.client && image.client.id) { + image.client = image.client.id; + } + if (image.repository && image.repository.id) { + image.repository = image.repository.id; + } + return super.toJson(image); + } +} diff --git a/admin/WebConsole3/frontend/src/app/service/og-commands.service.ts b/admin/WebConsole3/frontend/src/app/service/og-commands.service.ts index 7ea08bb8..14e80e84 100644 --- a/admin/WebConsole3/frontend/src/app/service/og-commands.service.ts +++ b/admin/WebConsole3/frontend/src/app/service/og-commands.service.ts @@ -1,236 +1,235 @@ -import {ToasterService} from './toaster.service';
-import {OgSweetAlertService} from './og-sweet-alert.service';
-import {CommandService} from '../api/command.service';
-import {OgCommonService} from './og-common.service';
-import {TranslateService} from '@ngx-translate/core';
-import {Router} from '@angular/router';
-import {Injectable} from '@angular/core';
-import * as _ from 'lodash';
-import {environment} from '../../environments/environment';
-
-@Injectable({
- providedIn: 'root'
-})
-export class OGCommandsService {
- public ogInstructions = '';
- public execution: any;
- private commands = [];
-
- constructor(private router: Router, private ogCommonService: OgCommonService, private toaster: ToasterService, private ogSweetAlert: OgSweetAlertService, private commandService: CommandService, private translate: TranslateService) {
- this.execution = {};
- this.ogCommonService.loadEngineConfig().subscribe(
- (response) => {
- this.commands = response.constants.commandtypes;
- }
- );
- }
-
- sendCommand() {
- let result = true;
- // TODO - Comprobar parametros
- if (!this.execution.script) {
- result = false;
- this.toaster.pop({type: 'error', title: 'error', body: this.translate.instant('command_not_valid')});
- } else if (!this.execution.clients) {
- result = false;
- this.toaster.pop({type: 'error', title: 'error', body: this.translate.instant('not_clients_selected')});
- }
- // Si no hubo ningun error
- if (result === true) {
- this.execution.script = this.execution.script.replace(/\"/g, '\\"').replace(/\$/g, '\\\$');
- // Resetar las instrucciones del script opengnsys almacenadas.
- this.ogInstructions = '';
- this.commandService.execute(this.execution).subscribe(
- (response: any[]) => {
- // Buscar en la respuesta si hay algún statuscode diferente de 200
- const errors = response.filter(function(value) {
- return (value.statusCode && value.statusCode !== '!200');
- } );
- let errorStr = '';
- let toasterOpts = {type: 'success', title: 'success', body: this.translate.instant('successfully_executed')};
- if (errors.length > 0) {
- for (let e = 0; e < errors.length; e++) {
- errorStr += this.translate.instant('execution_failed_in') + ' ' + errors[e].name + '\n';
- }
-
- toasterOpts = {type: 'error', title: 'error', body: errorStr};
- }
- this.toaster.pop(toasterOpts);
- this.router.navigate(['/app/ous']);
- },
- (error) => {
- this.toaster.pop({type: 'error', title: 'error', body: error});
- }
- );
- }
- }
-
- execute(command, params?) {
-
- this.execution.type = command;
-
- if (command === 'HISTORY_LOG') {
- let clientIp = null;
- // Abrir ventana de log
- if (typeof params === 'undefined' || typeof params.clientIp === 'undefined') {
- const client = this.ogCommonService.selectedClients[Object.keys(this.ogCommonService.selectedClients)[0]];
- if (client) {
- clientIp = client.ip;
- }
- } else {
- clientIp = params.clientIp;
- }
-
- if (clientIp) {
- const url = 'http://' + clientIp + environment.commands.HISTORY_LOG;
- window.open(url, '', 'resizable=yes,toolbar=no,status=no,location=no,menubar=no,scrollbars=yes');
- }
- } else if (command === 'REALTIME_LOG') {
- let clientIp = null;
- // Abrir ventana de log
- if (typeof params === 'undefined' || typeof params.clientIp === 'undefined') {
- const client = this.ogCommonService.selectedClients[Object.keys(this.ogCommonService.selectedClients)[0]];
- if (client) {
- clientIp = client.ip;
- }
- } else {
- clientIp = params.clientIp;
- }
-
- if (clientIp) {
- const url = 'http://' + clientIp + environment.commands.REALTIME_LOG;
- window.open(url, '', 'resizable=yes,toolbar=no,status=no,location=no,menubar=no,scrollbars=yes');
- }
- } else if (command === 'SOFTWARE_INVENTORY') {
- const client = this.ogCommonService.selectedClients[Object.keys(this.ogCommonService.selectedClients)[0]];
- // Preparar el scope para el sweet alert
- const options = {
- scope: {
- partitions: [],
- selectedPart: null
- }
- };
-
- // Comprobar tipo de cada particion para ver si es clonable
- // var parttable = $rootScope.constants.partitiontable[client.partitions[0].partitionCode-1];
- // buscar las particiones que sean clonables
- for (let index = 1; index < client.partitions.length; index++) {
- if (client.partitions[index].osName !== 'DATA' && client.partitions[index].osName !== '') {
- // Crear como nombre para mostrar, el disco y partición del sistema
- const obj = Object.assign({}, client.partitions[index]);
- obj.name = 'disco: ' + obj.numDisk + ', part: ' + obj.numPartition + ', SO: ' + client.partitions[index].osName;
- options.scope.partitions.push(obj);
- }
- }
-
- this.ogSweetAlert.swal({
- title: this.translate.instant('select_partition_to_inventary'),
- // text: $filter("translate")("action_cannot_be_undone"),
- type: 'info',
- input: 'select',
- inputOptions: options.scope.partitions,
- showCancelButton: true,
- confirmButtonColor: '#3c8dbc',
- confirmButtonText: this.translate.instant('done'),
- closeOnConfirm: true
- }).then(
- function(result) {
- if (result.value) {
- // Montar el script con el disco y partición elegida
- this.execution.script = this.commands.SOFTWARE_INVENTORY + ' ' + result.value;
- this.loadClients();
- this.sendCommand();
- }
- },
- null);
- } else {
- if (command === 'REBOOT') {
- this.execution.script = environment.commands.REBOOT;
- } else if (command === 'POWER_OFF') {
- this.execution.script = environment.commands.POWER_OFF;
- } else if (command === 'POWER_ON') {
- this.execution.script = 'wakeonlan';
- } else if (command === 'HARDWARE_INVENTORY') {
- this.execution.script = environment.commands.HARDWARE_INVENTORY;
- } else if (command === 'RUN_SCRIPT') {
- this.execution.script = params ? (params.script || this.ogInstructions) : this.ogInstructions;
- } else if (command === 'REFRESH_INFO') {
- this.execution.script = environment.commands.REFRESH_INFO;
- }
-
- // Comprobar si en los parametros viene la opcion de guardar
- if (typeof params !== 'undefined' && params.save === true) {
- const self = this;
- // Mostrar cuadro de dialogo para guardar procedimiento
- this.ogSweetAlert.swal({
- title: this.translate.instant('new_command_name'),
- type: 'info',
- html:
- '<form style="text-align: left; padding-left: 10px">\
- <div class="form-group">\
- <label for="execute" translate="execute">\
- </label>\
- <div class="checkbox clip-check check-primary checkbox-inline">\
- <input id="execute" icheck checkbox-class="icheckbox_square-blue" radio-class="iradio_square-blue" type="checkbox" class="selection-checkbox" />\
- </div>\
- </div>\
- <div class="form-group">\
- <label translate="title"></label>\
- <input type="text" class="form-control" id="command.title" />\
- </div>\
- <div class="form-group">\
- <label for="parameters" translate="parameters"></label>\
- <div class="checkbox clip-check check-primary checkbox-inline">\
- <input id="parameters" icheck checkbox-class="icheckbox_square-blue" radio-class="iradio_square-blue" type="checkbox" class="selection-checkbox" />\
- </div>\
- <p class="help-block" translate="help_command_parameters"></p>\
- </div>\
- </form>',
- showCancelButton: true,
- confirmButtonColor: '#3c8dbc',
- confirmButtonText: this.translate.instant('done'),
- closeOnConfirm: true,
- preConfirm: () => {
- return {
- execute: (<HTMLInputElement>document.getElementById('execute')).value,
- command: {
- title: (<HTMLInputElement>document.getElementById('command.title')).value,
- parameters: (<HTMLInputElement>document.getElementById('parameters')).value
- }
- };
- }
- }).then(
- function(response) {
- if (response.value) {
- response.value.command.script = this.execution.script;
- response.value.command.type = this.execution.type;
- self.commandService.create(response.value.command).subscribe(
- (success) => {
- // Si se seleccionó continuar con la ejecución
- if (response.value.execute) {
- self.loadClients();
- self.sendCommand();
- } else {
- self.router.navigate(['app/commands']);
- }
- },
- (error) => {
- self.toaster.pop({type: 'error', title: 'error', body: error});
- }
- );
- }
- });
- } else {
- this.loadClients();
- this.sendCommand();
- }
- }
- }
-
- loadClients() {
- if (this.ogCommonService.selectedClients) {
- this.execution.clients = _.join(Object.keys(this.ogCommonService.selectedClients));
- }
- }
-
-}
+import {ToasterService} from './toaster.service'; +import {OgSweetAlertService} from './og-sweet-alert.service'; +import {CommandService} from '../api/command.service'; +import {OgCommonService} from './og-common.service'; +import {TranslateService} from '@ngx-translate/core'; +import {Router} from '@angular/router'; +import {Injectable} from '@angular/core'; +import * as _ from 'lodash'; +import {environment} from '../../environments/environment'; + +@Injectable({ + providedIn: 'root' +}) +export class OGCommandsService { + public ogInstructions = ''; + public execution: any; + private commands = []; + + constructor(private router: Router, private ogCommonService: OgCommonService, private toaster: ToasterService, private ogSweetAlert: OgSweetAlertService, private commandService: CommandService, private translate: TranslateService) { + this.execution = {}; + this.ogCommonService.loadEngineConfig().subscribe( + (response) => { + this.commands = response.constants.commandtypes; + } + ); + } + + sendCommand() { + let result = true; + // TODO - Comprobar parametros + if (!this.execution.script) { + result = false; + this.toaster.pop({type: 'error', title: 'error', body: this.translate.instant('command_not_valid')}); + } else if (!this.execution.clients) { + result = false; + this.toaster.pop({type: 'error', title: 'error', body: this.translate.instant('not_clients_selected')}); + } + // Si no hubo ningun error + if (result === true) { + this.execution.script = this.execution.script.replace(/\"/g, '\\"').replace(/\$/g, '\\\$'); + // Resetar las instrucciones del script opengnsys almacenadas. + this.ogInstructions = ''; + this.commandService.execute(this.execution).subscribe( + (response: any[]) => { + // Buscar en la respuesta si hay algún statuscode diferente de 200 + const errors = response.filter(function(value) { + return (value.statusCode && value.statusCode !== '!200'); + } ); + let errorStr = ''; + let toasterOpts = {type: 'success', title: 'success', body: this.translate.instant('successfully_executed')}; + if (errors.length > 0) { + for (let e = 0; e < errors.length; e++) { + errorStr += this.translate.instant('execution_failed_in') + ' ' + errors[e].name + '\n'; + } + + toasterOpts = {type: 'error', title: 'error', body: errorStr}; + } + this.toaster.pop(toasterOpts); + this.router.navigate(['/app/ous']); + }, + (error) => { + this.toaster.pop({type: 'error', title: 'error', body: error}); + } + ); + } + } + + execute(command, params?) { + + this.execution.type = command; + + if (command === 'HISTORY_LOG') { + let clientIp = null; + // Abrir ventana de log + if (typeof params === 'undefined' || typeof params.clientIp === 'undefined') { + const client = this.ogCommonService.selectedClients[Object.keys(this.ogCommonService.selectedClients)[0]]; + if (client) { + clientIp = client.ip; + } + } else { + clientIp = params.clientIp; + } + + if (clientIp) { + const url = 'http://' + clientIp + environment.commands.HISTORY_LOG; + window.open(url, '', 'resizable=yes,toolbar=no,status=no,location=no,menubar=no,scrollbars=yes'); + } + } else if (command === 'REALTIME_LOG') { + let clientIp = null; + // Abrir ventana de log + if (typeof params === 'undefined' || typeof params.clientIp === 'undefined') { + const client = this.ogCommonService.selectedClients[Object.keys(this.ogCommonService.selectedClients)[0]]; + if (client) { + clientIp = client.ip; + } + } else { + clientIp = params.clientIp; + } + + if (clientIp) { + const url = 'http://' + clientIp + environment.commands.REALTIME_LOG; + window.open(url, '', 'resizable=yes,toolbar=no,status=no,location=no,menubar=no,scrollbars=yes'); + } + } else if (command === 'SOFTWARE_INVENTORY') { + const client = this.ogCommonService.selectedClients[Object.keys(this.ogCommonService.selectedClients)[0]]; + // Preparar el scope para el sweet alert + const options = { + scope: { + partitions: [], + selectedPart: null + } + }; + + // Comprobar tipo de cada particion para ver si es clonable + // var parttable = $rootScope.constants.partitiontable[client.partitions[0].partitionCode-1]; + // buscar las particiones que sean clonables + for (let index = 1; index < client.partitions.length; index++) { + if (client.partitions[index].osName !== 'DATA' && client.partitions[index].osName !== '') { + // Crear como nombre para mostrar, el disco y partición del sistema + const obj = Object.assign({}, client.partitions[index]); + obj.name = 'disco: ' + obj.numDisk + ', part: ' + obj.numPartition + ', SO: ' + client.partitions[index].osName; + options.scope.partitions.push(obj); + } + } + + this.ogSweetAlert.swal({ + title: this.translate.instant('select_partition_to_inventary'), + // text: $filter("translate")("action_cannot_be_undone"), + type: 'info', + input: 'select', + inputOptions: options.scope.partitions, + showCancelButton: true, + confirmButtonColor: '#3c8dbc', + confirmButtonText: this.translate.instant('done'), + closeOnConfirm: true + }).then( + function(result) { + if (result.value) { + // Montar el script con el disco y partición elegida + this.execution.script = this.commands.SOFTWARE_INVENTORY + ' ' + result.value; + this.loadClients(); + this.sendCommand(); + } + }, + null); + } else { + if (command === 'REBOOT') { + this.execution.script = environment.commands.REBOOT; + } else if (command === 'POWER_OFF') { + this.execution.script = environment.commands.POWER_OFF; + } else if (command === 'POWER_ON') { + this.execution.script = 'wakeonlan'; + } else if (command === 'HARDWARE_INVENTORY') { + this.execution.script = environment.commands.HARDWARE_INVENTORY; + } else if (command === 'RUN_SCRIPT') { + this.execution.script = params ? (params.script || this.ogInstructions) : this.ogInstructions; + } else if (command === 'REFRESH_INFO') { + this.execution.script = environment.commands.REFRESH_INFO; + } + + // Comprobar si en los parametros viene la opcion de guardar + if (typeof params !== 'undefined' && params.save === true) { + const self = this; + // Mostrar cuadro de dialogo para guardar procedimiento + this.ogSweetAlert.swal({ + title: this.translate.instant('new_command_name'), + type: 'info', + html: + '<form style="text-align: left; padding-left: 10px">\ + <div class="form-group">\ + <label for="execute">' + this.translate.instant('execute') + '</label>\ + <div class="checkbox clip-check check-primary checkbox-inline">\ + <input id="execute" icheck checkbox-class="icheckbox_square-blue" radio-class="iradio_square-blue" type="checkbox" class="selection-checkbox" />\ + </div>\ + </div>\ + <div class="form-group">\ + <label>' + this.translate.instant('title') + '</label>\ + <input type="text" class="form-control" id="command.title" />\ + </div>\ + <div class="form-group">\ + <label for="parameters">' + this.translate.instant('parameters') + '</label>\ + <div class="checkbox clip-check check-primary checkbox-inline">\ + <input id="parameters" icheck checkbox-class="icheckbox_square-blue" radio-class="iradio_square-blue" type="checkbox" class="selection-checkbox" />\ + </div>\ + <p class="help-block">' + this.translate.instant('help_command_parameters') + '</p>\ + </div>\ + </form>', + showCancelButton: true, + confirmButtonColor: '#3c8dbc', + confirmButtonText: this.translate.instant('done'), + closeOnConfirm: true, + preConfirm: () => { + return { + execute: (<HTMLInputElement>document.getElementById('execute')).checked, + command: { + title: (<HTMLInputElement>document.getElementById('command.title')).value, + parameters: (<HTMLInputElement>document.getElementById('parameters')).checked + } + }; + } + }).then( + function(response) { + if (response.value) { + response.value.command.script = self.execution.script; + response.value.command.type = self.execution.type; + self.commandService.create(response.value.command).subscribe( + (success) => { + // Si se seleccionó continuar con la ejecución + if (response.value.execute) { + self.loadClients(); + self.sendCommand(); + } else { + self.router.navigate(['app/commands']); + } + }, + (error) => { + self.toaster.pop({type: 'error', title: 'error', body: error}); + } + ); + } + }); + } else { + this.loadClients(); + this.sendCommand(); + } + } + } + + loadClients() { + if (this.ogCommonService.selectedClients) { + this.execution.clients = _.join(Object.keys(this.ogCommonService.selectedClients)); + } + } + +} diff --git a/admin/WebConsole3/frontend/src/app/service/og-common.service.ts b/admin/WebConsole3/frontend/src/app/service/og-common.service.ts index ee5a8a9d..8a2bbe56 100644 --- a/admin/WebConsole3/frontend/src/app/service/og-common.service.ts +++ b/admin/WebConsole3/frontend/src/app/service/og-common.service.ts @@ -42,7 +42,8 @@ export class OgCommonService { ou: environment.ou, themes: environment.themes, menus: environment.menus, - languages: environment.languages + languages: environment.languages, + deployMethods: environment.deployMethods }; this.constants = Object.assign(this.constants, data[0]); // inicializar timers generales para refresco de información diff --git a/admin/WebConsole3/frontend/src/styles.scss b/admin/WebConsole3/frontend/src/styles.scss index 57a04153..65c2fd6d 100644 --- a/admin/WebConsole3/frontend/src/styles.scss +++ b/admin/WebConsole3/frontend/src/styles.scss @@ -1,4 +1,8 @@ /* You can add global styles to this file, and also import other style files */ +.input-group { + width: 100%; +} + .capitalize { text-transform: capitalize; } |