Commit 7008964e authored by Alejandro Sarmiento's avatar Alejandro Sarmiento

AS test

parent 7f5bff9f
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
......@@ -25,11 +25,7 @@ const routes: Routes = [
{
path: 'configuration', data: { breadcrumb: 'Agentes' }, canLoad: [AuthGuard],
loadChildren: () => import('./modules/agent/agent.module').then(m => m.AgentModule)
},
{
path: 'dashboards', data: { breadcrumb: 'Dashboards' }, canLoad: [AuthGuard],
loadChildren: () => import('./modules/dashboards/dashboards.module').then(m => m.DashboardsModule)
},
}
],
canActivate: [AuthGuard]
},
......
......@@ -117,20 +117,20 @@ export function createTranslateLoader(http: HttpClient) {
{ provide: ResourceAuthGuard, useClass: ResourceAuthGuard },
// descomentar estas lineas para OAUTH
{ provide: AuthGuard, useClass: OAuthGuard },
{ provide: AuthenticationService, useClass: OAuthAuthenticationService },
{ provide: APP_INITIALIZER, useFactory: loginLoaderFactory, deps: [AuthenticationService], multi: true },
//{ provide: AuthGuard, useClass: OAuthGuard },
//{ provide: AuthenticationService, useClass: OAuthAuthenticationService },
//{ provide: APP_INITIALIZER, useFactory: loginLoaderFactory, deps: [AuthenticationService], multi: true },
// Para probar mantenimientos
// comentar estas lineas para OAUTH
// { provide: AuthGuard, useClass: AuthGuard},
// { provide: AuthenticationService, useClass: ByteAuthenticationService },
// { provide: HTTP_INTERCEPTORS, useClass: AuthenticationFakeBackendInterceptor, multi: true},
// { provide: HTTP_INTERCEPTORS, useClass: SettingsFakeBackendInterceptor, multi: true },
// { provide: HTTP_INTERCEPTORS, useClass: CustomProgramsFakeBackendInterceptor, multi: true },
// { provide: HTTP_INTERCEPTORS, useClass: AgentFakeBackendInterceptor, multi: true },
// { provide: HTTP_INTERCEPTORS, useClass: OperativeDashboardFakeBackendInterceptor, multi: true },
{ provide: AuthGuard, useClass: AuthGuard},
{ provide: AuthenticationService, useClass: ByteAuthenticationService },
{ provide: HTTP_INTERCEPTORS, useClass: AuthenticationFakeBackendInterceptor, multi: true},
{ provide: HTTP_INTERCEPTORS, useClass: SettingsFakeBackendInterceptor, multi: true },
{ provide: HTTP_INTERCEPTORS, useClass: CustomProgramsFakeBackendInterceptor, multi: true },
{ provide: HTTP_INTERCEPTORS, useClass: AgentFakeBackendInterceptor, multi: true },
{ provide: HTTP_INTERCEPTORS, useClass: OperativeDashboardFakeBackendInterceptor, multi: true },
{ provide: APP_INITIALIZER, useFactory: init_app, deps: [InitCommonsService, TranslateService], multi: true }
......
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { OperativeDashboardComponent } from './views/operative-dashboard/components/operative-dashboard/operative-dashboard.component';
import { CustomerInteractionComponent } from './views/customer-interaction-dashboard/componentes/customer-interaction/customer-interaction.component';
const routes: Routes = [
{
path: 'operative', component: OperativeDashboardComponent,
data: {
program: 'CONVERSATIONAL_AGENT',
breadcrumb: 'Operativo',
title: 'dashboards.operative.title',
titleDesc: 'dashboards.operative.title.desc'
}
},
{
path: 'customer-interaction', component: CustomerInteractionComponent,
data: {
program: 'CONVERSATIONAL_AGENT',
breadcrumb: 'Operativo',
title: 'dashboards.customer.interaction.title',
titleDesc: 'dashboards.customer.interaction.title.desc'
}
}
];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule]
})
export class DashboardsRoutingModule { }
import { NgModule } from '@angular/core';
import { DirtyGuard, XdfGalleryModule, EditableDataTableTemplateResolver } from '@xdf/gallery';
import { DashboardsRoutingModule } from './dashboards-routing.module';
import { TranslateModule } from '@ngx-translate/core';
import { ReactiveFormsModule, FormsModule } from '@angular/forms';
import { CommonModule } from '@angular/common';
import { MatFormFieldModule, MatSelectModule, MatTooltipModule, MatButtonModule, MatDatepickerModule,
MatInputModule, MatPaginatorModule, MatSortModule, MatIconModule } from '@angular/material';
import { XdfSettingsModule } from '@xdf/settings';
import { XdfLayoutsModule } from '@xdf/layouts';
import { OperativeDashboardComponent } from './views/operative-dashboard/components/operative-dashboard/operative-dashboard.component';
import { SummaryPetiWidgetComponent } from './views/operative-dashboard/components/summary-peti-widget/summary-peti-widget.component';
import { CustomerActivityWidgetComponent } from './views/operative-dashboard/components/customer-activity-widget/customer-activity-widget.component';
import { ChartsModule } from 'ng2-charts';
import { NgxChartsModule } from '@swimlane/ngx-charts';
import { ChartModule, HIGHCHARTS_MODULES } from 'angular-highcharts';
import more from 'highcharts/highcharts-more.src';
import exporting from 'highcharts/modules/exporting.src';
import highmaps from 'highcharts/modules/map.src';
import sankey from 'highcharts/modules/sankey.src';
import { XdfGraphModule } from '@xdf/graph';
import { WidgetPetiComponent } from './views/operative-dashboard/components/widget-peti/widget-peti.component';
import { GaugeChartComponent } from './views/operative-dashboard/components/gauge-chart/gauge-chart.component';
import { GaugeChartModule } from 'angular-gauge-chart';
import { InactivitySesionComponent } from './views/operative-dashboard/components/inactivity-sesion/inactivity-sesion.component';
import { HeatMapComponent } from './views/operative-dashboard/components/heat-map/heat-map.component';
import { OperativeDashboardFilterComponent } from './views/operative-dashboard/components/operative-dashboard-filter/operative-dashboard-filter.component';
import { NgxMatDateAdapter, NgxMatDatetimePickerModule, NgxMatNativeDateModule, NgxMatTimepickerModule } from '@angular-material-components/datetime-picker';
import { LocalizedDateModule } from '@xdf/commons';
import { StackedColumnChartComponent } from './views/customer-interaction-dashboard/componentes/stacked-column-chart/stacked-column-chart.component';
import { CustomerInteractionComponent } from './views/customer-interaction-dashboard/componentes/customer-interaction/customer-interaction.component';
import { CustomerInteractionFilterComponent } from './views/customer-interaction-dashboard/componentes/customer-interaction-filter/customer-interaction-filter.component';
import { SankeyDiagramComponent } from './views/customer-interaction-dashboard/componentes/sankey-diagram/sankey-diagram.component';
import { MatTabsModule } from '@angular/material/tabs';
import { MessageByIntentTableComponent } from './views/customer-interaction-dashboard/componentes/message-by-intent-table/message-by-intent-table.component';
import { UnidentifiedSentencesTableComponent } from './views/customer-interaction-dashboard/componentes/unidentified-sentences-table/unidentified-sentences-table.component';
import { MatTableModule } from '@angular/material/table';
import { AvgIntentByCustomerComponent } from './views/customer-interaction-dashboard/componentes/avg-intent-by-customer/avg-intent-by-customer.component';
import { TracingIntentByCustomerComponent } from './views/customer-interaction-dashboard/componentes/tracing-intent-by-customer/tracing-intent-by-customer.component';
import { MillisToDayHourMinuteSecond } from './pipes/millis-to-day-hour-minute-second.pipe';
import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
export function highchartsModules() {
// apply Highcharts Modules to this array
return [ more, exporting, highmaps, sankey];
}
@NgModule({
declarations: [
OperativeDashboardComponent,
SummaryPetiWidgetComponent,
CustomerActivityWidgetComponent,
WidgetPetiComponent,
GaugeChartComponent,
InactivitySesionComponent,
HeatMapComponent,
OperativeDashboardFilterComponent,
StackedColumnChartComponent,
CustomerInteractionComponent,
CustomerInteractionFilterComponent,
SankeyDiagramComponent,
MessageByIntentTableComponent,
UnidentifiedSentencesTableComponent,
AvgIntentByCustomerComponent,
MillisToDayHourMinuteSecond,
TracingIntentByCustomerComponent],
imports: [
CommonModule,
FormsModule,
ReactiveFormsModule,
TranslateModule,
DashboardsRoutingModule,
MatFormFieldModule,
MatSelectModule,
MatTooltipModule,
XdfGalleryModule,
XdfSettingsModule,
XdfLayoutsModule,
MatButtonModule,
ChartModule,
XdfGraphModule,
GaugeChartModule,
NgxChartsModule,
ChartsModule,
MatDatepickerModule,
NgxMatDatetimePickerModule,
NgxMatTimepickerModule,
NgxMatNativeDateModule,
MatInputModule,
LocalizedDateModule,
MatTabsModule,
MatTableModule,
MatPaginatorModule,
MatSortModule,
MatIconModule,
NgbModule
],
entryComponents: [
],
providers: [
{ provide: DirtyGuard, useClass: DirtyGuard },
EditableDataTableTemplateResolver,
{ provide: HIGHCHARTS_MODULES, useFactory: highchartsModules }
]
})
export class DashboardsModule { }
import { Pipe, PipeTransform } from '@angular/core';
import { TranslateService } from '@ngx-translate/core';
@Pipe({
name: 'millisToDayHourMinuteSecond'
})
export class MillisToDayHourMinuteSecond implements PipeTransform {
constructor(private translateService: TranslateService) {}
transform(value: any, ...args: any[]) {
let valueNumber: number;
const type = typeof value;
if (type === 'number') {
valueNumber = value;
} else if (type === 'string') {
valueNumber = + value;
}
if (valueNumber > 0) {
const days = Math.trunc(valueNumber / 86400);
valueNumber = valueNumber % 86400;
const hours = Math.trunc(valueNumber / 3600);
valueNumber = valueNumber % 3600;
const minutes = Math.trunc(valueNumber / 60);
valueNumber = valueNumber % 60;
const seconds = valueNumber;
return (days < 10 ? '0' : '') + days + this.translateService.instant('pipe.format.day')
+ ' ' + (hours < 10 ? '0' : '') + hours + this.translateService.instant('pipe.format.hour')
+ ' ' + (minutes < 10 ? '0' : '') + minutes + this.translateService.instant('pipe.format.minute')
+ ' ' + (seconds < 10 ? '0' : '') + seconds + this.translateService.instant('pipe.format.seconds');
}
return value;
}
}
import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
@Injectable({
providedIn: 'root'
})
export class CustomerInteractionService {
constructor(protected http: HttpClient) {
}
get serviceURL(): string {
return './dashboard/customer-interaction';
}
getSummary(startDate: Date, endDate: Date, channel: string) {
return this.http.post(this.serviceURL, {startDate, endDate, channel});
}
}
import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
@Injectable({
providedIn: 'root'
})
export class OperationalConsultationService {
constructor(protected http: HttpClient) {
}
get serviceURL(): string {
return './dashboard/operative';
}
getSummary(startDate: Date, endDate: Date, channel: string) {
return this.http.post(this.serviceURL, {startDate, endDate, channel});
}
}
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { AvgIntentByCustomerComponent } from './avg-intent-by-customer.component';
describe('AvgIntentByCustomerComponent', () => {
let component: AvgIntentByCustomerComponent;
let fixture: ComponentFixture<AvgIntentByCustomerComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ AvgIntentByCustomerComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(AvgIntentByCustomerComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
import { Component, Input, OnInit } from '@angular/core';
import { Chart } from 'angular-highcharts';
import * as Highcharts from 'highcharts';
import { utc } from 'moment';
@Component({
selector: 'byte-avg-intent-by-customer',
templateUrl: './avg-intent-by-customer.component.html',
styleUrls: ['./avg-intent-by-customer.component.scss']
})
export class AvgIntentByCustomerComponent implements OnInit {
chart: Chart;
@Input()
data: Array<number> = [];
@Input()
minDate: Date = new Date();
constructor() { }
ngOnInit() {
if (!this.data) {
return;
}
this.chart = new Chart({
title: {
text: ''
},
exporting: {
enabled: false
},
credits: {
enabled: false
},
legend: {
enabled: false
},
chart: {
renderTo: 'container',
type: 'column',
zoomType: 'xy'
},
xAxis: {
type: 'datetime',
tickInterval: 86400000,
labels: {
formatter() {
return Highcharts.dateFormat('%e - %b',
this.value);
}
}
},
yAxis: {
title: {
text: ''
}
},
series: [
{
name: 'Promedio',
pointStart: this.getDate(this.minDate),
pointInterval: 86400000,
dataLabels: {
inside: false,
enabled: true,
style: {
color: 'white'
}
},
data: this.data
}
] as Array<any>
});
}
private getDate(date: Date): any {
// let dateNumber = Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDay(), 0, 0, 0);
// console.log(dateNumber);
// return dateNumber;
return (new Date(Date.UTC(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0))).getTime();
}
}
<div class="row">
<div class="col-12">
<div class="mail-box-content consult pb-3" style="margin: -15px -15px 15px -15px;">
<div class="expansion-content pull-right">
<div class="row">
<div class="col-5">
<mat-form-field class="full-width">
<mat-label>{{'query.filters.startDate' | translate }}</mat-label>
<input matInput [ngxMatDatetimePicker]="startPicker" [(ngModel)]="startDateTime"
id="startPickerCIP" (click)="startPicker.open()" onkeyup="this.value=this.value.replace(/.*/gi, '');">
<mat-datepicker-toggle matSuffix [for]="startPicker"></mat-datepicker-toggle>
<ngx-mat-datetime-picker #startPicker></ngx-mat-datetime-picker>
</mat-form-field>
</div>
<div class="col-4">
<mat-form-field class="full-width">
<mat-label>{{'query.filters.endDate' | translate }}</mat-label>
<input matInput [ngxMatDatetimePicker]="endPicker" [(ngModel)]="endDateTime"
(click)="endPicker.open()" onkeyup="this.value=this.value.replace(/.*/gi, '');">
<mat-datepicker-toggle matSuffix [for]="endPicker"></mat-datepicker-toggle>
<ngx-mat-datetime-picker #endPicker></ngx-mat-datetime-picker>
</mat-form-field>
</div>
<div class="col-3">
<button class="btn btn-primary btn-sm ng-star-inserted" style="margin-left: 10px;
margin-top: 10px !important;"
type="button" [disabled]="!startDateTime || !endDateTime" (click)="search()">
<i class="fa fa-search"></i><span class="btn-label">Buscar</span>
</button>
</div>
</div>
</div>
<div class="pull-left icon" *ngIf="icon">
<div [innerHTML]="icon"></div>
</div>
<h3 class="grid-title">
<span>{{ header | translate }}</span>
</h3>
<span *ngIf="headerDesc" class="small">{{ headerDesc | translate }}</span>
</div>
</div>
</div>
<router-outlet></router-outlet>
\ No newline at end of file
.ibox-content {
font-size: 12px;
}
.table.invoice-total {
margin-bottom: 0px;
}
.grid-title {
margin-top: 2px !important;
}
.mat-form-field + .mat-form-field {
margin-left: 8px;
}
.expansion-content {
padding-top: 5px;
}
.mail-box-content.consult {
padding: 10px 20px;
}
.mail-box-content {
h3 {
margin: 0;
font-weight: 500;
}
}
.icon {
padding: 5px 10px 0 0;
}
.debit {
color: red;
}
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { CustomerInteractionFilterComponent } from './customer-interaction-filter.component';
describe('CustomerInteractionFilterComponent', () => {
let component: CustomerInteractionFilterComponent;
let fixture: ComponentFixture<CustomerInteractionFilterComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ CustomerInteractionFilterComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(CustomerInteractionFilterComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
import { NgxMatDatetimePicker } from '@angular-material-components/datetime-picker';
import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
import { FormControl, FormGroup, Validators } from '@angular/forms';
import { ActivatedRoute, Router } from '@angular/router';
import { SharedFilterService } from 'projects/bytebot-html/src/app/services/shared-filters.service';
@Component({
selector: 'byte-customer-interaction-filter',
templateUrl: './customer-interaction-filter.component.html',
styleUrls: ['./customer-interaction-filter.component.scss']
})
export class CustomerInteractionFilterComponent implements OnInit {
form: FormGroup;
channels = [
{
value: 'W',
label: 'Whatsapp'
},
{
value: 'F',
label: 'Facebook'
}
];
endDateTime: Date;
startDateTime: Date;
selectedChannel: string;
isLoading = false;
@Input()
header: string;
@Input()
headerDesc: string;
@Input()
icon = '<i class="fa fa-bar-chart-o"></i>';
@Output()
filtered: EventEmitter<any> = new EventEmitter();
constructor(
protected route: ActivatedRoute,
protected router: Router,
protected sharedFilterService: SharedFilterService) {
}
ngOnInit() {
const title = this.route.snapshot.data['title'];
const titleDesc = this.route.snapshot.data['titleDesc'];
this.header = title;
this.headerDesc = titleDesc;
this.form = new FormGroup({
id: new FormControl('', Validators.required),
period: new FormControl('', Validators.required)
});
this.endDateTime = new Date();
this.startDateTime = this.getStartDate(this.endDateTime);
this.search();
}
search() {
const filters = {startDateTime: this.startDateTime, endDateTime: this.endDateTime, channel: this.selectedChannel};
this.filtered.emit(filters);
}
private getStartDate(endDate: Date): Date {
return new Date(Date.UTC(endDate.getFullYear(), endDate.getMonth(), endDate.getDate(), 5, 0, 0));
}
keyup(event) {
event.preventDefault();
}
clickEvent(event: NgxMatDatetimePicker<any>) {
event.open();
}
}
<byte-customer-interaction-filter (filtered)="filter($event)"></byte-customer-interaction-filter>
<ng-container *ngIf="isLoading">
<div class="spiner-example">
<div class="sk-spinner sk-spinner-circle">
<div class="sk-circle1 sk-circle"></div>
<div class="sk-circle2 sk-circle"></div>
<div class="sk-circle3 sk-circle"></div>
<div class="sk-circle4 sk-circle"></div>
<div class="sk-circle5 sk-circle"></div>
<div class="sk-circle6 sk-circle"></div>
<div class="sk-circle7 sk-circle"></div>
<div class="sk-circle8 sk-circle"></div>
<div class="sk-circle9 sk-circle"></div>
<div class="sk-circle10 sk-circle"></div>
<div class="sk-circle11 sk-circle"></div>
<div class="sk-circle12 sk-circle"></div>
</div>
</div>
</ng-container>
<ng-container *ngIf="!isLoading && isDataLoaded">
<!-- <div class="ibox" style="padding-top: 15px;">
<div class="ibox-content b-s no-padding sankey-ibox" style="text-align: center;">
<div class="row">
<div class="col-5 sankey-diagram">
<byte-sankey-diagram [data]="data?.sessionFlow?.intent"></byte-sankey-diagram>
</div>
<div class="col-7 sankey-table">
<byte-message-by-intent-table [minDate]="startDate" [maxDate]="endDate"></byte-message-by-intent-table>
</div>
</div>
</div>
</div> -->
<div class="row">
<div class="col-12">
<xdf-widget-panel [options]="intentCustomer">
<div class="row sankey-ibox">
<div class="col-5 sankey-diagram">
<byte-sankey-diagram [data]="data?.sessionFlow?.intent"></byte-sankey-diagram>
</div>
<div class="col-7 sankey-table">
<byte-message-by-intent-table [minDate]="startDate" [maxDate]="endDate"></byte-message-by-intent-table>
</div>
</div>
</xdf-widget-panel>
</div>
</div>
<div class="row">
<div class="col-12">
<xdf-widget-panel [options]="sentencesCustomer">
<div class="row sankey-ibox">
<div class="col-6 sankey-table-left">
<byte-unidentified-sentences-table [minDate]="startDate" [maxDate]="endDate"></byte-unidentified-sentences-table>
</div>
<div class="col-6 sankey-diagram-right">
<byte-sankey-diagram [data]="data?.sessionFlow?.sentence"></byte-sankey-diagram>
</div>
</div>
</xdf-widget-panel>
</div>
</div>
<div class="row">
<div class="col-12">
<xdf-widget-panel [options]="tracingPanelOptions">
<div class="row">
<div class="col-12">
<byte-tracing-intent-by-customer [data]="data?.summaryIntents" [minDate]="startDate" [maxDate]="endDate"></byte-tracing-intent-by-customer>
</div>
</div>
</xdf-widget-panel>
</div>
</div>
<div class="row">
<div class="col-12">
<xdf-widget-panel [options]="avgIntentOptions">
<div class="row">
<div class="col-12">
<byte-avg-intent-by-customer [data]="data?.intentAvgByCustomer" [minDate]="startDate"></byte-avg-intent-by-customer>
</div>
</div>
</xdf-widget-panel>
</div>
</div>
<div class="row">
<div class="col-12">
<xdf-widget-panel [options]="goalPanelOptions">
<div class="row">
<div class="col-12">
<byte-stacked-column-chart [data]="data?.summaryGoals"></byte-stacked-column-chart>
</div>
</div>
</xdf-widget-panel>
</div>
</div>
</ng-container>
\ No newline at end of file
.ibox {
margin-bottom: 15px !important;
}
.b-s {
box-shadow: 0 0 13px 0 rgba(62, 44, 90, 0.08);
// border: 1px solid rgba(0, 0, 0, 0.09);
}
.no-padding {
padding: 0 !important;
}
.sankey-ibox {
.sankey-table {
padding-left: 0 !important;
}
.sankey-table-left {
padding-right: 0 !important;
border-right: 1px solid #e7eaec !important;
}
.sankey-diagram{
padding-right: 0 !important;
border-right: 1px solid #e7eaec !important;
}
.sankey-diagram-right{
padding-left: 0 !important;
border-right: 1px solid #e7eaec !important;
}
}
::ng-deep xdf-widget-panel .panel-toolbar button {
display: none !important;
}
::ng-deep xdf-widget-panel .panel-container {
background-color: #fff !important;
}
::ng-deep.navbar-header {
margin-bottom: 10px;
}
\ No newline at end of file
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { CustomerInteractionComponent } from './customer-interaction.component';
describe('CustomerInteractionComponent', () => {
let component: CustomerInteractionComponent;
let fixture: ComponentFixture<CustomerInteractionComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ CustomerInteractionComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(CustomerInteractionComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
import { Component, OnInit } from '@angular/core';
import { ThemePalette } from '@angular/material';
import { NotificationService, NotificationType } from '@xdf/commons';
import { CustomerInteractionService } from '../../../../services/customer-interaction.service';
@Component({
selector: 'byte-customer-interaction',
templateUrl: './customer-interaction.component.html',
styleUrls: ['./customer-interaction.component.scss']
})
export class CustomerInteractionComponent implements OnInit {
links = ['Graph', 'Detail'];
activeLink = this.links[0];
latestDate = new Date();
existDateRange = false;
isLoading = false;
startDate: Date;
endDate: Date;
data: any;
isDataLoaded = false;
background: ThemePalette = undefined;
panelOptions = {
elevation: false,
title: {
primary: 'Mensajes por horario de actividad del cliente',
secondary: ''
}
};
tracingPanelOptions = {
elevation: false,
title: {
primary: 'dashboards.customer.interaction.tracing.intent',
secondary: ''
}
};
avgIntentOptions = {
elevation: false,
title: {
primary: 'dashboards.customer.interaction.avg.intent',
secondary: ''
}
};
goalPanelOptions = {
elevation: false,
title: {
primary: 'dashboards.customer.interaction.goals',
secondary: ''
}
};
intentCustomer = {
elevation: false,
title: {
primary: 'dashboards.customer.interaction.intents',
secondary: ''
}
};
sentencesCustomer = {
elevation: false,
title: {
primary: 'dashboards.customer.interaction.sentences',
secondary: ''
}
};
constructor(
protected customerInteractionService: CustomerInteractionService,
protected notificationService: NotificationService
) { }
ngOnInit() {
}
toggleBackground() {
this.background = this.background ? undefined : 'primary';
}
addLink() {
this.links.push(`Link ${this.links.length + 1}`);
}
filter(filters) {
this.isDataLoaded = false;
this.isLoading = true;
this.startDate = filters['startDateTime'];
this.endDate = filters['endDateTime'];
const channel = filters['channel'];
this.customerInteractionService.getSummary(this.startDate, this.endDate, channel).subscribe(response => {
this.data = response;
this.isLoading = false;
this.isDataLoaded = this.isValidData(this.data);
if (!this.isDataLoaded) {
this.notificationService.showMessage('No se encontró información para el rango de fechas seleccionado', '', NotificationType.error);
}
}, err => {
this.isLoading = false;
});
}
private isValidData(data: any): boolean {
if (data['sessionFlow'] && data['sessionFlow']['intent'] && data['sessionFlow']['sentence']) {
if (data['sessionFlow']['intent']['total'] > 0 || data['sessionFlow']['sentence']['total'] > 0) {
return true;
}
}
return false;
}
}
<table mat-table [dataSource]="dataSource" matSort [matSortActive]="sortColumn" matSortDisableClear
[matSortDirection]="sortDirection" class="crud-table table" style="width: 100%; margin-bottom: 0;">
<ng-container matColumnDef="sentence">
<th mat-header-cell *matHeaderCellDef mat-sort-header> Frase
<mat-icon *ngIf="sortColumn === 'sentence'">
<i class="fa fa-sort-amount-desc" *ngIf="sortDirection === 'desc'"></i>
<i class="fa fa-sort-amount-asc" *ngIf="sortDirection === 'asc'"></i>
</mat-icon>
</th>
<td mat-cell *matCellDef="let element" style="text-align: left; width: 300px;"
[matTooltip]="element.sentence.length > 30 ? element.sentence: null" triggers="hover">
{{ (element.sentence.length>30)? (element.sentence | slice:0:30)+'...':(element.sentence) }}
</td>
</ng-container>
<ng-container matColumnDef="identifier">
<th mat-header-cell *matHeaderCellDef mat-sort-header> Intención
<mat-icon *ngIf="sortColumn === 'identifier'">
<i class="fa fa-sort-amount-desc" *ngIf="sortDirection === 'desc'"></i>
<i class="fa fa-sort-amount-asc" *ngIf="sortDirection === 'asc'"></i>
</mat-icon>
</th>
<td mat-cell *matCellDef="let element" style="text-align: left;">
{{ (element.identifier.length>30)? (element.identifier | slice:0:30)+'...':(element.identifier) }} </td>
</ng-container>
<ng-container matColumnDef="count">
<th mat-header-cell *matHeaderCellDef mat-sort-header> Ocurrencia
<mat-icon *ngIf="sortColumn === 'count'">
<i class="fa fa-sort-amount-desc" *ngIf="sortDirection === 'desc'"></i>
<i class="fa fa-sort-amount-asc" *ngIf="sortDirection === 'asc'"></i>
</mat-icon>
</th>
<td mat-cell *matCellDef="let element"> {{element.count}} </td>
</ng-container>
<ng-container matColumnDef="customer">
<th mat-header-cell *matHeaderCellDef> Clientes </th>
<td mat-cell *matCellDef="let element"> {{element.customerCount}} </td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
</table>
<mat-paginator #paginator [length]="pagination?.totalItems" [pageSize]="pagination?.itemsPerPage"
[pageSizeOptions]="[8, 10, 15]" [pageIndex]="pagination?.currentPage">
</mat-paginator>
\ No newline at end of file
$fontcolor: #676a6c;
.content {
width: 100%;
display: flex;
padding-right: 0px !important;
.grid-container, .filter-panel {
.crud-table {
margin-bottom: 0px;
width: 100%;
}
}
.filter-panel {
margin-bottom: 10px;
}
.toolbar-option {
margin-left: 10px;
margin-right: -10px;
}
}
.grid-ibox-content {
// width: calc(100% - 35px);
width: 100%;
}
.grid-ibox-content-options {
width: calc(100% - 35px);
}
.btn-actions {
.btn {
font-size: 10px;
white-space: nowrap;
}
}
.spinner-container {
height: 100%;
width: 100%;
padding-top: 50px;
position: fixed;
}
.spinner-container {
height: 100%;
width: 100%;
padding-top: 50px;
position: fixed;
}
.spinner-container mat-spinner {
margin: -10px auto 0 auto;
}
th.mat-column-actions {
width: 1px !important;
padding-right: 0px !important;
}
td.mat-column-actions {
padding-right: 20px !important;
cursor: default !important;
}
td {
vertical-align: middle !important;
color: $fontcolor;
font-size: 12px;
}
th {
vertical-align: middle !important;
}
tr.mat-header-row {
height: 50px !important;
}
tr.mat-footer-row, tr.mat-row:not(.inner-detail-row) {
height: 40px;
}
.table-toolbar {
right: 10px;
top: 10px;
button {
font-size: 12px;
}
}
.status-button-bar {
button {
font-size: 16px;
}
padding-top: 8px;
padding-left: 15px;
}
.mat-raised-button {
padding: 0px 10px;
}
.icon-centered-button span.mat-button-wrapper {
display: flex;
}
.icon-centered-button mat-icon {
font-size: 15px;
padding-top: 2px;
}
::ng-deep .mat-sort-header-arrow {
visibility: hidden;
}
::ng-deep .mat-sort-header-button {
.mat-icon {
padding-left: 10px;
font-size: 12px;
padding-top: 5px;
}
}
@media (min-width: 576px) {
::ng-deep .d-sm-block {
display: table-cell !important;
}
}
@media (max-width: 576px) {
::ng-deep .mat-paginator-page-size-label {
display: none !important;
}
}
tr.inner-detail-row {
height: 0;
.mat-column-expandedDetail {
padding: 0 10px;
}
}
.inner-element-detail {
overflow: hidden;
display: flex;
}
//@extend
tr.inner-detail-row {
td {
border-bottom: 1px solid #dee2e6;
border-top: 0px;
}
}
tr.inner-element-row.odd, tr.inner-detail-row.odd {
background-color: rgba(0, 0, 0, 0.05);
}
// tr.inner-detail-row {
// cursor: pointer !important;
// }
tr.mat-row-auth:not(.inner-expanded-row):hover {
background-color:#f8f9fa;
cursor: pointer !important;
}
tr.mat-row-auth.inner-expanded-row:hover {
cursor: pointer !important;
}
tr.inner-element-row-expanded td {
border-top: 0px;
border-bottom: 0px;
}
.additional-options-section {
padding: 0;
width: 100%;
display: inline-grid;
button {
margin: 1px 0;
color: inherit;
font-size: inherit;
border-radius: 0px;
}
}
::ng-deep .mat-menu-item {
padding: 0 10px;
}
@media (min-width: 992px) {
.d-t-lg-block {
display: table-cell !important;
}
}
th {
background: #f2f2f2;
}
\ No newline at end of file
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { MessageByIntentTableComponent } from './message-by-intent-table.component';
describe('MessageByIntentTableComponent', () => {
let component: MessageByIntentTableComponent;
let fixture: ComponentFixture<MessageByIntentTableComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ MessageByIntentTableComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(MessageByIntentTableComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
import { DataSource } from '@angular/cdk/table';
import { AfterViewInit, Component, Input, OnInit, ViewChild } from '@angular/core';
import { MatPaginator, MatSort } from '@angular/material';
import { Pagination, SortField } from '@xdf/commons';
import { DynaDataSource } from '@xdf/gallery';
import { tap } from 'rxjs/operators';
import { MessageByIntentService } from './services/message-by-intent.service';
@Component({
selector: 'byte-message-by-intent-table',
templateUrl: './message-by-intent-table.component.html',
styleUrls: ['./message-by-intent-table.component.scss']
})
export class MessageByIntentTableComponent implements OnInit, AfterViewInit {
displayedColumns: string[] = ['sentence', 'identifier', 'count', 'customer'];
dataSource: DynaDataSource;
@ViewChild(MatPaginator, { static: false }) paginator: MatPaginator;
@ViewChild(MatSort, { static: false }) sort: MatSort;
sortColumn = 'count';
sortDirection = 'desc';
statusQuickFilter: string;
pagingSize = 8;
@Input()
minDate: Date;
@Input()
maxDate: Date;
pagination: Pagination;
constructor(protected service: MessageByIntentService) { }
ngOnInit() {
this.dataSource = new DynaDataSource(this.service);
// Paginación
this.pagination = new Pagination();
this.pagination.currentPage = 0;
this.pagination.itemsPerPage = this.pagingSize;
this.pagination.filterExpression = 'startDate=' + this.minDate.getTime() + '&&endDate=' + this.maxDate.getTime();
// Ordenación por defecto
if (this.sortColumn && this.sortDirection) {
this.pagination.sortFields = new Array();
const sortField: SortField = new SortField();
sortField.direction = this.sortDirection;
sortField.field = this.sortColumn;
this.pagination.sortFields.push(sortField);
}
this.dataSource.load(this.pagination);
}
ngAfterViewInit(): void {
this.sort.sortChange.subscribe(() => {
if (!this.sort.disabled && this.sort.active) {
this.pagination.sortFields = new Array();
const sortField: SortField = new SortField();
sortField.direction = this.sortDirection = this.sort.direction;
sortField.field = this.sortColumn = this.sort.active;
this.pagination.sortFields.push(sortField);
}
this.paginator.pageIndex = 0;
this.dataSource.load(this.pagination);
});
this.paginator.page
.pipe(
tap(() => {
this.pagination.currentPage = this.paginator.pageIndex;
this.pagination.itemsPerPage = this.paginator.pageSize;
this.dataSource.load(this.pagination);
})
)
.subscribe();
}
disabledPopper(value: number): boolean {
return value <= 30;
}
}
export interface MessageByIntent {
sentence: string;
intent: string;
ocurrency: number;
customers: number;
}
import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { Pagination } from '@xdf/commons';
import { DynaDataService } from '@xdf/gallery';
import { DataService } from '@xdf/gallery/lib/views/crud/services/data.service';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
@Injectable({
providedIn: 'root'
})
export class MessageByIntentService extends DynaDataService {
serviceURL = './dashboard/customer-interaction/message-by-intent';
constructor(private httpClient: HttpClient) {
super(httpClient);
}
getResultPagination(pagination: Pagination): Observable<Pagination> {
return this.httpClient.post(this.serviceURL + '/page', pagination).pipe(map(data => this.getPage(data as Pagination)));
}
}
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { SankeyDiagramComponent } from './sankey-diagram.component';
describe('SankeyDiagramComponent', () => {
let component: SankeyDiagramComponent;
let fixture: ComponentFixture<SankeyDiagramComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ SankeyDiagramComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(SankeyDiagramComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
import { Component, Input, OnInit } from '@angular/core';
import { Chart } from 'angular-highcharts';
@Component({
selector: 'byte-sankey-diagram',
templateUrl: './sankey-diagram.component.html',
styleUrls: ['./sankey-diagram.component.scss']
})
export class SankeyDiagramComponent implements OnInit {
chart: Chart;
startPoint = 'Session start';
private percentDetail = {};
@Input()
data;
constructor() { }
ngOnInit() {
if (!this.data) {
return;
}
const dataDiagram = this.generateData(this.data);
if (!dataDiagram) {
return;
}
this.chart = new Chart({
title: {
text: ''
},
exporting: {
enabled: false
},
chart: {
marginTop: 30
},
credits: {
enabled: false
},
accessibility: {
point: {
valueDescriptionFormat: '{index}. {point.from} to {point.to}, {point.weight}.'
}
},
// tooltip: {
// formatter: function() {
// return update(this.key);
// }
// },
series: [{
marker: {
symbol: 'url(https://www.highcharts.com/samples/graphics/sun.png)'
},
lineWidth: 5,
keys: ['from', 'to', 'weight'],
data: dataDiagram,
type: 'sankey',
name: 'Intenciones',
// dataLabels: {
// formatter: function () {
// console.log(this);
// return '';
// }
// },
}] as Array<any>
});
}
private generateData(data: any) {
if (!data['topList']) {
return undefined;
}
const dataForDiagram = [];
data['topList'].forEach(x => {
// PercentageInventary.getInstance().setPercent(x['identifier'], x['count']/data['total']*100);
dataForDiagram.push([this.startPoint, x['identifier'], x['count']]);
});
return dataForDiagram;
}
}
function update(key) {
return PercentageInventary.getInstance().getPercent(key);
}
export class PercentageInventary {
private static instance: PercentageInventary;
private percentages: any = {};
public static getInstance(): PercentageInventary {
if (!PercentageInventary.instance) {
PercentageInventary.instance = new PercentageInventary();
}
return PercentageInventary.instance;
}
getPercent(name: string) {
if (this.percentages[name]) {
return (this.percentages[name] as number).toFixed(2) + '%';
}
return null;
}
setPercent(name: string, value: any) {
this.percentages[name] = value;
}
}
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { StackedColumnChartComponent } from './stacked-column-chart.component';
describe('StackedColumnChartComponent', () => {
let component: StackedColumnChartComponent;
let fixture: ComponentFixture<StackedColumnChartComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ StackedColumnChartComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(StackedColumnChartComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
import { Component, Input, OnInit } from '@angular/core';
import { Chart } from 'angular-highcharts';
import * as Highcharts from 'highcharts';
@Component({
selector: 'byte-stacked-column-chart',
templateUrl: './stacked-column-chart.component.html',
styleUrls: ['./stacked-column-chart.component.scss']
})
export class StackedColumnChartComponent implements OnInit {
chart: Chart;
@Input()
data: any;
constructor() { }
ngOnInit() {
if (!this.data) {
return;
}
const categories = this.generateData(this.data, 'goal');
const dataSeries = this.generateData(this.data, 'count');
this.chart = new Chart({
chart: {
type: 'column'
},
exporting: {
enabled: false
},
legend: {
enabled: false
},
title: {
text: ''
},
xAxis: {
categories
},
credits: {
enabled: false
},
yAxis: {
labels: {
enabled: false
},
title: {
text: ''
}
},
tooltip: {
headerFormat: '<b>{point.x}</b><br/>',
pointFormat: '{point.stackTotal}'
},
plotOptions: {
column: {
stacking: 'normal',
dataLabels: {
enabled: false
}
}
},
series: [{
dataLabels: {
inside: false,
enabled: true,
style: {
color: 'white'
}
},
name: 'John',
data: dataSeries,
linearGradient: { x1: 0, x2: 0, y1: 0, y2: 1 },
stops: [
[0, '#1ab394'], // start
[1, '#FFFFFF'] // end
]
}] as Array<any>
});
}
private generateData(data: Array<any>, field: string) {
const dataGenerated = [];
data.forEach(x => {
dataGenerated.push(x[field]);
});
return dataGenerated;
}
}
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { TracingIntentByCustomerComponent } from './tracing-intent-by-customer.component';
describe('TracingIntentByCustomerComponent', () => {
let component: TracingIntentByCustomerComponent;
let fixture: ComponentFixture<TracingIntentByCustomerComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ TracingIntentByCustomerComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(TracingIntentByCustomerComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
import { Component, Input, OnInit } from '@angular/core';
import { Chart } from 'angular-highcharts';
import * as Highcharts from 'highcharts';
@Component({
selector: 'byte-tracing-intent-by-customer',
templateUrl: './tracing-intent-by-customer.component.html',
styleUrls: ['./tracing-intent-by-customer.component.scss']
})
export class TracingIntentByCustomerComponent implements OnInit {
chart: Chart;
@Input()
minDate: Date;
@Input()
maxDate: Date;
@Input()
data: any;
constructor() { }
ngOnInit() {
console.log(this.minDate);
console.log(this.maxDate);
const series: Array<any> = this.getGenerateData(this.data);
this.chart = new Chart({
chart: {
type: 'line'
},
credits: {
enabled: false
},
title: {
text: ''
},
subtitle: {
text: null
},
exporting: {
enabled: false
},
legend: {
layout: 'vertical',
align: 'right',
verticalAlign: 'middle',
itemMarginTop: 10,
itemMarginBottom: 10
},
xAxis: {
type: 'datetime',
min: this.getDate(this.minDate),
max: this.getDate(this.maxDate),
labels: {
formatter() {
return Highcharts.dateFormat('%e - %b', this.value * 1000);
}
}
},
yAxis: {
title: {
text: ''
},
},
tooltip: {
formatter() {
return '<b>' + this.series.name + '</b><br/>' +
Highcharts.dateFormat('%e - %b',
this.x * 1000) +
' date, ' + this.y;
}
},
plotOptions: {
line: {
marker: {
enabled: true
}
}
},
series
});
}
private getGenerateData(data: any): Array<any> {
const series: Array<any> = [];
for (const intent in data) {
if (data.hasOwnProperty(intent)) {
const serie = {};
serie['name'] = intent;
serie['data'] = data[intent];
series.push(serie);
console.log(serie);
}
}
return series;
}
private getDate(date: Date) {
console.log(date);
let dateNumber = date.getTime();
dateNumber = dateNumber / 1000;
return Math.trunc(dateNumber);
}
}
import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { Pagination } from '@xdf/commons';
import { DynaDataService } from '@xdf/gallery';
import { DataService } from '@xdf/gallery/lib/views/crud/services/data.service';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
@Injectable({
providedIn: 'root'
})
export class UnidentifiedSentenceService extends DynaDataService {
serviceURL = './dashboard/operative/sentence-by-intent';
constructor(private httpClient: HttpClient) {
super(httpClient);
}
getResultPagination(pagination: Pagination): Observable<Pagination> {
return this.httpClient.post(this.serviceURL + '/page', pagination).pipe(map(data => this.getPage(data as Pagination)));
}
}
<table mat-table [dataSource]="dataSource" matSort [matSortActive]="sortColumn" [matSortDirection]="sortDirection" matSortDisableClear
class="crud-table table" style="width: 100%;margin-bottom: 0;">
<ng-container matColumnDef="identifier">
<th mat-header-cell *matHeaderCellDef mat-sort-header> Frase
<mat-icon *ngIf="sortColumn === 'identifier'">
<i class="fa fa-sort-amount-desc"
*ngIf="sortDirection === 'desc'"></i>
<i class="fa fa-sort-amount-asc"
*ngIf="sortDirection === 'asc'"></i>
</mat-icon>
</th>
<td mat-cell *matCellDef="let element" style="text-align: left; width: 300px;"> {{ (element.identifier.length>30)? (element.identifier | slice:0:30)+'...':(element.identifier) }} </td>
</ng-container>
<ng-container matColumnDef="count">
<th mat-header-cell *matHeaderCellDef mat-sort-header> Ocurrencia
<mat-icon *ngIf="sortColumn === 'count'">
<i class="fa fa-sort-amount-desc"
*ngIf="sortDirection === 'desc'"></i>
<i class="fa fa-sort-amount-asc"
*ngIf="sortDirection === 'asc'"></i>
</mat-icon>
</th>
<td mat-cell *matCellDef="let element"> {{element.count}} </td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
</table>
<mat-paginator #paginator [length]="pagination?.totalItems" [pageSize]="pagination?.itemsPerPage"
[pageSizeOptions]="[8, 10, 15]" [pageIndex]="pagination?.currentPage">
</mat-paginator>
\ No newline at end of file
$fontcolor: #676a6c;
.content {
width: 100%;
display: flex;
padding-right: 0px !important;
.grid-container, .filter-panel {
.crud-table {
margin-bottom: 0px;
width: 100%;
}
}
.filter-panel {
margin-bottom: 10px;
}
.toolbar-option {
margin-left: 10px;
margin-right: -10px;
}
}
.grid-ibox-content {
// width: calc(100% - 35px);
width: 100%;
}
.grid-ibox-content-options {
width: calc(100% - 35px);
}
.btn-actions {
.btn {
font-size: 10px;
white-space: nowrap;
}
}
.spinner-container {
height: 100%;
width: 100%;
padding-top: 50px;
position: fixed;
}
.spinner-container {
height: 100%;
width: 100%;
padding-top: 50px;
position: fixed;
}
.spinner-container mat-spinner {
margin: -10px auto 0 auto;
}
th.mat-column-actions {
width: 1px !important;
padding-right: 0px !important;
}
td.mat-column-actions {
padding-right: 20px !important;
cursor: default !important;
}
td {
vertical-align: middle !important;
color: $fontcolor;
font-size: 12px;
}
th {
vertical-align: middle !important;
}
tr.mat-header-row {
height: 50px !important;
}
tr.mat-footer-row, tr.mat-row:not(.inner-detail-row) {
height: 40px;
}
.table-toolbar {
right: 10px;
top: 10px;
button {
font-size: 12px;
}
}
.status-button-bar {
button {
font-size: 16px;
}
padding-top: 8px;
padding-left: 15px;
}
.mat-raised-button {
padding: 0px 10px;
}
.icon-centered-button span.mat-button-wrapper {
display: flex;
}
.icon-centered-button mat-icon {
font-size: 15px;
padding-top: 2px;
}
::ng-deep .mat-sort-header-arrow {
visibility: hidden;
}
::ng-deep .mat-sort-header-button {
.mat-icon {
padding-left: 10px;
font-size: 12px;
padding-top: 5px;
}
}
@media (min-width: 576px) {
::ng-deep .d-sm-block {
display: table-cell !important;
}
}
@media (max-width: 576px) {
::ng-deep .mat-paginator-page-size-label {
display: none !important;
}
}
tr.inner-detail-row {
height: 0;
.mat-column-expandedDetail {
padding: 0 10px;
}
}
.inner-element-detail {
overflow: hidden;
display: flex;
}
//@extend
tr.inner-detail-row {
td {
border-bottom: 1px solid #dee2e6;
border-top: 0px;
}
}
tr.inner-element-row.odd, tr.inner-detail-row.odd {
background-color: rgba(0, 0, 0, 0.05);
}
// tr.inner-detail-row {
// cursor: pointer !important;
// }
tr.mat-row-auth:not(.inner-expanded-row):hover {
background-color:#f8f9fa;
cursor: pointer !important;
}
tr.mat-row-auth.inner-expanded-row:hover {
cursor: pointer !important;
}
tr.inner-element-row-expanded td {
border-top: 0px;
border-bottom: 0px;
}
.additional-options-section {
padding: 0;
width: 100%;
display: inline-grid;
button {
margin: 1px 0;
color: inherit;
font-size: inherit;
border-radius: 0px;
}
}
::ng-deep .mat-menu-item {
padding: 0 10px;
}
@media (min-width: 992px) {
.d-t-lg-block {
display: table-cell !important;
}
}
th {
background: #f2f2f2;
}
\ No newline at end of file
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { UnidentifiedSentencesTableComponent } from './unidentified-sentences-table.component';
describe('UnidentifiedSentencesTableComponent', () => {
let component: UnidentifiedSentencesTableComponent;
let fixture: ComponentFixture<UnidentifiedSentencesTableComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ UnidentifiedSentencesTableComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(UnidentifiedSentencesTableComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
import { AfterViewInit, Component, Input, OnInit, ViewChild } from '@angular/core';
import { MatPaginator, MatSort } from '@angular/material';
import { Pagination, SortField } from '@xdf/commons';
import { DynaDataSource } from '@xdf/gallery';
import { tap } from 'rxjs/operators';
import { UnidentifiedSentenceService } from './services/unidentified-sentences.service';
@Component({
selector: 'byte-unidentified-sentences-table',
templateUrl: './unidentified-sentences-table.component.html',
styleUrls: ['./unidentified-sentences-table.component.scss']
})
export class UnidentifiedSentencesTableComponent implements OnInit, AfterViewInit {
displayedColumns: string[] = ['identifier', 'count'];
dataSource: DynaDataSource;
@ViewChild(MatPaginator, { static: false }) paginator: MatPaginator;
@ViewChild(MatSort, { static: false }) sort: MatSort;
sortColumn = 'count';
sortDirection = 'desc';
statusQuickFilter: string;
pagingSize = 8;
@Input()
minDate: Date;
@Input()
maxDate: Date;
pagination: Pagination;
constructor(protected service: UnidentifiedSentenceService) { }
ngOnInit() {
this.dataSource = new DynaDataSource(this.service);
// Paginación
this.pagination = new Pagination();
this.pagination.currentPage = 0;
this.pagination.itemsPerPage = this.pagingSize;
this.pagination.filterExpression = 'startDate=' + this.minDate.getTime() + '&&endDate=' + this.maxDate.getTime();
// Ordenación por defecto
if (this.sortColumn && this.sortDirection) {
this.pagination.sortFields = new Array();
const sortField: SortField = new SortField();
sortField.direction = this.sortDirection;
sortField.field = this.sortColumn;
this.pagination.sortFields.push(sortField);
}
this.dataSource.load(this.pagination);
}
ngAfterViewInit(): void {
this.sort.sortChange.subscribe(() => {
console.log(this.sort);
if (!this.sort.disabled && this.sort.active) {
this.pagination.sortFields = new Array();
const sortField: SortField = new SortField();
sortField.direction = this.sortDirection = this.sort.direction;
sortField.field = this.sortColumn = this.sort.active;
this.pagination.sortFields.push(sortField);
}
this.paginator.pageIndex = 0;
this.dataSource.load(this.pagination);
});
this.paginator.page
.pipe(
tap(() => {
this.pagination.currentPage = this.paginator.pageIndex;
this.pagination.itemsPerPage = this.paginator.pageSize;
this.dataSource.load(this.pagination);
})
)
.subscribe();
}
}
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { CustomerActivityWidgetComponent } from './customer-activity-widget.component';
describe('CustomerActivityWidgetComponent', () => {
let component: CustomerActivityWidgetComponent;
let fixture: ComponentFixture<CustomerActivityWidgetComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ CustomerActivityWidgetComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(CustomerActivityWidgetComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
import { Component, OnInit } from '@angular/core';
import { Chart } from 'angular-highcharts';
@Component({
selector: 'byte-customer-activity-widget',
templateUrl: './customer-activity-widget.component.html',
styleUrls: ['./customer-activity-widget.component.scss']
})
export class CustomerActivityWidgetComponent implements OnInit {
chart = new Chart({
chart: {
type: 'area'
},
accessibility: {
description: 'Image description: An area chart compares the nuclear stockpiles of the USA and the USSR/Russia between 1945 and 2017. The number of nuclear weapons is plotted on the Y-axis and the years on the X-axis. The chart is interactive, and the year-on-year stockpile levels can be traced for each country. The US has a stockpile of 6 nuclear weapons at the dawn of the nuclear age in 1945. This number has gradually increased to 369 by 1950 when the USSR enters the arms race with 6 weapons. At this point, the US starts to rapidly build its stockpile culminating in 32,040 warheads by 1966 compared to the USSR’s 7,089. From this peak in 1966, the US stockpile gradually decreases as the USSR’s stockpile expands. By 1978 the USSR has closed the nuclear gap at 25,393. The USSR stockpile continues to grow until it reaches a peak of 45,000 in 1986 compared to the US arsenal of 24,401. From 1986, the nuclear stockpiles of both countries start to fall. By 2000, the numbers have fallen to 10,577 and 21,000 for the US and Russia, respectively. The decreases continue until 2017 at which point the US holds 4,018 weapons compared to Russia’s 4,500.'
},
title: {
text: 'US and USSR nuclear stockpiles'
},
subtitle: {
text: 'Sources: <a href="https://thebulletin.org/2006/july/global-nuclear-stockpiles-1945-2006">' +
'thebulletin.org</a> & <a href="https://www.armscontrol.org/factsheets/Nuclearweaponswhohaswhat">' +
'armscontrol.org</a>'
},
xAxis: {
allowDecimals: false,
labels: {
},
accessibility: {
rangeDescription: 'Range: 1940 to 2017.'
}
},
yAxis: {
title: {
text: 'Nuclear weapon states'
},
labels: {
formatter() {
return this.value / 1000 + 'k';
}
}
},
tooltip: {
pointFormat: '{series.name} had stockpiled <b>{point.y:,.0f}</b><br/>warheads in {point.x}'
},
plotOptions: {
area: {
pointStart: 1940,
marker: {
enabled: false,
symbol: 'circle',
radius: 2,
states: {
hover: {
enabled: true
}
}
}
}
},
series: [{
name: 'USA',
data: [
null, null, null, null, null, 6, 11, 32, 110, 235,
369, 640, 1005, 1436, 2063, 3057, 4618, 6444, 9822, 15468,
20434, 24126, 27387, 29459, 31056, 31982, 32040, 31233, 29224, 27342,
26662, 26956, 27912, 28999, 28965, 27826, 25579, 25722, 24826, 24605,
24304, 23464, 23708, 24099, 24357, 24237, 24401, 24344, 23586, 22380,
21004, 17287, 14747, 13076, 12555, 12144, 11009, 10950, 10871, 10824,
10577, 10527, 10475, 10421, 10358, 10295, 10104, 9914, 9620, 9326,
5113, 5113, 4954, 4804, 4761, 4717, 4368, 4018
]
}, {
name: 'USSR/Russia',
data: [null, null, null, null, null, null, null, null, null, null,
5, 25, 50, 120, 150, 200, 426, 660, 869, 1060,
1605, 2471, 3322, 4238, 5221, 6129, 7089, 8339, 9399, 10538,
11643, 13092, 14478, 15915, 17385, 19055, 21205, 23044, 25393, 27935,
30062, 32049, 33952, 35804, 37431, 39197, 45000, 43000, 41000, 39000,
37000, 35000, 33000, 31000, 29000, 27000, 25000, 24000, 23000, 22000,
21000, 20000, 19000, 18000, 18000, 17000, 16000, 15537, 14162, 12787,
12600, 11400, 5500, 4512, 4502, 4502, 4500, 4500
]
}] as Array<any>
});
constructor() { }
ngOnInit() {
}
}
<rg-gauge-chart
[canvasWidth]="canvasWidth"
[needleValue]="value"
[options]="options"
[name]="name"
[bottomLabel]="bottomLabel" *ngIf="options"></rg-gauge-chart>
\ No newline at end of file
::ng-deep rg-gauge-chart .gauge-chart span:first-child{
font-size: 1em !important;
}
\ No newline at end of file
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { GaugeChartComponent } from './gauge-chart.component';
describe('GaugeChartComponent', () => {
let component: GaugeChartComponent;
let fixture: ComponentFixture<GaugeChartComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ GaugeChartComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(GaugeChartComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
import { DecimalPipe } from '@angular/common';
import { Component, Input, OnInit } from '@angular/core';
export class GaugeChart {
hasNeedle?: boolean;
needleColor?: string;
needleUpdateSpeed?: number;
arcColors?: Array<string>;
arcDelimiters?: Array<number>;
rangeLabel?: Array<string>;
needleStartValue?: number;
}
export const DEFAULT_OPTIONS_GAUGE_CHART: GaugeChart = {
hasNeedle: true,
needleColor: '#676a6c',
needleUpdateSpeed: 1000,
arcColors: ['#1ab394', '#f8ac59', '#ed5565'],
arcDelimiters: [16, 33],
rangeLabel: ['0', '6'],
needleStartValue: 1,
};
@Component({
selector: 'byte-gauge-chart',
templateUrl: './gauge-chart.component.html',
styleUrls: ['./gauge-chart.component.scss']
})
export class GaugeChartComponent implements OnInit {
@Input()
name = 'Gauge chart';
@Input()
value: any = 1.2;
@Input()
unit = '';
@Input()
options: GaugeChart;
@Input()
format = false;
@Input()
maxValue = 6;
canvasWidth = 250;
centralLabel = '25';
bottomLabel = '';
constructor() { }
ngOnInit() {
let valueNumber = +this.value;
this.value = this.value / this.maxValue * 100;
console.log(this.value);
if (this.format) {
valueNumber = valueNumber / 1000;
}
let valueFormater = 0;
if (valueNumber >= 86400) {
this.unit = 'd';
valueFormater = valueNumber / 86400;
} else if (valueNumber >= 3600) {
this.unit = 'h';
valueFormater = valueNumber / 3600;
} else if (valueNumber >= 60) {
this.unit = 'm';
valueFormater = valueNumber / 60;
} else {
this.unit = 's';
valueFormater = valueNumber;
}
this.bottomLabel = valueFormater.toFixed(1) + ' ' + this.unit;
if (!this.options) {
this.options = DEFAULT_OPTIONS_GAUGE_CHART;
}
}
}
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { HeatMapComponent } from './heat-map.component';
describe('HeatMapComponent', () => {
let component: HeatMapComponent;
let fixture: ComponentFixture<HeatMapComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ HeatMapComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(HeatMapComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
import { Component, Input, OnDestroy, OnInit } from '@angular/core';
// import { ToogleService } from '@xdf/layouts';
import { Chart } from 'angular-highcharts';
import * as Highcharts from 'highcharts';
import { Subscription } from 'rxjs';
@Component({
selector: 'byte-heat-map',
templateUrl: './heat-map.component.html',
styleUrls: ['./heat-map.component.scss']
})
export class HeatMapComponent implements OnInit, OnDestroy {
@Input()
data: Array<any> = [];
@Input()
minDate: Date;
@Input()
maxDate: Date;
subscriptionToogle: Subscription;
chart: Chart;
constructor(
// protected toogleService: ToogleService
) {
}
ngOnDestroy(): void {
if (this.subscriptionToogle) {
this.subscriptionToogle.unsubscribe();
}
}
ngOnInit() {
if (!this.maxDate || !this.minDate) {
return;
}
this.chart = new Chart({
chart: {
marginTop: 50,
marginBottom: 100,
marginLeft: 150,
marginRight: 40,
type: 'heatmap',
events: {
load: (event: any) => {
event.target.reflow();
}
}
},
boost: {
useGPUTranslations: true
},
credits: {
enabled: false
},
title: {
text: '',
align: 'center',
x: 40
},
exporting: {
enabled: false
},
legend: {
enabled: true
},
xAxis: {
type: 'datetime',
min: this.minDate.getTime(),
max: this.maxDate.getTime(),
labels: {
align: 'left',
x: 5,
y: 14,
format: '{value:%d/%m}' // long month
},
showLastLabel: false,
tickLength: 10,
tickWidth: 1
},
yAxis: {
title: {
text: null
},
labels: {
formatter() {
// return 'H' + (this.value + 1) + ': ' + (this.value < 10 ? '0' : '') + this.value + ':00' ;
return 'H' + (this.value + 1) + ': ' + (3 * this.value < 10 ? '0' : '') + 3 * this.value + ':00'
+ ' - ' + ((3 * this.value + 3) < 10 ? '0' : '') + (3 * this.value + 3) + ':00';
},
format: 'H{value:}:{3*value}:00 - {value + 3}:00'
},
minPadding: 0,
maxPadding: 0,
startOnTick: false,
endOnTick: false,
tickPositions: [0, 1, 2, 3, 4, 5, 6, 7],
tickWidth: 1,
min: 0,
max: 7,
reversed: true
},
colorAxis: {
stops: [
[0, '#dceefa'],
[0.5, '#85c5ed'],
[1, '#1c84c6']
],
min: 0,
max: 25,
startOnTick: false,
endOnTick: false,
labels: {
format: '{value}'
}
},
series: [{
boostThreshold: 100,
borderWidth: 4,
nullColor: '#f3f3f4',
borderColor: '#f3f3f4',
colsize: 24 * 36e5, // one day
tooltip: {
headerFormat: '{point.x:%e %b}',
// pointFormat: '{point.x:%e %b, %Y} {point.y}:00: <b>{point.value} ℃</b>'
pointFormat: '<b>{point.value} mensajes</b>'
},
turboThreshold: Number.MAX_VALUE, // #3404, remove after 4.0.5 release
data: this.data
}] as Array<any>
});
// this.subscriptionToogle = this.toogleService.changeEmitted$.subscribe(change => {
// setTimeout(() => {
// Highcharts.charts.forEach(chart => chart.reflow());;
// console.log("test");
// }, 500);
// });
}
}
<div class="ccard h-100 d-flex flex-column px-2 py-3">
<div class="d-flex text-center">
<div class="flex-grow-1 mb-3">
<div class="text-nowrap lh text-100 text-dark-l2">
{{ header | translate }}&nbsp;<i class="fa fa-info-circle" matTooltip="{{ 'dashboards.operative.session.time.desc' | translate }}"></i>
</div>
<div class="lh">
<span class="text-170 text-secondary-d4" style="font-size: 1.3em !important;">
{{ value?.value | millisToDayHourMinuteSecond }}
</span>
</div>
</div>
<!-- <div class="session-icon">
<i class="fa fa-2x fa-clock-o" matTooltip="{{ 'action.grid.refresh' | translate }}"></i>
</div> -->
</div>
<div class="align-self-center">
<xdf-peity #peti [values]="value?.history" [type]="'line'" theme="primary" [attributes]='options'></xdf-peity>
</div>
</div>
\ No newline at end of file
.ccard {
box-shadow: 0 0.125rem 0.25rem rgba(0,0,0,.075);
border-radius: .5rem;
border: 1px solid #e0e5e8;
background-color: #fff;
position: relative;
}
.text-dark-l2 {
color: #60626a!important;
}
.text-100 {
font-size: 1em!important;
}
.text-secondary-d4 {
color: #4c5b70!important;
}
.text-170 {
font-size: 1.7em!important;
}
.text-blue {
color: #1279cd!important;
}
.text-nowrap {
white-space: nowrap!important;
}
.lh {
line-height: 1.5 !important;
}
.session-icon {
position: relative;
top: 0px;
right: 12px;
}
\ No newline at end of file
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { InactivitySesionComponent } from './inactivity-sesion.component';
describe('InactivitySesionComponent', () => {
let component: InactivitySesionComponent;
let fixture: ComponentFixture<InactivitySesionComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ InactivitySesionComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(InactivitySesionComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
import { AfterViewInit, Component, HostListener, Input, OnInit, ViewChild } from '@angular/core';
import { PeityComponent } from '@xdf/graph';
import { PetyWidgetModel } from '../summary-peti-widget/summary-peti-widget.component';
@Component({
selector: 'byte-inactivity-sesion',
templateUrl: './inactivity-sesion.component.html',
styleUrls: ['./inactivity-sesion.component.scss']
})
export class InactivitySesionComponent implements OnInit, AfterViewInit {
@Input() options = {
width: 200,
height: 60,
fill: '#dfecf9',
stroke: '#024990',
strokeWidth: 1
};
@Input() values = [1, 12, 3, 15, 5, -1, 10];
@Input() header;
@Input() value: PetyWidgetModel;
@ViewChild('peti', { static: false })
peti: PeityComponent;
constructor() { }
ngOnInit() {
}
ngAfterViewInit() {
if (this.peti) {
const width = window.innerWidth;
this.updateWidth(width);
this.peti.updateSize();
}
}
@HostListener('window:resize', ['$event'])
public onResize(event) {
const width = event.target.innerWidth;
this.updateWidth(width);
this.peti.updateSize();
}
private updateWidth(width: number) {
if (width >= 1600) {
this.options.width = 300;
} else if (width >= 1350) {
this.options.width = 200;
} else if (width >= 768) {
this.options.width = 150;
} else if (width >= 576) {
this.options.width = 200;
} else {
this.options.width = 300;
}
}
}
<div class="row">
<div class="col-12">
<div class="mail-box-content consult pb-3" style="margin: -15px -15px 15px -15px;">
<div class="expansion-content pull-right">
<mat-form-field>
<mat-label>{{'query.filters.startDate' | translate }}</mat-label>
<input matInput [ngxMatDatetimePicker]="startPicker" [(ngModel)]="startDateTime" id="startPickerCIP" (click)="startPicker.open()"
onkeyup="this.value=this.value.replace(/.*/gi, '');">
<mat-datepicker-toggle matSuffix [for]="startPicker"></mat-datepicker-toggle>
<ngx-mat-datetime-picker #startPicker></ngx-mat-datetime-picker>
</mat-form-field>
<mat-form-field style="margin-left: 20px;">
<mat-label>{{'query.filters.endDate' | translate }}</mat-label>
<input matInput [ngxMatDatetimePicker]="endPicker" [(ngModel)]="endDateTime" (click)="endPicker.open()" onkeyup="this.value=this.value.replace(/.*/gi, '');">
<mat-datepicker-toggle matSuffix [for]="endPicker"></mat-datepicker-toggle>
<ngx-mat-datetime-picker #endPicker></ngx-mat-datetime-picker>
</mat-form-field>
<!-- <mat-form-field style="margin-left: 20px;">
<mat-label>{{'query.filters.channel' | translate }}</mat-label>
<mat-select [(ngModel)]="selectedChannel" name="food">
<mat-option *ngFor="let channel of channels" [value]="channel.value">
{{ channel.label | translate }}
</mat-option>
</mat-select>
</mat-form-field> -->
<button class="btn btn-primary btn-sm ng-star-inserted" style="margin-left: 15px;
margin-top: 0px !important;" type="button" [disabled]="!startDateTime || !endDateTime"
(click)="search()">
<i class="fa fa-search"></i><span class="btn-label">Buscar</span>
</button>
</div>
<div class="pull-left icon" *ngIf="icon">
<div [innerHTML]="icon"></div>
</div>
<h3 class="grid-title">
<span>{{ header | translate }}</span>
</h3>
<span *ngIf="headerDesc" class="small">{{ headerDesc | translate }}</span>
</div>
</div>
</div>
\ No newline at end of file
.ibox-content {
font-size: 12px;
}
.table.invoice-total {
margin-bottom: 0px;
}
.grid-title {
margin-top: 2px !important;
}
.mat-form-field + .mat-form-field {
margin-left: 8px;
}
.expansion-content {
padding-top: 5px;
}
.mail-box-content.consult {
padding: 10px 20px;
}
.mail-box-content {
h3 {
margin: 0;
font-weight: 500;
}
}
.icon {
padding: 5px 10px 0 0;
}
.debit {
color: red;
}
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { OperativeDashboardFilterComponent } from './operative-dashboard-filter.component';
describe('OperativeDashboardFilterComponent', () => {
let component: OperativeDashboardFilterComponent;
let fixture: ComponentFixture<OperativeDashboardFilterComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ OperativeDashboardFilterComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(OperativeDashboardFilterComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
import { NgxMatDatetimePicker } from '@angular-material-components/datetime-picker';
import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
import { FormControl, FormGroup, Validators } from '@angular/forms';
import { ActivatedRoute, Router } from '@angular/router';
@Component({
selector: 'byte-operative-dashboard-filter',
templateUrl: './operative-dashboard-filter.component.html',
styleUrls: ['./operative-dashboard-filter.component.scss']
})
export class OperativeDashboardFilterComponent implements OnInit {
form: FormGroup;
channels = [
{
value: 'W',
label: 'Whatsapp'
},
{
value: 'F',
label: 'Facebook'
}
];
endDateTime: Date;
startDateTime: Date;
selectedChannel: string;
isLoading = false;
@Input()
header: string;
@Input()
headerDesc: string;
@Input()
icon = '<i class="fa fa-bar-chart-o"></i>';
@Output()
filtered: EventEmitter<any> = new EventEmitter();
constructor(
protected route: ActivatedRoute,
protected router: Router) {
this.selectedChannel = this.channels[0].value;
}
ngOnInit() {
const title = this.route.snapshot.data['title'];
const titleDesc = this.route.snapshot.data['titleDesc'];
this.header = title;
this.headerDesc = titleDesc;
this.form = new FormGroup({
id: new FormControl('', Validators.required),
period: new FormControl('', Validators.required)
});
this.endDateTime = new Date();
this.startDateTime = this.getStartDate(this.endDateTime);
this.search();
}
search() {
const filters = { startDateTime: this.startDateTime, endDateTime: this.endDateTime, channel: this.selectedChannel };
this.filtered.emit(filters);
}
private getStartDate(endDate: Date): Date {
return new Date(Date.UTC(endDate.getFullYear(), endDate.getMonth(), endDate.getDate(), 5, 0, 0));
}
keyup(event) {
event.preventDefault();
}
clickEvent(event: NgxMatDatetimePicker<any>) {
event.open();
}
}
<byte-operative-dashboard-filter (filtered)="filter($event)"></byte-operative-dashboard-filter>
<ng-container *ngIf="isLoading">
<div class="spiner-example">
<div class="sk-spinner sk-spinner-circle">
<div class="sk-circle1 sk-circle"></div>
<div class="sk-circle2 sk-circle"></div>
<div class="sk-circle3 sk-circle"></div>
<div class="sk-circle4 sk-circle"></div>
<div class="sk-circle5 sk-circle"></div>
<div class="sk-circle6 sk-circle"></div>
<div class="sk-circle7 sk-circle"></div>
<div class="sk-circle8 sk-circle"></div>
<div class="sk-circle9 sk-circle"></div>
<div class="sk-circle10 sk-circle"></div>
<div class="sk-circle11 sk-circle"></div>
<div class="sk-circle12 sk-circle"></div>
</div>
</div>
</ng-container>
<ng-container *ngIf="!isLoading && isDataLoaded">
<div class="row">
<div class="col-lg-3 col-sm-6 col-xs-12">
<byte-inactivity-sesion header="dashboards.operative.inactivity.sessions" [value]="data?.summary?.sessionInactivity"
[options]="optionsInactivitySesion"></byte-inactivity-sesion>
</div>
<div class="col-lg-3 col-sm-6 col-xs-12">
<byte-summary-peti-widget header="dashboards.operative.sessions" [value]="data?.summary?.totalSessions"
[options]="totalSesionsOptions" tooltip="dashboards.operative.session.total.desc">
</byte-summary-peti-widget>
</div>
<div class="col-lg-3 col-sm-6 col-xs-12">
<byte-summary-peti-widget header="dashboards.operative.receveid"
[value]="data?.summary?.totalReceivedMessages" [options]="totalReceivedOptions"
tooltip="dashboards.operative.message.received.desc" format="true" [formatter]="formatterNumber">
</byte-summary-peti-widget>
</div>
<div class="col-lg-3 col-sm-6 col-xs-12">
<byte-summary-peti-widget header="dashboards.operative.sended" [value]="data?.summary?.totalSentMessages"
[options]="totalSentOptions" tooltip="dashboards.operative.message.sended.desc" format="true"
[formatter]="formatterNumber"></byte-summary-peti-widget>
</div>
</div>
<div class="row">
<div class="col-xs-12 col-sm-6 col-lg-8">
<div class="ibox" style="padding-top: 15px;">
<div class="ibox-content b-s" style="text-align: center;">
<byte-gauge-chart [value]="data?.averages?.firstResponseAverage" unit="s"
name="{{ 'Tiempo promedio de primera respuesta' | translate }}" style="display: inline-block;">
</byte-gauge-chart>
</div>
</div>
</div>
<div class="col-xs-12 col-sm-6 col-lg-4">
<div class="ibox" style="padding-top: 15px;">
<div class="ibox-content b-s" style="text-align: center;">
<!-- <byte-gauge-chart [value]="data?.averages?.sessionAverage" name="{{ 'dashboards.operative.avg.sessions' | translate }}" style="display: inline-block;">
</byte-gauge-chart> -->
<div class="widget style1">
<div class="row">
<div class="col-12 text-center">
<i class="fa fa-user fa-5x"></i>
</div>
<div class="col-12 text-center">
<span> {{ 'dashboards.operative.avg.sessions' | translate }} </span>
<h2 class="font-bold">{{ data?.averages?.sessionAverage | number : '1.1-1'}}</h2>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="row" *ngIf="startDate && endDate">
<div class="col-12">
<xdf-widget-panel [options]="panelOptions">
<div class="row">
<div class="col-12">
<byte-heat-map [data]="data?.customerMessageDetail" [minDate]="startDate" [maxDate]="endDate">
</byte-heat-map>
</div>
</div>
</xdf-widget-panel>
</div>
</div>
</ng-container>
\ No newline at end of file
/* PROGRESS CIRCLE COMPONENT */
.circliful {
margin:auto;
position: relative;
}
.circle-text, .circle-info, .circle-text-half, .circle-info-half {
width: 100%;
position: absolute;
text-align: center;
display: inline-block;
}
.circle-info, .circle-info-half {
color: #999;
}
.circliful .fa {
margin: -10px 3px 0 3px;
position: relative;
bottom: 4px;
}
.ibox {
margin-bottom: 15px !important;
}
.b-s {
box-shadow: 0 0 13px 0 rgba(62, 44, 90, 0.08);
// border: 1px solid rgba(0, 0, 0, 0.09);
}
:host.row.wrapper.border-bottom.white-bg.page-heading {
display: none !important;
}
.dashboard-panel {
font-family: Roboto,"Helvetica Neue",Helvetica,Arial;
font-size: .7125rem;
margin: -10px -15px;
}
.uppanel {
padding: 15px 20px 5px;
margin-bottom: 15px;
}
.headerpanel {
padding: 10px 30px;
background-color: white;
margin-left: -15px;
margin-right: -15px;
margin-bottom: 15px;
}
.mypanel {
margin: 10px;
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-orient: vertical;
-webkit-box-direction: normal;
-ms-flex-direction: column;
flex-direction: column;
position: relative;
background-color: #fff;
-webkit-box-shadow: 0 0 13px 0 rgba(62,44,90,.08);
box-shadow: 0 0 13px 0 rgba(62,44,90,.08);
margin-bottom: 1.5rem;
border-radius: 4px;
border: 1px solid rgba(0,0,0,.09);
border-bottom: 1px solid #e0e0e0;
border-radius: 4px;
-webkit-transition: border .5s ease-out;
transition: border .5s ease-out;
}
.header-date {
padding-bottom: 20px;
}
.subheader {
padding-top: 20px;
margin-bottom: 20px;
position: relative;
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-orient: horizontal;
-webkit-box-direction: normal;
-ms-flex-direction: row;
flex-direction: row;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
}
.subheader-icon {
color: #a8a6ac;
margin-right: .25rem;
}
.subheader-title {
font-size: 1.375rem;
font-weight: 500;
color: #505050;
text-shadow: #fff 0 1px;
margin: 0;
-webkit-box-flex: 1;
-ms-flex: 1;
flex: 1;
}
.stat-list {
padding: 10px 15px 20px;
}
::ng-deep xdf-widget-panel .panel-toolbar button {
display: none !important;
}
::ng-deep.navbar-header {
margin-bottom: 10px;
}
@media (max-width: 1180px) {
.text-100 {
font-size: 11px !important;
}
}
@media (max-width: 990px) {
.text-100 {
font-size: 1em !important;
}
}
\ No newline at end of file
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { OperativeDashboardComponent } from './operative-dashboard.component';
describe('OperativeDashboardComponent', () => {
let component: OperativeDashboardComponent;
let fixture: ComponentFixture<OperativeDashboardComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ OperativeDashboardComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(OperativeDashboardComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
import { Component, OnInit } from '@angular/core';
import { NotificationService, NotificationType } from '@xdf/commons';
import { SharedFilterService } from 'projects/bytebot-html/src/app/services/shared-filters.service';
import { OperationalConsultationService } from '../../../../services/operational-consultation.service';
import { PetiFormatter } from '../summary-peti-widget/formatter/formatter';
import { MessageCountFormatter } from '../summary-peti-widget/formatter/message-count.formatter';
import { PetyWidgetModel } from '../summary-peti-widget/summary-peti-widget.component';
@Component({
selector: 'byte-operative-dashboard',
templateUrl: './operative-dashboard.component.html',
styleUrls: ['./operative-dashboard.component.scss']
})
export class OperativeDashboardComponent implements OnInit {
latestDate = new Date();
existDateRange = false;
isLoading = false;
startDate: Date;
endDate: Date;
data: any;
isDataLoaded = false;
formatterNumber: PetiFormatter = new MessageCountFormatter();
panelOptions = {
elevation: false,
title: {
primary: 'dashboards.operative.message.customer.activity',
secondary: ''
}
};
optionsInactivitySesion = {
width: 300,
height: 60,
fill: '#C8FEFF',
stroke: '#23c6c8',
strokeWidth: 1
};
totalSesionsOptions = {
width: 300,
height: 60,
fill: '#CFECFF',
stroke: '#1c84c6',
strokeWidth: 1
};
totalReceivedOptions = {
width: 300,
height: 60,
fill: '#D2EEE9',
stroke: '#1ab394',
strokeWidth: 1
};
totalSentOptions = {
width: 300,
height: 60,
fill: '#FFD9DD',
stroke: '#ed5565',
strokeWidth: 1
};
constructor(
protected operationalConsultationService: OperationalConsultationService,
protected notificationService: NotificationService) { }
ngOnInit() {
}
filter(filters) {
this.isDataLoaded = false;
this.isLoading = true;
this.startDate = filters['startDateTime'];
this.endDate = filters['endDateTime'];
const channel = filters['channel'];
this.operationalConsultationService.getSummary(this.startDate, this.endDate, channel).subscribe(response => {
this.data = response;
this.isLoading = false;
this.isDataLoaded = true;
}, err => {
this.isLoading = false;
});
}
}
import { PetiFormatter } from './formatter';
export class MessageCountFormatter implements PetiFormatter {
format(value: number): string {
if (value < 1000) {
return '' + value;
}
const newNumber: number = value / 1000;
return newNumber.toFixed(1) + 'K';
}
}
<div class="ccard h-100 d-flex flex-column px-2 py-3">
<div class="d-flex text-center">
<div class="flex-grow-1 mb-3">
<div class="text-nowrap lh text-100 text-dark-l2">
{{ header | translate }}&nbsp;<i class="fa fa-info-circle" matTooltip="{{ tooltip | translate }}"></i>
</div>
<div class="lh">
<span class="text-170 text-secondary-d4">
{{ formatterValue }}
</span>
<!-- <span class="text-blue text-nowrap ml-n1">
&nbsp;+{{value?.percent}}%
<i *ngIf="value?.up" class="fa fa-caret-up"></i>
<i *ngIf="value?.down" class="fa fa-caret-down"></i>
</span> -->
</div>
</div>
</div>
<div class="align-self-center">
<xdf-peity #peti [values]="value?.history" [type]="'line'" theme="primary" [attributes]='options'></xdf-peity>
</div>
</div>
.ccard {
box-shadow: 0 0.125rem 0.25rem rgba(0,0,0,.075);
border-radius: .5rem;
border: 1px solid #e0e5e8;
background-color: #fff;
position: relative;
}
.text-dark-l2 {
color: #60626a!important;
}
.text-100 {
font-size: 1em;
}
.text-secondary-d4 {
color: #4c5b70!important;
}
.text-170 {
font-size: 1.7em;
}
.text-blue {
color: #1279cd!important;
}
.text-nowrap {
white-space: nowrap!important;
}
.lh {
line-height: 1.5 !important;
}
\ No newline at end of file
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { SummaryPetiWidgetComponent } from './summary-peti-widget.component';
describe('SummaryPetiWidgetComponent', () => {
let component: SummaryPetiWidgetComponent;
let fixture: ComponentFixture<SummaryPetiWidgetComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ SummaryPetiWidgetComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(SummaryPetiWidgetComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
import { AfterViewInit, Component, HostListener, Input, OnInit, ViewChild } from '@angular/core';
import { PeityComponent } from '@xdf/graph';
import { PetiFormatter } from './formatter/formatter';
declare var jQuery: any;
export class PetyWidgetModel {
percent: number;
up?: boolean;
down?: boolean;
value: number;
history: Array<number>;
}
@Component({
selector: 'byte-summary-peti-widget',
templateUrl: './summary-peti-widget.component.html',
styleUrls: ['./summary-peti-widget.component.scss']
})
export class SummaryPetiWidgetComponent implements OnInit, AfterViewInit {
@Input() options = {
width: 200,
height: 60,
fill: '#dfecf9',
stroke: '#024990',
strokeWidth: 1
};
@Input() values = [1, 12, 3, 15, 5, -1, 10];
@Input() header;
@Input() value: PetyWidgetModel;
@Input() tooltip: string;
@Input() formatter: PetiFormatter;
@ViewChild('peti', { static: false })
peti: PeityComponent;
constructor() { }
ngOnInit() {
}
ngAfterViewInit() {
if (this.peti) {
const width = window.innerWidth;
this.updateWidth(width);
this.peti.updateSize();
}
}
get formatterValue(): string|number {
if (this.formatter) {
return this.formatter.format(this.value.value);
}
return this.value.value;
}
@HostListener('window:resize', ['$event'])
public onResize(event) {
console.log('aea');
const width = event.target.innerWidth;
this.updateWidth(width);
this.peti.updateSize();
}
private updateWidth(width: number) {
if (width >= 1600) {
this.options.width = 300;
} else if (width >= 1350) {
this.options.width = 200;
} else if (width >= 768) {
this.options.width = 150;
} else if (width >= 576) {
this.options.width = 200;
} else {
this.options.width = 300;
}
}
}
<div class="card amount-card o-hidden"><iframe class="chartjs-hidden-iframe" tabindex="-1" style="display: block; overflow: hidden; border: 0px; margin: 0px; top: 0px; left: 0px; bottom: 0px; right: 0px; height: 100%; width: 100%; position: absolute; pointer-events: none; z-index: -1;"></iframe>
<div class="card-block">
<h2 class="f-w-400">$23,567</h2>
<p class="text-muted f-w-600 f-16"><span class="text-c-blue">Amount</span> processed</p>
</div>
<canvas id="amount-processed" height="100" width="475" style="display: block;"></canvas>
</div>
\ No newline at end of file
.amount-card {
overflow: hidden;
}
.o-hidden {
overflow: hidden;
}
.card {
border-radius: 5px;
-webkit-box-shadow: 0 1px 11px 0 rgba(0, 0, 0, 0.12);
box-shadow: 0 1px 11px 0 rgba(0, 0, 0, 0.12);
border: none;
margin-bottom: 30px;
}
\ No newline at end of file
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { WidgetPetiComponent } from './widget-peti.component';
describe('WidgetPetiComponent', () => {
let component: WidgetPetiComponent;
let fixture: ComponentFixture<WidgetPetiComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ WidgetPetiComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(WidgetPetiComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'byte-widget-peti',
templateUrl: './widget-peti.component.html',
styleUrls: ['./widget-peti.component.scss']
})
export class WidgetPetiComponent implements OnInit {
constructor() { }
ngOnInit() {
}
}
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment