Amendments due to backend changes, added ability to search users by name and email, added setting to disable reassignment of alarm to alarm widget

This commit is contained in:
rusikv 2023-02-20 14:13:41 +02:00
parent 7f642f5415
commit 80ec4d85e2
15 changed files with 120 additions and 114 deletions

View File

@ -16,7 +16,7 @@
import { Injectable } from '@angular/core';
import { defaultHttpOptionsFromConfig, RequestConfig } from './http-utils';
import { User } from '@shared/models/user.model';
import { User, UserEmailInfo } from '@shared/models/user.model';
import { Observable } from 'rxjs';
import { HttpClient, HttpParams } from '@angular/common/http';
import { PageLink } from '@shared/models/page/page-link';
@ -84,4 +84,8 @@ export class UserService {
return this.http.post<User>(url, null, defaultHttpOptionsFromConfig(config));
}
public findUsersByQuery(pageLink: PageLink, config?: RequestConfig) : Observable<PageData<UserEmailInfo>> {
return this.http.get<PageData<UserEmailInfo>>(`/api/users/info${pageLink.toQuery()}`, defaultHttpOptionsFromConfig(config));
}
}

View File

@ -36,9 +36,10 @@
<span class="user-avatar" [innerHTML]="getUserInitials(user)"
[style.background-color]="getAvatarBgColor(user)">
</span>
<div fxLayout="column" fxLayoutGap="2px">
<span class="user-email" [innerHTML]="user.email | highlight:searchText"></span>
<span class="user-name" *ngIf="user.firstName || user.lastName" [innerHTML]="getFullName(user)"></span>
<div class="user-display-name" fxLayout="column" fxLayoutGap="2px">
<span *ngIf="user.firstName || user.lastName"
[innerHTML]="getFullName(user) | highlight:searchText"></span>
<span [innerHTML]="user.email | highlight:searchText"></span>
</div>
</mat-option>
<mat-option *ngIf="!(filteredUsers | async)?.length" [value]="null">

View File

@ -76,19 +76,22 @@
background-color: #5cb445;
width: 28px;
height: 28px;
min-width: 28px;
min-height: 28px;
color: white;
font-size: 13px;
font-weight: 700
}
.user-email {
color: rgba(0, 0, 0, 0.76);
overflow: hidden;
text-overflow: ellipsis;
max-width: 185px
}
.user-name {
color: rgba(0, 0, 0, 0.38);
font-size: 13px;
.user-display-name {
max-width: 180px;
span {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
span + span {
color: rgba(0, 0, 0, 0.38);
}
}
.mat-option-text {
display: flex;

View File

@ -34,7 +34,7 @@ import {
switchMap,
takeUntil,
} from 'rxjs/operators';
import { User } from '@shared/models/user.model';
import { User, UserEmailInfo } from '@shared/models/user.model';
import { TranslateService } from '@ngx-translate/core';
import { UserService } from '@core/http/user.service';
import { PageLink } from '@shared/models/page/page-link';
@ -69,7 +69,7 @@ export class AlarmAssigneePanelComponent implements OnInit, AfterViewInit, OnDe
@ViewChild('userInput', {static: true}) userInput: ElementRef;
filteredUsers: Observable<Array<User>>;
filteredUsers: Observable<Array<UserEmailInfo>>;
searchText = '';
@ -138,15 +138,15 @@ export class AlarmAssigneePanelComponent implements OnInit, AfterViewInit, OnDe
() => this.overlayRef.dispose());
}
fetchUsers(searchText?: string): Observable<Array<User>> {
fetchUsers(searchText?: string): Observable<Array<UserEmailInfo>> {
this.searchText = searchText;
const pageLink = new PageLink(50, 0, searchText, {
property: 'email',
direction: Direction.ASC
});
return this.userService.getUsers(pageLink, {ignoreLoading: true})
return this.userService.findUsersByQuery(pageLink, {ignoreLoading: true})
.pipe(
catchError(() => of(emptyPageData<User>())),
catchError(() => of(emptyPageData<UserEmailInfo>())),
map(pageData => {
return pageData.data;
})

View File

@ -88,9 +88,6 @@ export class AlarmDetailsDialogComponent extends DialogComponent<AlarmDetailsDia
{
createdTime: [''],
originatorName: [''],
assigneeFirstName: [''],
assigneeLastName: [''],
assigneeEmail: [''],
assigneeId: [''],
startTime: [''],
endTime: [''],
@ -125,18 +122,6 @@ export class AlarmDetailsDialogComponent extends DialogComponent<AlarmDetailsDia
.patchValue(this.datePipe.transform(alarm.createdTime, 'yyyy-MM-dd HH:mm:ss'));
this.alarmFormGroup.get('originatorName')
.patchValue(alarm.originatorName);
if(alarm.assigneeFirstName) {
this.alarmFormGroup.get('assigneeFirstName')
.patchValue(alarm.assigneeFirstName);
}
if(alarm.assigneeLastName) {
this.alarmFormGroup.get('assigneeLastName')
.patchValue(alarm.assigneeLastName);
}
if(alarm.assigneeEmail) {
this.alarmFormGroup.get('assigneeEmail')
.patchValue(alarm.assigneeEmail);
}
if(alarm.assigneeId) {
this.alarmFormGroup.get('assigneeId')
.patchValue(alarm.assigneeId.id);
@ -209,35 +194,35 @@ export class AlarmDetailsDialogComponent extends DialogComponent<AlarmDetailsDia
getUserDisplayName(entity: AlarmInfo) {
let displayName = '';
if ((entity.assigneeFirstName && entity.assigneeFirstName.length > 0) ||
(entity.assigneeLastName && entity.assigneeLastName.length > 0)) {
if (entity.assigneeFirstName) {
displayName += entity.assigneeFirstName;
if ((entity.assignee.firstName && entity.assignee.firstName.length > 0) ||
(entity.assignee.lastName && entity.assignee.lastName.length > 0)) {
if (entity.assignee.firstName) {
displayName += entity.assignee.firstName;
}
if (entity.assigneeLastName) {
if (entity.assignee.lastName) {
if (displayName.length > 0) {
displayName += ' ';
}
displayName += entity.assigneeLastName;
displayName += entity.assignee.lastName;
}
} else {
displayName = entity.assigneeEmail;
displayName = entity.assignee.email;
}
return displayName;
}
getUserInitials(entity: AlarmInfo): string {
let initials = '';
if (entity.assigneeFirstName && entity.assigneeFirstName.length ||
entity.assigneeLastName && entity.assigneeLastName.length) {
if (entity.assigneeFirstName) {
initials += entity.assigneeFirstName.charAt(0);
if (entity.assignee.firstName && entity.assignee.firstName.length ||
entity.assignee.lastName && entity.assignee.lastName.length) {
if (entity.assignee.firstName) {
initials += entity.assignee.firstName.charAt(0);
}
if (entity.assigneeLastName) {
initials += entity.assigneeLastName.charAt(0);
if (entity.assignee.lastName) {
initials += entity.assignee.lastName.charAt(0);
}
} else {
initials += entity.assigneeEmail.charAt(0);
initials += entity.assignee.email.charAt(0);
}
return initials.toUpperCase();
}

View File

@ -116,7 +116,7 @@ export class AlarmTableConfig extends EntityTableConfig<AlarmInfo, TimePageLink>
color: alarmSeverityColors.get(entity.severity)
})));
this.columns.push(
new EntityTableColumn<AlarmInfo>('assigneeEmail', 'alarm.assignee', '200px',
new EntityTableColumn<AlarmInfo>('assignee', 'alarm.assignee', '200px',
(entity) => {
return this.getAssigneeTemplate(entity)
},
@ -190,7 +190,7 @@ export class AlarmTableConfig extends EntityTableConfig<AlarmInfo, TimePageLink>
<span class="user-avatar" style="background-color: ${this.getAvatarBgColor(entity)}">
${this.getUserInitials(entity)}
</span>
<span>${this.getUserDisplayName(entity)}</span>
<span class="user-display-name">${this.getUserDisplayName(entity)}</span>
</span>`
:
`<mat-icon class="material-icons unassigned-icon">account_circle</mat-icon>
@ -201,35 +201,35 @@ export class AlarmTableConfig extends EntityTableConfig<AlarmInfo, TimePageLink>
getUserDisplayName(entity: AlarmInfo) {
let displayName = '';
if ((entity.assigneeFirstName && entity.assigneeFirstName.length > 0) ||
(entity.assigneeLastName && entity.assigneeLastName.length > 0)) {
if (entity.assigneeFirstName) {
displayName += entity.assigneeFirstName;
if ((entity.assignee.firstName && entity.assignee.firstName.length > 0) ||
(entity.assignee.lastName && entity.assignee.lastName.length > 0)) {
if (entity.assignee.firstName) {
displayName += entity.assignee.firstName;
}
if (entity.assigneeLastName) {
if (entity.assignee.lastName) {
if (displayName.length > 0) {
displayName += ' ';
}
displayName += entity.assigneeLastName;
displayName += entity.assignee.lastName;
}
} else {
displayName = entity.assigneeEmail;
displayName = entity.assignee.email;
}
return displayName;
}
getUserInitials(entity: AlarmInfo): string {
let initials = '';
if (entity.assigneeFirstName && entity.assigneeFirstName.length ||
entity.assigneeLastName && entity.assigneeLastName.length) {
if (entity.assigneeFirstName) {
initials += entity.assigneeFirstName.charAt(0);
if (entity.assignee.firstName && entity.assignee.firstName.length ||
entity.assignee.lastName && entity.assignee.lastName.length) {
if (entity.assignee.firstName) {
initials += entity.assignee.firstName.charAt(0);
}
if (entity.assigneeLastName) {
initials += entity.assigneeLastName.charAt(0);
if (entity.assignee.lastName) {
initials += entity.assignee.lastName.charAt(0);
}
} else {
initials += entity.assigneeEmail.charAt(0);
initials += entity.assignee.email.charAt(0);
}
return initials.toUpperCase();
}

View File

@ -22,6 +22,10 @@
justify-content: flex-start;
align-items: center;
.assigned-container {
max-width: 180px;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
.user-avatar {
display: inline-flex;
justify-content: center;
@ -30,6 +34,8 @@
border-radius: 50%;
width: 28px;
height: 28px;
min-width: 28px;
min-height: 28px;
color: white;
font-size: 13px;
font-weight: 700;

View File

@ -84,20 +84,23 @@
<mat-cell *matCellDef="let alarm; let row = index"
[ngStyle]="cellStyle(alarm, column, row)">
<span [innerHTML]="cellContent(alarm, column, row)"></span>
<ng-container *ngIf="column.entityKey.key === 'assigneeEmail'">
<ng-container *ngIf="column.entityKey.key === 'assignee'">
<span class="assignee-cell" fxLayout="row" fxLayoutAlign="start center">
<span *ngIf="alarm.assigneeId" class="assigned-container">
<span class="user-avatar" [style.backgroundColor]="getAvatarBgColor(alarm)">
{{ getUserInitials(alarm) }}
</span>
<span style="text-overflow: ellipsis">{{ getUserDisplayName(alarm) }}</span>
<span [matTooltip]="getUserDisplayName(alarm)"
matTooltipPosition="above"
style="text-overflow: ellipsis">{{ getUserDisplayName(alarm) }}</span>
</span>
<span *ngIf="!alarm.assigneeId" class="unassigned-container" fxLayout="row" fxLayoutAlign="start center">
<mat-icon class="material-icons unassigned-icon">account_circle</mat-icon>
<span translate>alarm.unassigned</span>
</span>
<button mat-icon-button [disabled]="isLoading$ | async"
matTooltip="{{ alarm.assign | translate }}"
<button *ngIf="allowAssign"
mat-icon-button [disabled]="isLoading$ | async"
matTooltip="{{ 'alarm.assign' | translate }}"
matTooltipPosition="above"
(click)="openAlarmAssigneePanel($event, alarm)">
<mat-icon>

View File

@ -40,6 +40,8 @@
border-radius: 50%;
width: 28px;
height: 28px;
min-width: 28px;
min-height: 28px;
color: white;
font-size: 13px;
font-weight: 700;

View File

@ -142,6 +142,7 @@ interface AlarmsTableWidgetSettings extends TableWidgetSettings {
displayDetails: boolean;
allowAcknowledgment: boolean;
allowClear: boolean;
allowAssign: boolean;
}
interface AlarmWidgetActionDescriptor extends TableCellButtonActionDescriptor {
@ -193,6 +194,7 @@ export class AlarmsTableWidgetComponent extends PageComponent implements OnInit,
private displayDetails = true;
public allowAcknowledgment = true;
private allowClear = true;
public allowAssign = true;
private defaultPageSize = 10;
private defaultSortOrder = '-' + alarmFields.createdTime.value;
@ -329,6 +331,7 @@ export class AlarmsTableWidgetComponent extends PageComponent implements OnInit,
this.displayDetails = isDefined(this.settings.displayDetails) ? this.settings.displayDetails : true;
this.allowAcknowledgment = isDefined(this.settings.allowAcknowledgment) ? this.settings.allowAcknowledgment : true;
this.allowClear = isDefined(this.settings.allowClear) ? this.settings.allowClear : true;
this.allowAssign = isDefined(this.settings.allowAssign) ? this.settings.allowAssign : true;
if (this.settings.alarmsTitle && this.settings.alarmsTitle.length) {
this.alarmsTitlePattern = this.utils.customTranslation(this.settings.alarmsTitle, this.settings.alarmsTitle);
@ -422,7 +425,7 @@ export class AlarmsTableWidgetComponent extends PageComponent implements OnInit,
if (alarmField && alarmField.time) {
keySettings.columnWidth = '120px';
}
if (alarmField && alarmField.keyName === alarmFields.assigneeEmail.keyName) {
if (alarmField && alarmField.keyName === alarmFields.assignee.keyName) {
keySettings.columnWidth = '120px'
}
}
@ -973,7 +976,7 @@ export class AlarmsTableWidgetComponent extends PageComponent implements OnInit,
return alarmStatusTranslations.get(value) ? this.translate.instant(alarmStatusTranslations.get(value)) : value;
} else if (alarmField.value === alarmFields.originatorType.value) {
return this.translate.instant(entityTypeTranslations.get(value).type);
} else if (alarmField.value === alarmFields.assigneeEmail.value) {
} else if (alarmField.value === alarmFields.assignee.value) {
return '';
}
else {
@ -1026,35 +1029,35 @@ export class AlarmsTableWidgetComponent extends PageComponent implements OnInit,
getUserDisplayName(entity: AlarmInfo) {
let displayName = '';
if ((entity.assigneeFirstName && entity.assigneeFirstName.length > 0) ||
(entity.assigneeLastName && entity.assigneeLastName.length > 0)) {
if (entity.assigneeFirstName) {
displayName += entity.assigneeFirstName;
if ((entity.assignee.firstName && entity.assignee.firstName.length > 0) ||
(entity.assignee.lastName && entity.assignee.lastName.length > 0)) {
if (entity.assignee.firstName) {
displayName += entity.assignee.firstName;
}
if (entity.assigneeLastName) {
if (entity.assignee.lastName) {
if (displayName.length > 0) {
displayName += ' ';
}
displayName += entity.assigneeLastName;
displayName += entity.assignee.lastName;
}
} else {
displayName = entity.assigneeEmail;
displayName = entity.assignee.email;
}
return displayName;
}
getUserInitials(entity: AlarmInfo): string {
let initials = '';
if (entity.assigneeFirstName && entity.assigneeFirstName.length ||
entity.assigneeLastName && entity.assigneeLastName.length) {
if (entity.assigneeFirstName) {
initials += entity.assigneeFirstName.charAt(0);
if (entity.assignee.firstName && entity.assignee.firstName.length ||
entity.assignee.lastName && entity.assignee.lastName.length) {
if (entity.assignee.firstName) {
initials += entity.assignee.firstName.charAt(0);
}
if (entity.assigneeLastName) {
initials += entity.assigneeLastName.charAt(0);
if (entity.assignee.lastName) {
initials += entity.assignee.lastName.charAt(0);
}
} else {
initials += entity.assigneeEmail.charAt(0);
initials += entity.assignee.email.charAt(0);
}
return initials.toUpperCase();
}

View File

@ -67,6 +67,9 @@
<mat-slide-toggle formControlName="allowClear">
{{ 'widgets.table.allow-alarms-clear' | translate }}
</mat-slide-toggle>
<mat-slide-toggle formControlName="allowAssign">
{{ 'widgets.table.allow-alarms-assign' | translate }}
</mat-slide-toggle>
<section fxLayout="column" fxLayout.gt-xs="row" fxLayoutGap="8px" fxLayoutAlign.gt-xs="start center">
<mat-slide-toggle fxFlex formControlName="displayPagination">
{{ 'widgets.table.display-pagination' | translate }}

View File

@ -51,6 +51,7 @@ export class AlarmsTableWidgetSettingsComponent extends WidgetSettingsComponent
displayDetails: true,
allowAcknowledgment: true,
allowClear: true,
allowAssign: true,
displayPagination: true,
defaultPageSize: 10,
defaultSortOrder: '-createdTime',
@ -72,6 +73,7 @@ export class AlarmsTableWidgetSettingsComponent extends WidgetSettingsComponent
displayDetails: [settings.displayDetails, []],
allowAcknowledgment: [settings.allowAcknowledgment, []],
allowClear: [settings.allowClear, []],
allowAssign: [settings.allowAssign, []],
displayPagination: [settings.displayPagination, []],
defaultPageSize: [settings.defaultPageSize, [Validators.min(1)]],
defaultSortOrder: [settings.defaultSortOrder, []],

View File

@ -107,9 +107,13 @@ export interface Alarm extends BaseData<AlarmId> {
export interface AlarmInfo extends Alarm {
originatorName: string;
originatorLabel: string;
assigneeFirstName: string;
assigneeLastName: string;
assigneeEmail: string;
assignee: AlarmAssignee;
}
export interface AlarmAssignee {
firstName: string;
lastName: string;
email: string;
}
export interface AlarmDataInfo extends AlarmInfo {
@ -131,9 +135,11 @@ export const simulatedAlarm: AlarmInfo = {
assignTs: 0,
originatorName: 'Simulated',
originatorLabel: 'Simulated',
assigneeFirstName: "",
assigneeLastName: "",
assigneeEmail: "test@example.com",
assignee: {
firstName: "",
lastName: "",
email: "test@example.com",
},
originator: {
entityType: EntityType.DEVICE,
id: '1'
@ -221,25 +227,10 @@ export const alarmFields: {[fieldName: string]: AlarmField} = {
value: 'status',
name: 'alarm.status'
},
assigneeId: {
keyName: 'assigneeId',
value: 'assigneeId.id',
name: 'alarm.assignee-id'
},
assigneeFirstName: {
keyName: 'assigneeFirstName',
value: 'assigneeFirstName',
name: 'alarm.assignee-first-name'
},
assigneeLastName: {
keyName: 'assigneeLastName',
value: 'assigneeLastName',
name: 'alarm.assignee-last-name'
},
assigneeEmail: {
keyName: 'assigneeEmail',
value: 'assigneeEmail',
name: 'alarm.assignee-email'
assignee: {
keyName: 'assignee',
value: 'assignee',
name: 'alarm.assignee'
}
};

View File

@ -54,3 +54,10 @@ export interface AuthUser {
isPublic: boolean;
authority: Authority;
}
export interface UserEmailInfo {
id: UserId;
email: string;
firstName: string;
lastName: string;
}

View File

@ -433,12 +433,7 @@
"type": "Type",
"severity": "Severity",
"originator": "Originator",
"originator-label": "Originator label",
"originator-type": "Originator type",
"assignee-id": "Assignee id",
"assignee-first-name": "Assignee first name",
"assignee-last-name": "Assignee last name",
"assignee-email": "Assignee email",
"details": "Details",
"originator-label": "Originator label",
"assign": "Assign",
@ -4752,7 +4747,8 @@
"enable-alarm-filter": "Enable alarm filter",
"display-alarm-details": "Display alarm details",
"allow-alarms-ack": "Allow alarms acknowledgment",
"allow-alarms-clear": "Allow alarms clear"
"allow-alarms-clear": "Allow alarms clear",
"allow-alarms-assign": "Allow alarms assignment"
},
"value-source": {
"value-source": "Value source",