RED-2544: User management filters
This commit is contained in:
parent
fa3125302f
commit
b95410f6fd
@ -25,6 +25,7 @@
|
|||||||
[strokeWidth]="15"
|
[strokeWidth]="15"
|
||||||
[subtitle]="'user-stats.chart.users' | translate"
|
[subtitle]="'user-stats.chart.users' | translate"
|
||||||
direction="row"
|
direction="row"
|
||||||
|
filterKey="roleFilters"
|
||||||
totalType="sum"
|
totalType="sum"
|
||||||
></redaction-simple-doughnut-chart>
|
></redaction-simple-doughnut-chart>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -11,6 +11,7 @@ import {
|
|||||||
IconButtonTypes,
|
IconButtonTypes,
|
||||||
ListingComponent,
|
ListingComponent,
|
||||||
LoadingService,
|
LoadingService,
|
||||||
|
NestedFilter,
|
||||||
TableColumnConfig,
|
TableColumnConfig,
|
||||||
} from '@iqser/common-ui';
|
} from '@iqser/common-ui';
|
||||||
import { Observable } from 'rxjs';
|
import { Observable } from 'rxjs';
|
||||||
@ -18,6 +19,7 @@ import { map } from 'rxjs/operators';
|
|||||||
import { rolesTranslations } from '../../../../translations/roles-translations';
|
import { rolesTranslations } from '../../../../translations/roles-translations';
|
||||||
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
|
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
|
||||||
import { User } from '@red/domain';
|
import { User } from '@red/domain';
|
||||||
|
import { userTypeChecker, userTypeFilters, UserTypes } from '../../../../utils';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
templateUrl: './user-listing-screen.component.html',
|
templateUrl: './user-listing-screen.component.html',
|
||||||
@ -110,38 +112,30 @@ export class UserListingScreenComponent extends ListingComponent<User> implement
|
|||||||
|
|
||||||
private _computeStats() {
|
private _computeStats() {
|
||||||
this.chartData = this._translateChartService.translateRoles(
|
this.chartData = this._translateChartService.translateRoles(
|
||||||
[
|
UserTypes.map(type => ({
|
||||||
{
|
value: this.allEntities.filter(userTypeFilters[type]).length,
|
||||||
value: this.allEntities.filter(user => !user.isActive).length,
|
color: type.replace('RED_', ''),
|
||||||
color: 'INACTIVE',
|
label: type,
|
||||||
label: 'INACTIVE',
|
key: type,
|
||||||
},
|
})).filter(type => type.value > 0),
|
||||||
{
|
|
||||||
value: this.allEntities.filter(user => user.roles.length === 1 && user.roles[0] === 'RED_USER').length,
|
|
||||||
color: 'REGULAR',
|
|
||||||
label: 'REGULAR',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: this.allEntities.filter(user => user.isManager && !user.isAdmin).length,
|
|
||||||
color: 'MANAGER',
|
|
||||||
label: 'RED_MANAGER',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: this.allEntities.filter(user => user.isManager && user.isAdmin).length,
|
|
||||||
color: 'MANAGER_ADMIN',
|
|
||||||
label: 'MANAGER_ADMIN',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: this.allEntities.filter(user => user.isUserAdmin && !user.isAdmin).length,
|
|
||||||
color: 'USER_ADMIN',
|
|
||||||
label: 'RED_USER_ADMIN',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: this.allEntities.filter(user => user.isAdmin && !user.isManager).length,
|
|
||||||
color: 'ADMIN',
|
|
||||||
label: 'RED_ADMIN',
|
|
||||||
},
|
|
||||||
].filter(type => type.value > 0),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
|
this._computeAllFilters();
|
||||||
|
}
|
||||||
|
|
||||||
|
private _computeAllFilters() {
|
||||||
|
const roleFilters = this.chartData.map(
|
||||||
|
config =>
|
||||||
|
new NestedFilter({
|
||||||
|
id: config.key,
|
||||||
|
label: config.label,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
this.filterService.addFilterGroup({
|
||||||
|
slug: 'roleFilters',
|
||||||
|
filters: roleFilters,
|
||||||
|
checker: userTypeChecker,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import { Component, Input, OnChanges } from '@angular/core';
|
import { Component, Input, OnChanges, OnInit } from '@angular/core';
|
||||||
import { Color } from '@utils/types';
|
import { Color } from '@utils/types';
|
||||||
import { FilterService } from '@iqser/common-ui';
|
import { FilterService, INestedFilter } from '@iqser/common-ui';
|
||||||
import { Observable, of } from 'rxjs';
|
import { Observable, of } from 'rxjs';
|
||||||
import { map } from 'rxjs/operators';
|
import { map } from 'rxjs/operators';
|
||||||
|
|
||||||
@ -12,14 +12,12 @@ export interface DoughnutChartConfig {
|
|||||||
active?: boolean;
|
active?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const FILTER_KEY = 'statusFilters';
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'redaction-simple-doughnut-chart',
|
selector: 'redaction-simple-doughnut-chart',
|
||||||
templateUrl: './simple-doughnut-chart.component.html',
|
templateUrl: './simple-doughnut-chart.component.html',
|
||||||
styleUrls: ['./simple-doughnut-chart.component.scss'],
|
styleUrls: ['./simple-doughnut-chart.component.scss'],
|
||||||
})
|
})
|
||||||
export class SimpleDoughnutChartComponent implements OnChanges {
|
export class SimpleDoughnutChartComponent implements OnChanges, OnInit {
|
||||||
@Input() subtitle: string;
|
@Input() subtitle: string;
|
||||||
@Input() config: DoughnutChartConfig[] = [];
|
@Input() config: DoughnutChartConfig[] = [];
|
||||||
@Input() radius = 85;
|
@Input() radius = 85;
|
||||||
@ -27,7 +25,8 @@ export class SimpleDoughnutChartComponent implements OnChanges {
|
|||||||
@Input() direction: 'row' | 'column' = 'column';
|
@Input() direction: 'row' | 'column' = 'column';
|
||||||
@Input() totalType: 'sum' | 'count' = 'sum';
|
@Input() totalType: 'sum' | 'count' = 'sum';
|
||||||
@Input() counterText: string;
|
@Input() counterText: string;
|
||||||
readonly filtersEnabled: boolean;
|
@Input() filterKey = 'statusFilters';
|
||||||
|
filtersEnabled: boolean;
|
||||||
|
|
||||||
chartData: any[] = [];
|
chartData: any[] = [];
|
||||||
perimeter: number;
|
perimeter: number;
|
||||||
@ -35,10 +34,12 @@ export class SimpleDoughnutChartComponent implements OnChanges {
|
|||||||
cy = 0;
|
cy = 0;
|
||||||
size = 0;
|
size = 0;
|
||||||
|
|
||||||
readonly statusFilters$ = this.filterService.getFilterModels$(FILTER_KEY) ?? of([]);
|
filters$: Observable<INestedFilter[]>;
|
||||||
|
|
||||||
constructor(readonly filterService: FilterService) {
|
constructor(readonly filterService: FilterService) {
|
||||||
this.filtersEnabled = !!this.filterService.filterGroups.find(g => g.slug === FILTER_KEY);
|
this.filterService.filterGroups$.subscribe(() => {
|
||||||
|
this.filtersEnabled = !!this.filterService.filterGroups.find(g => g.slug === this.filterKey);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
get circumference(): number {
|
get circumference(): number {
|
||||||
@ -53,6 +54,10 @@ export class SimpleDoughnutChartComponent implements OnChanges {
|
|||||||
return this.totalType === 'sum' ? this.dataTotal : this.config.length;
|
return this.totalType === 'sum' ? this.dataTotal : this.config.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
this.filters$ = this.filterService.getFilterModels$(this.filterKey) ?? of([]);
|
||||||
|
}
|
||||||
|
|
||||||
ngOnChanges(): void {
|
ngOnChanges(): void {
|
||||||
this.calculateChartData();
|
this.calculateChartData();
|
||||||
this.cx = this.radius + this.strokeWidth / 2;
|
this.cx = this.radius + this.strokeWidth / 2;
|
||||||
@ -61,7 +66,7 @@ export class SimpleDoughnutChartComponent implements OnChanges {
|
|||||||
}
|
}
|
||||||
|
|
||||||
filterChecked$(key: string): Observable<boolean> {
|
filterChecked$(key: string): Observable<boolean> {
|
||||||
return this.statusFilters$.pipe(map(all => all?.find(e => e.id === key)?.checked));
|
return this.filters$.pipe(map(all => all?.find(e => e.id === key)?.checked));
|
||||||
}
|
}
|
||||||
|
|
||||||
calculateChartData() {
|
calculateChartData() {
|
||||||
@ -96,7 +101,7 @@ export class SimpleDoughnutChartComponent implements OnChanges {
|
|||||||
|
|
||||||
selectValue(key: string): void {
|
selectValue(key: string): void {
|
||||||
if (this.filtersEnabled) {
|
if (this.filtersEnabled) {
|
||||||
this.filterService.toggleFilter(FILTER_KEY, key);
|
this.filterService.toggleFilter(this.filterKey, key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { File } from '@models/file/file';
|
import { File } from '@models/file/file';
|
||||||
import { Dossier } from '@red/domain';
|
import { Dossier, User } from '@red/domain';
|
||||||
import { handleCheckedValue, INestedFilter } from '@iqser/common-ui';
|
import { handleCheckedValue, INestedFilter } from '@iqser/common-ui';
|
||||||
|
|
||||||
export function handleFilterDelta(oldFilters: INestedFilter[], newFilters: INestedFilter[], allFilters: INestedFilter[]) {
|
export function handleFilterDelta(oldFilters: INestedFilter[], newFilters: INestedFilter[], allFilters: INestedFilter[]) {
|
||||||
@ -85,3 +85,17 @@ export const dossierMemberChecker = (dw: Dossier, filter: INestedFilter) => dw.h
|
|||||||
export const dossierTemplateChecker = (dw: Dossier, filter: INestedFilter) => dw.dossierTemplateId === filter.id;
|
export const dossierTemplateChecker = (dw: Dossier, filter: INestedFilter) => dw.dossierTemplateId === filter.id;
|
||||||
|
|
||||||
export const dossierApproverChecker = (dw: Dossier, filter: INestedFilter) => dw.approverIds.includes(filter.id);
|
export const dossierApproverChecker = (dw: Dossier, filter: INestedFilter) => dw.approverIds.includes(filter.id);
|
||||||
|
|
||||||
|
export const UserTypes = ['INACTIVE', 'REGULAR', 'RED_MANAGER', 'MANAGER_ADMIN', 'RED_USER_ADMIN', 'RED_ADMIN'] as const;
|
||||||
|
export type UserType = typeof UserTypes[number];
|
||||||
|
|
||||||
|
export const userTypeFilters: { [key in UserType]: (user: User) => boolean } = {
|
||||||
|
INACTIVE: (user: User) => !user.isActive,
|
||||||
|
REGULAR: (user: User) => user.roles.length === 1 && user.roles[0] === 'RED_USER',
|
||||||
|
RED_MANAGER: (user: User) => user.isManager && !user.isAdmin,
|
||||||
|
MANAGER_ADMIN: (user: User) => user.isManager && user.isAdmin,
|
||||||
|
RED_USER_ADMIN: (user: User) => user.isUserAdmin && !user.isAdmin,
|
||||||
|
RED_ADMIN: (user: User) => user.isAdmin && !user.isManager,
|
||||||
|
};
|
||||||
|
|
||||||
|
export const userTypeChecker = (user: User, filter: INestedFilter) => userTypeFilters[filter.id](user);
|
||||||
|
|||||||
@ -23,7 +23,7 @@ export class User implements IUser, IListable {
|
|||||||
this.firstName = user.firstName;
|
this.firstName = user.firstName;
|
||||||
this.lastName = user.lastName;
|
this.lastName = user.lastName;
|
||||||
this.name = this.firstName && this.lastName ? `${this.firstName} ${this.lastName}` : this.username;
|
this.name = this.firstName && this.lastName ? `${this.firstName} ${this.lastName}` : this.username;
|
||||||
this.searchKey = `${this.name}${this.username}${this.email}`;
|
this.searchKey = `${this.name || '-'}${this.username || '-'}${this.email || ''}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
hasRole(role: string): boolean {
|
hasRole(role: string): boolean {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user