Skip to content
Snippets Groups Projects
Commit 2fdcb5d3 authored by Alex ORLUC's avatar Alex ORLUC
Browse files

FEAT #12073 TIME 1:30 front history component

parent 656e464c
No related branches found
No related tags found
No related merge requests found
...@@ -29,15 +29,15 @@ ...@@ -29,15 +29,15 @@
<mat-form-field (click)="startPicker.open()" style="cursor:pointer;" class="dateFilter"> <mat-form-field (click)="startPicker.open()" style="cursor:pointer;" class="dateFilter">
<mat-label style="color:white;">{{lang.since}} <mat-label style="color:white;">{{lang.since}}
</mat-label> </mat-label>
<input [(ngModel)]="startDateFilter" matInput [matDatepicker]="startPicker" <input [(ngModel)]="appHistoryList.startDateFilter" matInput [matDatepicker]="startPicker"
[placeholder]="lang.since" [max]="endDateFilter" readonly style="cursor:pointer;" [placeholder]="lang.since" [max]="appHistoryList.endDateFilter" readonly style="cursor:pointer;"
(dateChange)="filterStartDate()"> (dateChange)="appHistoryList.filterStartDate()">
<mat-datepicker-toggle matSuffix [for]="startPicker" *ngIf="!startDateFilter"> <mat-datepicker-toggle matSuffix [for]="startPicker" *ngIf="!appHistoryList.startDateFilter">
</mat-datepicker-toggle> </mat-datepicker-toggle>
<mat-datepicker [touchUi]="appService.getViewMode()" #startPicker> <mat-datepicker [touchUi]="appService.getViewMode()" #startPicker>
</mat-datepicker> </mat-datepicker>
<button mat-button color="warn" matSuffix mat-icon-button *ngIf="startDateFilter" <button mat-button color="warn" matSuffix mat-icon-button *ngIf="appHistoryList.startDateFilter"
(click)="$event.stopPropagation();startDateFilter = '';filterStartDate()" [title]="lang.eraseValue"> (click)="$event.stopPropagation();appHistoryList.startDateFilter = '';appHistoryList.filterStartDate()" [title]="lang.eraseValue">
<mat-icon color="warn" class="fa fa-calendar-times"> <mat-icon color="warn" class="fa fa-calendar-times">
</mat-icon> </mat-icon>
</button> </button>
...@@ -45,15 +45,15 @@ ...@@ -45,15 +45,15 @@
<mat-form-field (click)="endPicker.open()" style="cursor:pointer;" class="dateFilter"> <mat-form-field (click)="endPicker.open()" style="cursor:pointer;" class="dateFilter">
<mat-label style="color:white;">{{lang.until}} <mat-label style="color:white;">{{lang.until}}
</mat-label> </mat-label>
<input [(ngModel)]="endDateFilter" matInput [matDatepicker]="endPicker" <input [(ngModel)]="appHistoryList.endDateFilter" matInput [matDatepicker]="endPicker"
[placeholder]="lang.until" [min]="startDateFilter" readonly style="cursor:pointer;" [placeholder]="lang.until" [min]="appHistoryList.startDateFilter" readonly style="cursor:pointer;"
(dateChange)="filterEndDate()"> (dateChange)="appHistoryList.filterEndDate()">
<mat-datepicker-toggle matSuffix [for]="endPicker" *ngIf="!endDateFilter"> <mat-datepicker-toggle matSuffix [for]="endPicker" *ngIf="!appHistoryList.endDateFilter">
</mat-datepicker-toggle> </mat-datepicker-toggle>
<mat-datepicker [touchUi]="appService.getViewMode()" #endPicker> <mat-datepicker [touchUi]="appService.getViewMode()" #endPicker>
</mat-datepicker> </mat-datepicker>
<button mat-button color="warn" matSuffix mat-icon-button *ngIf="endDateFilter" <button mat-button color="warn" matSuffix mat-icon-button *ngIf="appHistoryList.endDateFilter"
(click)="$event.stopPropagation();endDateFilter = '';filterEndDate()" [title]="lang.eraseValue"> (click)="$event.stopPropagation();appHistoryList.endDateFilter = '';appHistoryList.filterEndDate()" [title]="lang.eraseValue">
<mat-icon color="warn" class="fa fa-calendar-times"> <mat-icon color="warn" class="fa fa-calendar-times">
</mat-icon> </mat-icon>
</button> </button>
...@@ -63,93 +63,7 @@ ...@@ -63,93 +63,7 @@
</div> </div>
<div class="container" [class.fullContainer]="appService.getViewMode()"> <div class="container" [class.fullContainer]="appService.getViewMode()">
<div class="container-content"> <div class="container-content">
<div class="example-loading-shade" *ngIf="isLoadingResults"> <app-history-list #appHistoryList></app-history-list>
<mat-spinner *ngIf="isLoadingResults"></mat-spinner>
</div>
<div class="table-head">
<div class="table-head-result">
<mat-form-field floatLabel="never" style="font-size: 13px;">
<input type="text" #autoCompleteInput [matAutocomplete]="auto" [placeholder]="lang.filterBy"
matInput [formControl]="searchHistory" (click)="$event.stopPropagation()"
maxlength="128">
<mat-autocomplete #auto="matAutocomplete" (optionSelected)="addItemFilter($event.option)"
(opened)="initFilterListHistory()">
<mat-option disabled *ngIf="loadingFilters">
<div style="display: flex;justify-content: center;">
<mat-spinner diameter="35"></mat-spinner>
</div>
</mat-option>
<ng-container *ngIf="filterList!==null && !loadingFilters">
<ng-container *ngFor="let keyVal of filterList | keyvalue">
<mat-optgroup *ngIf="(filteredList[keyVal.key] | async)?.length > 0"
[label]="lang[keyVal.key]" class="filterList">
<mat-option [id]="keyVal.key"
[style.color]="!filter.used ? filterColor[keyVal.key] : ''"
*ngFor="let filter of filteredList[keyVal.key] | async | sortBy : 'label'"
[value]="filter" [disabled]="filter.used">
{{filter.label}}
</mat-option>
</mat-optgroup>
</ng-container>
</ng-container>
</mat-autocomplete>
</mat-form-field>
</div>
<div class="table-head-tool">
<mat-paginator #paginatorHistoryList [length]="resultsLength" [hidePageSize]="true"
[pageSize]="10" class="paginatorResultList"></mat-paginator>
</div>
</div>
<div style="height:90%;overflow:auto;position:absolute;width:100%;">
<div class="filterBadges">
<ng-container *ngFor="let keyVal of filterUsed | keyvalue">
<ng-container *ngIf="['startDate','endDate'].indexOf(keyVal.key) === -1">
<span *ngFor="let filter of filterUsed[keyVal.key]; let i=index;" class="label"
[style.background]="filterColor[keyVal.key]" [title]="lang[keyVal.key]"
(click)="removeItemFilter(filter,keyVal.key,i)">{{filter.label}}
<i class="fa fa-times-circle"></i></span>
</ng-container>
</ng-container>
</div>
<mat-table id="history-list" #tableHistoryListSort="matSort" [dataSource]="data" matSort
matSortActive="event_date" matSortDirection="desc" style="width:100%;">
<ng-container matColumnDef="event_date">
<mat-header-cell *matHeaderCellDef mat-sort-header>{{lang.event}}</mat-header-cell>
<mat-cell mat-cell *matCellDef="let element"
[title]="element.event_date | fullDate">
{{element.event_date | timeAgo : 'full' | ucfirst}} </mat-cell>
</ng-container>
<ng-container matColumnDef="userLabel">
<mat-header-cell *matHeaderCellDef mat-sort-header>{{lang.user | ucfirst}}</mat-header-cell>
<mat-cell *matCellDef="let element">
{{element.userLabel}} </mat-cell>
</ng-container>
<ng-container matColumnDef="info">
<mat-header-cell *matHeaderCellDef mat-sort-header
style="flex: 2;">{{lang.information}}
</mat-header-cell>
<mat-cell *matCellDef="let element"
style="flex: 2;">
{{element.info}} </mat-cell>
</ng-container>
<ng-container matColumnDef="remote_ip">
<mat-header-cell *matHeaderCellDef mat-sort-header
>{{lang.ip}}
</mat-header-cell>
<mat-cell *matCellDef="let element">
{{element.remote_ip}} </mat-cell>
</ng-container>
<mat-header-row *matHeaderRowDef="displayedColumnsHistory"></mat-header-row>
<mat-row *matRowDef="let row; columns: displayedColumnsHistory;">
</mat-row>
</mat-table>
<div class="mat-paginator"
style="min-height:48px;min-height: 48px;display: flex;justify-content: end;align-items: center;padding-right: 20px;">
{{resultsLength}} {{lang.elements}}</div>
</div>
<div class="table-head">
</div>
</div> </div>
</div> </div>
</mat-sidenav-content> </mat-sidenav-content>
......
import { Component, OnInit, ViewChild, EventEmitter, ElementRef } from '@angular/core'; import { Component, OnInit, ViewChild } from '@angular/core';
import { HttpClient } from '@angular/common/http'; import { HttpClient } from '@angular/common/http';
import { LANG } from '../../translate.component'; import { LANG } from '../../translate.component';
import { NotificationService } from '../../notification.service';
import { HeaderService } from '../../../service/header.service';
import { MatSidenav } from '@angular/material/sidenav'; import { MatSidenav } from '@angular/material/sidenav';
import { AppService } from '../../../service/app.service'; import { AppService } from '../../../service/app.service';
import { Observable, merge, Subject, of as observableOf, of } from 'rxjs';
import { MatPaginator, MatSort, MatDialog } from '@angular/material';
import { takeUntil, startWith, switchMap, map, catchError, filter, exhaustMap, tap, debounceTime, distinctUntilChanged, finalize } from 'rxjs/operators';
import { ConfirmComponent } from '../../../plugins/modal/confirm.component';
import { FormControl } from '@angular/forms';
import { FunctionsService } from '../../../service/functions.service'; import { FunctionsService } from '../../../service/functions.service';
import { LatinisePipe } from 'ngx-pipes'; import { HistoryComponent } from '../../history/history.component';
@Component({ @Component({
selector: 'contact-list', selector: 'contact-list',
...@@ -25,42 +18,11 @@ export class HistoryAdministrationComponent implements OnInit { ...@@ -25,42 +18,11 @@ export class HistoryAdministrationComponent implements OnInit {
@ViewChild('snav2', { static: true }) public sidenavRight: MatSidenav; @ViewChild('snav2', { static: true }) public sidenavRight: MatSidenav;
lang: any = LANG; lang: any = LANG;
loading: boolean = false;
filtersChange = new EventEmitter();
data: any;
displayedColumnsHistory: string[] = ['event_date', 'userLabel', 'info', 'remote_ip'];
isLoadingResults = true;
routeUrl: string = '../../rest/history';
resultListDatabase: HistoryListHttpDao | null;
resultsLength = 0;
searchHistory = new FormControl();
startDateFilter: any = ''; startDateFilter: any = '';
endDateFilter: any = ''; endDateFilter: any = '';
filterUrl: string = '';
filterList: any = null;
filteredList: any = {};
filterUsed: any = {};
filterColor = {
startDate: '#b5cfd8',
endDate: '#7393a7',
actions: '#7d5ba6',
systemActions: '#d6716f',
users: '#009dc5',
};
loadingFilters: boolean = true; @ViewChild('appHistoryList', { static: false }) appHistoryList: HistoryComponent;
@ViewChild(MatPaginator, { static: true }) paginator: MatPaginator;
@ViewChild('tableHistoryListSort', { static: true }) sort: MatSort;
@ViewChild('autoCompleteInput', { static: true }) autoCompleteInput: ElementRef;
private destroy$ = new Subject<boolean>();
subMenus: any[] = [ subMenus: any[] = [
{ {
...@@ -79,215 +41,8 @@ export class HistoryAdministrationComponent implements OnInit { ...@@ -79,215 +41,8 @@ export class HistoryAdministrationComponent implements OnInit {
constructor( constructor(
public http: HttpClient, public http: HttpClient,
private notify: NotificationService,
private headerService: HeaderService,
public appService: AppService, public appService: AppService,
public dialog: MatDialog, public functions: FunctionsService) { }
public functions: FunctionsService,
private latinisePipe: LatinisePipe) { }
ngOnInit(): void {
this.loading = true;
this.initHistoryList();
}
initHistoryList() {
this.resultListDatabase = new HistoryListHttpDao(this.http);
this.paginator.pageIndex = 0;
this.sort.active = 'event_date';
this.sort.direction = 'desc';
this.sort.sortChange.subscribe(() => this.paginator.pageIndex = 0);
// When list is refresh (sort, page, filters)
merge(this.sort.sortChange, this.paginator.page, this.filtersChange)
.pipe(
takeUntil(this.destroy$),
startWith({}),
switchMap(() => {
this.isLoadingResults = true;
return this.resultListDatabase!.getRepoIssues(
this.sort.active, this.sort.direction, this.paginator.pageIndex, this.routeUrl, this.filterUrl);
}),
map(data => {
this.isLoadingResults = false;
data = this.processPostData(data);
this.resultsLength = data.count;
this.headerService.setHeader(this.lang.administration + ' ' + this.lang.history.toLowerCase(), '', '');
return data.history;
}),
catchError((err: any) => {
this.notify.handleErrors(err);
this.isLoadingResults = false;
return observableOf([]);
})
).subscribe(data => this.data = data);
}
processPostData(data: any) {
data.history = data.history.map((item: any) => {
return {
...item,
userLabel : !this.functions.empty(item.userLabel) ? item.userLabel : this.lang.userDeleted
}
})
return data;
}
refreshDao() {
this.paginator.pageIndex = 0;
this.filtersChange.emit();
}
initFilterListHistory() {
if (this.filterList === null) {
this.filterList = {};
this.loadingFilters = true;
this.http.get("../../rest/history/availableFilters").pipe(
map((data: any) => {
let deletedActions = data.actions.filter((action: any) => action.label === null).map((action: any) => action.id);
let deletedUser = data.users.filter((user: any) => user.label === null).map((user: any) => user.login);
data.actions = data.actions.filter((action: any) => action.label !== null);
if (deletedActions.length > 0) {
data.actions.push({
id: deletedActions,
label: this.lang.actionDeleted
});
}
data.users = data.users.filter((user: any) => user.label !== null);
if (deletedUser.length > 0) {
data.users.push({
id: deletedUser,
label: this.lang.userDeleted
});
}
data.systemActions = data.systemActions.map((syst: any) => {
return {
id: syst.id,
label: this.lang[syst.id]
}
});
return data;
}),
tap((data: any) => {
Object.keys(data).forEach((filterType: any) => {
if (this.functions.empty(this.filterList[filterType])) {
this.filterList[filterType] = [];
this.filteredList[filterType] = [];
}
data[filterType].forEach((element: any) => {
this.filterList[filterType].push(element);
});
this.filteredList[filterType] = this.searchHistory.valueChanges
.pipe(
startWith(''),
map(element => element ? this.filter(element, filterType) : this.filterList[filterType].slice())
);
});
}),
finalize(() => this.loadingFilters = false),
catchError((err: any) => {
this.notify.handleSoftErrors(err);
return of(false);
})
).subscribe();
}
}
filterStartDate() {
if (this.functions.empty(this.filterUsed['startDate'])) {
this.filterUsed['startDate'] = [];
}
this.filterUsed['startDate'][0] = {
id: this.functions.empty(this.startDateFilter) ? '' : this.functions.formatDateObjectToDateString(this.startDateFilter),
label: this.functions.empty(this.startDateFilter) ? '' : this.functions.formatDateObjectToDateString(this.startDateFilter)
};
this.generateUrlFilter();
this.refreshDao();
}
filterEndDate() {
if (this.functions.empty(this.filterUsed['endDate'])) {
this.filterUsed['endDate'] = [];
}
this.filterUsed['endDate'][0] = {
id: this.functions.empty(this.endDateFilter) ? '' : this.functions.formatDateObjectToDateString(this.endDateFilter, true),
label: this.functions.empty(this.endDateFilter) ? '' : this.functions.formatDateObjectToDateString(this.endDateFilter)
};
this.generateUrlFilter();
this.refreshDao();
}
addItemFilter(elem: any) {
elem.value.used = true;
if (this.functions.empty(this.filterUsed[elem.id])) {
this.filterUsed[elem.id] = [];
}
this.filterUsed[elem.id].push(elem.value);
this.generateUrlFilter();
this.searchHistory.reset();
this.autoCompleteInput.nativeElement.blur();
this.refreshDao();
}
removeItemFilter(elem: any, type: string, index: number) {
elem.used = false;
this.filterUsed[type].splice(index, 1);
this.generateUrlFilter();
this.refreshDao();
}
generateUrlFilter() {
this.filterUrl = '';
let arrTmpUrl: any[] = [];
Object.keys(this.filterUsed).forEach((type: any) => {
this.filterUsed[type].forEach((filter: any) => {
if (!this.functions.empty(filter.id)) {
if (['startDate', 'endDate'].indexOf(type) > -1) {
arrTmpUrl.push(`${type}=${filter.id}`);
} else {
arrTmpUrl.push(`${type}[]=${filter.id}`);
}
}
});
});
if (arrTmpUrl.length > 0) {
this.filterUrl = '&' + arrTmpUrl.join('&');
}
}
private filter(value: string, type: string): any[] {
if (typeof value === 'string') {
const filterValue = this.latinisePipe.transform(value.toLowerCase());
return this.filterList[type].filter((elem: any) => this.latinisePipe.transform(elem.label.toLowerCase()).includes(filterValue));
} else {
return this.filterList[type];
}
}
}
export interface HistoryList {
history: any[];
count: number;
}
export class HistoryListHttpDao {
constructor(private http: HttpClient) { }
getRepoIssues(sort: string, order: string, page: number, href: string, search: string): Observable<HistoryList> {
let offset = page * 10;
const requestUrl = `${href}?limit=10&offset=${offset}&order=${order}&orderBy=${sort}${search}`;
return this.http.get<HistoryList>(requestUrl); ngOnInit(): void { }
}
} }
\ No newline at end of file
...@@ -63,7 +63,7 @@ import { TagInputComponent } from '../app/tag/indexing/ta ...@@ -63,7 +63,7 @@ import { TagInputComponent } from '../app/tag/indexing/ta
import { DragDropDirective } from '../app/viewer/upload-file-dnd.directive'; import { DragDropDirective } from '../app/viewer/upload-file-dnd.directive';
import { ContactAutocompleteComponent } from './contact/autocomplete/contact-autocomplete.component'; import { ContactAutocompleteComponent } from './contact/autocomplete/contact-autocomplete.component';
import { ContactsFormComponent } from './administration/contact/page/form/contacts-form.component'; import { ContactsFormComponent } from './administration/contact/page/form/contacts-form.component';
import { HistoryComponent } from './history/history.component';
import { DiffusionsListComponent } from './diffusions/diffusions-list.component'; import { DiffusionsListComponent } from './diffusions/diffusions-list.component';
...@@ -125,7 +125,8 @@ export class MyHammerConfig extends HammerGestureConfig { ...@@ -125,7 +125,8 @@ export class MyHammerConfig extends HammerGestureConfig {
EcplOnlyofficeViewerComponent, EcplOnlyofficeViewerComponent,
ContactAutocompleteComponent, ContactAutocompleteComponent,
ContactsFormComponent, ContactsFormComponent,
CustomSnackbarComponent CustomSnackbarComponent,
HistoryComponent,
], ],
exports: [ exports: [
CommonModule, CommonModule,
...@@ -167,7 +168,8 @@ export class MyHammerConfig extends HammerGestureConfig { ...@@ -167,7 +168,8 @@ export class MyHammerConfig extends HammerGestureConfig {
DragDropDirective, DragDropDirective,
EcplOnlyofficeViewerComponent, EcplOnlyofficeViewerComponent,
ContactAutocompleteComponent, ContactAutocompleteComponent,
ContactsFormComponent ContactsFormComponent,
HistoryComponent,
], ],
providers: [ providers: [
HeaderService, HeaderService,
......
<div class="example-loading-shade" *ngIf="isLoadingResults">
<mat-spinner *ngIf="isLoadingResults"></mat-spinner>
</div>
<div class="table-head">
<div class="table-head-result">
<mat-form-field floatLabel="never" style="font-size: 13px;">
<input type="text" #autoCompleteInput [matAutocomplete]="auto" [placeholder]="lang.filterBy" matInput
[formControl]="searchHistory" (click)="$event.stopPropagation()" maxlength="128">
<mat-autocomplete #auto="matAutocomplete" (optionSelected)="addItemFilter($event.option)"
(opened)="initFilterListHistory()">
<mat-option disabled *ngIf="loadingFilters">
<div style="display: flex;justify-content: center;">
<mat-spinner diameter="35"></mat-spinner>
</div>
</mat-option>
<ng-container *ngIf="filterList!==null && !loadingFilters">
<ng-container *ngFor="let keyVal of filterList | keyvalue">
<mat-optgroup *ngIf="(filteredList[keyVal.key] | async)?.length > 0" [label]="lang[keyVal.key]"
class="filterList">
<mat-option [id]="keyVal.key" [style.color]="!filter.used ? filterColor[keyVal.key] : ''"
*ngFor="let filter of filteredList[keyVal.key] | async | sortBy : 'label'"
[value]="filter" [disabled]="filter.used">
{{filter.label}}
</mat-option>
</mat-optgroup>
</ng-container>
</ng-container>
</mat-autocomplete>
</mat-form-field>
</div>
<button color="primary" mat-icon-button title="Afficher tout l'historique">
<mat-icon class="fas fa-history"></mat-icon>
</button>
<div class="table-head-tool">
<mat-paginator #paginatorHistoryList [length]="resultsLength" [hidePageSize]="true" [pageSize]="10"
class="paginatorResultList"></mat-paginator>
</div>
</div>
<div [class.table-admin]="resId === null">
<div class="filterBadges">
<ng-container *ngFor="let keyVal of filterUsed | keyvalue">
<ng-container *ngIf="['startDate','endDate'].indexOf(keyVal.key) === -1">
<span *ngFor="let filter of filterUsed[keyVal.key]; let i=index;" class="label"
[style.background]="filterColor[keyVal.key]" [title]="lang[keyVal.key]"
(click)="removeItemFilter(filter,keyVal.key,i)">{{filter.label}}
<i class="fa fa-times-circle"></i></span>
</ng-container>
</ng-container>
</div>
<mat-table id="history-list" #tableHistoryListSort="matSort" [dataSource]="data" matSort matSortActive="event_date"
matSortDirection="desc" style="width:100%;">
<ng-container matColumnDef="event_date">
<mat-header-cell *matHeaderCellDef mat-sort-header>{{lang.event}}</mat-header-cell>
<mat-cell mat-cell *matCellDef="let element" [title]="element.event_date | fullDate"
[class.smallText]="resId !== null">
<div *ngIf="resId !== null" style="font-size: 10px;">
{{element.userLabel}}
</div>
<div>
{{element.event_date | timeAgo : 'full' | ucfirst}}
</div>
</mat-cell>
</ng-container>
<ng-container matColumnDef="userLabel">
<mat-header-cell *matHeaderCellDef mat-sort-header>{{lang.user | ucfirst}}</mat-header-cell>
<mat-cell *matCellDef="let element">
{{element.userLabel}} </mat-cell>
</ng-container>
<ng-container matColumnDef="info">
<mat-header-cell *matHeaderCellDef mat-sort-header style="flex: 2;">{{lang.information}}
</mat-header-cell>
<mat-cell *matCellDef="let element" style="flex: 2;">
{{element.info}}
</mat-cell>
</ng-container>
<ng-container matColumnDef="remote_ip">
<mat-header-cell *matHeaderCellDef mat-sort-header>{{lang.ip}}
</mat-header-cell>
<mat-cell *matCellDef="let element">
{{element.remote_ip}} </mat-cell>
</ng-container>
<ng-container *ngIf="resId === null">
<mat-header-row *matHeaderRowDef="displayedColumnsHistory"></mat-header-row>
</ng-container>
<mat-row *matRowDef="let row; columns: displayedColumnsHistory;">
</mat-row>
</mat-table>
<div class="mat-paginator"
style="min-height:48px;min-height: 48px;display: flex;justify-content: end;align-items: center;padding-right: 20px;">
{{resultsLength}} {{lang.elements}}</div>
</div>
\ No newline at end of file
@import '../../css/vars.scss';
.active,
.active:hover,
.active:active,
.active:focus {
color: $primary;
border-left: solid 5px $primary;
background: rgba($primary, 0.14);
}
.paginatorResultList {
::ng-deep.mat-paginator-range-label {
justify-content: flex-end;
display: flex;
}
}
.filterList {
::ng-deep.mat-optgroup-label {
color: $primary;
position: sticky;
top: 0px;
background: white !important;
z-index: 1;
}
}
.label {
cursor: pointer;
margin: 5px;
}
.bg-head-content {
::ng-deep .mat-focused .mat-form-field-label {
/*change color of label*/
color: white !important;
}
::ng-deep.mat-form-field-underline {
/*change color of underline*/
background-color: white !important;
}
::ng-deep.mat-form-field-ripple {
/*change color of underline when focused*/
background-color: white !important;
}
.mat-icon,
.mat-datepicker-toggle {
color: white;
}
}
.table-admin {
height: 90%;
overflow: auto;
position: absolute;
width: 100%;
}
.smallText {
flex-direction: column;
align-items: center;
justify-content: center;
font-size: 10px;
opacity: 0.5;
width: 150px;
flex: initial;
}
\ No newline at end of file
import { Component, OnInit, ViewChild, EventEmitter, ElementRef, Input } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { LANG } from '../translate.component';
import { NotificationService } from '../notification.service';
import { HeaderService } from '../../service/header.service';
import { Observable, merge, Subject, of as observableOf, of } from 'rxjs';
import { MatPaginator, MatSort, MatDialog } from '@angular/material';
import { takeUntil, startWith, switchMap, map, catchError, filter, exhaustMap, tap, debounceTime, distinctUntilChanged, finalize } from 'rxjs/operators';
import { FormControl } from '@angular/forms';
import { FunctionsService } from '../../service/functions.service';
import { LatinisePipe } from 'ngx-pipes';
@Component({
selector: 'app-history-list',
templateUrl: "history.component.html",
styleUrls: ['history.component.scss'],
})
export class HistoryComponent implements OnInit {
lang: any = LANG;
loading: boolean = false;
filtersChange = new EventEmitter();
data: any;
displayedColumnsHistory: string[] = ['event_date', 'userLabel', 'info', 'remote_ip'];
isLoadingResults = true;
routeUrl: string = '../../rest/history';
resultListDatabase: HistoryListHttpDao | null;
resultsLength = 0;
searchHistory = new FormControl();
startDateFilter: any = '';
endDateFilter: any = '';
filterUrl: string = '';
filterList: any = null;
filteredList: any = {};
filterUsed: any = {};
filterColor = {
startDate: '#b5cfd8',
endDate: '#7393a7',
actions: '#7d5ba6',
systemActions: '#d6716f',
users: '#009dc5',
};
loadingFilters: boolean = true;
@Input('resId') resId: number = null;
@ViewChild(MatPaginator, { static: true }) paginator: MatPaginator;
@ViewChild('tableHistoryListSort', { static: true }) sort: MatSort;
@ViewChild('autoCompleteInput', { static: true }) autoCompleteInput: ElementRef;
private destroy$ = new Subject<boolean>();
constructor(
public http: HttpClient,
private notify: NotificationService,
private headerService: HeaderService,
public dialog: MatDialog,
public functions: FunctionsService,
private latinisePipe: LatinisePipe) { }
ngOnInit(): void {
if (this.resId !== null) {
this.routeUrl = '../../rest/history';
this.displayedColumnsHistory = ['event_date', 'info'];
} else {
this.routeUrl = '../../rest/history';
this.displayedColumnsHistory = ['event_date', 'userLabel', 'info', 'remote_ip'];
}
this.loading = true;
this.initHistoryList();
}
initHistoryList() {
this.resultListDatabase = new HistoryListHttpDao(this.http);
this.paginator.pageIndex = 0;
this.sort.active = 'event_date';
this.sort.direction = 'desc';
this.sort.sortChange.subscribe(() => this.paginator.pageIndex = 0);
// When list is refresh (sort, page, filters)
merge(this.sort.sortChange, this.paginator.page, this.filtersChange)
.pipe(
takeUntil(this.destroy$),
startWith({}),
switchMap(() => {
this.isLoadingResults = true;
return this.resultListDatabase!.getRepoIssues(
this.sort.active, this.sort.direction, this.paginator.pageIndex, this.routeUrl, this.filterUrl);
}),
map(data => {
this.isLoadingResults = false;
data = this.processPostData(data);
this.resultsLength = data.count;
this.headerService.setHeader(this.lang.administration + ' ' + this.lang.history.toLowerCase(), '', '');
return data.history;
}),
catchError((err: any) => {
this.notify.handleErrors(err);
this.isLoadingResults = false;
return observableOf([]);
})
).subscribe(data => this.data = data);
}
processPostData(data: any) {
data.history = data.history.map((item: any) => {
return {
...item,
userLabel : !this.functions.empty(item.userLabel) ? item.userLabel : this.lang.userDeleted
}
})
return data;
}
refreshDao() {
this.paginator.pageIndex = 0;
this.filtersChange.emit();
}
initFilterListHistory() {
if (this.filterList === null) {
this.filterList = {};
this.loadingFilters = true;
this.http.get("../../rest/history/availableFilters").pipe(
map((data: any) => {
let deletedActions = data.actions.filter((action: any) => action.label === null).map((action: any) => action.id);
let deletedUser = data.users.filter((user: any) => user.label === null).map((user: any) => user.login);
data.actions = data.actions.filter((action: any) => action.label !== null);
if (deletedActions.length > 0) {
data.actions.push({
id: deletedActions,
label: this.lang.actionDeleted
});
}
data.users = data.users.filter((user: any) => user.label !== null);
if (deletedUser.length > 0) {
data.users.push({
id: deletedUser,
label: this.lang.userDeleted
});
}
data.systemActions = data.systemActions.map((syst: any) => {
return {
id: syst.id,
label: this.lang[syst.id]
}
});
return data;
}),
tap((data: any) => {
Object.keys(data).forEach((filterType: any) => {
if (this.functions.empty(this.filterList[filterType])) {
this.filterList[filterType] = [];
this.filteredList[filterType] = [];
}
data[filterType].forEach((element: any) => {
this.filterList[filterType].push(element);
});
this.filteredList[filterType] = this.searchHistory.valueChanges
.pipe(
startWith(''),
map(element => element ? this.filter(element, filterType) : this.filterList[filterType].slice())
);
});
}),
finalize(() => this.loadingFilters = false),
catchError((err: any) => {
this.notify.handleSoftErrors(err);
return of(false);
})
).subscribe();
}
}
filterStartDate() {
if (this.functions.empty(this.filterUsed['startDate'])) {
this.filterUsed['startDate'] = [];
}
this.filterUsed['startDate'][0] = {
id: this.functions.empty(this.startDateFilter) ? '' : this.functions.formatDateObjectToDateString(this.startDateFilter),
label: this.functions.empty(this.startDateFilter) ? '' : this.functions.formatDateObjectToDateString(this.startDateFilter)
};
this.generateUrlFilter();
this.refreshDao();
}
filterEndDate() {
if (this.functions.empty(this.filterUsed['endDate'])) {
this.filterUsed['endDate'] = [];
}
this.filterUsed['endDate'][0] = {
id: this.functions.empty(this.endDateFilter) ? '' : this.functions.formatDateObjectToDateString(this.endDateFilter, true),
label: this.functions.empty(this.endDateFilter) ? '' : this.functions.formatDateObjectToDateString(this.endDateFilter)
};
this.generateUrlFilter();
this.refreshDao();
}
addItemFilter(elem: any) {
elem.value.used = true;
if (this.functions.empty(this.filterUsed[elem.id])) {
this.filterUsed[elem.id] = [];
}
this.filterUsed[elem.id].push(elem.value);
this.generateUrlFilter();
this.searchHistory.reset();
this.autoCompleteInput.nativeElement.blur();
this.refreshDao();
}
removeItemFilter(elem: any, type: string, index: number) {
elem.used = false;
this.filterUsed[type].splice(index, 1);
this.generateUrlFilter();
this.refreshDao();
}
generateUrlFilter() {
this.filterUrl = '';
let arrTmpUrl: any[] = [];
Object.keys(this.filterUsed).forEach((type: any) => {
this.filterUsed[type].forEach((filter: any) => {
if (!this.functions.empty(filter.id)) {
if (['startDate', 'endDate'].indexOf(type) > -1) {
arrTmpUrl.push(`${type}=${filter.id}`);
} else {
arrTmpUrl.push(`${type}[]=${filter.id}`);
}
}
});
});
if (arrTmpUrl.length > 0) {
this.filterUrl = '&' + arrTmpUrl.join('&');
}
}
private filter(value: string, type: string): any[] {
if (typeof value === 'string') {
const filterValue = this.latinisePipe.transform(value.toLowerCase());
return this.filterList[type].filter((elem: any) => this.latinisePipe.transform(elem.label.toLowerCase()).includes(filterValue));
} else {
return this.filterList[type];
}
}
}
export interface HistoryList {
history: any[];
count: number;
}
export class HistoryListHttpDao {
constructor(private http: HttpClient) { }
getRepoIssues(sort: string, order: string, page: number, href: string, search: string): Observable<HistoryList> {
let offset = page * 10;
const requestUrl = `${href}?limit=10&offset=${offset}&order=${order}&orderBy=${sort}${search}`;
return this.http.get<HistoryList>(requestUrl);
}
}
\ No newline at end of file
...@@ -70,6 +70,9 @@ ...@@ -70,6 +70,9 @@
</div> </div>
</ng-container> </ng-container>
<ng-container *ngIf="!isModalOpen(); else elseTemplate"> <ng-container *ngIf="!isModalOpen(); else elseTemplate">
<app-history-list *ngIf="currentTool === 'history' && !loading" #appHistoryList
[resId]="currentResourceInformations.resId">
</app-history-list>
<app-notes-list *ngIf="currentTool === 'notes' && !loading" #appNotesList [editMode]="true" <app-notes-list *ngIf="currentTool === 'notes' && !loading" #appNotesList [editMode]="true"
[resId]="currentResourceInformations.resId"> [resId]="currentResourceInformations.resId">
</app-notes-list> </app-notes-list>
...@@ -77,9 +80,11 @@ ...@@ -77,9 +80,11 @@
[adminMode]="false" [resId]="currentResourceInformations.resId" [expanded]="true"> [adminMode]="false" [resId]="currentResourceInformations.resId" [expanded]="true">
</app-diffusions-list> </app-diffusions-list>
<app-visa-workflow *ngIf="currentTool === 'visaCircuit' && !loading" #appVisaWorkflow <app-visa-workflow *ngIf="currentTool === 'visaCircuit' && !loading" #appVisaWorkflow
[resId]="currentResourceInformations.resId" [adminMode]="privilegeService.hasCurrentUserPrivilege('config_visa_workflow')"></app-visa-workflow> [resId]="currentResourceInformations.resId"
[adminMode]="privilegeService.hasCurrentUserPrivilege('config_visa_workflow')"></app-visa-workflow>
<app-avis-workflow *ngIf="currentTool === 'opinionCircuit' && !loading" #appAvisWorkflow <app-avis-workflow *ngIf="currentTool === 'opinionCircuit' && !loading" #appAvisWorkflow
[resId]="currentResourceInformations.resId" [adminMode]="privilegeService.hasCurrentUserPrivilege('config_avis_workflow')"></app-avis-workflow> [resId]="currentResourceInformations.resId"
[adminMode]="privilegeService.hasCurrentUserPrivilege('config_avis_workflow')"></app-avis-workflow>
<app-attachments-list *ngIf="currentTool === 'attachments' && !loading" #appAttachmentsList <app-attachments-list *ngIf="currentTool === 'attachments' && !loading" #appAttachmentsList
[resId]="currentResourceInformations.resId" [target]="'process'" [resId]="currentResourceInformations.resId" [target]="'process'"
(reloadBadgeAttachments)="refreshBadge($event,'attachments')"> (reloadBadgeAttachments)="refreshBadge($event,'attachments')">
...@@ -87,11 +92,11 @@ ...@@ -87,11 +92,11 @@
<app-indexing-form *ngIf="currentTool === 'info' && !loading" #indexingForm [groupId]="currentGroupId" <app-indexing-form *ngIf="currentTool === 'info' && !loading" #indexingForm [groupId]="currentGroupId"
[resId]="currentResourceInformations.resId" [indexingFormId]="currentResourceInformations.modelId" [resId]="currentResourceInformations.resId" [indexingFormId]="currentResourceInformations.modelId"
[mode]="'process'" [canEdit]="canEditData" [hideDiffusionList]="true" [mode]="'process'" [canEdit]="canEditData" [hideDiffusionList]="true"
(loadingFormEndEvent)="triggerProcessAction()" (retrieveDocumentEvent)="appDocumentViewer.saveDocService()"></app-indexing-form> (loadingFormEndEvent)="triggerProcessAction()"
(retrieveDocumentEvent)="appDocumentViewer.saveDocService()"></app-indexing-form>
<div style="position: sticky;bottom: 0px;text-align:right;"> <div style="position: sticky;bottom: 0px;text-align:right;">
<button mat-fab [title]="lang.saveModifications" <button mat-fab [title]="lang.saveModifications" *ngIf="isToolModified()" (click)="saveTool()"
*ngIf="isToolModified()" color="accent">
(click)="saveTool()" color="accent">
<mat-icon style="height:auto;font-size:20px;" class="fas fa-check"></mat-icon> <mat-icon style="height:auto;font-size:20px;" class="fas fa-check"></mat-icon>
</button> </button>
</div> </div>
...@@ -238,17 +243,22 @@ ...@@ -238,17 +243,22 @@
</button> </button>
</div> </div>
<div class="modal-module-content"> <div class="modal-module-content">
<app-history-list *ngIf="currentTool === 'history' && !loading" #appHistoryList
[resId]="currentResourceInformations.resId">
</app-history-list>
<app-notes-list *ngIf="modal.id === 'notes' && !loading" #appNotesList [editMode]="true" <app-notes-list *ngIf="modal.id === 'notes' && !loading" #appNotesList [editMode]="true"
[resId]="currentResourceInformations.resId"> [resId]="currentResourceInformations.resId">
</app-notes-list> </app-notes-list>
<app-diffusions-list *ngIf="modal.id === 'diffusionList' && !loading" #appDiffusionsList [adminMode]="false" <app-diffusions-list *ngIf="modal.id === 'diffusionList' && !loading" #appDiffusionsList [adminMode]="false"
[resId]="currentResourceInformations.resId" [expanded]="true"> [resId]="currentResourceInformations.resId" [expanded]="true">
</app-diffusions-list> </app-diffusions-list>
<app-visa-workflow *ngIf="modal.id === 'visaCircuit' && !loading" [adminMode]="privilegeService.hasCurrentUserPrivilege('config_visa_workflow')" #appVisaWorkflow <app-visa-workflow *ngIf="modal.id === 'visaCircuit' && !loading"
[resId]="currentResourceInformations.resId" > [adminMode]="privilegeService.hasCurrentUserPrivilege('config_visa_workflow')" #appVisaWorkflow
[resId]="currentResourceInformations.resId">
</app-visa-workflow> </app-visa-workflow>
<app-avis-workflow *ngIf="modal.id === 'opinionCircuit' && !loading" #appAvisWorkflow <app-avis-workflow *ngIf="modal.id === 'opinionCircuit' && !loading" #appAvisWorkflow
[resId]="currentResourceInformations.resId" [adminMode]="privilegeService.hasCurrentUserPrivilege('config_avis_workflow')"> [resId]="currentResourceInformations.resId"
[adminMode]="privilegeService.hasCurrentUserPrivilege('config_avis_workflow')">
</app-avis-workflow> </app-avis-workflow>
<app-attachments-list *ngIf="modal.id === 'attachments' && !loading" #appAttachmentsList <app-attachments-list *ngIf="modal.id === 'attachments' && !loading" #appAttachmentsList
[resId]="currentResourceInformations.resId" (reloadBadgeAttachments)="refreshBadge($event,'attachments')"> [resId]="currentResourceInformations.resId" (reloadBadgeAttachments)="refreshBadge($event,'attachments')">
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment