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

FEAT #9105 front actions list + manage lock user

parent 80077b95
No related branches found
No related tags found
No related merge requests found
<button *ngIf="!contextMode" mat-icon-button [matMenuTriggerFor]="menu" title="{{lang.selectAction}}" [disabled]="selectedRes.length==0"
style="height: 20px;width: 20px;position: absolute;left: 25px;top: 7px;">
<mat-icon fontSet="fas" fontIcon="fa-sort-down fa-2x" style="height: 20px;width: 20px;margin-top: -30px;"></mat-icon>
</button>
<span *ngIf="contextMode" [matMenuTriggerFor]="menu" #menu2 style="position: absolute;" [style.left]="contextMenuPosition.x"
[style.top]="contextMenuPosition.y"></span>
<mat-menu #menu="matMenu">
<div style="text-align: center;font-size: 10px;opacity: 0.5;margin-top:-10px;">
{{menuTitle}}
<ng-container *ngIf="!contextMode">
{{selectedRes.length}} {{lang.selectedElements}}
</ng-container>
<ng-container *ngIf="contextMode">
{{this.contextMenuTitle}}
</ng-container>
</div>
<button mat-menu-item (click)="launchEvent('confirmAction');">
<span>Valider le document</span>
</button>
<button mat-menu-item (click)="launchEvent('err');">
<span>Action erronée</span>
</button>
</mat-menu>
\ No newline at end of file
import { Component, OnInit } from '@angular/core'; import { Component, OnInit, Input, 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 { NotificationService } from '../notification.service';
import { MatDialog } from '@angular/material'; import { MatDialog, MatMenuTrigger } from '@angular/material';
import { ConfirmActionComponent } from './confirm-action/confirm-action.component'; import { ConfirmActionComponent } from './confirm-action/confirm-action.component';
...@@ -17,6 +17,16 @@ export class ActionsListComponent implements OnInit { ...@@ -17,6 +17,16 @@ export class ActionsListComponent implements OnInit {
lang: any = LANG; lang: any = LANG;
loading: boolean = false; loading: boolean = false;
@ViewChild(MatMenuTrigger) contextMenu: MatMenuTrigger;
contextMenuPosition = { x: '0px', y: '0px' };
contextMenuTitle = '';
contextResId = 0;
@Input('selectedRes') selectedRes: any;
@Input('totalRes') totalRes: number;
@Input('contextMode') contextMode: boolean;
constructor(public http: HttpClient, private notify: NotificationService, public dialog: MatDialog) { } constructor(public http: HttpClient, private notify: NotificationService, public dialog: MatDialog) { }
ngOnInit(): void { ngOnInit(): void {
...@@ -29,10 +39,52 @@ export class ActionsListComponent implements OnInit { ...@@ -29,10 +39,52 @@ export class ActionsListComponent implements OnInit {
this.loading = false; this.loading = false;
} }
open(x: number, y: number, row: any) {
// Adjust the menu anchor position
this.contextMenuPosition.x = x + 'px';
this.contextMenuPosition.y = y + 'px';
this.contextMenuTitle = row.alt_identifier;
this.contextResId = row.res_id;
// Opens the menu
this.contextMenu.openMenu();
// prevents default
return false;
}
launchEvent(action: string) {
let arrRes: any[] = [];
if (this.contextMode) {
arrRes = [this.contextResId];
} else {
arrRes = this.selectedRes;
}
this.http.put('../../rest/resources/lock', {resources : arrRes})
.subscribe((data: any) => {
try {
this[action]();
}
catch (error) {
alert("L'action n'existe pas!");
}
this.loading = false;
}, (err: any) => {
if (err.error.lockBy) {
alert("Courrier suivant : " + arrRes.join(', ') + " verrouillé par " + err.error.lockBy.join(', '));
} else {
this.notify.handleErrors(err);
}
});
}
/* OPEN SPECIFIC ACTION */ /* OPEN SPECIFIC ACTION */
confirmAction() { confirmAction() {
this.dialog.open(ConfirmActionComponent, { this.dialog.open(ConfirmActionComponent, {
width: '800px', width: 'auto',
data: { } data: { }
}); });
} }
......
.mat-dialog-actions, .mat-dialog-title {
justify-content: center;
text-align: center;
}
\ No newline at end of file
...@@ -18,7 +18,7 @@ ...@@ -18,7 +18,7 @@
<div class="row" style="margin:0px;"> <div class="row" style="margin:0px;">
<div class="col-md-12" style="display:flex;"> <div class="col-md-12" style="display:flex;">
<app-filters-tool style="flex:1;" #filtersTool [currentBasketInfo]="currentBasketInfo" <app-filters-tool style="flex:1;" #filtersTool [currentBasketInfo]="currentBasketInfo"
[listProperties]="this.listProperties" [snavR]="snav2" [selectedRes]="selectedRes" (toggleAllRes)="toggleAllRes($event)" (refreshEvent)="refreshDao()"></app-filters-tool> [listProperties]="this.listProperties" [snavR]="snav2" [totalRes]="allResInBasket.length" [selectedRes]="selectedRes" (toggleAllRes)="toggleAllRes($event)" (refreshEvent)="refreshDao()"></app-filters-tool>
<mat-paginator #paginatorResultList [length]="resultsLength" [pageSize]="10" class="paginatorResultList"></mat-paginator> <mat-paginator #paginatorResultList [length]="resultsLength" [pageSize]="10" class="paginatorResultList"></mat-paginator>
</div> </div>
</div> </div>
...@@ -95,9 +95,8 @@ ...@@ -95,9 +95,8 @@
</td> </td>
</ng-container> </ng-container>
<tr mat-row *matRowDef="let row; columns: displayedColumnsBasket;" (swipeleft)="paginatorResultList.nextPage()" <tr mat-row *matRowDef="let row; columns: displayedColumnsBasket;" (swipeleft)="paginatorResultList.nextPage()"
(swiperight)="paginatorResultList.previousPage()"></tr> (swiperight)="paginatorResultList.previousPage()" (contextmenu)="open($event,row);$event.preventDefault();"></tr>
</table> </table>
<app-actions-list #actionsList></app-actions-list>
</mat-card> </mat-card>
</mat-sidenav-content> </mat-sidenav-content>
<mat-sidenav #snav2 mode="over" [fixedInViewport]="mobileQuery.matches" fixedTopGap="56" position='end' <mat-sidenav #snav2 mode="over" [fixedInViewport]="mobileQuery.matches" fixedTopGap="56" position='end'
...@@ -112,4 +111,5 @@ ...@@ -112,4 +111,5 @@
<mat-divider></mat-divider> <mat-divider></mat-divider>
</mat-sidenav> </mat-sidenav>
</mat-sidenav-container> </mat-sidenav-container>
</div> </div>
\ No newline at end of file <app-actions-list #actionsListContext [contextMode]="true" [totalRes]="totalRes" [selectedRes]="selectedRes"></app-actions-list>
\ No newline at end of file
import { ChangeDetectorRef, Component, OnInit, ViewChild, EventEmitter, ComponentFactoryResolver } from '@angular/core'; import { ChangeDetectorRef, Component, OnInit, ViewChild, EventEmitter, ComponentFactoryResolver, ViewContainerRef, TemplateRef } from '@angular/core';
import { MediaMatcher } from '@angular/cdk/layout'; import { MediaMatcher } from '@angular/cdk/layout';
import { HttpClient } from '@angular/common/http'; import { HttpClient } from '@angular/common/http';
import { LANG } from '../translate.component'; import { LANG } from '../translate.component';
import { merge, Observable, of as observableOf } from 'rxjs'; import { merge, Observable, of as observableOf, fromEvent, Subscription } from 'rxjs';
import { NotificationService } from '../notification.service'; import { NotificationService } from '../notification.service';
import { MatDialog, MatSidenav, MatPaginator, MatSort, MatBottomSheet } from '@angular/material'; import { MatDialog, MatSidenav, MatPaginator, MatSort, MatBottomSheet, MatMenu, MatMenuTrigger } from '@angular/material';
import { DomSanitizer, SafeHtml } from '@angular/platform-browser'; import { DomSanitizer, SafeHtml } from '@angular/platform-browser';
import { startWith, switchMap, map, catchError } from 'rxjs/operators'; import { startWith, switchMap, map, catchError } from 'rxjs/operators';
import { ActivatedRoute, Router } from '@angular/router'; import { ActivatedRoute, Router, RouterLinkWithHref } from '@angular/router';
import { HeaderService } from '../../service/header.service'; import { HeaderService } from '../../service/header.service';
import { FiltersListService } from '../../service/filtersList.service'; import { FiltersListService } from '../../service/filtersList.service';
import { NotesListComponent } from '../notes/notes.component'; import { NotesListComponent } from '../notes/notes.component';
...@@ -17,6 +17,7 @@ import { DiffusionsListComponent } from '../diffusions/diffusions-list.component ...@@ -17,6 +17,7 @@ import { DiffusionsListComponent } from '../diffusions/diffusions-list.component
import { FiltersToolComponent } from './filters/filters-tool.component'; import { FiltersToolComponent } from './filters/filters-tool.component';
import { ActionsListComponent } from '../actions/actions-list.component'; import { ActionsListComponent } from '../actions/actions-list.component';
import { Overlay, OverlayRef } from '@angular/cdk/overlay';
declare function $j(selector: any): any; declare function $j(selector: any): any;
...@@ -75,13 +76,15 @@ export class BasketListComponent implements OnInit { ...@@ -75,13 +76,15 @@ export class BasketListComponent implements OnInit {
selectedRes: number[] = []; selectedRes: number[] = [];
allResInBasket: number[] = []; allResInBasket: number[] = [];
@ViewChild('actionsListContext') actionsList: ActionsListComponent;
@ViewChild('filtersTool') filtersTool: FiltersToolComponent; @ViewChild('filtersTool') filtersTool: FiltersToolComponent;
@ViewChild('actionsList') actionsList: ActionsListComponent;
currentSelectedChrono: string = '';
@ViewChild(MatPaginator) paginator: MatPaginator; @ViewChild(MatPaginator) paginator: MatPaginator;
@ViewChild('tableBasketListSort') sort: MatSort; @ViewChild('tableBasketListSort') sort: MatSort;
constructor(changeDetectorRef: ChangeDetectorRef, private router: Router, private route: ActivatedRoute, media: MediaMatcher, public http: HttpClient, public dialog: MatDialog, private sanitizer: DomSanitizer, private bottomSheet: MatBottomSheet, private headerService: HeaderService, public filtersListService: FiltersListService, private notify: NotificationService, private componentFactoryResolver: ComponentFactoryResolver) { constructor(changeDetectorRef: ChangeDetectorRef, private router: Router, private route: ActivatedRoute, media: MediaMatcher, public http: HttpClient, public dialog: MatDialog, private sanitizer: DomSanitizer, private bottomSheet: MatBottomSheet, private headerService: HeaderService, public filtersListService: FiltersListService, private notify: NotificationService, public overlay: Overlay, public viewContainerRef: ViewContainerRef) {
this.mobileMode = angularGlobals.mobileMode; this.mobileMode = angularGlobals.mobileMode;
$j("link[href='merged_css.php']").remove(); $j("link[href='merged_css.php']").remove();
this.mobileQuery = media.matchMedia('(max-width: 768px)'); this.mobileQuery = media.matchMedia('(max-width: 768px)');
...@@ -348,15 +351,12 @@ export class BasketListComponent implements OnInit { ...@@ -348,15 +351,12 @@ export class BasketListComponent implements OnInit {
} }
} }
launchEvent() { open({ x, y }: MouseEvent, row: any) {
/* FOR TEST */
let action = 'confirmAction'; this.actionsList.open(x, y, row)
try {
this.actionsList[action](); // prevents default
} return false;
catch (error) {
alert("L'action n'existe pas!");
}
} }
} }
export interface BasketList { export interface BasketList {
......
<mat-button-toggle-group #group="matButtonToggleGroup" class="envFilter" multiple> <mat-button-toggle-group #group="matButtonToggleGroup" class="envFilter" multiple>
<mat-checkbox color="primary" style="margin: 10px;" title="{{lang.selectAllResInBasket}}" (change)="toggleAll($event)"></mat-checkbox> <mat-checkbox color="primary" [checked]="selectedRes.length == totalRes" [indeterminate]="selectedRes.length > 0 && selectedRes.length < totalRes" style="margin: 10px;padding-right: 10px;"
title="{{lang.selectAllResInBasket}}" (change)="toggleAll($event)"></mat-checkbox>
<app-actions-list #actionsList [contextMode]="false" [totalRes]="totalRes" [selectedRes]="selectedRes"></app-actions-list>
<form [formGroup]="stateForm" [style.flex]="1"> <form [formGroup]="stateForm" [style.flex]="1">
<mat-form-field appearance="outline" floatLabel="never" [style.fontSize.px]="10" style="top: -2px;"> <mat-form-field appearance="outline" floatLabel="never" [style.fontSize.px]="10" style="top: -2px;">
<input class="metaSearch" type="text" matInput placeholder="{{lang.searchMailInBasket}}" formControlName="stateGroup" <input class="metaSearch" type="text" matInput placeholder="{{lang.searchMailInBasket}}" formControlName="stateGroup"
...@@ -36,12 +38,13 @@ ...@@ -36,12 +38,13 @@
</mat-option> </mat-option>
</mat-select> </mat-select>
</mat-form-field> </mat-form-field>
<button [disabled]="this.listProperties.order == ''" [style.opacity]="this.listProperties.order == '' ? '0.2' : '1'" mat-icon-button [title]="this.listProperties.orderDir == 'DESC' ? lang.descOrder : lang.ascOrder" <button [disabled]="this.listProperties.order == ''" [style.opacity]="this.listProperties.order == '' ? '0.2' : '1'"
style="color: rgba(0,0,0,0.38);" (click)="changeOrderDir();"> mat-icon-button [title]="this.listProperties.orderDir == 'DESC' ? lang.descOrder : lang.ascOrder" style="color: rgba(0,0,0,0.38);"
(click)="changeOrderDir();">
<mat-icon *ngIf="this.listProperties.orderDir == 'DESC'" fontSet="fas" fontIcon="fa-sort-amount-down fa-2x"></mat-icon> <mat-icon *ngIf="this.listProperties.orderDir == 'DESC'" fontSet="fas" fontIcon="fa-sort-amount-down fa-2x"></mat-icon>
<mat-icon *ngIf="this.listProperties.orderDir == 'ASC'" fontSet="fas" fontIcon="fa-sort-amount-up fa-2x"></mat-icon> <mat-icon *ngIf="this.listProperties.orderDir == 'ASC'" fontSet="fas" fontIcon="fa-sort-amount-up fa-2x"></mat-icon>
</button> </button>
<button mat-icon-button [matMenuTriggerFor]="menuParamList"> <button mat-icon-button [matMenuTriggerFor]="menuParamList" title="{{lang.tools}}">
<mat-icon color="primary" fontSet="fas" fontIcon="fa-cog fa-2x"></mat-icon> <mat-icon color="primary" fontSet="fas" fontIcon="fa-cog fa-2x"></mat-icon>
</button> </button>
<mat-menu class="actionsTool" #menuParamList="matMenu"> <mat-menu class="actionsTool" #menuParamList="matMenu">
...@@ -59,18 +62,25 @@ ...@@ -59,18 +62,25 @@
</mat-menu> </mat-menu>
</mat-button-toggle-group> </mat-button-toggle-group>
<div class="filterBadges"> <div class="filterBadges">
<span *ngIf="haveFilters()" class="label badge-eraser" title="{{lang.eraseAllFilters}}" (click)="this.listProperties.search='';removeFilters();"><i class="fas fa-eraser"></i></span> <span *ngIf="haveFilters()" class="label badge-eraser" title="{{lang.eraseAllFilters}}" (click)="this.listProperties.search='';removeFilters();"><i
class="fas fa-eraser"></i></span>
<span class="label badge-search" *ngIf="this.listProperties.search !== ''" title="{{lang.subject}} / {{lang.chronoNumber}}" (click)="this.listProperties.search='';updateFilters();">{{this.listProperties.search}}
<span class="label badge-search" *ngIf="this.listProperties.search !== ''" title="{{lang.subject}} / {{lang.chronoNumber}}"
(click)="this.listProperties.search='';updateFilters();">{{this.listProperties.search}}
<i class="fa fa-times-circle"></i></span> <i class="fa fa-times-circle"></i></span>
<span class="label badge-categories" title="{{lang.categories}}" *ngFor="let category of this.listProperties.categories; let i=index" (click)="removeFilter('categories', i)">{{category.label}} <span class="label badge-categories" title="{{lang.categories}}" *ngFor="let category of this.listProperties.categories; let i=index"
(click)="removeFilter('categories', i)">{{category.label}}
<i class="fa fa-times-circle"></i></span> <i class="fa fa-times-circle"></i></span>
<span class="label badge-priorities" title="{{lang.priorities}}" *ngFor="let priority of this.listProperties.priorities; let i=index" (click)="removeFilter('priorities', i)">{{priority.label}} <span class="label badge-priorities" title="{{lang.priorities}}" *ngFor="let priority of this.listProperties.priorities; let i=index"
(click)="removeFilter('priorities', i)">{{priority.label}}
<i class="fa fa-times-circle"></i></span> <i class="fa fa-times-circle"></i></span>
<span class="label badge-statuses" title="{{lang.statuses}}" *ngFor="let status of this.listProperties.statuses; let i=index" (click)="removeFilter('statuses', i)">{{status.label}} <span class="label badge-statuses" title="{{lang.statuses}}" *ngFor="let status of this.listProperties.statuses; let i=index"
(click)="removeFilter('statuses', i)">{{status.label}}
<i class="fa fa-times-circle"></i></span> <i class="fa fa-times-circle"></i></span>
<span class="label badge-entities" title="{{lang.entities}}" *ngFor="let entity of this.listProperties.entities; let i=index" (click)="removeFilter('entities', i)">{{entity.label}} <span class="label badge-entities" title="{{lang.entities}}" *ngFor="let entity of this.listProperties.entities; let i=index"
(click)="removeFilter('entities', i)">{{entity.label}}
<i class="fa fa-times-circle"></i></span> <i class="fa fa-times-circle"></i></span>
<span class="label badge-subEntities" title="{{lang.subEntities}}" *ngFor="let subEntity of this.listProperties.subEntities; let i=index" (click)="removeFilter('subEntities', i)">{{subEntity.label}} <span class="label badge-subEntities" title="{{lang.subEntities}}" *ngFor="let subEntity of this.listProperties.subEntities; let i=index"
(click)="removeFilter('subEntities', i)">{{subEntity.label}}
<i class="fa fa-times-circle"></i></span> <i class="fa fa-times-circle"></i></span>
</div> </div>
\ No newline at end of file
...@@ -9,6 +9,7 @@ import { startWith, map } from 'rxjs/operators'; ...@@ -9,6 +9,7 @@ import { startWith, map } from 'rxjs/operators';
import { LatinisePipe } from 'ngx-pipes'; import { LatinisePipe } from 'ngx-pipes';
import { ExportComponent } from '../export/export.component'; import { ExportComponent } from '../export/export.component';
import { SummarySheetComponent } from '../summarySheet/summary-sheet.component'; import { SummarySheetComponent } from '../summarySheet/summary-sheet.component';
import { ActionsListComponent } from '../../actions/actions-list.component';
declare function $j(selector: any): any; declare function $j(selector: any): any;
...@@ -59,11 +60,14 @@ export class FiltersToolComponent implements OnInit { ...@@ -59,11 +60,14 @@ export class FiltersToolComponent implements OnInit {
isLoading: boolean = false; isLoading: boolean = false;
@ViewChild('actionsList') actionsList: ActionsListComponent;
@Input('listProperties') listProperties: any; @Input('listProperties') listProperties: any;
@Input('currentBasketInfo') currentBasketInfo: any; @Input('currentBasketInfo') currentBasketInfo: any;
@Input('snavR') sidenavRight: MatSidenav; @Input('snavR') sidenavRight: MatSidenav;
@Input('selectedRes') selectedRes: any; @Input('selectedRes') selectedRes: any;
@Input('totalRes') totalRes: number;
@Output('refreshEvent') refreshEvent = new EventEmitter<string>(); @Output('refreshEvent') refreshEvent = new EventEmitter<string>();
@Output('toggleAllRes') toggleAllRes = new EventEmitter<string>(); @Output('toggleAllRes') toggleAllRes = new EventEmitter<string>();
......
...@@ -839,5 +839,6 @@ export const LANG_EN = { ...@@ -839,5 +839,6 @@ export const LANG_EN = {
"userIsNotDeletable" : "You do not have <b>full access rights</b> to diffusion list or mails for the user ", "userIsNotDeletable" : "You do not have <b>full access rights</b> to diffusion list or mails for the user ",
"userIsDeletableBy" : "Only a user with the <b>totality of access rights</b> can delete or suspend this user.", "userIsDeletableBy" : "Only a user with the <b>totality of access rights</b> can delete or suspend this user.",
"mailEntitiesList" : "List of entities attached to mails", "mailEntitiesList" : "List of entities attached to mails",
"firstSummarySheetsGenerated" : "Only first 500 summary sheets will be generated." "firstSummarySheetsGenerated" : "Only first 500 summary sheets will be generated.",
"selectAction" : "Select an action",
}; };
...@@ -865,5 +865,6 @@ export const LANG_FR = { ...@@ -865,5 +865,6 @@ export const LANG_FR = {
"userIsNotDeletable" : "Vous n'avez pas la totalité des <b>droits d'accès</b> sur les listes de diffusion ou les courriers de l'utilisateur ", "userIsNotDeletable" : "Vous n'avez pas la totalité des <b>droits d'accès</b> sur les listes de diffusion ou les courriers de l'utilisateur ",
"userIsDeletableBy" : "Seul un utilisateur ayant la <b>totalité des droits d'accès</b> pourra supprimer ou suspendre cet utilisateur.", "userIsDeletableBy" : "Seul un utilisateur ayant la <b>totalité des droits d'accès</b> pourra supprimer ou suspendre cet utilisateur.",
"mailEntitiesList" : "Liste des entités rattachées aux courriers", "mailEntitiesList" : "Liste des entités rattachées aux courriers",
"firstSummarySheetsGenerated" : "Seules les 500 premières fiches de liaison seront générés." "firstSummarySheetsGenerated" : "Seules les 500 premières fiches de liaison seront générés.",
"selectAction" : "Effectuer une action",
}; };
...@@ -868,5 +868,6 @@ export const LANG_NL = { ...@@ -868,5 +868,6 @@ export const LANG_NL = {
"userIsNotDeletable" : "You do not have <b>full access rights</b> to diffusion list or mails for the user ", //_TO_TRANSLATE "userIsNotDeletable" : "You do not have <b>full access rights</b> to diffusion list or mails for the user ", //_TO_TRANSLATE
"userIsDeletableBy" : "Only a user with the <b>totality of access rights</b> can delete or suspend this user.", //_TO_TRANSLATE "userIsDeletableBy" : "Only a user with the <b>totality of access rights</b> can delete or suspend this user.", //_TO_TRANSLATE
"mailEntitiesList" : "List of entities attached to mails", //_TO_TRANSLATE "mailEntitiesList" : "List of entities attached to mails", //_TO_TRANSLATE
"firstSummarySheetsGenerated" : "Only first 500 summary sheets will be generated."//_TO_TRANSLATE "firstSummarySheetsGenerated" : "Only first 500 summary sheets will be generated.", //_TO_TRANSLATE,
"selectAction" : "Select an action", //_TO_TRANSLATE,
}; };
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