Normalisation de la liste des employés et des groupes.

This commit is contained in:
FyloZ 2021-03-15 18:01:50 -04:00
parent 4cafcf2142
commit 99cf9f7c0a
7 changed files with 129 additions and 182 deletions

View File

@ -64,7 +64,10 @@ export class AccountService implements OnDestroy {
this.setLoggedInEmployeeFromApi()
success()
},
error: err => this.errorService.handleError(err)
error: err => {
this.errorService.handleError(err)
globalLoadingWheel.hide()
}
})
}

View File

@ -1,66 +1,13 @@
<div class="action-bar">
<button *ngIf="canEditEmployee" mat-raised-button color="accent" routerLink="/employee/add">Ajouter</button>
</div>
<cre-entity-list
addLink="/employee/add"
addPermission="EDIT_EMPLOYEE"
[entities$]="employees$"
[columns]="columns"
[buttons]="buttons"
[expandable]="true"
[rowDetailsTemplate]="employeeDetailsTemplate">
</cre-entity-list>
<table class="mx-auto" *ngIf="employees$ | async as employees" mat-table multiTemplateDataRows [dataSource]="employees">
<ng-container matColumnDef="id">
<th mat-header-cell *matHeaderCellDef>Numéro d'employé</th>
<td mat-cell *matCellDef="let employee">{{employee.id}}</td>
</ng-container>
<ng-container matColumnDef="name">
<th mat-header-cell *matHeaderCellDef>Nom</th>
<td mat-cell *matCellDef="let employee">{{employee.firstName}} {{employee.lastName}}</td>
</ng-container>
<ng-container matColumnDef="group">
<th mat-header-cell *matHeaderCellDef>Groupe</th>
<td mat-cell *matCellDef="let employee">
<ng-container *ngIf="employee.group">{{employee.group.name}}</ng-container>
<ng-container *ngIf="!employee.group">Aucun</ng-container>
</td>
</ng-container>
<ng-container matColumnDef="lastLogin">
<th mat-header-cell *matHeaderCellDef>Dernière connexion</th>
<td mat-cell *matCellDef="let employee">
<ng-container *ngIf="employee.lastLoginTime">{{getDate(employee.lastLoginTime).toLocaleString()}}</ng-container>
<ng-container *ngIf="!employee.lastLoginTime">Jamais</ng-container>
</td>
</ng-container>
<ng-container matColumnDef="permissionCount">
<th mat-header-cell *matHeaderCellDef>Permissions</th>
<td mat-cell *matCellDef="let employee">
<ng-container *ngIf="employee.permissions">{{employee.permissions.length}}</ng-container>
<ng-container *ngIf="!employee.permissions">0</ng-container>
</td>
</ng-container>
<ng-container matColumnDef="editButton">
<th mat-header-cell *matHeaderCellDef></th>
<td mat-cell [class.disabled]="!canEditEmployee" *matCellDef="let employee">
<button mat-raised-button color="accent" routerLink="/employee/edit/{{employee.id}}">Modifier</button>
</td>
</ng-container>
<ng-container matColumnDef="editPasswordButton">
<th mat-header-cell *matHeaderCellDef></th>
<td mat-cell [class.disabled]="!canEditEmployeePassword" *matCellDef="let employee">
<button mat-raised-button color="accent" routerLink="/employee/password/edit/{{employee.id}}">Modifier mot de passe</button>
</td>
</ng-container>
<ng-container matColumnDef="expandedDetail">
<td mat-cell *matCellDef="let employee" [attr.colspan]="columns.length">
<div class="entity-detail"
[@detailExpand]="employee === expandedElement ? 'expanded' : 'collapsed'">
<cre-permissions-list [employee]="employee" class="w-100"></cre-permissions-list>
</div>
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="columns"></tr>
<tr
mat-row
*matRowDef="let employee; columns: columns"
class="entity-row can-expand"
[class.expanded-row]="expandedElement === employee"
(click)="expandedElement = expandedElement === employee ? null : employee">
</tr>
<tr mat-row *matRowDef="let row; columns: ['expandedDetail']" class="detail-row"></tr>
</table>
<ng-template #employeeDetailsTemplate let-employee="entity">
<cre-permissions-list [employee]="employee" class="w-100"></cre-permissions-list>
</ng-template>

View File

@ -23,9 +23,22 @@ import {ErrorService} from '../../../shared/service/error.service'
})
export class ListComponent extends ErrorHandlingComponent {
employees$: Observable<Employee[]>
columns = ['id', 'name', 'group', 'permissionCount', 'lastLogin', 'editButton', 'editPasswordButton']
expandedElement: Employee | null
columns = [
{def: 'id', title: 'Numéro d\'employé', valueFn: e => e.id},
{def: 'name', title: 'Nom', valueFn: e => `${e.firstName} ${e.lastName}`},
{def: 'group', title: 'Groupe', valueFn: e => e.group ? e.group.name : 'Aucun'},
{def: 'permissionCount', title: 'Nombre de permissions', valueFn: e => e.permissions.length},
{def: 'lastLogin', title: 'Dernière connexion', valueFn: e => e.lastLoginTime ? this.getDate(e.lastLoginTime).toLocaleString() : 'Jamais'}
]
buttons = [{
text: 'Modifier',
linkFn: employee => `/employee/edit/${employee.id}`,
permission: EmployeePermission.EDIT_EMPLOYEE
}, {
text: 'Modifier mot de passe',
linkFn: employee => `/employee/password/edit/${employee.id}`,
permission: EmployeePermission.EDIT_EMPLOYEE_PASSWORD
}]
constructor(
private employeeService: EmployeeService,
@ -44,12 +57,4 @@ export class ListComponent extends ErrorHandlingComponent {
getDate(dateString: string) {
return new Date(dateString)
}
get canEditEmployee(): boolean {
return this.accountService.hasPermission(EmployeePermission.EDIT_EMPLOYEE)
}
get canEditEmployeePassword(): boolean {
return this.accountService.hasPermission(EmployeePermission.EDIT_EMPLOYEE_PASSWORD)
}
}

View File

@ -1,66 +1,13 @@
<div class="action-bar">
<button *ngIf="canEditGroup" mat-raised-button color="accent" routerLink="/group/add">Ajouter</button>
</div>
<cre-entity-list
addLink="/group/add"
addPermission="EDIT_EMPLOYEE_GROUP"
[entities$]="groups$"
[columns]="columns"
[buttons]="buttons"
[expandable]="true"
[rowDetailsTemplate]="groupDetailsTemplate">
</cre-entity-list>
<table *ngIf="groups$ | async as groups" mat-table class="mx-auto" multiTemplateDataRows [dataSource]="groups">
<ng-container matColumnDef="name">
<th mat-header-cell *matHeaderCellDef>Nom</th>
<td mat-cell *matCellDef="let group">{{group.name}}</td>
</ng-container>
<ng-container matColumnDef="permissionCount">
<th mat-header-cell *matHeaderCellDef>Nombre de permissions</th>
<td mat-cell *matCellDef="let group">{{group.permissions.length}}</td>
</ng-container>
<ng-container matColumnDef="employeeCount">
<th mat-header-cell *matHeaderCellDef>Nombre d'utilisateurs</th>
<td mat-cell *matCellDef="let group">{{group.employeeCount}}</td>
</ng-container>
<ng-container matColumnDef="defaultGroup">
<th mat-header-cell *matHeaderCellDef></th>
<td mat-cell [class.disabled]="!canSetBrowserDefaultGroup" *matCellDef="let group">
<button
mat-raised-button
color="accent"
[disabled]="isDefaultGroup(group) ? true : null"
(click)="setDefaultGroup(group)">
<ng-container *ngIf="!isDefaultGroup(group)">
Définir par défaut
</ng-container>
<ng-container *ngIf="isDefaultGroup(group)">
Par défaut
</ng-container>
</button>
</td>
</ng-container>
<ng-container matColumnDef="editGroup">
<th mat-header-cell *matHeaderCellDef></th>
<td mat-cell [class.disabled]="!canEditGroup" *matCellDef="let group">
<button
mat-raised-button
color="accent"
routerLink="/group/edit/{{group.id}}">
Modifier
</button>
</td>
</ng-container>
<ng-container matColumnDef="expandedDetail">
<td mat-cell *matCellDef="let group" [attr.colspan]="columns.length">
<div class="entity-detail"
[@detailExpand]="group == expandedElement && canViewEmployee ? 'expanded' : 'collapsed'">
<cre-permissions-list [group]="group"></cre-permissions-list>
</div>
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="columns"></tr>
<tr
mat-row
*matRowDef="let group; columns: columns"
class="entity-row"
[class.expanded-row]="expandedElement === group"
[class.can-expand]="canViewEmployee"
(click)="expandedElement = expandedElement === group ? null : group">
</tr>
<tr mat-row *matRowDef="let row; columns: ['expandedDetail']" class="detail-row"></tr>
</table>
<ng-template #groupDetailsTemplate let-group="entity">
<cre-permissions-list [group]="group"></cre-permissions-list>
</ng-template>

View File

@ -2,31 +2,35 @@ import {Component} from '@angular/core'
import {GroupService} from '../../services/group.service'
import {EmployeeGroup, EmployeePermission} from '../../../shared/model/employee'
import {map} from 'rxjs/operators'
import {animate, state, style, transition, trigger} from '@angular/animations'
import {AccountService} from '../../../accounts/services/account.service'
import {ErrorHandlingComponent} from '../../../shared/components/subscribing.component'
import {ActivatedRoute, Router} from '@angular/router'
import {ErrorModel, ErrorService} from '../../../shared/service/error.service'
import {AlertService} from '../../../shared/service/alert.service'
import {globalLoadingWheel} from '../../../shared/components/loading-wheel/loading-wheel.component'
@Component({
selector: 'cre-groups',
templateUrl: './list.component.html',
styleUrls: ['./list.component.sass'],
animations: [
trigger('detailExpand', [
state('collapsed', style({height: '0px', minHeight: '0'})),
state('expanded', style({height: '*'})),
transition('expanded <=> collapsed', animate('225ms cubic-bezier(0.4, 0.0, 0.2, 1)'))
])
]
styleUrls: ['./list.component.sass']
})
export class ListComponent extends ErrorHandlingComponent {
groups$ = this.groupService.all.pipe(map(groups => groups.filter(g => g.id >= 0)))
defaultGroup: EmployeeGroup = null
columns = ['name', 'permissionCount', 'employeeCount', 'defaultGroup', 'editGroup']
expandedElement: EmployeeGroup | null
columns = [
{def: 'name', title: 'Nom', valueFn: g => g.name},
{def: 'permissionCount', title: 'Nombre de permissions', valueFn: g => g.permissions.length},
{def: 'employeeCount', title: 'Nombre d\'utilisateurs', valueFn: g => g.employeeCount}
]
buttons = [{
text: 'Définir par défaut',
clickFn: group => this.setDefaultGroup(group),
permission: EmployeePermission.SET_BROWSER_DEFAULT_GROUP,
disabledFn: group => this.isDefaultGroup(group)
}, {
text: 'Modifier',
linkFn: group => `/group/edit/${group.id}`,
permission: EmployeePermission.EDIT_EMPLOYEE_GROUP
}]
handledErrorModels: ErrorModel[] = [{
filter: error => error.status === 404,
@ -48,6 +52,7 @@ export class ListComponent extends ErrorHandlingComponent {
this.subscribe(
this.groupService.defaultGroup,
group => this.defaultGroup = group,
true
)
}
@ -62,16 +67,4 @@ export class ListComponent extends ErrorHandlingComponent {
isDefaultGroup(group: EmployeeGroup): boolean {
return this.defaultGroup && this.defaultGroup.id == group.id
}
get canViewEmployee(): boolean {
return this.accountService.hasPermission(EmployeePermission.VIEW_EMPLOYEE)
}
get canEditGroup(): boolean {
return this.accountService.hasPermission(EmployeePermission.EDIT_EMPLOYEE_GROUP)
}
get canSetBrowserDefaultGroup(): boolean {
return this.accountService.hasPermission(EmployeePermission.SET_BROWSER_DEFAULT_GROUP)
}
}

View File

@ -2,7 +2,7 @@
<button *ngIf="hasPermission(addPermission)" mat-raised-button color="accent" [routerLink]="addLink">Ajouter</button>
</div>
<table class="mx-auto" *ngIf="entities$ | async as entities" mat-table [dataSource]="entities">
<table class="mx-auto" *ngIf="entities$ | async as entities" mat-table multiTemplateDataRows [dataSource]="entities">
<!-- Columns -->
<ng-container *ngFor="let column of columns" [matColumnDef]="column.def">
<th mat-header-cell *matHeaderCellDef>{{column.title}}</th>
@ -20,20 +20,40 @@
<!-- Buttons -->
<ng-container *ngFor="let button of buttons; let buttonIndex = index" matColumnDef="button{{buttonIndex}}">
<th mat-header-cell *matHeaderCellDef></th>
<td mat-cell [class.disabled]="!hasPermissionToUseButton(button)" *matCellDef="let entity; let i = index">
<td mat-cell [class.disabled]="!hasPermissionToUseButton(button)" *matCellDef="let entity; let i = dataIndex">
<ng-container *ngIf="(!hoveredEntity && i === 0) || hoveredEntity === entity">
<button
mat-raised-button
color="accent"
[routerLink]="button.link ? button.link.externalLink ? undefined : button.link : button.linkFn(entity).externalLink ? undefined : button.linkFn(entity)"
[routerLink]="getRouterLink(button, entity)"
[disabled]="button.disabledFn && button.disabledFn(entity)"
(click)="openExternalLink(button, entity)">
(click)="clickButton(button, entity)">
{{button.text}}
</button>
</ng-container>
</td>
</ng-container>
<ng-container *ngIf="expandable" matColumnDef="expandedDetail">
<td mat-cell *matCellDef="let entity" [attr.colspan]="tableCols.length">
<div class="entity-detail" [@detailExpand]="entity === expandedEntity ? 'expanded' : 'collapsed'">
<ng-container [ngTemplateOutlet]="rowDetailsTemplate"
[ngTemplateOutletContext]="{entity: entity, expandedEntity: expandedEntity}"></ng-container>
</div>
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="tableCols"></tr>
<tr mat-row *matRowDef="let row; columns: tableCols" (mouseover)="hoveredEntity = row"></tr>
<tr
mat-row
class="entity-row"
*matRowDef="let row; columns: tableCols"
[class.expanded-row]="expandedEntity === row"
[class.can-expand]="expandable"
(mouseover)="hoveredEntity = row"
(click)="expandedEntity = expandedEntity === row ? null : row">
</tr>
<ng-container *ngIf="expandable">
<tr mat-row *matRowDef="let row; columns: ['expandedDetail']" class="detail-row"></tr>
</ng-container>
</table>

View File

@ -2,11 +2,19 @@ import {Component, Input} from '@angular/core'
import {Observable} from 'rxjs'
import {AccountService} from '../../../accounts/services/account.service'
import {EmployeePermission} from '../../model/employee'
import {animate, state, style, transition, trigger} from '@angular/animations'
@Component({
selector: 'cre-entity-list',
templateUrl: './entity-list.component.html',
styleUrls: ['./entity-list.component.sass']
styleUrls: ['./entity-list.component.sass'],
animations: [
trigger('detailExpand', [
state('collapsed', style({height: '0px', minHeight: '0'})),
state('expanded', style({height: '*'})),
transition('expanded <=> collapsed', animate('225ms cubic-bezier(0.4, 0.0, 0.2, 1)'))
])
]
})
export class EntityListComponent<T> {
@Input() entities$: Observable<T>
@ -15,8 +23,11 @@ export class EntityListComponent<T> {
@Input() buttons?: TableButton[]
@Input() addLink: string
@Input() addPermission: EmployeePermission
@Input() expandable = false
@Input() rowDetailsTemplate
hoveredEntity: T | null
expandedEntity: T | null
constructor(
private accountService: AccountService
@ -31,23 +42,43 @@ export class EntityListComponent<T> {
return this.accountService.hasPermission(permission)
}
openExternalLink(button: TableButton, entity: T) {
let externalLink = null
getRouterLink(button: TableButton, entity: T): string {
// @ts-ignore
if (button.link && button.link.externalLink) {
if (button.link && !button.link.externalLink) {
// @ts-ignore
externalLink = button.link.externalLink
} else {
const linkFnResult = button.linkFn(entity)
return button.link
} else if (button.linkFn) {
const fnResult = button.linkFn(entity)
// @ts-ignore
if (linkFnResult && linkFnResult.externalLink) {
if (!fnResult.externalLink) {
// @ts-ignore
externalLink = linkFnResult.externalLink
return fnResult
}
}
return undefined
}
if (externalLink) {
window.open(externalLink, '_blank')
clickButton(button: TableButton, entity: T) {
if (button.link || button.linkFn) {
let externalLink = null
// @ts-ignore
if (button.link && button.link.externalLink) {
// @ts-ignore
externalLink = button.link.externalLink
} else {
const linkFnResult = button.linkFn(entity)
// @ts-ignore
if (linkFnResult && linkFnResult.externalLink) {
// @ts-ignore
externalLink = linkFnResult.externalLink
}
}
if (externalLink) {
window.open(externalLink, '_blank')
}
} else if (button.clickFn) {
button.clickFn(entity)
}
}
@ -87,6 +118,7 @@ export class TableButton {
public text: string,
public link: string | { externalLink: string } | null,
public linkFn: (T) => string | { externalLink: string } | null,
public clickFn: (T) => void,
public permission: EmployeePermission | null,
public disabledFn: (T) => boolean | null
) {