summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--admin/WebConsole3/frontend/src/app/app-routing.module.ts19
-rw-r--r--admin/WebConsole3/frontend/src/app/app.component.html12
-rw-r--r--admin/WebConsole3/frontend/src/app/app.module.ts15
-rw-r--r--admin/WebConsole3/frontend/src/app/core/header-inner/header-inner.component.html22
-rw-r--r--admin/WebConsole3/frontend/src/app/core/header-inner/header-inner.component.ts2
-rw-r--r--admin/WebConsole3/frontend/src/app/core/sidebar-left-inner/sidebar-left-inner.component.html2
-rw-r--r--admin/WebConsole3/frontend/src/app/core/sidebar-left-inner/sidebar-left-inner.component.ts22
-rw-r--r--admin/WebConsole3/frontend/src/app/form-type/menu.form-type.ts4
-rw-r--r--admin/WebConsole3/frontend/src/app/form-type/repository.form-type.ts20
-rw-r--r--admin/WebConsole3/frontend/src/app/model/image.ts1
-rw-r--r--admin/WebConsole3/frontend/src/app/model/repository.ts42
-rw-r--r--admin/WebConsole3/frontend/src/app/pages/command/delete-cache-image-command/delete-cache-image-command.component.html62
-rw-r--r--admin/WebConsole3/frontend/src/app/pages/command/delete-cache-image-command/delete-cache-image-command.component.scss3
-rw-r--r--admin/WebConsole3/frontend/src/app/pages/command/delete-cache-image-command/delete-cache-image-command.component.ts120
-rw-r--r--admin/WebConsole3/frontend/src/app/pages/command/format-command/format-command.component.html96
-rw-r--r--admin/WebConsole3/frontend/src/app/pages/command/format-command/format-command.component.scss3
-rw-r--r--admin/WebConsole3/frontend/src/app/pages/command/format-command/format-command.component.ts150
-rw-r--r--admin/WebConsole3/frontend/src/app/pages/command/partition-format-command/partition-format-command.component.html164
-rw-r--r--admin/WebConsole3/frontend/src/app/pages/command/partition-format-command/partition-format-command.component.scss22
-rw-r--r--admin/WebConsole3/frontend/src/app/pages/command/partition-format-command/partition-format-command.component.ts618
-rw-r--r--admin/WebConsole3/frontend/src/app/pages/common/directive/col-resizable.directive.ts81
-rw-r--r--admin/WebConsole3/frontend/src/app/pages/common/og-options/og-selected-clients/og-selected-clients.component.html14
-rw-r--r--admin/WebConsole3/frontend/src/app/pages/common/table-action/ng2-table-action.component.css6
-rw-r--r--admin/WebConsole3/frontend/src/app/pages/dashboard/dashboard.component.ts4
-rw-r--r--admin/WebConsole3/frontend/src/app/pages/hardware-component/hardware-component.component.html9
-rw-r--r--admin/WebConsole3/frontend/src/app/pages/hardware-component/hardware-component.component.ts65
-rw-r--r--admin/WebConsole3/frontend/src/app/pages/image/image.component.ts292
-rw-r--r--admin/WebConsole3/frontend/src/app/pages/menu/edit/menu-edit.component.html7
-rw-r--r--admin/WebConsole3/frontend/src/app/pages/menu/edit/menu-edit.component.ts3
-rw-r--r--admin/WebConsole3/frontend/src/app/pages/menu/menu.component.ts19
-rw-r--r--admin/WebConsole3/frontend/src/app/pages/organizational-unit/organizational-unit.component.ts5
-rw-r--r--admin/WebConsole3/frontend/src/app/pages/organizational-unit/ou-clients/ou-client.component.html2
-rw-r--r--admin/WebConsole3/frontend/src/app/pages/organizational-unit/ou-clients/ou-client.component.scss11
-rw-r--r--admin/WebConsole3/frontend/src/app/pages/organizational-unit/ou-clients/ou-client.component.ts3
-rw-r--r--admin/WebConsole3/frontend/src/app/pages/organizational-unit/ou-group/ou-group.component.ts14
-rw-r--r--admin/WebConsole3/frontend/src/app/pages/profile/profile.component.html9
-rw-r--r--admin/WebConsole3/frontend/src/app/pages/profile/profile.component.ts1
-rw-r--r--admin/WebConsole3/frontend/src/app/pages/repository/repository.component.html200
-rw-r--r--admin/WebConsole3/frontend/src/app/pages/software/software.component.scss (renamed from admin/WebConsole3/frontend/src/app/pages/software/software.component.css)0
-rw-r--r--admin/WebConsole3/frontend/src/app/pages/software/software.component.ts2
-rw-r--r--admin/WebConsole3/frontend/src/app/pages/trace/trace.component.ts524
-rw-r--r--admin/WebConsole3/frontend/src/app/service/og-commands.service.ts22
-rw-r--r--admin/WebConsole3/frontend/src/app/service/og-common.service.ts27
-rw-r--r--admin/WebConsole3/frontend/src/styles.scss17
44 files changed, 2089 insertions, 647 deletions
diff --git a/admin/WebConsole3/frontend/src/app/app-routing.module.ts b/admin/WebConsole3/frontend/src/app/app-routing.module.ts
index 80d357fa..f91738a4 100644
--- a/admin/WebConsole3/frontend/src/app/app-routing.module.ts
+++ b/admin/WebConsole3/frontend/src/app/app-routing.module.ts
@@ -27,6 +27,9 @@ 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';
+import {DeleteCacheImageCommandComponent} from './pages/command/delete-cache-image-command/delete-cache-image-command.component';
+import {FormatCommandComponent} from './pages/command/format-command/format-command.component';
+import {PartitionFormatCommandComponent} from './pages/command/partition-format-command/partition-format-command.component';
const routes: Routes = [
@@ -132,10 +135,18 @@ const routes: Routes = [
component: MenuEditComponent
},
{
+ path: 'menus/edit/:id',
+ component: MenuEditComponent
+ },
+ {
path: 'commands',
component: CommandComponent
},
{
+ path: 'commands/partition_format',
+ component: PartitionFormatCommandComponent
+ },
+ {
path: 'commands/deploy_image',
component: DeployImageCommandComponent
},
@@ -152,6 +163,14 @@ const routes: Routes = [
component: CreateImageCommandComponent
},
{
+ path: 'commands/delete_cache_image',
+ component: DeleteCacheImageCommandComponent
+ },
+ {
+ path: 'commands/format',
+ component: FormatCommandComponent
+ },
+ {
path: 'commands/:id',
component: EditCommandComponent
},
diff --git a/admin/WebConsole3/frontend/src/app/app.component.html b/admin/WebConsole3/frontend/src/app/app.component.html
index 8e5b9670..d6c88664 100644
--- a/admin/WebConsole3/frontend/src/app/app.component.html
+++ b/admin/WebConsole3/frontend/src/app/app.component.html
@@ -4,8 +4,8 @@
<ng-template #layoutEnabled>
<mk-layout-wrapper>
<mk-layout-header logoLink="/">
- <mk-layout-header-logo><b>Angular </b>AdminLTE</mk-layout-header-logo>
- <mk-layout-header-logo-mini><b>A</b>LTE</mk-layout-header-logo-mini>
+ <mk-layout-header-logo>Open<b>GnSys</b> 3</mk-layout-header-logo>
+ <mk-layout-header-logo-mini>O<b>G</b>3</mk-layout-header-logo-mini>
<app-header-inner></app-header-inner>
</mk-layout-header>
<mk-layout-sidebar-left>
@@ -15,12 +15,12 @@
<app-sidebar-right-inner></app-sidebar-right-inner>
</mk-layout-sidebar-right>
<mk-layout-content>
- <div mk-layout-content-before-header>
- <div *mkLoadingPage="{checkPendingHttp: true, checkPendingRoute: true}">
- <mk-material-bar></mk-material-bar>
+ <router-outlet></router-outlet>
+ <div>
+ <div class="loader" *mkLoadingPage="{checkPendingHttp: true, checkPendingRoute: true}">
+ <mk-circle></mk-circle>
</div>
</div>
- <router-outlet></router-outlet>
</mk-layout-content>
<mk-layout-footer>
<mk-layout-footer-left>
diff --git a/admin/WebConsole3/frontend/src/app/app.module.ts b/admin/WebConsole3/frontend/src/app/app.module.ts
index 5f861c65..34af2cb2 100644
--- a/admin/WebConsole3/frontend/src/app/app.module.ts
+++ b/admin/WebConsole3/frontend/src/app/app.module.ts
@@ -10,7 +10,7 @@ import {AuthModule, TokenInterceptorService} from 'globunet-angular/core';
import {HTTP_INTERCEPTORS, HttpClient, HttpClientModule} from '@angular/common/http';
import {LoginComponent} from './pages/login/login.component';
import {ImageComponent} from './pages/image/image.component';
-import { LoadingPageModule, MaterialBarModule } from 'angular-loading-page';
+import { LoadingPageModule, CircleModule } from 'angular-loading-page';
import { DashboardComponent } from './pages/dashboard/dashboard.component';
import {TranslateHttpLoader} from '@ngx-translate/http-loader';
import {TranslateLoader, TranslateModule, TranslateService} from '@ngx-translate/core';
@@ -75,6 +75,10 @@ import {SoftwareComponentsGroupComponent} from './pages/software/software-compon
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';
+import {DeleteCacheImageCommandComponent} from './pages/command/delete-cache-image-command/delete-cache-image-command.component';
+import {FormatCommandComponent} from './pages/command/format-command/format-command.component';
+import {PartitionFormatCommandComponent} from './pages/command/partition-format-command/partition-format-command.component';
+import {ColResizableDirective} from './pages/common/directive/col-resizable.directive';
@@ -121,9 +125,13 @@ import {CreateImageCommandComponent} from './pages/command/create-image-command/
LoginCommandComponent,
ExecuteCommandComponent,
CreateImageCommandComponent,
+ DeleteCacheImageCommandComponent,
+ FormatCommandComponent,
+ PartitionFormatCommandComponent,
EditCommandComponent,
IcheckDirective,
FixedToolboxBarDirective,
+ ColResizableDirective,
OgInformationOptionsComponent,
OgCommandsOptionsComponent,
OgExecuteCommandOptionsComponent,
@@ -166,6 +174,9 @@ import {CreateImageCommandComponent} from './pages/command/create-image-command/
LoginCommandComponent,
ExecuteCommandComponent,
CreateImageCommandComponent,
+ DeleteCacheImageCommandComponent,
+ FormatCommandComponent,
+ PartitionFormatCommandComponent,
EditCommandComponent,
OgOuGeneralOptionsComponent,
TraceComponent,
@@ -179,7 +190,7 @@ import {CreateImageCommandComponent} from './pages/command/create-image-command/
CoreModule,
DropdownModule,
LayoutModule.forRoot(AdminLteConf.staticConf),
- LoadingPageModule, MaterialBarModule,
+ LoadingPageModule, CircleModule,
BrowserAnimationsModule,
HttpClientModule,
AuthModule.forRoot(environment),
diff --git a/admin/WebConsole3/frontend/src/app/core/header-inner/header-inner.component.html b/admin/WebConsole3/frontend/src/app/core/header-inner/header-inner.component.html
index ad565376..31b4286d 100644
--- a/admin/WebConsole3/frontend/src/app/core/header-inner/header-inner.component.html
+++ b/admin/WebConsole3/frontend/src/app/core/header-inner/header-inner.component.html
@@ -2,20 +2,16 @@
<ul class="nav navbar-nav">
<li mk-dropdown type="list" [isWrapper]="false" class="notifications-menu">
<mk-dropdown-toggle>
- <a [routerLink]="'/app/traces'" *ngIf="executionTasks.length == 0" #toggleElement>
- <i class="fa fa-bell-o"></i>
- </a>
- <a *ngIf="executionTasks.length > 0" #toggleElement>
- <i class="fa fa-bell-o"></i>
- <span class="label label-warning" *ngIf="executionTasks.length > 0">{{executionTasks.length}}</span>
- </a>
+ <a #toggleElement>
+ <i class="fa fa-bell-o"></i>
+ <span class="label label-warning" *ngIf="executionTasks.length > 0">{{executionTasks.length}}</span>
+ </a>
</mk-dropdown-toggle>
- <mk-dropdown-menu *ngIf="executionTasks.length > 0">
- <li class="header">You have 10 notifications</li>
- <li class="header">
+ <mk-dropdown-menu>
+ <li class="header" *ngIf="executionTasks.length > 0">
<span translate="you_have_x_exectution_taks" translate-values="{values: executionTasks.length}"></span>
</li>
- <li>
+ <li *ngIf="executionTasks.length > 0">
<!-- inner menu: contains the actual data -->
<ul class="menu" *ngFor="let task of executionTasks">
<li>
@@ -25,7 +21,7 @@
</a>
<a href="javascript:void(0)" (click)="relaunchExecutionTask(task)" class="btn btn-sm pull-right small-box-footer">
<i class="fa fa-refresh"></i>
- </a>
+ </a>A
</div>
<a href="javascript:void(0)" (click)="ogCommandsService.execute('REALTIME_LOG', {clientIp: task.client.ip})">
<i class="fa fa-warning text-yellow"></i> {{task.client.name}} ({{task.client.ip}})<br>{{task.commandType|translate}}
@@ -36,7 +32,7 @@
<li class="footer">
<a href="javascript:void(0)" translate="view_all" [routerLink]="['/app/traces']"></a>
</li>
- </mk-dropdown-menu>
+ </mk-dropdown-menu>
</li>
<!-- Tasks: style can be found in dropdown.less -->
<li mk-dropdown type="list" [isWrapper]="false" class="tasks-menu">
diff --git a/admin/WebConsole3/frontend/src/app/core/header-inner/header-inner.component.ts b/admin/WebConsole3/frontend/src/app/core/header-inner/header-inner.component.ts
index d009ebe7..8aaef052 100644
--- a/admin/WebConsole3/frontend/src/app/core/header-inner/header-inner.component.ts
+++ b/admin/WebConsole3/frontend/src/app/core/header-inner/header-inner.component.ts
@@ -62,7 +62,7 @@ export class HeaderInnerComponent implements OnInit {
self.getExectutionTasks();
},
function(error) {
- this.toaster.pop({type: 'error', title: 'error', body: error});
+ self.toaster.pop({type: 'error', title: 'error', body: error});
}
);
diff --git a/admin/WebConsole3/frontend/src/app/core/sidebar-left-inner/sidebar-left-inner.component.html b/admin/WebConsole3/frontend/src/app/core/sidebar-left-inner/sidebar-left-inner.component.html
index 7b2b79b6..68bebc52 100644
--- a/admin/WebConsole3/frontend/src/app/core/sidebar-left-inner/sidebar-left-inner.component.html
+++ b/admin/WebConsole3/frontend/src/app/core/sidebar-left-inner/sidebar-left-inner.component.html
@@ -3,7 +3,7 @@
<img src="assets/img/no-image.png" class="img-circle" alt="User Image">
</div>
<div class="pull-left info">
- <p>Alexander Pierce</p>
+ <p>{{user.username}}</p>
<a href="#"><i class="fa fa-circle text-success"></i> Online</a>
</div>
</div>
diff --git a/admin/WebConsole3/frontend/src/app/core/sidebar-left-inner/sidebar-left-inner.component.ts b/admin/WebConsole3/frontend/src/app/core/sidebar-left-inner/sidebar-left-inner.component.ts
index 036da6cb..991abdb2 100644
--- a/admin/WebConsole3/frontend/src/app/core/sidebar-left-inner/sidebar-left-inner.component.ts
+++ b/admin/WebConsole3/frontend/src/app/core/sidebar-left-inner/sidebar-left-inner.component.ts
@@ -1,7 +1,15 @@
-import { Component } from '@angular/core';
-
-@Component({
- selector: 'app-sidebar-left-inner',
- templateUrl: './sidebar-left-inner.component.html'
-})
-export class SidebarLeftInnerComponent {}
+import { Component } from '@angular/core';
+import {AuthModule} from 'globunet-angular/core';
+
+@Component({
+ selector: 'app-sidebar-left-inner',
+ templateUrl: './sidebar-left-inner.component.html'
+})
+export class SidebarLeftInnerComponent {
+ user: any;
+
+ constructor(private authModule: AuthModule) {
+ this.user = this.authModule.getLoggedUser();
+ }
+
+}
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
index 94a8d97b..b17cc7a0 100644
--- a/admin/WebConsole3/frontend/src/app/form-type/menu.form-type.ts
+++ b/admin/WebConsole3/frontend/src/app/form-type/menu.form-type.ts
@@ -6,7 +6,11 @@ export class MenuFormType extends GlobunetFormType {
getForm() {
const form: any[] = GlobunetFormType.getForm(new Menu());
this.setFieldType(form, 'description', 'textarea');
+ this.setFieldType(form, 'comments', 'textarea');
this.setFieldType(form, 'resolution', 'select');
+ this.getField(form, 'resolution').options = {
+ items: []
+ };
return form;
}
}
diff --git a/admin/WebConsole3/frontend/src/app/form-type/repository.form-type.ts b/admin/WebConsole3/frontend/src/app/form-type/repository.form-type.ts
index 15b1b9f8..c0a8fffd 100644
--- a/admin/WebConsole3/frontend/src/app/form-type/repository.form-type.ts
+++ b/admin/WebConsole3/frontend/src/app/form-type/repository.form-type.ts
@@ -1,9 +1,11 @@
-import {Repository} from '../model/repository';
-import {GlobunetFormType} from './globunet.form-type';
-
-
-export class RepositoryFormType {
- getForm() {
- return GlobunetFormType.getForm(new Repository());
- }
-}
+import {Repository} from '../model/repository';
+import {GlobunetFormType} from './globunet.form-type';
+
+
+export class RepositoryFormType extends GlobunetFormType{
+ getForm() {
+ const form = GlobunetFormType.getForm(new Repository());
+ this.setFieldType(form, 'description', 'textarea');
+ return form;
+ }
+}
diff --git a/admin/WebConsole3/frontend/src/app/model/image.ts b/admin/WebConsole3/frontend/src/app/model/image.ts
index 2d52cf63..5df31b74 100644
--- a/admin/WebConsole3/frontend/src/app/model/image.ts
+++ b/admin/WebConsole3/frontend/src/app/model/image.ts
@@ -9,6 +9,7 @@ export class PartitionInfo {
partitionCode: string;
filesystem: string;
osName: string;
+ type: string;
}
export class Image extends Resource {
diff --git a/admin/WebConsole3/frontend/src/app/model/repository.ts b/admin/WebConsole3/frontend/src/app/model/repository.ts
index 5b6756d2..36838128 100644
--- a/admin/WebConsole3/frontend/src/app/model/repository.ts
+++ b/admin/WebConsole3/frontend/src/app/model/repository.ts
@@ -1,25 +1,17 @@
-import { Resource } from 'globunet-angular/core/models/api/resource';
-
-export class Repository extends Resource {
- name: string;
- ip: string;
- port: number;
- password: string;
- configurationpath: string;
- adminpath: string;
- pxepath: string;
- description: string;
- info: any;
-
- constructor() {
- super();
- this.name = '';
- this.ip = '';
- this.port = 0;
- this.password = '';
- this.configurationpath = '';
- this.adminpath = '';
- this.pxepath = '';
- this.description = '';
- }
-}
+import { Resource } from 'globunet-angular/core/models/api/resource';
+
+export class Repository extends Resource {
+ name: string;
+ ip: string;
+ password: string;
+ description: string;
+ info: any;
+
+ constructor() {
+ super();
+ this.name = '';
+ this.ip = '';
+ this.password = '';
+ this.description = '';
+ }
+}
diff --git a/admin/WebConsole3/frontend/src/app/pages/command/delete-cache-image-command/delete-cache-image-command.component.html b/admin/WebConsole3/frontend/src/app/pages/command/delete-cache-image-command/delete-cache-image-command.component.html
new file mode 100644
index 00000000..5d09b0aa
--- /dev/null
+++ b/admin/WebConsole3/frontend/src/app/pages/command/delete-cache-image-command/delete-cache-image-command.component.html
@@ -0,0 +1,62 @@
+<section class="content-header">
+ <h1 translate="delete_cache_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="delete_cache_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">
+ <div>
+ <table class="table">
+ <thead>
+ <tr>
+ <th translate="select">
+ </th>
+ <th translate="type">
+ </th>
+ <th translate="name">
+ </th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr *ngFor="let image of cacheImages" >
+ <td>
+ <input icheck type="checkbox" checkbox-class="icheckbox_square-blue" radio-class="iradio_square-blue" class="selection-checkbox" [(ngModel)]="image.selected" />
+ </td>
+ <td>
+ {{image.type}}
+ </td>
+ <td>
+ {{image.name}}
+ </td>
+ </tr>
+ </tbody>
+ </table>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+</section>
diff --git a/admin/WebConsole3/frontend/src/app/pages/command/delete-cache-image-command/delete-cache-image-command.component.scss b/admin/WebConsole3/frontend/src/app/pages/command/delete-cache-image-command/delete-cache-image-command.component.scss
new file mode 100644
index 00000000..08b1082b
--- /dev/null
+++ b/admin/WebConsole3/frontend/src/app/pages/command/delete-cache-image-command/delete-cache-image-command.component.scss
@@ -0,0 +1,3 @@
+app-execute-command {
+
+}
diff --git a/admin/WebConsole3/frontend/src/app/pages/command/delete-cache-image-command/delete-cache-image-command.component.ts b/admin/WebConsole3/frontend/src/app/pages/command/delete-cache-image-command/delete-cache-image-command.component.ts
new file mode 100644
index 00000000..efc14d6d
--- /dev/null
+++ b/admin/WebConsole3/frontend/src/app/pages/command/delete-cache-image-command/delete-cache-image-command.component.ts
@@ -0,0 +1,120 @@
+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} from '../../../model/client';
+import {Repository} from '../../../model/repository';
+import {RepositoryService} from '../../../api/repository.service';
+import {ImageService} from '../../../api/image.service';
+
+@Component({
+ selector: 'app-delete-cache-image-command',
+ templateUrl: './delete-cache-image-command.component.html',
+ styleUrls: [ './delete-cache-image-command.component.scss' ]
+})
+export class DeleteCacheImageCommandComponent implements OnInit {
+ private readonly user: User;
+ private constants: any;
+ public repositories: Repository[];
+ public execution = new Excecution();
+ public commands: Command[] = [];
+ public client: Client;
+ public cacheImages = [];
+ public command = {canonicalName: '', image: new Image()};
+
+
+ // 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) {
+ this.ogCommonService.loadEngineConfig().subscribe(
+ data => {
+ this.constants = data.constants;
+ }
+ );
+ const clientIds = Object.keys(this.ogCommonService.selectedClients);
+ this.execution.clients = clientIds.join(',');
+ // Capturar para todos los clientes todas las imágenes de cache
+ this.cacheImages = [];
+ for (let index = 0; index < clientIds.length; index++) {
+ const client = this.ogCommonService.selectedClients[clientIds[index]];
+ const diskConfigs = this.ogCommonService.getDisksConfigFromPartitions(client.partitions);
+ for (let dc = 0; dc < diskConfigs.length; dc++) {
+ const diskConfig = diskConfigs[dc];
+ for (let p = 0; p < diskConfig.partitions.length; p++) {
+ const partition = diskConfig.partitions[p];
+ if (partition.partitionCode === 'ca') {
+ // Solo cogemos las imagenes .img, no los .sum
+ for (let f = 0; f < partition.cacheContent.files.length; f++) {
+ const file = partition.cacheContent.files[f];
+ // Si no es un .sum
+ if (!file.name.match('.sum')) {
+ this.cacheImages.push(file);
+ }
+ }
+ }
+ }
+ }
+ }
+ } else {
+ // TODO - dar error?
+ this.ogSweetAlert.error(this.translate.instant('opengnsys_error'), this.translate.instant('not_clients_selected'));
+ this.router.navigate(['app.ous']);
+ }
+ }
+
+
+ sendCommand() {
+ this.execution.script = '';
+ for (let f = 0; f < this.cacheImages.length; f++) {
+ if (this.cacheImages[f].selected === true) {
+ if (this.cacheImages[f].type !== 'D') {
+ this.execution.script += 'rm -rf $OGCAC/$OGIMG/' + this.cacheImages[f].name.trim() + '*';
+ } else {
+ this.execution.script += 'rm -rf $OGCAC/$OGIMG/' + this.cacheImages[f].name.trim();
+ }
+ this.execution.script += '\n';
+ }
+ }
+ this.execution.script += this.constants.commands.REFRESH_INFO + '\n';
+ 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});
+ }
+ );
+ }
+
+}
diff --git a/admin/WebConsole3/frontend/src/app/pages/command/format-command/format-command.component.html b/admin/WebConsole3/frontend/src/app/pages/command/format-command/format-command.component.html
new file mode 100644
index 00000000..a14c8510
--- /dev/null
+++ b/admin/WebConsole3/frontend/src/app/pages/command/format-command/format-command.component.html
@@ -0,0 +1,96 @@
+<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" *ngFor="let item of clientGroups | keyvalue">
+ <div class="box-header with-border">
+ </div>
+ <div class="box-body">
+ <div *ngFor="let client of item.value">
+ <div class="form-group">
+ <span translate="clients"></span>
+ <label>
+ {{client.name}}
+ </label>
+ </div>
+ <div>
+ <table class="table">
+ <thead>
+ <tr>
+ <th translate="select">
+ </th>
+ <th translate="disk">
+ </th>
+ <th translate="partition">
+ </th>
+ <th translate="type">
+ </th>
+ <th translate="filesystem">
+ </th>
+ <th translate="size">
+ </th>
+ <th translate="osname">
+ </th>
+ </tr>
+ </thead>
+ <tbody>
+ <ng-container *ngFor="let partition of client.partitions">
+ <tr *ngIf="partition.numPartition !== 0 && partition.size > 0">
+ <td>
+ <input icheck type="checkbox" checkbox-class="icheckbox_square-blue" radio-class="iradio_square-blue" type="checkbox" class="selection-checkbox" [(ngModel)]="partition.selected" />
+ </td>
+ <td>
+ {{partition.numDisk}}
+ </td>
+ <td>
+ {{partition.numPartition}}
+ </td>
+ <td>
+ <select [(ngModel)]="partition.partitionCode">
+ <option *ngFor="let type of getPartitionTypes(client.partitions)" [ngValue]="type.id">{{type.type}}</option>
+ </select>
+ </td>
+ <td>
+ <select [(ngModel)]="partition.filesystem">
+ <option [ngValue]="filesystem" *ngFor="let filesystem of constants.filesystems">{{filesystem}}</option>
+ </select>
+ </td>
+ <td>
+ {{ogCommonService.getUnits(partition.size*1024)}}
+ </td>
+ <td>
+ {{partition.osName}}
+ </td>
+ </tr>
+ </ng-container>
+ </tbody>
+ </table>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+</section>
diff --git a/admin/WebConsole3/frontend/src/app/pages/command/format-command/format-command.component.scss b/admin/WebConsole3/frontend/src/app/pages/command/format-command/format-command.component.scss
new file mode 100644
index 00000000..ccb34440
--- /dev/null
+++ b/admin/WebConsole3/frontend/src/app/pages/command/format-command/format-command.component.scss
@@ -0,0 +1,3 @@
+command {
+
+}
diff --git a/admin/WebConsole3/frontend/src/app/pages/command/format-command/format-command.component.ts b/admin/WebConsole3/frontend/src/app/pages/command/format-command/format-command.component.ts
new file mode 100644
index 00000000..62b733b8
--- /dev/null
+++ b/admin/WebConsole3/frontend/src/app/pages/command/format-command/format-command.component.ts
@@ -0,0 +1,150 @@
+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 {Client, Partition} from '../../../model/client';
+import {CommandService} from '../../../api/command.service';
+import {forkJoin} from 'rxjs';
+
+@Component({
+ selector: 'app-format-command',
+ templateUrl: './format-command.component.html',
+ styleUrls: [ './format-command.component.scss' ]
+})
+export class FormatCommandComponent implements OnInit {
+ execution = {clients: '', script: '', type: ''};
+ command = {};
+ user: User;
+ clientGroups = {};
+ constants: any;
+
+ // 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,
+ public ogCommonService: OgCommonService,
+ private commandService: CommandService,
+ private ogSweetAlert: OgSweetAlertService,
+ private toaster: ToasterService,
+ private translate: TranslateService) {
+ this.user = this.authModule.getLoggedUser();
+ }
+
+
+ ngOnInit() {
+ if (this.user && this.ogCommonService.selectedClients) {
+ this.ogCommonService.loadEngineConfig().subscribe(
+ data => {
+ this.constants = data.constants;
+ }
+ );
+ const clientIds = Object.keys(this.ogCommonService.selectedClients);
+ // Recorrer todos los clientes y formar los grupos según el partitionCode de sus particiones, deben coincidir todos
+ for (let index = 0; index < clientIds.length; index++) {
+ // Generamos una clave usando disco-particion-code para comparar
+ const client = this.ogCommonService.selectedClients[clientIds[index]];
+ const key = this.getPartitionsCode(client.partitions);
+
+ if (!this.clientGroups[key]) {
+ this.clientGroups[key] = [];
+ }
+ this.clientGroups[key].push(client);
+ }
+ } else {
+ // TODO - dar error?
+ this.ogSweetAlert.error(this.translate.instant('opengnsys_error'), this.translate.instant('not_clients_selected'));
+ this.router.navigate(['/app/ous']);
+ }
+ }
+
+ getPartitionsCode(partitions) {
+ let key = '';
+ for (let p = 0; p < partitions.length; p++) {
+ // Además de calcular la clave, alteramos el partitionCode pasandolo a mayusculas y aplicando padding de "0" a la izquierda si es necesario
+ partitions[p].partitionCode = partitions[p].partitionCode.toUpperCase();
+ if (partitions[p].partitionCode.length === 1) {
+ partitions[p].partitionCode = '0' + partitions[p].partitionCode;
+ }
+ key += partitions[p].numDisk + partitions[p].numPartition + partitions[p].partitionCode;
+ }
+ return key;
+ }
+
+
+ sendCommand() {
+ // Comrobar qué particiones se han seleccionado de qué grupos
+ const executions = {};
+ const groups = Object.keys(this.clientGroups);
+ for (let g = 0; g < groups.length; g++) {
+ if (!executions[g]) {
+ executions[g] = {
+ clients: '',
+ script: ''
+ };
+ }
+ // Recorrer las particiones del primer cliente de la lista y ver si hay alguna seleccionada
+ const found = false;
+ // La partición 0 no se usa, solo indica las propiedades del disco
+ let index = 1;
+ const client = this.clientGroups[groups[g]][0];
+ for (let c = 0; c < this.clientGroups[groups[g]].length; c++) {
+ executions[g].clients += client.id + ',';
+ }
+ while (!found && index < client.partitions.length) {
+ const partition = client.partitions[index];
+ if (partition.selected === true) {
+ if(executions[g].script === '') {
+ executions[g].script = 'ogUnmountAll ' + partition.numDisk + '\n';
+ }
+ // Si la particion es cache
+ if (partition.partitionCode.toUpperCase() === 'CA') {
+ executions[g].script += 'ogFormatCache' + '\n';
+ } else {
+ executions[g].script += 'ogFormat ' + partition.numDisk + ' ' + partition.numPartition + ' ' + partition.filesystem + '\n';
+ }
+ }
+ index++;
+ }
+ }
+
+ // Creamos tantas promises como diferentes grupos de ejecución haya
+ const promises = [];
+ const len = Object.keys(executions).length;
+ for (let index = 0; index < len; index++) {
+ const execution = {
+ type: 'RUN_SCRIPT',
+ script: executions[index].script,
+ clients: executions[index].clients.substring(0, executions[index].clients.length - 1) // Quitar la ultima ","
+ };
+ promises.push(this.commandService.execute(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});
+ }
+ );
+ }
+
+ getPartitionTypes(partitions) {
+ let types = [];
+ const infoPart = partitions.filter((partition: Partition) => partition.numPartition === 0);
+ if (infoPart.length === 1) {
+ const partitionTable = this.ogCommonService.getPartitionTable(infoPart[0]);
+ types = partitionTable.partitions;
+ }
+ return types;
+ }
+
+}
diff --git a/admin/WebConsole3/frontend/src/app/pages/command/partition-format-command/partition-format-command.component.html b/admin/WebConsole3/frontend/src/app/pages/command/partition-format-command/partition-format-command.component.html
new file mode 100644
index 00000000..fab8b8d7
--- /dev/null
+++ b/admin/WebConsole3/frontend/src/app/pages/command/partition-format-command/partition-format-command.component.html
@@ -0,0 +1,164 @@
+<section class="content-header">
+ <h1 translate="partition_format"></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="partition_format"></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 class="row">
+ <div class="col-md-4">
+ <span translate="num_disk"></span>: <input name="number" type="number" step="1" min="1" [(ngModel)]="diskConfig.disk" >
+ </div>
+ <div class="col-md-4">
+ <span translate="part_table"></span>: <b>
+ <select name="partTableType" [(ngModel)]="diskConfig.parttable.type" (change)="checkPartitionTableType()">
+ <option *ngFor="let partitionTableTypes of partitionTableTypes">{{partitionTableTypes.type}}</option>
+ </select></b>
+ </div>
+ <div class="col-md-4">
+ <span translate="size"></span>: <b>{{getSizeInGB(diskConfig.size)}} GB ({{getSizeInGB(diskConfig.size*diskConfig.remaining/100)}} GB <span translate="free"></span>)</b>
+ </div>
+ </div>
+ <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">
+ <div class="row">
+ <div class="col-md-12">
+ <table col-resizable class="disk-partitions" [elements]="diskConfig.partitions" cr-update-property="usage" (onResize)="updatePartitionUsage($event)">
+ <tr>
+ <td *ngFor="let partition of diskConfig.partitions" [style]="sanitizer.bypassSecurityTrustStyle('width: '+ partition.usage + '%; background-color:' + getPartitionColor(partition))">
+ <span><span translate="{{partition.type}}"></span> ({{partition.usage}}%)</span>
+ <table *ngIf="partition.partitions && partition.partitions.length > 0" [elements]="partition.partitions" col-resizable class="disk-partitions" cr-update-property="usage" (onResize)="updateExtendedPartitions($event)" cr-force-refresh="refresh-extended-partitions">
+ <tr>
+ <td *ngFor="let extendedPartition of partition.partitions" [style]="sanitizer.bypassSecurityTrustStyle('width: '+extendedPartition.usage+'%; background-color: '+ getPartitionColor(extendedPartition))">
+ <span>{{extendedPartition.type}} ({{extendedPartition.usage}}%)</span>
+ </td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ </table>
+ </div>
+ </div>
+ <div class="row">
+ <div class="col-md-8">
+ <button translate="add" class="btn btn-primary" (click)="addPartition()"></button>
+ <table class="table table-condensed table-striped partitions">
+ <tbody>
+ <tr>
+ <th translate="partition"></th>
+ <th translate="part_type"></th>
+ <th translate="filesystem"></th>
+ <th><span translate="size"></span> (bytes)</th>
+ <th translate="usage"></th>
+ <th translate="format"></th>
+ <th translate="remove"></th>
+ </tr>
+ </tbody>
+ <tbody *ngFor="let partition of diskConfig.partitions; let index = index;" ng-class="{'extended-partition': partition.partitions.length > 0}">
+ <tr [ngClass]="index%2 == 0 ? 'odd' : 'even'" *ngIf="partition.partition != 0">
+ <td>{{partition.partition}} ({{getSizeInGB(partition.size)}}GB)</td>
+ <td>
+ <select name="partitionType" [disabled]="partTableTypeIsGPT() && index == 0 && isEFI(partition)" [(ngModel)]="partition.type" (change)="checkPartitionType(partition)">
+ <option *ngFor="let partitionType of diskConfig.parttable.partitions">{{partitionType.type}}</option>
+ </select>
+ </td>
+ <td>{{partition.filesystem}}</td>
+ <td>
+ <input step=".01" name="partitionSize" type="number" [(ngModel)]="partition.size" (change)="setPartitionUsage(diskConfig, partition)"/>
+ </td>
+ <td>
+ <input step=".01" name="partitionUsage" type="number" [(ngModel)]="partition.usage" (change)="updatePartitionUsage(partition)">
+ <span>%</span>
+ </td>
+ <td>
+ <div *ngIf="isEXTENDED(partition) != true" class="checkbox clip-check check-primary checkbox-inline" style="margin-top: 0">
+ <input name="format" icheck checkbox-class="icheckbox_square-blue" radio-class="iradio_square-blue" type="checkbox" class="selection-checkbox" value="true" [(ngModel)]="partition.format" />
+ </div>
+ </td>
+ <td>
+ <button *ngIf="!(partTableTypeIsGPT() && $index == 0 && isEFI(partition))" class="btn btn-danger btn-xs"><i class="fa fa-times" (click)="removePartition(partition)"></i></button>
+ </td>
+ <td *ngIf="isEXTENDED(partition) == true">
+ <button class="btn btn-primary btn-xs"><i class="fa fa-plus" (click)="addExtendedPartition(partition)"></i></button>
+ </td>
+ </tr>
+ <tr *ngFor="let extendedPartition of partition.partitions" class="extended" ng-class="{'odd': $index%2 == 0, 'even': $index%2 != 0}">
+ <td>{{extendedPartition.partition}}</td>
+ <td>
+ <select name="extendedPartitionType" [(ngModel)]="extendedPartition.type" (change)="checkPartitionType(extendedPartition)">
+ <option *ngFor="let partitionType of diskConfig.parttable.partitions">{{partitionType.type}}</option>
+ </select>
+ </td>
+ <td>{{extendedPartition.filesystem}}</td>
+ <td><input step=".01" name="extendedPartitonSize" type="number"[(ngModel)]="extendedPartition.size" (change)="updateExtendedPartitions(extendedPartition)"/></td>
+ <td>
+ <input step=".01" name="extendedPartitionUsage" type="number"[(ngModel)]="extendedPartition.usage" (change)="updateExtendedPartitionsUsage(extendedPartition)">
+ <span>%</span>
+ </td>
+ <td>
+ <div class="checkbox clip-check check-primary checkbox-inline" style="margin-top: 0">
+ <input name="format" icheck checkbox-class="icheckbox_square-blue" radio-class="iradio_square-blue" type="checkbox" class="selection-checkbox" value="true"[(ngModel)]="extendedPartition.format" />
+ </div>
+ </td>
+ <td>
+ <button class="btn btn-danger btn-xs"><i class="fa fa-times" (click)="removeExtendedPartition(extendedPartition)"></i></button>
+ </td>
+ </tr>
+ </tbody>
+ </table>
+ </div>
+ <div class="col-md-4">
+ <!--flot dataset="diskConfig.diskChartData" options="diskConfig.diskChartOptions" height="200px"></flot-->
+ <div class="chart" >
+ <canvas baseChart
+ [data]="diskConfig.diskChartData"
+ [labels]="diskConfig.diskChartLabels"
+ [colors]="diskConfig.diskPieChartColors"
+ [chartType]="'doughnut'"
+ [options]="diskConfig.diskChartOptions">
+ </canvas>
+ </div>
+ </div>
+ </div>
+ </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/partition-format-command/partition-format-command.component.scss b/admin/WebConsole3/frontend/src/app/pages/command/partition-format-command/partition-format-command.component.scss
new file mode 100644
index 00000000..97d2231d
--- /dev/null
+++ b/admin/WebConsole3/frontend/src/app/pages/command/partition-format-command/partition-format-command.component.scss
@@ -0,0 +1,22 @@
+::ng-deep app-partition-format-command {
+ ::ng-deep table.disk-partitions {
+ min-height: 40px;
+ }
+ ::ng-deep table.disk-partitions td {
+ position: relative;
+ }
+ ::ng-deep span.resizer {
+ display: block;
+ position: absolute;
+ top: 0;
+ right: 0;
+ margin: 0;
+ background-color: black;
+ width: 2px;
+ height: 100%;
+ padding: 0 !important;
+ cursor: col-resize;
+ border: 1px solid transparent;
+ }
+
+}
diff --git a/admin/WebConsole3/frontend/src/app/pages/command/partition-format-command/partition-format-command.component.ts b/admin/WebConsole3/frontend/src/app/pages/command/partition-format-command/partition-format-command.component.ts
new file mode 100644
index 00000000..8c75fa2e
--- /dev/null
+++ b/admin/WebConsole3/frontend/src/app/pages/command/partition-format-command/partition-format-command.component.ts
@@ -0,0 +1,618 @@
+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 {DomSanitizer} from '@angular/platform-browser';
+import {ChartOptions} from 'chart.js';
+import {Client} from '../../../model/client';
+
+@Component({
+ selector: 'app-partition-format-command',
+ templateUrl: './partition-format-command.component.html',
+ styleUrls: [ './partition-format-command.component.scss' ]
+})
+export class PartitionFormatCommandComponent implements OnInit {
+ execution = {clients: '', script: '', type: ''};
+ command = {};
+ user: User;
+ constants: any;
+ diskConfig: any;
+ partitionTableTypes = ['MSDOS', 'GPT'];
+ partitionTypes = [];
+ editInstructions = false;
+
+ // this tells the tabs component which Pages
+ // should be each tab's root Page
+ constructor(public ogCommandsService: OGCommandsService,
+ public sanitizer: DomSanitizer,
+ private authModule: AuthModule,
+ private router: Router,
+ private activatedRoute: ActivatedRoute,
+ public ogCommonService: OgCommonService,
+ private commandService: CommandService,
+ private ogSweetAlert: OgSweetAlertService,
+ private toaster: ToasterService,
+ private translate: TranslateService) {
+ this.user = this.authModule.getLoggedUser();
+ this.diskConfig = {};
+ this.ogCommonService.saveSelection();
+ }
+
+ ngOnInit() {
+ if (this.user) {
+ this.ogCommonService.loadEngineConfig().subscribe(
+ data => {
+ this.constants = data.constants;
+ // Comprobar la selección de clientes
+ if (this.ogCommonService.selectedClients) {
+
+ // Recorrer todos los clientes seleccionados y usar el tamaño del disco de menor tamaño
+ const clientsId = Object.keys(this.ogCommonService.selectedClients);
+ let minSize = 0;
+ // por defecto la tabla de particiones msdos
+ let parttable = this.ogCommonService.getPartitionTable({partitionCode: 1});
+ if (this.ogCommonService.selectedClients[clientsId[0]].partitions[0]) {
+ minSize = this.ogCommonService.selectedClients[clientsId[0]].partitions[0].size;
+ parttable = this.ogCommonService.getPartitionTable(this.ogCommonService.selectedClients[clientsId[0]].partitions[0]);
+ }
+
+ for (let c = 1; c < clientsId.length; c++) {
+ if (this.ogCommonService.selectedClients[clientsId[0]].partitions[0].size < minSize) {
+ minSize = this.ogCommonService.selectedClients[clientsId[0]].partitions[0].size;
+
+ }
+ }
+
+ this.diskConfig = {
+ disk: 1,
+ parttable: parttable,
+ size: minSize,
+ partitions: [
+ {
+ partition: 0,
+ type: 'free_space',
+ filesystem: '',
+ size: minSize,
+ usage: 100,
+ }
+ ]
+ };
+ // TODO - Revisar Usamos la tabla de particiones del cliente seleccionado
+ const client: Client = this.ogCommonService.selectedClients[clientsId[0]];
+ const clientPartitions = [];
+ client.partitions.forEach((partition) => {
+ if (partition.numPartition !== 0 && partition.filesystem !== 'EMPTY') {
+
+ // Obtener el tipo de partición según su code
+ if (partition.partitionCode.length === 1) {
+ partition.partitionCode = '0' + partition.partitionCode;
+ }
+ const partTypes = this.diskConfig.parttable.partitions.filter(p => p.id === partition.partitionCode.toUpperCase());
+ if (partTypes.length > 0) {
+ partition.type = partTypes[0].type;
+ }
+ clientPartitions.push(partition);
+ }
+ });
+ this.diskConfig.partitions = clientPartitions.concat((this.diskConfig.partitions));
+ this.reorderPartitions();
+
+ this.setChartData(this.diskConfig);
+ this.partitionTableTypes = this.constants.partitiontable;
+ } else {
+ // TODO - dar error?
+ this.ogSweetAlert.error(this.translate.instant('opengnsys_error'), this.translate.instant('not_clients_selected'));
+ this.router.navigate(['app/ous']);
+ }
+
+ }
+ );
+ }
+ }
+
+
+ partTableTypeIsGPT() {
+ return this.diskConfig.parttable.type === 'GPT';
+ }
+
+ partTableTypeIsMSDOS() {
+ return this.diskConfig.parttable.type === 'MSDOS';
+ }
+
+ partTableTypeIsLVM() {
+ return this.diskConfig.parttable.type === 'LVM';
+ }
+ partTableTypeIsZPOOL() {
+ return this.diskConfig.parttable.type === 'ZPOOL';
+ }
+
+ isEFI(partition) {
+ return partition.type === 'EFI';
+ }
+
+ isCACHE(partition) {
+ return partition.type === 'CACHE';
+ }
+
+ isEXTENDED(partition) {
+ return partition.type === 'EXTENDED';
+ }
+
+ isWINDOWS(partition) {
+ return partition.type === 'NTFS' || partition.type === 'WINDOWS';
+ }
+
+ isLINUX(partition) {
+ return typeof partition.type === 'string' && partition.type.includes('LINUX');
+ }
+
+ isLINUXSWAP(partition) {
+ return partition.type === 'LINUX-SWAP';
+ }
+
+ isDATA(partition) {
+ return partition.type === 'DATA';
+ }
+
+ isUNKNOWN(partition) {
+ return partition.type === 'UNKNOWN';
+ }
+
+ isFreeSpace(partition) {
+ return partition.type === 'free_space';
+ }
+
+
+ convertPartitionType(partition) {
+ if (this.partTableTypeIsMSDOS()) {
+ if (this.isWINDOWS(partition)) {
+ partition.type = 'NTFS';
+ } else if (this.isUNKNOWN(partition)) {
+ partition.type = 'NTFS';
+ }
+ } else if (this.partTableTypeIsGPT()) {
+ if (this.isWINDOWS(partition)) {
+ partition.type = 'WINDOWS';
+ } else if (this.isDATA(partition)) {
+ partition.type = 'UNKNOWN';
+ }
+ } else if (this.partTableTypeIsLVM()) {
+ partition.type = 'LVM-LV';
+ } else if (this.partTableTypeIsZPOOL()) {
+ partition.type = 'ZFS-VOL';
+ }
+ }
+
+ checkPartitionTableType() {
+ const self = this;
+ if (this.partTableTypeIsMSDOS()) {
+ if (this.diskConfig.partitions.length > 5) {
+ this.ogSweetAlert.info('opengnsys_info', 'En MS-DOS sólo puede haber 4 particiones primarias, se creará una extendida con el resto de particiones');
+ const tmpPartitions = [];
+ const extendedPartition = {
+ type: 'EXTENDED',
+ partitions: [],
+ size: 0,
+ usage: 0
+ };
+ const hasCache = (this.diskConfig.partitions.filter((partition) => partition.type === 'CACHE').length > 0);
+ // Si tiene cache se añaden 2 particiones, más la cache y el espacio libre
+ const numParts = hasCache ? 2 : 3;
+ this.diskConfig.partitions.forEach(function(partition, index) {
+ self.convertPartitionType(partition);
+ if (index < numParts || self.isFreeSpace(partition) || self.isCACHE(partition)) {
+ tmpPartitions.push(partition);
+ } else {
+ extendedPartition.partitions.push(partition);
+ extendedPartition.size += partition.size;
+ }
+ });
+ // Actualizar porcentajes de las particiones extendidas
+ for (let p = 0; p < extendedPartition.partitions.length; p++) {
+ self.setPartitionUsage(extendedPartition, extendedPartition.partitions[p]);
+ }
+ tmpPartitions.push(extendedPartition);
+ self.diskConfig.partitions = tmpPartitions;
+ self.updatePartitionUsage(this.diskConfig.partitions[0]);
+ } else {
+ self.diskConfig.partitions.forEach(function(partition, index) {
+ self.convertPartitionType(partition);
+ });
+ }
+
+ } else {
+ const tmpPartitions = [];
+ // Para particiones GPT se crea una particion EFI en primer lugar de 512M
+ if (this.partTableTypeIsGPT()) {
+ // Comprobar si existe ya una partición EFI al principio del disco, sino, crearla
+ if (!this.isEFI(this.diskConfig.partitions[0])) {
+ tmpPartitions.push({
+ type: 'EFI',
+ size: 512000,
+ usage: (512000 / this.diskConfig.size) * 100
+ });
+ }
+ }
+
+ this.diskConfig.partitions.forEach(function(partition) {
+ self.convertPartitionType(partition);
+ if (!self.isEXTENDED(partition)) {
+ tmpPartitions.push(partition);
+ } else {
+ partition.partitions.forEach(function(extPart) {
+ self.convertPartitionType(extPart);
+ tmpPartitions.push(extPart);
+ self.setPartitionUsage(this.diskConfig, extPart);
+ });
+ }
+ });
+ this.diskConfig.partitions = tmpPartitions;
+ this.updatePartitionUsage(this.diskConfig.partitions[0]);
+ }
+ }
+
+ addPartition() {
+ // Si el tipo de tabla de particiones es MSDOS, sólo se admiten 4 particiones
+ if (this.partTableTypeIsGPT() || (this.partTableTypeIsMSDOS() && this.diskConfig.partitions.length < 5)) {
+ this.diskConfig.partitions.push({
+ partition: (this.diskConfig.partitions.length),
+ type: this.partTableTypeIsGPT() ? 'WINDOWS' : 'NTFS',
+ filesystem: '',
+ size: 0,
+ usage: 5
+
+ });
+ this.updatePartitionUsage(this.diskConfig.partitions[this.diskConfig.partitions.length - 1]);
+ } else if (this.partTableTypeIsMSDOS()) {
+ this.ogSweetAlert.warning('opengnsys_warning', 'En MS-DOS sólo puede haber 4 particiones primarias, utilice alguna como extendida si necesita más particiones');
+ }
+ // Actualizar información
+ // setChartData(this.diskConfig);
+ }
+
+ addExtendedPartition(partition) {
+ partition.partitions.push({
+ partition: (partition.partitions.length + 1),
+ type: 'NTFS',
+ filesystem: '',
+ size: 0,
+ usage: 0
+
+ });
+ const extendedPartUsage = Math.round(100 / partition.partitions.length);
+ partition.partitions.forEach(function(extPart) {
+ extPart.usage = extendedPartUsage;
+ });
+ // Actualiza tamaños en funcion del porcentaje de uso
+ this.updateExtendedPartitions(partition);
+ }
+
+ updateExtendedPartitions(extPartition) {
+ const parentPartition = this.diskConfig.partitions.filter((partition) => partition.type === 'EXTENDED')[0];
+ const totalSize = parentPartition.size;
+ parentPartition.partitions.forEach( function(extPart, index) {
+ extPart.partition = (index + 1);
+ extPart.size = Math.round((extPart.usage || 0) * totalSize / 100);
+ });
+ }
+
+ updateExtendedPartitionsUsage(extPartition) {
+ const parentPartition = this.diskConfig.partitions.filter((partition) => partition.type === 'EXTENDED')[0];
+ const index = parentPartition.partitions.indexOf(extPartition);
+ let nextPart = null;
+ // si solo hay una partición el uso es siempre el 100%
+ if (parentPartition.partitions.length === 1) {
+ extPartition.usage = 100;
+ } else {
+ nextPart = null;
+ // el porcentaje que crezca la particion, se le resta a la siguiente o a la anterior si es la ultima
+ if (index === parentPartition.partitions.length - 1) {
+ nextPart = parentPartition.partitions[index - 1];
+ } else {
+ nextPart = parentPartition.partitions[index + 1];
+ }
+ let restPercent = 100;
+ parentPartition.partitions.forEach(function(extPart) {
+ restPercent -= (extPart.usage || 0); // Hay casos en los que se obtiene NaN
+ });
+ // Le quitamos el porcentaje a la particion contigua hasta que quede con un mínimo de 1
+ if (nextPart.usage > (restPercent * -1)) {
+ nextPart.usage += restPercent;
+ } else {
+ // restamos 1 al resto del porcentaje que será lo que ocupe la particion contigua
+ restPercent = Math.abs(restPercent) - (nextPart.usage - 1);
+ nextPart.usage = 1;
+
+ extPartition.usage -= restPercent;
+ }
+ }
+ this.updateExtendedPartitions(extPartition);
+ }
+
+ removeExtendedPartition(extPartition) {
+ const parentPartition = this.diskConfig.partitions.filter((partition) => partition.type === 'EXTENDED')[0];
+ const index = parentPartition.partitions.indexOf(extPartition);
+ if (index !== -1) {
+ parentPartition.partitions.splice(index, 1);
+ }
+ // Comprobamos el % que queda libre ahora
+ const freePercent = Math.round(extPartition.usage / parentPartition.partitions.length);
+ parentPartition.partitions.forEach(function(extPart) {
+ extPart.usage += freePercent;
+ extPart.size = Math.round(extPart.usage * parentPartition.size / 100);
+ });
+ }
+
+
+ reorderPartitions() {
+ const self = this;
+ const tmpPartitions = [];
+ let indexFreeSpace = -1;
+ let indexCache = -1;
+ this.diskConfig.partitions.forEach(function(partition, index) {
+ if (partition.type !== 'free_space' && !self.isCACHE(partition)) {
+ partition.partition = (tmpPartitions.length + 1);
+ tmpPartitions.push(partition);
+ } else if (self.isCACHE(partition)) {
+ indexCache = index;
+ } else if (partition.type === 'free_space') {
+ indexFreeSpace = index;
+ }
+ });
+ // Añadir el espacio libre y la cache
+ if (indexFreeSpace !== -1) {
+ this.diskConfig.partitions[indexFreeSpace].usage = this.calculateFreeSpace(this.diskConfig.partitions[indexFreeSpace]);
+ tmpPartitions.push(this.diskConfig.partitions[indexFreeSpace]);
+ }
+ if (indexCache !== -1) {
+ tmpPartitions.push(this.diskConfig.partitions[indexCache]);
+ }
+ this.diskConfig.partitions = tmpPartitions;
+ }
+
+ setChartData(diskConfig) {
+ const self = this;
+ const diskChartData = [];
+ const diskChartLabels = [];
+ const diskPieChartColors = [{
+ backgroundColor: []
+ }];
+ let usedSpace = 0;
+
+ diskConfig.partitions.forEach( function(partition) {
+ if (partition.size > 0) {
+ self.setPartitionUsage(diskConfig, partition);
+ if (partition.type === 'free_space') {
+ partition.usage = self.calculateFreeSpace(partition);
+ }
+ // El espacio libre solo se añade si es 0
+ if (partition.type !== 'free_space' || (partition.type === 'free_space' && partition.usage > 0)) {
+ diskChartData.push(partition.usage);
+ diskChartLabels.push([
+ self.translate.instant(partition.os || partition.filesystem || partition.type),
+ (partition.usage + '%')
+ ]);
+ diskPieChartColors[0].backgroundColor.push(self.getPartitionColor(partition));
+ }
+ if (partition.type !== 'free_space') {
+ usedSpace += partition.usage;
+ }
+ }
+ });
+
+ this.diskConfig.remaining = Math.round(100 * (100 - usedSpace)) / 100;
+
+ const diskChartOptions: ChartOptions = {
+ responsive: true,
+ legend: {
+ position: 'bottom'
+ },
+ plugins: {
+ datalabels: {
+ formatter: (value, ctx) => {
+ const label = ctx.chart.data.labels[ctx.dataIndex];
+ return label;
+ },
+ },
+ }
+ };
+
+ diskConfig.diskChartData = diskChartData;
+ diskConfig.diskChartOptions = diskChartOptions;
+ diskConfig.diskChartLabels = diskChartLabels;
+ diskConfig.diskPieChartColors = diskPieChartColors;
+ }
+
+ getPartitionColor(partition) {
+ let color = '#c5e72b';
+ // Para la partición de datos se usa un color específico
+ if (this.isDATA(partition)) {
+ color = 'rgb(237,194,64)';
+ } else if (this.isEFI(partition)) {
+ color = '#bfe4e5';
+ } else if (this.isWINDOWS(partition)) {
+ color = '#00c0ef';
+ } else if (this.isLINUXSWAP(partition)) {
+ color = '#545454';
+ } else if (this.isLINUX(partition)) {
+ color = '#605ca8';
+ } else if (this.isCACHE(partition)) {
+ color = '#FC5A5A';
+ } else if (this.isFreeSpace(partition)) {
+ color = '#bcbcbc';
+ }
+ return color;
+ }
+
+ /*
+ * Custom Label formatter
+ * ----------------------
+ */
+ labelFormatter(label, series) {
+ return '<div style="font-size:13px; text-align:center; padding:2px; color: #000; font-weight: 600;">'
+ + '<br>'
+ + series.usage + '%</div>';
+ }
+
+ getSizeInGB(size) {
+ size = size / (1024 * 1024);
+ return Math.round(size * 100) / 100;
+ }
+
+ setPartitionUsage(diskConfig, partition) {
+ partition.usage = Math.round(((partition.size * 100) / diskConfig.size) * 100) / 100;
+ }
+
+ checkPartitionType(partition) {
+ let ok = true;
+ if (this.isCACHE(partition)) {
+ // Comprobar si ya hay alguna partición como CACHE
+ if (this.diskConfig.partitions.filter((p) => p.type === 'CACHE').length > 1) {
+ this.ogSweetAlert.error('opengnsys_error', 'Solo debe haber una CACHE');
+ partition.type = 'NTFS';
+ ok = false;
+ }
+ } else if (this.isEXTENDED(partition)) {
+ // Comprobar si ya hay alguna partición como EXTENDIDA
+ if (this.diskConfig.partitions.filter((p) => p.type === 'EXTENDED').length > 1) {
+ this.ogSweetAlert.error('opengnsys_error', 'Solo debe haber una EXTENDIDA');
+ partition.type = 'NTFS';
+ ok = false;
+ } else {
+ partition.partitions = [
+ {
+ partition: 1,
+ type: 'NTFS',
+ filesystem: '',
+ size: partition.size,
+ usage: 100
+
+ }
+ ];
+ }
+ } else if (typeof partition.partitions !== 'undefined' && partition.partitions.length > 0) {
+ ok = false;
+ const self = this;
+ this.ogSweetAlert.question('opengnsys_question', 'Esta particion contiene otras partitiones!, si continua, dichas particiones serán eliminadas....',
+ function(yes) {
+ partition.partitions = [];
+ self.updatePartitionUsage(partition);
+ },
+ function(cancel) {
+ // Si contesta no se deja el tipo extendido
+ partition.type = 'EXTENDED';
+ }
+ );
+ }
+
+ if (ok) {
+ this.updatePartitionUsage(partition);
+ }
+ }
+
+ updatePartitionUsage(partition) {
+ const remaining = this.calculateFreeSpace(partition);
+ if (partition.usage > remaining) {
+ partition.usage = remaining;
+ }
+ partition.size = Math.round(this.diskConfig.size * partition.usage / 100);
+ this.setChartData(this.diskConfig);
+ this.reorderPartitions();
+ // Si es una partición extendida
+ if (typeof partition.partitions !== 'undefined' && partition.partitions.length > 0) {
+ this.updateExtendedPartitions(partition.partitions[0]);
+ }
+ }
+
+ calculateFreeSpace(asignedPartition) {
+ let usedSpace = 0;
+ this.diskConfig.partitions.forEach(function(partition, index) {
+ if (partition !== asignedPartition && partition.type !== 'free_space') {
+ usedSpace += partition.usage || 0;
+ }
+ });
+ return Math.round(100 * (100 - usedSpace)) / 100;
+ }
+
+ removePartition(partition) {
+ const index = this.diskConfig.partitions.indexOf(partition);
+ if (index !== -1) {
+ this.diskConfig.partitions.splice(index, 1);
+ }
+
+ this.setChartData(this.diskConfig);
+
+ }
+
+
+// var RC='@';
+// document.fdatosejecucion.atributos.value="scp="+escape(document.fdatos.codigo.value)+RC;
+
+
+ /**/
+ generateOgInstruction() {
+ const self = this;
+ let initPartitionTable = 'ogCreatePartitionTable ' + this.diskConfig.disk + ' ' + this.diskConfig.parttable.type + '\n';
+ initPartitionTable += 'ogEcho log session "[0] $MSG_HELP_ogCreatePartitions"\n';
+ initPartitionTable += 'ogEcho session "[10] $MSG_HELP_ogUnmountAll ' + this.diskConfig.disk + '"\n';
+ initPartitionTable += 'ogUnmountAll ' + this.diskConfig.disk + ' 2>/dev/null\n';
+ initPartitionTable += 'ogUnmountCache\n';
+ initPartitionTable += 'ogEcho session "[30] $MSG_HELP_ogUpdatePartitionTable ' + this.diskConfig.disk + '"\n';
+ initPartitionTable += 'ogDeletePartitionTable ' + this.diskConfig.disk + '\n';
+ initPartitionTable += 'ogUpdatePartitionTable ' + this.diskConfig.disk + '\n';
+
+ let createPartitions = 'ogEcho session "[60] $MSG_HELP_ogListPartitions ' + this.diskConfig.disk + '"\n';
+ createPartitions += 'ogExecAndLog command session ogListPartitions ' + this.diskConfig.disk + '\n';
+
+ let cacheInstruction = '';
+ let partitionList = '';
+ let formatInstructions = '';
+ this.diskConfig.partitions.forEach(function(partition, index) {
+ if (partition.type !== 'free_space') {
+ // La unica particion especial es la 4 que es cache, para el resto
+ if (!self.isCACHE(partition)) {
+ partitionList += ' ' + partition.type + ':' + partition.size;
+ if (self.isEXTENDED(partition)) {
+ for (let p = 0; p < partition.partitions.length; p++) {
+ partitionList += ' ' + partition.partitions[p].type + ':' + partition.partitions[p].size;
+ if (partition.partitions[p].format === true) {
+ formatInstructions += 'ogUnmount ' + self.diskConfig.disk + ' ' + (partition.partition + (partition.partitions[p].partition - 1)) + '\n';
+ formatInstructions += 'ogFormat ' + self.diskConfig.disk + ' ' + (partition.partition + (partition.partitions[p].partition - 1)) + '\n';
+ }
+ }
+ }
+ if (partition.format === true) {
+ formatInstructions += 'ogUnmount ' + self.diskConfig.disk + ' ' + partition.partition + '\n';
+ formatInstructions += 'ogFormat ' + self.diskConfig.disk + ' ' + partition.partition + '\n';
+ }
+ } else {
+ cacheInstruction = 'ogEcho session "[50] $MSG_HELP_ogCreateCache"\n';
+ cacheInstruction += 'initCache ' + self.diskConfig.disk + ' ' + partition.size + ' NOMOUNT &>/dev/null\n';
+
+ if (partition.format === true) {
+ formatInstructions += 'ogUnmountCache\n';
+ formatInstructions += 'ogFormatCache\n';
+ }
+ }
+ }
+ });
+
+ createPartitions += 'ogEcho session "[70] $MSG_HELP_ogCreatePartitions ' + partitionList + '"\n';
+ createPartitions += 'ogExecAndLog command ogCreatePartitions ' + this.diskConfig.disk + partitionList + '\n';
+ createPartitions += 'ogEcho session "[80] $MSG_HELP_ogSetPartitionActive ' + this.diskConfig.disk + ' 1"\n';
+ createPartitions += 'ogSetPartitionActive ' + this.diskConfig.disk + ' 1\n';
+ createPartitions += 'ogEcho log session "[100] $MSG_HELP_ogListPartitions ' + this.diskConfig.disk + '"\n';
+ createPartitions += 'ogUpdatePartitionTable ' + this.diskConfig.disk + '\n';
+ createPartitions += 'ms-sys /dev/sda | grep unknow && ms-sys /dev/sda\n';
+ createPartitions += 'ogExecAndLog command session log ogListPartitions ' + this.diskConfig.disk + '\n';
+
+ this.ogCommandsService.ogInstructions = initPartitionTable + cacheInstruction + createPartitions + formatInstructions;
+ }
+}
diff --git a/admin/WebConsole3/frontend/src/app/pages/common/directive/col-resizable.directive.ts b/admin/WebConsole3/frontend/src/app/pages/common/directive/col-resizable.directive.ts
new file mode 100644
index 00000000..7c32f406
--- /dev/null
+++ b/admin/WebConsole3/frontend/src/app/pages/common/directive/col-resizable.directive.ts
@@ -0,0 +1,81 @@
+import {Directive, DoCheck, ElementRef, EventEmitter, Input, OnDestroy, OnInit, Output, Renderer2} from '@angular/core';
+
+
+class ResizeInfo {
+ width: number;
+ percent: number;
+}
+
+@Directive({
+ selector: '[col-resizable]'
+})
+export class ColResizableDirective implements OnInit, DoCheck {
+ private el: ElementRef;
+ private start: any;
+ private pressed: boolean;
+ private startX: number;
+ private startWidth: any;
+
+ @Input()
+ elements: any[];
+
+ @Output()
+ onResize = new EventEmitter<ResizeInfo>();
+ private elementProperty: string;
+
+
+ constructor(el: ElementRef, private renderer: Renderer2) {
+ this.el = el;
+
+ }
+
+ ngOnInit() {
+ this.elementProperty = this.el.nativeElement.getAttribute('cr-update-property') || '';
+ }
+ ngDoCheck(): void {
+ const table = this.el.nativeElement;
+ const trs = table.getElementsByTagName('tr');
+ let tds = null;
+
+ for (let i = 0; i < trs.length; i++) {
+ tds = trs[i].getElementsByTagName('td');
+ if (tds.length > 0) {
+ for (let n = 0; n < tds.length; n++) {
+
+ if (tds[n].getElementsByClassName('resizer').length === 0) {
+ const span = document.createElement('span');
+ span.classList.add('resizer');
+ tds[n].appendChild(span);
+ span.addEventListener('mousedown', (event) => {
+ this.start = event.target;
+ this.pressed = true;
+ this.startX = event.x;
+ this.startWidth = this.start.parentElement.offsetWidth;
+ this.initResizableColumns();
+ });
+ }
+ }
+ }
+ }
+
+ }
+
+ private initResizableColumns() {
+ this.renderer.listen('body', 'mousemove', (event) => {
+ if (this.pressed) {
+ const width = this.startWidth + (event.x - this.startX);
+ this.start.parentElement.style.width = width + 'px';
+ const element = this.elements[this.start.parentElement.cellIndex];
+ if (typeof element !== 'undefined' && this.elementProperty !== ''){
+ element[this.elementProperty] = ((width / this.el.nativeElement.offsetWidth) * 100);
+ }
+ this.onResize.emit(element);
+ }
+ })
+ this.renderer.listen('body', 'mouseup', (event) => {
+ if (this.pressed) {
+ this.pressed = false;
+ }
+ });
+ }
+}
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 ebb52d60..91d187ff 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,19 +1,19 @@
<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">
+ <div *ngFor="let client of selectedClients | keyvalue" class="col-md-2 col-xs-6 padding-5">
+ <div class="info-box client" *ngIf="client.value && client.value.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)"/>
+ class="selection-checkbox" [(ngModel)]="client.value.selected"
+ (change)="ogCommonService.selectClient(client.value, client.value.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>
+ <span class="info-box-text">{{client.value.name}}</span>
+ <span class="info-box-text">{{client.value.ip}}</span>
+ <span class="info-box-text">{{client.value.mac}}</span>
</div>
<!-- /.info-box-content -->
</div>
diff --git a/admin/WebConsole3/frontend/src/app/pages/common/table-action/ng2-table-action.component.css b/admin/WebConsole3/frontend/src/app/pages/common/table-action/ng2-table-action.component.css
index 4e8eee70..975006ac 100644
--- a/admin/WebConsole3/frontend/src/app/pages/common/table-action/ng2-table-action.component.css
+++ b/admin/WebConsole3/frontend/src/app/pages/common/table-action/ng2-table-action.component.css
@@ -1,3 +1,3 @@
-ul.dropdown-menu {
- background-color: transparent;
-}
+::ng-deep ng2-smart-table ul.dropdown-menu {
+ background-color: transparent;
+}
diff --git a/admin/WebConsole3/frontend/src/app/pages/dashboard/dashboard.component.ts b/admin/WebConsole3/frontend/src/app/pages/dashboard/dashboard.component.ts
index 97d26ae1..ef11a47f 100644
--- a/admin/WebConsole3/frontend/src/app/pages/dashboard/dashboard.component.ts
+++ b/admin/WebConsole3/frontend/src/app/pages/dashboard/dashboard.component.ts
@@ -87,11 +87,13 @@ export class DashboardComponent implements OnInit, OnDestroy {
this.ogCommonService.loadEngineConfig().subscribe(
(config) => {
this.timers = config.timers;
- if (this.timers.serverStatusInterval.object == null) {
+ if (this.timers.serverStatusInterval.object == null && this.timers.serverStatusInterval.tick > 0) {
this.updateStatus();
this.timers.serverStatusInterval.object = setInterval(() => {
this.updateStatus();
}, this.timers.serverStatusInterval.tick);
+ } else {
+ this.updateStatus();
}
},
(error) => {
diff --git a/admin/WebConsole3/frontend/src/app/pages/hardware-component/hardware-component.component.html b/admin/WebConsole3/frontend/src/app/pages/hardware-component/hardware-component.component.html
index 0ddd6b5c..60c60cd1 100644
--- a/admin/WebConsole3/frontend/src/app/pages/hardware-component/hardware-component.component.html
+++ b/admin/WebConsole3/frontend/src/app/pages/hardware-component/hardware-component.component.html
@@ -11,7 +11,7 @@
<div>
<div class="col-md-12">
<div class="box-tools pull-right">
- <button class="btn btn-primary" translate="save" ng-click="vm.save(Form)"></button>
+ <button class="btn btn-primary" translate="save" (click)="save(Form)"></button>
</div>
</div>
</div>
@@ -21,13 +21,12 @@
<div class="col-md-12">
<div class="box box-primary">
<div class="box-header with-border">
- <h3 ng-if="!vm.hardwareComponent.id" class="box-title" translate="new_hardware_component"></h3>
- <h3 ng-if="vm.hardwareComponent.id" class="box-title" translate="hardware_component"></h3>
+ <h3 *ngIf="!hardwareComponent.id" class="box-title" translate="new_hardware_component"></h3>
+ <h3 *ngIf="hardwareComponent.id" class="box-title" translate="hardware_component"></h3>
</div>
<div class="box-body">
- <form role="form" gbn-auto-form name="Form" form-options="vm.formOptions" form-model="vm.hardwareComponent">
+ <app-form-input [model]="hardwareComponent" [formType]="formType"></app-form-input>
- </form>
</div>
</div>
</div>
diff --git a/admin/WebConsole3/frontend/src/app/pages/hardware-component/hardware-component.component.ts b/admin/WebConsole3/frontend/src/app/pages/hardware-component/hardware-component.component.ts
index a7ef127f..4b4306af 100644
--- a/admin/WebConsole3/frontend/src/app/pages/hardware-component/hardware-component.component.ts
+++ b/admin/WebConsole3/frontend/src/app/pages/hardware-component/hardware-component.component.ts
@@ -1,17 +1,48 @@
-import { Component } from '@angular/core';
-
-import { HardwareComponentService } from 'src/app/api/hardware-component.service';
-import { HardwareComponent } from 'src/app/model/hardware-component';
-
-@Component({
- selector: 'app-hardware-component',
- templateUrl: './hardware-component.component.html',
- styleUrls: [ './hardware-component.component.scss' ]
-})
-export class HardwareComponentComponent {
- // this tells the tabs component which Pages
- // should be each tab's root Page
- constructor(public hardwareComponentService: HardwareComponentService) {
- }
-
-}
+import { Component } from '@angular/core';
+
+import { HardwareComponentService } from 'src/app/api/hardware-component.service';
+import { HardwareComponent } from 'src/app/model/hardware-component';
+import {Observable} from 'rxjs';
+import {ToasterService} from '../../service/toaster.service';
+import {TranslateService} from '@ngx-translate/core';
+import {Router} from '@angular/router';
+
+@Component({
+ selector: 'app-hardware-component',
+ templateUrl: './hardware-component.component.html',
+ styleUrls: [ './hardware-component.component.scss' ]
+})
+export class HardwareComponentComponent {
+ // this tells the tabs component which Pages
+ public hardwareComponent: HardwareComponent;
+ formType: any;
+ // should be each tab's root Page
+ constructor(public hardwareComponentService: HardwareComponentService, private toaster: ToasterService, private translate: TranslateService, private router: Router) {
+ this.hardwareComponent = new HardwareComponent();
+ this.formType = [{
+ field: 'description',
+ name: 'description',
+ label: 'description',
+ type: 'textarea'
+ }];
+ }
+
+ save() {
+ let request: Observable<HardwareComponent>;
+ if (this.hardwareComponent.id !== 0) {
+ request = this.hardwareComponentService.update(this.hardwareComponent);
+ } else {
+ request = this.hardwareComponentService.create(this.hardwareComponent);
+ }
+
+ request.subscribe(
+ (response) => {
+ this.toaster.pop({type: this.translate.instant('success'), title: this.translate.instant('success'), body: this.translate.instant('successfully_saved')});
+ this.router.navigate(['/app/hardware']);
+ },
+ (error) => {
+ this.toaster.pop({type: 'error', title: 'error', body: error});
+ }
+ );
+ }
+}
diff --git a/admin/WebConsole3/frontend/src/app/pages/image/image.component.ts b/admin/WebConsole3/frontend/src/app/pages/image/image.component.ts
index 821f63a4..76629163 100644
--- a/admin/WebConsole3/frontend/src/app/pages/image/image.component.ts
+++ b/admin/WebConsole3/frontend/src/app/pages/image/image.component.ts
@@ -1,146 +1,146 @@
-import {Component, OnInit} from '@angular/core';
-
-import { ImageService } from 'src/app/api/image.service';
-import {Image, PartitionInfo} from 'src/app/model/image';
-import {OgCommonService} from '../../service/og-common.service';
-import {TranslateService} from '@ngx-translate/core';
-import {ToasterService} from '../../service/toaster.service';
-import {OgSweetAlertService} from '../../service/og-sweet-alert.service';
-import {Ng2TableActionComponent} from '../common/table-action/ng2-table-action.component';
-import {Router} from '@angular/router';
-
-@Component({
- selector: 'app-image',
- templateUrl: './image.component.html',
- styleUrls: [ './image.component.scss' ]
-})
-export class ImageComponent implements OnInit {
- images: Image[];
- constants: any;
- removeFile = false;
- tableSettings: any;
-
- // this tells the tabs component which Pages
- // should be each tab's root Page
- constructor(private router: Router, public imageService: ImageService, private ogCommonService: OgCommonService, private translate: TranslateService, private toaster: ToasterService, private ogSweetAlert: OgSweetAlertService) {
- this.ogCommonService.loadEngineConfig().subscribe(
- data => {
- this.constants = data.constants;
- }
- );
- }
-
- ngOnInit(): void {
- this.imageService.list().subscribe(
- data => {
- this.images = data;
- }
- );
- const self = this;
- this.tableSettings = {
- columns: {
- canonicalName: {
- title: this.translate.instant('canonical_name')
- },
- description: {
- title: this.translate.instant('description')
- },
- partitionInfo: {
- title: this.translate.instant('filesystem'),
- valuePrepareFunction: (cell, image) => {
- return this.getImageFileSystem(image);
- },
- filterFunction: (value: PartitionInfo, search: string) => {
- return (value.filesystem) ? value.filesystem.includes(search) : false;
- }
-
- },
- createdAt: {
- title: this.translate.instant('createdAt')
- },
- options: {
- title: 'Options',
- filter: false,
- sort: false,
- type: 'custom',
- renderComponent: Ng2TableActionComponent,
- onComponentInitFunction(instance) {
- instance.edit.subscribe(row => {
- self.router.navigate(['/app/images/edit/', row.id]);
- });
- instance.delete.subscribe(row => {
- self.deleteImage(row);
- });
- }
- },
- },
- actions: {
- position: 'right',
- add: false,
- edit: false,
- delete: false
- }
- };
- }
-
- 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;
- }
-
- deleteImage(image) {
- const self = this;
- this.removeFile = false;
- this.ogSweetAlert.swal({
- title: this.translate.instant('sure_to_delete') + '?',
- html: '<form style="text-align: center; padding-left: 10px">\
- <div class="form-group" translate="action_cannot_be_undone"></div>\
- <div class="form-group">\
- <div class="checkbox clip-check check-primary checkbox-inline">\
- <input id="removeFile" icheck checkbox-class="icheckbox_square-blue" radio-class="iradio_square-blue" type="checkbox" class="selection-checkbox" [(ngModel)]="removeFile" />\
- </div>\
- <label for="removeFile" translate="remove_file">\
- </label>?\
- </div>\
- </form>',
- type: 'warning',
- showCancelButton: true,
- confirmButtonColor: '#3c8dbc',
- confirmButtonText: this.translate.instant('yes_delete'),
- closeOnConfirm: true
- }).then(
- function(result) {
- if (result === true) {
- if (self.removeFile === true) {
- // TODO Borrar fichero físico...
- }
- this.imageService.delete(image.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(image);
- if (index !== -1) {
- this.images.splice(index, 1);
- }
- },
- function(error) {
- this.toaster.pop({type: 'error', title: 'error', body: error});
- }
- );
- }
- });
- }
-}
+import {Component, OnInit} from '@angular/core';
+
+import { ImageService } from 'src/app/api/image.service';
+import {Image, PartitionInfo} from 'src/app/model/image';
+import {OgCommonService} from '../../service/og-common.service';
+import {TranslateService} from '@ngx-translate/core';
+import {ToasterService} from '../../service/toaster.service';
+import {OgSweetAlertService} from '../../service/og-sweet-alert.service';
+import {Ng2TableActionComponent} from '../common/table-action/ng2-table-action.component';
+import {Router} from '@angular/router';
+
+@Component({
+ selector: 'app-image',
+ templateUrl: './image.component.html',
+ styleUrls: [ './image.component.scss' ]
+})
+export class ImageComponent implements OnInit {
+ images: Image[];
+ constants: any;
+ removeFile = false;
+ tableSettings: any;
+
+ // this tells the tabs component which Pages
+ // should be each tab's root Page
+ constructor(private router: Router, public imageService: ImageService, private ogCommonService: OgCommonService, private translate: TranslateService, private toaster: ToasterService, private ogSweetAlert: OgSweetAlertService) {
+ this.ogCommonService.loadEngineConfig().subscribe(
+ data => {
+ this.constants = data.constants;
+ }
+ );
+ }
+
+ ngOnInit(): void {
+ this.imageService.list().subscribe(
+ data => {
+ this.images = data;
+ }
+ );
+ const self = this;
+ this.tableSettings = {
+ columns: {
+ canonicalName: {
+ title: this.translate.instant('canonical_name')
+ },
+ description: {
+ title: this.translate.instant('description')
+ },
+ partitionInfo: {
+ title: this.translate.instant('filesystem'),
+ valuePrepareFunction: (cell, image) => {
+ return this.getImageFileSystem(image);
+ },
+ filterFunction: (value: PartitionInfo, search: string) => {
+ return (value.filesystem) ? value.filesystem.includes(search) : false;
+ }
+
+ },
+ createdAt: {
+ title: this.translate.instant('createdAt')
+ },
+ options: {
+ title: 'Options',
+ filter: false,
+ sort: false,
+ type: 'custom',
+ renderComponent: Ng2TableActionComponent,
+ onComponentInitFunction(instance) {
+ instance.edit.subscribe(row => {
+ self.router.navigate(['/app/images/edit/', row.id]);
+ });
+ instance.delete.subscribe(row => {
+ self.deleteImage(row);
+ });
+ }
+ },
+ },
+ actions: {
+ position: 'right',
+ add: false,
+ edit: false,
+ delete: false
+ }
+ };
+ }
+
+ 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;
+ }
+
+ deleteImage(image) {
+ const self = this;
+ this.removeFile = false;
+ this.ogSweetAlert.swal({
+ title: this.translate.instant('sure_to_delete') + '?',
+ html: '<form style="text-align: center; padding-left: 10px">\
+ <div class="form-group" translate="action_cannot_be_undone"></div>\
+ <div class="form-group">\
+ <div class="checkbox clip-check check-primary checkbox-inline">\
+ <input id="removeFile" icheck checkbox-class="icheckbox_square-blue" radio-class="iradio_square-blue" type="checkbox" class="selection-checkbox" [(ngModel)]="removeFile" />\
+ </div>\
+ <label for="removeFile" translate="remove_file">\
+ </label>?\
+ </div>\
+ </form>',
+ type: 'warning',
+ showCancelButton: true,
+ confirmButtonColor: '#3c8dbc',
+ confirmButtonText: this.translate.instant('yes_delete'),
+ closeOnConfirm: true
+ }).then(
+ function(result) {
+ if (result.value === true) {
+ if (self.removeFile === true) {
+ // TODO Borrar fichero físico...
+ }
+ self.imageService.delete(image.id).subscribe(
+ (response) => {
+ self.toaster.pop({type: 'success', title: 'success', body: self.translate.instant('successfully_deleted')});
+ // Buscar el elemento en el array y borrarlo
+ const index = self.images.indexOf(image);
+ if (index !== -1) {
+ self.images.splice(index, 1);
+ }
+ },
+ (error) => {
+ self.toaster.pop({type: 'error', title: 'error', body: error});
+ }
+ );
+ }
+ });
+ }
+}
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
index 9d96cde9..dd147bf3 100644
--- 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
@@ -19,16 +19,19 @@
<!-- Main content -->
<section class="content">
<div class="row">
- <div class="col-md-12">
+ <div class="col-md-4">
<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">
+ <form role="form" gbn-auto-form name="Form" form-model="image">
<app-form-input [model]="menu" [cols]="1" [formType]="form"></app-form-input>
</form>
</div>
</div>
</div>
+ <div class="col-md-8">
+ <iframe class="e2e-trusted-url" [src]="sanitizer.bypassSecurityTrustResourceUrl(menu.publicUrl)" width="100%" height="500px"></iframe>
+ </div>
</div>
</section>
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
index d52f53ad..c16bf372 100644
--- 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
@@ -10,6 +10,7 @@ import {Observable} from 'rxjs';
import {MenuService} from '../../../api/menu.service';
import {Menu} from '../../../model/menu';
import {OgCommonService} from '../../../service/og-common.service';
+import {DomSanitizer} from '@angular/platform-browser';
@Component({
selector: 'app-menu',
@@ -24,7 +25,7 @@ export class MenuEditComponent implements OnInit {
// 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) {
+ constructor(public sanitizer: DomSanitizer, private router: Router, private activatedRouter: ActivatedRoute, private ogCommonService: OgCommonService, private menuService: MenuService, private translate: TranslateService, private toaster: ToasterService) {
this.form = this.formType.getForm();
}
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 4c47eb73..2d803c86 100644
--- a/admin/WebConsole3/frontend/src/app/pages/menu/menu.component.ts
+++ b/admin/WebConsole3/frontend/src/app/pages/menu/menu.component.ts
@@ -7,6 +7,7 @@ import {Ng2TableActionComponent} from '../common/table-action/ng2-table-action.c
import {TranslateService} from '@ngx-translate/core';
import {Router} from '@angular/router';
import {OgSweetAlertService} from '../../service/og-sweet-alert.service';
+import {ToasterService} from '../../service/toaster.service';
@Component({
selector: 'app-menu',
@@ -18,7 +19,7 @@ export class MenuComponent implements OnInit {
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) {
+ constructor(public menuService: MenuService, private router: Router, private ogSweetAlert: OgSweetAlertService, private toaster: ToasterService, private translate: TranslateService) {
}
ngOnInit(): void {
@@ -82,19 +83,19 @@ export class MenuComponent implements OnInit {
closeOnConfirm: true
}).then(
function(result) {
- if (result === true) {
+ if (result.value === true) {
- this.menuService.delete(menu.id).then(
- function(response) {
- this.toaster.pop({type: 'success', title: 'success', body: this.translate.instant('successfully_deleted')});
+ self.menuService.delete(menu.id).subscribe(
+ (response) => {
+ self.toaster.pop({type: 'success', title: 'success', body: self.translate.instant('successfully_deleted')});
// Buscar el elemento en el array y borrarlo
- const index = this.images.indexOf(menu);
+ const index = self.menus.indexOf(menu);
if (index !== -1) {
- this.images.splice(menu, 1);
+ self.menus.splice(menu, 1);
}
},
- 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/organizational-unit/organizational-unit.component.ts b/admin/WebConsole3/frontend/src/app/pages/organizational-unit/organizational-unit.component.ts
index 8a59d77b..c020b7fc 100644
--- a/admin/WebConsole3/frontend/src/app/pages/organizational-unit/organizational-unit.component.ts
+++ b/admin/WebConsole3/frontend/src/app/pages/organizational-unit/organizational-unit.component.ts
@@ -55,7 +55,7 @@ export class OrganizationalUnitComponent implements OnInit, OnDestroy {
}
ngOnInit(): void {
- this.ogCommonService.loadEngineConfig().subscribe(
+ this.ogCommonService.loadEngineConfig().subscribe(
data => {
this.config = data;
@@ -74,7 +74,7 @@ export class OrganizationalUnitComponent implements OnInit, OnDestroy {
(response) => {
this.ous = Array.isArray(response) ? response : [response];
// La primera vez que entra
- if (this.config.timers.clientsStatusInterval.object == null) {
+ if (this.config.timers.clientsStatusInterval.object == null && this.config.timers.clientsStatusInterval.tick > 0) {
this.getClientStatus();
const self = this;
this.config.timers.clientsStatusInterval.object = window.setInterval(function() {
@@ -95,7 +95,6 @@ export class OrganizationalUnitComponent implements OnInit, OnDestroy {
);
-
}
showGrid(show) {
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 32b0a4db..02d60caa 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
@@ -49,7 +49,7 @@
<!-- *ngIf="selectedStatus[client.status] == true" -->
<div class="row">
<ng-container *ngFor="let client of ou.clients">
- <div class="col-md-2 col-xs-6 padding-5">
+ <div class="col-md-2 col-xs-6 og-client-box">
<div class="info-box client " *ngIf="mustShow(client)">
<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)="selectClient(client)" />
diff --git a/admin/WebConsole3/frontend/src/app/pages/organizational-unit/ou-clients/ou-client.component.scss b/admin/WebConsole3/frontend/src/app/pages/organizational-unit/ou-clients/ou-client.component.scss
new file mode 100644
index 00000000..118db555
--- /dev/null
+++ b/admin/WebConsole3/frontend/src/app/pages/organizational-unit/ou-clients/ou-client.component.scss
@@ -0,0 +1,11 @@
+.og-client-box {
+ padding: 0;
+ border: 1px solid lightgray;
+ box-shadow: 0 1px 1px rgba(0, 0, 0, 0.1);
+ margin: 0 5px;
+ background: white;
+}
+
+.og-client-box .info-box {
+ box-shadow: none;
+}
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 743ba965..0c5e8a14 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
@@ -9,7 +9,8 @@ import {OgCommonService} from '../../../service/og-common.service';
@Component({
selector: 'app-ou-client-component',
- templateUrl: 'ou-client.component.html'
+ templateUrl: 'ou-client.component.html',
+ styleUrls: ['ou-client.component.scss']
})
export class OuClientComponent {
private _ou: OrganizationalUnit;
diff --git a/admin/WebConsole3/frontend/src/app/pages/organizational-unit/ou-group/ou-group.component.ts b/admin/WebConsole3/frontend/src/app/pages/organizational-unit/ou-group/ou-group.component.ts
index 9d04c84e..e2f3d005 100644
--- a/admin/WebConsole3/frontend/src/app/pages/organizational-unit/ou-group/ou-group.component.ts
+++ b/admin/WebConsole3/frontend/src/app/pages/organizational-unit/ou-group/ou-group.component.ts
@@ -17,8 +17,20 @@ import {Router} from '@angular/router';
styleUrls: ['ou-group.component.css']
})
export class OuGroupComponent {
+ private _ou: OrganizationalUnit;
@Input() ous;
- @Input() content;
+ @Input()
+ set content(ou) {
+ this._ou = ou;
+ this._ou.clients.forEach((client) => {
+ if (this.ogCommonService.selectedClients[client.id]) {
+ client.selected = true;
+ }
+ });
+ }
+ get content() {
+ return this._ou;
+ }
@Input() clientStatus;
@Input() showGrid;
@Input() selectedStatus;
diff --git a/admin/WebConsole3/frontend/src/app/pages/profile/profile.component.html b/admin/WebConsole3/frontend/src/app/pages/profile/profile.component.html
index 97761b02..2f1b7bf5 100644
--- a/admin/WebConsole3/frontend/src/app/pages/profile/profile.component.html
+++ b/admin/WebConsole3/frontend/src/app/pages/profile/profile.component.html
@@ -16,6 +16,7 @@
</div>
</section>
<section class="content">
+ {{user.preferences|json}}
<div class="row">
<div class="col-md-12">
<div class="box box-primary">
@@ -26,7 +27,7 @@
<form role="form">
<div class="form-group col-md-2">
<label translate="username"></label>
- <input class="form-control" readonly="readonly" type="text" [(ngModel)]="user.username" name="username">
+ <input class="form-control" readonly="readonly" type="text" [value]="user.username" name="username">
</div>
<div class="form-group col-md-4">
<label translate="password"></label>
@@ -52,11 +53,11 @@
<label class="help-block" translate="display_as"></label>
<div class="row">
<div class="form-group col-md-1">
- <input icheck type="radio" name="displayGrid" checkbox-class="icheckbox_square-blue" radio-class="iradio_square-blue" class="selection-checkbox" [(ngModel)]="user.preferences.ous.showGrid" value="true" />
+ <input icheck type="radio" name="displayGrid" checkbox-class="icheckbox_square-blue" radio-class="iradio_square-blue" class="selection-checkbox" [(ngModel)]="user.preferences.ous.showGrid" [value]="true" />
<label translate="grid"></label>
</div>
<div class="form-group col-md-1">
- <input icheck type="radio" name="displayTable" checkbox-class="icheckbox_square-blue" radio-class="iradio_square-blue" class="selection-checkbox" [(ngModel)]="user.preferences.ous.showGrid" value="false" />
+ <input icheck type="radio" name="displayTable" checkbox-class="icheckbox_square-blue" radio-class="iradio_square-blue" class="selection-checkbox" [(ngModel)]="user.preferences.ous.showGrid" [value]="false" />
<label translate="table"></label>
</div>
</div>
@@ -66,7 +67,7 @@
<div class="row">
<div class="form-group col-md-2">
<label translate="language"></label>
- <select class="form-control" name="language" [(ngModel)]="user.preferences.language" (change)="ogCommonService.changeLanguage($event)">
+ <select class="form-control" name="language" [(ngModel)]="user.preferences.language" (ngModelChange)="ogCommonService.changeLanguage(user.preferences.language)">
<option *ngFor="let lang of constants.languages" [ngValue]="lang.id" >{{lang.name}}</option>
</select>
</div>
diff --git a/admin/WebConsole3/frontend/src/app/pages/profile/profile.component.ts b/admin/WebConsole3/frontend/src/app/pages/profile/profile.component.ts
index 149ad6f3..da6859c2 100644
--- a/admin/WebConsole3/frontend/src/app/pages/profile/profile.component.ts
+++ b/admin/WebConsole3/frontend/src/app/pages/profile/profile.component.ts
@@ -42,7 +42,6 @@ export class ProfileComponent implements OnInit {
}
changeTheme() {
- this.app.theme = this.user.preferences.theme;
this.layoutStore.setSkin(this.user.preferences.theme);
}
diff --git a/admin/WebConsole3/frontend/src/app/pages/repository/repository.component.html b/admin/WebConsole3/frontend/src/app/pages/repository/repository.component.html
index 38f08ade..a2d0cf28 100644
--- a/admin/WebConsole3/frontend/src/app/pages/repository/repository.component.html
+++ b/admin/WebConsole3/frontend/src/app/pages/repository/repository.component.html
@@ -1,100 +1,100 @@
-<section class="content-header">
- <h1 translate="repositories">
- </h1>
- <ol class="breadcrumb">
- <li><a [routerLink]="'/app/dashboard'"><i class="fa fa-dashboard"></i> {{'dashboard'|translate}}</a></li>
- <li class="active" translate="repositories"></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..." ng-model="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">
- <button class="btn btn-default" (click)="newRepository()" translate="new_repo"></button>
- </div>
- </div>
- </div>
-</section>
-<section class="content">
- <div class="row">
- <mk-box [header]="repository.name" [isLoading]="isRepositoryLoading()" [isCollapsable]="true" [isRemovable]="false" boxColor="primary" *ngFor="let repository of repositories" class="col-md-6">
- <div class="box-body">
- <form #form>
- <app-form-input [formType]="formType" [model]="repository" [cols]="2"></app-form-input>
- </form>
- <div class="box-footer">
-
- <button type="button" class="btn btn-primary" translate="save" (click)="saveRepository(Form, repository)"></button>
- <button type="button" class="btn btn-danger pull-right" (click)="deleteRepository(repository)" translate="delete">
- </button>
- </div>
- </div>
- <div class="box-footer">
- <mk-box header="{{'filesystem_info'|translate}}" [isCollapsable]="true" [isRemovable]="false" contentClasses="table-responsive">
- <button type="button" [disabled]="repository.password.length == 0" class="btn btn-primary pull-right" (click)="refreshRepoInfo(repository)">
- <i class="fa fa-refresh"></i> <span translate="refresh_info"></span>
- </button>
- <div class="box-body no-padding" >
-
- <div translate="connection_not_available" *ngIf="!repository.info"></div>
- <table class="table table-condensed table-striped" *ngIf="repository.info">
- <tbody>
- <tr>
- <th colspan="5" translate="disk_info"></th>
- </tr>
- <tr>
- <th translate="partition"></th>
- <th translate="total_disk"></th>
- <th translate="used_disk"></th>
- <th translate="free_disk"></th>
- <th translate="busy_percent_disk"></th>
- </tr>
- <tr>
- <td>{{repository.info.disk[0].partition}}</td>
- <td>{{repository.info.disk[0].total}}</td>
- <td>{{repository.info.disk[0].used}}</td>
- <td>
- {{repository.info.disk[0].free}}
- </td>
- <td>
- <span class="badge" ng-class="{'bg-green': repository.info.disk[0].percent.split('%')[0] < 60, 'bg-red': repository.info.disk[0].percent.split('%')[0] > 85, 'bg-yellow': repository.info.disk[0].percent.split('%')[0] >= 60 && repository.info.disk[0].percent.split('%')[0] <= 85}">{{repository.info.disk[0].percent}}
- </span>
- </td>
- </tr>
- </tbody>
- <tbody>
- <tr>
- <th colspan="2" translate="images_info"></th>
- </tr>
- <tr>
- <th translate="name"></th>
- <th translate="size"></th>
- <th translate="delete"></th>
- </tr>
- </tbody>
- <tbody ng-repeat="fileGroup in repository.info.files">
- <tr ng-repeat="file in fileGroup | orderBy: 'name'">
- <td>{{file.name}}</td>
- <td>{{OGCommonService.getUnits(file.size)}}</td>
- <td>
- <a *ngIf="isImageFile(file)" class="btn btn-danger" href="javascript:void(0)" translate="delete" (click)="deleteImageFile(file)"></a>
- </td>
- </tr>
- </tbody>
- </table>
- </div>
- </mk-box>
- </div>
- <!-- /.box-body -->
- </mk-box>
- </div>
-</section>
+<section class="content-header">
+ <h1 translate="repositories">
+ </h1>
+ <ol class="breadcrumb">
+ <li><a [routerLink]="'/app/dashboard'"><i class="fa fa-dashboard"></i> {{'dashboard'|translate}}</a></li>
+ <li class="active" translate="repositories"></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..." ng-model="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">
+ <button class="btn btn-default" (click)="newRepository()" translate="new_repo"></button>
+ </div>
+ </div>
+ </div>
+</section>
+<section class="content">
+ <div class="row">
+ <mk-box [header]="repository.name" [isLoading]="isRepositoryLoading()" [isCollapsable]="true" [isRemovable]="false" boxColor="primary" *ngFor="let repository of repositories" class="col-md-6">
+ <div class="box-body">
+ <form #form>
+ <app-form-input [formType]="formType" [model]="repository" [cols]="1"></app-form-input>
+ </form>
+ <div class="box-footer">
+
+ <button type="button" class="btn btn-primary" translate="save" (click)="saveRepository(Form, repository)"></button>
+ <button type="button" class="btn btn-danger pull-right" (click)="deleteRepository(repository)" translate="delete">
+ </button>
+ </div>
+ </div>
+ <div class="box-footer">
+ <mk-box header="{{'filesystem_info'|translate}}" [isCollapsable]="true" [isRemovable]="false" contentClasses="table-responsive">
+ <button type="button" [disabled]="repository.password.length == 0" class="btn btn-primary pull-right" (click)="refreshRepoInfo(repository)">
+ <i class="fa fa-refresh"></i> <span translate="refresh_info"></span>
+ </button>
+ <div class="box-body no-padding" >
+
+ <div translate="connection_not_available" *ngIf="!repository.info"></div>
+ <table class="table table-condensed table-striped" *ngIf="repository.info">
+ <tbody>
+ <tr>
+ <th colspan="5" translate="disk_info"></th>
+ </tr>
+ <tr>
+ <th translate="partition"></th>
+ <th translate="total_disk"></th>
+ <th translate="used_disk"></th>
+ <th translate="free_disk"></th>
+ <th translate="busy_percent_disk"></th>
+ </tr>
+ <tr>
+ <td>{{repository.info.disk[0].partition}}</td>
+ <td>{{repository.info.disk[0].total}}</td>
+ <td>{{repository.info.disk[0].used}}</td>
+ <td>
+ {{repository.info.disk[0].free}}
+ </td>
+ <td>
+ <span class="badge" ng-class="{'bg-green': repository.info.disk[0].percent.split('%')[0] < 60, 'bg-red': repository.info.disk[0].percent.split('%')[0] > 85, 'bg-yellow': repository.info.disk[0].percent.split('%')[0] >= 60 && repository.info.disk[0].percent.split('%')[0] <= 85}">{{repository.info.disk[0].percent}}
+ </span>
+ </td>
+ </tr>
+ </tbody>
+ <tbody>
+ <tr>
+ <th colspan="2" translate="images_info"></th>
+ </tr>
+ <tr>
+ <th translate="name"></th>
+ <th translate="size"></th>
+ <th translate="delete"></th>
+ </tr>
+ </tbody>
+ <tbody ng-repeat="fileGroup in repository.info.files">
+ <tr ng-repeat="file in fileGroup | orderBy: 'name'">
+ <td>{{file.name}}</td>
+ <td>{{OGCommonService.getUnits(file.size)}}</td>
+ <td>
+ <a *ngIf="isImageFile(file)" class="btn btn-danger" href="javascript:void(0)" translate="delete" (click)="deleteImageFile(file)"></a>
+ </td>
+ </tr>
+ </tbody>
+ </table>
+ </div>
+ </mk-box>
+ </div>
+ <!-- /.box-body -->
+ </mk-box>
+ </div>
+</section>
diff --git a/admin/WebConsole3/frontend/src/app/pages/software/software.component.css b/admin/WebConsole3/frontend/src/app/pages/software/software.component.scss
index e69de29b..e69de29b 100644
--- a/admin/WebConsole3/frontend/src/app/pages/software/software.component.css
+++ b/admin/WebConsole3/frontend/src/app/pages/software/software.component.scss
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 a51d9560..59b81298 100644
--- a/admin/WebConsole3/frontend/src/app/pages/software/software.component.ts
+++ b/admin/WebConsole3/frontend/src/app/pages/software/software.component.ts
@@ -11,7 +11,7 @@ import {SoftwareTypeService} from '../../api/software-type.service';
@Component({
selector: 'app-software',
templateUrl: './software.component.html',
- styleUrls: ['./software.component.css']
+ styleUrls: ['./software.component.scss']
})
export class SoftwareComponent implements OnInit {
public softwareProfileGroups: any[] = [];
diff --git a/admin/WebConsole3/frontend/src/app/pages/trace/trace.component.ts b/admin/WebConsole3/frontend/src/app/pages/trace/trace.component.ts
index af1b2cf7..750e5096 100644
--- a/admin/WebConsole3/frontend/src/app/pages/trace/trace.component.ts
+++ b/admin/WebConsole3/frontend/src/app/pages/trace/trace.component.ts
@@ -1,261 +1,263 @@
-import {Component, OnDestroy, OnInit} from '@angular/core';
-
-import { TraceService } from 'src/app/api/trace.service';
-import { Trace } from 'src/app/model/trace';
-import {ToasterService} from '../../service/toaster.service';
-import {OgSweetAlertService} from '../../service/og-sweet-alert.service';
-import {Router} from '@angular/router';
-import {OgCommonService} from '../../service/og-common.service';
-import {environment} from '../../../environments/environment';
-import {TranslateService} from '@ngx-translate/core';
-import {QueryOptions} from 'globunet-angular/core/providers/api/query-options';
-import {forkJoin} from 'rxjs';
-
-import * as moment from 'moment';
-
-@Component({
- selector: 'app-trace',
- templateUrl: './trace.component.html',
- styleUrls: [ './trace.component.scss' ]
-})
-export class TraceComponent implements OnInit, OnDestroy {
- public traces = [];
- public selection = [];
- public filters = {
- searchText: '',
- status: {
- 'finished': {
- name: 'finished',
- selected: true
- },
- 'execution': {
- name: 'execution',
- selected: true
- }
- },
- finishedStatus: {
- 'noErrors': {
- name: 'no-errors',
- selected: true
- },
- 'withErrors': {
- name: 'with-errors',
- selected: true
- },
- },
- dateRange: {
- startDate: null,
- endDate: null
- }
- };
- config: { constants: any; timers: any; };
-
- private datePickerOptions: { timePickerIncrement: number; timePicker: boolean; format: string; timePicker24Hour: boolean; locale: { fromLabel: any; toLabel: any; cancelLabel: any; firstDay: number; applyLabel: any; format: string; daysOfWeek: any[]; separator: string; customRangeLabel: any; weekLabel: string; monthNames: any[] } };
- private selectAll: any;
- private executionTasks: Trace[];
- public showInfo: string;
- // this tells the tabs component which Pages
- // should be each tab's root Page
- constructor(public traceService: TraceService,
- private ogCommonService: OgCommonService,
- private router: Router,
- private ogSweetAlert: OgSweetAlertService,
- private toaster: ToasterService,
- private translate: TranslateService) {
- }
-
- ngOnDestroy() {
- if (this.config.timers && this.config.timers.executionsInterval) {
- clearInterval(this.config.timers.executionsInterval.object);
- }
- }
-
-ngOnInit(): void {
- const self = this;
- this.ogCommonService.loadEngineConfig().subscribe(
- data => {
- this.config = data;
-
- if (this.config.timers.executionsInterval.object === null) {
- this.config.timers.executionsInterval.object = setInterval(function() {
- self.getExecutionTasks();
- }, this.config.timers.executionsInterval.tick);
- }
-
- this.datePickerOptions = {
- 'locale': {
- 'format': 'DD/MM/YYYY HH:mm',
- 'separator': ' - ',
- 'applyLabel': this.translate.instant('apply'),
- 'cancelLabel': this.translate.instant('cancel'),
- 'fromLabel': this.translate.instant('from'),
- 'toLabel': this.translate.instant('to'),
- 'customRangeLabel': this.translate.instant('custom_range'),
- 'weekLabel': 'W',
- 'daysOfWeek': [
- this.translate.instant('sun'),
- this.translate.instant('mon'),
- this.translate.instant('tue'),
- this.translate.instant('wed'),
- this.translate.instant('thu'),
- this.translate.instant('fri'),
- this.translate.instant('sat')
- ],
- 'monthNames': [
- this.translate.instant('january'),
- this.translate.instant('february'),
- this.translate.instant('march'),
- this.translate.instant('april'),
- this.translate.instant('may'),
- this.translate.instant('june'),
- this.translate.instant('july'),
- this.translate.instant('august'),
- this.translate.instant('september'),
- this.translate.instant('october'),
- this.translate.instant('november'),
- this.translate.instant('december')
- ],
- 'firstDay': 1
- },
- timePicker: true,
- timePickerIncrement: 30,
- timePicker24Hour: true,
- format: 'DD/MM/YYYY HH:mm'
- };
- this.traceService.list().subscribe(
- (response) => {
- this.traces = response;
- },
- (error) => {
- this.toaster.pop({type: 'error', title: 'error', body: error});
- }
- );
- }
- );
-}
-
-
- selectTrace(trace) {
- const index = this.selection.indexOf(trace);
- if (trace.selected === true && index === -1) {
- this.selection.push(trace);
- } else if (trace.selected === false && index !== -1) {
- this.selection.splice(index, 1);
- }
- }
-
- selectAllTraces() {
- const filter = this.traces.filter(function(trace: Trace) {
- return true;
- });
- for (let index = 0; index < filter.length; index++) {
- filter[index].selected = this.selectAll;
- this.selectTrace(filter[index]);
- }
- }
-
- relaunchTraces() {
-
- }
-
- deleteTraces() {
- this.ogSweetAlert.question( this.translate.instant('sure_to_delete') + '?', this.translate.instant('action_cannot_be_undone'), function(response) {
- const promises = [];
- for (let index = 0; index < this.selection.length; index++) {
- promises.push(this.traceService.delete(this.selection[index].id));
- }
- forkJoin(promises).subscribe(
- (success) => {
- this.toaster.pop({type: 'success', title: 'success', body: this.translate.instant('successfully_deleted')});
- this.selectAll = false;
- this.selection = [];
- this.searchText = '';
- },
- (error) => {
- this.toaster.pop({type: 'error', title: 'error', body: error});
- }
- );
- });
- }
-
- getExecutionTasks() {
- this.traceService.list(new QueryOptions({finished: 0})).subscribe(
- (result) => {
- this.executionTasks = result;
- },
- (error) => {
-
- }
- );
- }
-
- deleteExecutionTace(task) {
- this.ogSweetAlert.question(
- this.translate.instant('delete_task'),
- this.translate.instant('sure_to_delete_task') + '?',
- function(result) {
- if (result) {
- this.traceService.delete(task.id).subscribe(
- (response) => {
- this.toaster.pop({type: 'success', title: 'success', body: this.translate.instant('successfully_deleted')});
- this.getExecutionTasks();
- },
- (error) => {
- this.toaster.pop({type: 'error', title: 'error', body: error});
- }
- );
-
- }
- }
- );
-
- }
-
- relaunchExecutionTask(task) {
- this.ogSweetAlert.question(
- this.translate.instant('relaunch_task'),
- this.translate.instant('sure_to_relaunch_task') + '?',
- function(result) {
- if (result) {
-
- }
- }
- );
- }
-
- filterTraceStatus(trace, index, array) {
-
- // Comprobar si para el filtro de estado actual de la traza
- let result = (trace.finishedAt != null && this.filters.status['finished'].selected === true) || (trace.finishedAt === null && this.filters.status['execution'].selected === true);
- result = result && (trace.finishedAt != null && (trace.status === 0 && this.filters.finishedStatus['noErrors'].selected === true) || (trace.status !== 0 && this.filters.finishedStatus['withErrors'].selected === true));
- if (this.filters.dateRange.startDate != null) {
- result = result && moment(trace.executedAt).isAfter(this.filters.dateRange.startDate);
- }
- if (this.filters.dateRange.endDate != null) {
- result = result && moment(trace.executedAt).isBefore(this.filters.dateRange.endDate);
- }
-
- return result;
- }
-
-
- filteredTraces() {
- const self = this;
- return this.traces.filter(function(trace, index, array) {
- return self.filterTraceStatus(trace, index, array);
- });
- }
-
- getTraceCssClass(trace: any) {
- let result = '';
- if (!trace.finishedAt) {
- result = 'fa-warning text-yellow';
- }
- if (trace.status === 0) {
- result += ' fa-check-circle text-green';
- } else {
- result += ' fa-times-circle text-red';
- }
- return result;
- }
-}
+import {Component, OnDestroy, OnInit} from '@angular/core';
+
+import { TraceService } from 'src/app/api/trace.service';
+import { Trace } from 'src/app/model/trace';
+import {ToasterService} from '../../service/toaster.service';
+import {OgSweetAlertService} from '../../service/og-sweet-alert.service';
+import {Router} from '@angular/router';
+import {OgCommonService} from '../../service/og-common.service';
+import {environment} from '../../../environments/environment';
+import {TranslateService} from '@ngx-translate/core';
+import {QueryOptions} from 'globunet-angular/core/providers/api/query-options';
+import {forkJoin} from 'rxjs';
+
+import * as moment from 'moment';
+
+@Component({
+ selector: 'app-trace',
+ templateUrl: './trace.component.html',
+ styleUrls: [ './trace.component.scss' ]
+})
+export class TraceComponent implements OnInit, OnDestroy {
+ public traces = [];
+ public selection = [];
+ public searchText = '';
+ public filters = {
+ searchText: '',
+ status: {
+ 'finished': {
+ name: 'finished',
+ selected: true
+ },
+ 'execution': {
+ name: 'execution',
+ selected: true
+ }
+ },
+ finishedStatus: {
+ 'noErrors': {
+ name: 'no-errors',
+ selected: true
+ },
+ 'withErrors': {
+ name: 'with-errors',
+ selected: true
+ },
+ },
+ dateRange: {
+ startDate: null,
+ endDate: null
+ }
+ };
+ config: { constants: any; timers: any; };
+
+ private datePickerOptions: { timePickerIncrement: number; timePicker: boolean; format: string; timePicker24Hour: boolean; locale: { fromLabel: any; toLabel: any; cancelLabel: any; firstDay: number; applyLabel: any; format: string; daysOfWeek: any[]; separator: string; customRangeLabel: any; weekLabel: string; monthNames: any[] } };
+ private selectAll: any;
+ private executionTasks: Trace[];
+ public showInfo: string;
+ // this tells the tabs component which Pages
+ // should be each tab's root Page
+ constructor(public traceService: TraceService,
+ private ogCommonService: OgCommonService,
+ private router: Router,
+ private ogSweetAlert: OgSweetAlertService,
+ private toaster: ToasterService,
+ private translate: TranslateService) {
+ }
+
+ ngOnDestroy() {
+ if (this.config.timers && this.config.timers.executionsInterval) {
+ clearInterval(this.config.timers.executionsInterval.object);
+ }
+ }
+
+ngOnInit(): void {
+ const self = this;
+ this.ogCommonService.loadEngineConfig().subscribe(
+ data => {
+ this.config = data;
+
+ if (this.config.timers.executionsInterval.object === null && this.config.timers.executionsInterval.tick > 0) {
+ this.config.timers.executionsInterval.object = setInterval(function() {
+ self.getExecutionTasks();
+ }, this.config.timers.executionsInterval.tick);
+ }
+
+ this.datePickerOptions = {
+ 'locale': {
+ 'format': 'DD/MM/YYYY HH:mm',
+ 'separator': ' - ',
+ 'applyLabel': this.translate.instant('apply'),
+ 'cancelLabel': this.translate.instant('cancel'),
+ 'fromLabel': this.translate.instant('from'),
+ 'toLabel': this.translate.instant('to'),
+ 'customRangeLabel': this.translate.instant('custom_range'),
+ 'weekLabel': 'W',
+ 'daysOfWeek': [
+ this.translate.instant('sun'),
+ this.translate.instant('mon'),
+ this.translate.instant('tue'),
+ this.translate.instant('wed'),
+ this.translate.instant('thu'),
+ this.translate.instant('fri'),
+ this.translate.instant('sat')
+ ],
+ 'monthNames': [
+ this.translate.instant('january'),
+ this.translate.instant('february'),
+ this.translate.instant('march'),
+ this.translate.instant('april'),
+ this.translate.instant('may'),
+ this.translate.instant('june'),
+ this.translate.instant('july'),
+ this.translate.instant('august'),
+ this.translate.instant('september'),
+ this.translate.instant('october'),
+ this.translate.instant('november'),
+ this.translate.instant('december')
+ ],
+ 'firstDay': 1
+ },
+ timePicker: true,
+ timePickerIncrement: 30,
+ timePicker24Hour: true,
+ format: 'DD/MM/YYYY HH:mm'
+ };
+ this.traceService.list().subscribe(
+ (response) => {
+ this.traces = response;
+ },
+ (error) => {
+ this.toaster.pop({type: 'error', title: 'error', body: error});
+ }
+ );
+ }
+ );
+}
+
+
+ selectTrace(trace) {
+ const index = this.selection.indexOf(trace);
+ if (trace.selected === true && index === -1) {
+ this.selection.push(trace);
+ } else if (trace.selected === false && index !== -1) {
+ this.selection.splice(index, 1);
+ }
+ }
+
+ selectAllTraces() {
+ const filter = this.traces.filter(function(trace: Trace) {
+ return true;
+ });
+ for (let index = 0; index < filter.length; index++) {
+ filter[index].selected = this.selectAll;
+ this.selectTrace(filter[index]);
+ }
+ }
+
+ relaunchTraces() {
+
+ }
+
+ deleteTraces() {
+ const self = this;
+ this.ogSweetAlert.question( this.translate.instant('sure_to_delete') + '?', this.translate.instant('action_cannot_be_undone'), function(response) {
+ const promises = [];
+ for (let index = 0; index < self.selection.length; index++) {
+ promises.push(self.traceService.delete(self.selection[index].id));
+ }
+ forkJoin(promises).subscribe(
+ (success) => {
+ self.toaster.pop({type: 'success', title: 'success', body: self.translate.instant('successfully_deleted')});
+ self.selectAll = false;
+ self.selection = [];
+ self.searchText = '';
+ },
+ (error) => {
+ self.toaster.pop({type: 'error', title: 'error', body: error});
+ }
+ );
+ });
+ }
+
+ getExecutionTasks() {
+ this.traceService.list(new QueryOptions({finished: 0})).subscribe(
+ (result) => {
+ this.executionTasks = result;
+ },
+ (error) => {
+
+ }
+ );
+ }
+
+ deleteExecutionTace(task) {
+ this.ogSweetAlert.question(
+ this.translate.instant('delete_task'),
+ this.translate.instant('sure_to_delete_task') + '?',
+ function(result) {
+ if (result) {
+ this.traceService.delete(task.id).subscribe(
+ (response) => {
+ this.toaster.pop({type: 'success', title: 'success', body: this.translate.instant('successfully_deleted')});
+ this.getExecutionTasks();
+ },
+ (error) => {
+ this.toaster.pop({type: 'error', title: 'error', body: error});
+ }
+ );
+
+ }
+ }
+ );
+
+ }
+
+ relaunchExecutionTask(task) {
+ this.ogSweetAlert.question(
+ this.translate.instant('relaunch_task'),
+ this.translate.instant('sure_to_relaunch_task') + '?',
+ function(result) {
+ if (result) {
+
+ }
+ }
+ );
+ }
+
+ filterTraceStatus(trace, index, array) {
+
+ // Comprobar si para el filtro de estado actual de la traza
+ let result = (trace.finishedAt != null && this.filters.status['finished'].selected === true) || (trace.finishedAt === null && this.filters.status['execution'].selected === true);
+ result = result && (trace.finishedAt != null && (trace.status === 0 && this.filters.finishedStatus['noErrors'].selected === true) || (trace.status !== 0 && this.filters.finishedStatus['withErrors'].selected === true));
+ if (this.filters.dateRange.startDate != null) {
+ result = result && moment(trace.executedAt).isAfter(this.filters.dateRange.startDate);
+ }
+ if (this.filters.dateRange.endDate != null) {
+ result = result && moment(trace.executedAt).isBefore(this.filters.dateRange.endDate);
+ }
+
+ return result;
+ }
+
+
+ filteredTraces() {
+ const self = this;
+ return this.traces.filter(function(trace, index, array) {
+ return self.filterTraceStatus(trace, index, array);
+ });
+ }
+
+ getTraceCssClass(trace: any) {
+ let result = '';
+ if (!trace.finishedAt) {
+ result = 'fa-warning text-yellow';
+ }
+ if (trace.status === 0) {
+ result += ' fa-check-circle text-green';
+ } else {
+ result += ' fa-times-circle text-red';
+ }
+ return result;
+ }
+}
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 14e80e84..1ea33faa 100644
--- a/admin/WebConsole3/frontend/src/app/service/og-commands.service.ts
+++ b/admin/WebConsole3/frontend/src/app/service/og-commands.service.ts
@@ -14,15 +14,11 @@ import {environment} from '../../environments/environment';
export class OGCommandsService {
public ogInstructions = '';
public execution: any;
- private commands = [];
+ private commands: any;
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;
- }
- );
+ this.commands = environment.commands;
}
sendCommand() {
@@ -114,15 +110,19 @@ export class OGCommandsService {
// 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
+ const clonablePartitions = [];
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);
+ const str = 'disco: ' + obj.numDisk + ', part: ' + obj.numPartition + ', SO: ' + client.partitions[index].osName;
+ clonablePartitions.push(obj.numDisk + ' ' + obj.numPartition)
+ options.scope.partitions.push(str);
}
}
+ const self = this;
+
this.ogSweetAlert.swal({
title: this.translate.instant('select_partition_to_inventary'),
// text: $filter("translate")("action_cannot_be_undone"),
@@ -137,9 +137,9 @@ export class OGCommandsService {
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();
+ self.execution.script = self.commands.SOFTWARE_INVENTORY + ' ' + clonablePartitions[result.value];
+ self.loadClients();
+ self.sendCommand();
}
},
null);
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 8a2bbe56..b529199d 100644
--- a/admin/WebConsole3/frontend/src/app/service/og-common.service.ts
+++ b/admin/WebConsole3/frontend/src/app/service/og-common.service.ts
@@ -26,10 +26,13 @@ export class OgCommonService {
constructor(private layoutStore: LayoutStore, private adminLteConfig: AdminLteConf, private engineService: EngineService, private translate: TranslateService, private authModule: AuthModule) {
this.app = {};
- this.selectedClients = [];
+ this.selectedClients = {};
this.selectedOu = null;
this.movingOu = null;
this.movingClients = false;
+ if (localStorage.getItem('selectedClients')) {
+ this.selectedClients = JSON.parse(localStorage.getItem('selectedClients'));
+ }
}
loadEngineConfig(): Observable<{constants: any, timers: any}> {
@@ -43,21 +46,22 @@ export class OgCommonService {
themes: environment.themes,
menus: environment.menus,
languages: environment.languages,
- deployMethods: environment.deployMethods
+ deployMethods: environment.deployMethods,
+ commands: environment.commands
};
this.constants = Object.assign(this.constants, data[0]);
// inicializar timers generales para refresco de información
this.timers = {
serverStatusInterval: {
- tick: 5000,
+ tick: 0,
object: null
},
clientsStatusInterval: {
- tick: 5000,
+ tick: 0,
object: null
},
executionsInterval: {
- tick: 5000,
+ tick: 0,
object: null
},
@@ -190,6 +194,19 @@ export class OgCommonService {
} else {
delete this.selectedClients[client.id];
}
+ this.saveSelection();
+ }
+
+ saveSelection() {
+ if (Object.keys(this.selectedClients).length > 0) {
+ localStorage.setItem('selectedClients', JSON.stringify(this.selectedClients, function (key, value) {
+ let result = value;
+ if (key === 'parent' && typeof value === 'object') {
+ result = value.id;
+ }
+ return result;
+ }));
+ }
}
getSelectionSize() {
diff --git a/admin/WebConsole3/frontend/src/styles.scss b/admin/WebConsole3/frontend/src/styles.scss
index 65c2fd6d..b0a5eaec 100644
--- a/admin/WebConsole3/frontend/src/styles.scss
+++ b/admin/WebConsole3/frontend/src/styles.scss
@@ -19,6 +19,14 @@ table.table-no-border {
border: none;
}
+.loader {
+ position: absolute;
+ top: 0;
+ width: 100%;
+ height: 100%;
+ z-index: 999999;
+}
+
#loading-bar .bar {
background: white;
}
@@ -100,8 +108,7 @@ i.client {
}
.bg-lab{
- background-color: #d7dbef;
- padding: 10px 10px 0 10px;
+ background-color: #d7dbef !important;
}
tr.odd {
@@ -182,7 +189,7 @@ table.disk-partitions td {
}
table.disk-partitions td span {
- padding: 5px 10px;
+ padding: 5px 5px;
font-weight: bold;
}
@@ -306,3 +313,7 @@ ul.dropdown-menu.fit {
ng2-smart-table {
font-size: initial !important;
}
+
+.swal2-popup {
+ font-size: 1em !important;
+}