thingsboard/ui-ngx/src/app/modules/home/components/alarm/alarm-assignee-select.component.ts

237 lines
7.8 KiB
TypeScript
Raw Normal View History

///
2024-01-09 10:46:16 +02:00
/// Copyright © 2016-2024 The Thingsboard Authors
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
/// http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
import { Component, forwardRef, Injector, Input, OnInit, StaticProvider, ViewContainerRef } from '@angular/core';
import { UtilsService } from '@core/services/utils.service';
import { ConnectedPosition, Overlay, OverlayConfig, OverlayRef } from '@angular/cdk/overlay';
import { ComponentPortal } from '@angular/cdk/portal';
import { TranslateService } from '@ngx-translate/core';
import { ControlValueAccessor, NG_VALUE_ACCESSOR, UntypedFormBuilder, UntypedFormGroup } from '@angular/forms';
import { UserId } from '@shared/models/id/user-id';
import { UserService } from '@core/http/user.service';
import { User, UserEmailInfo } from '@shared/models/user.model';
import { catchError, map, of } from 'rxjs';
import { tap } from 'rxjs/operators';
import {
ALARM_ASSIGNEE_SELECT_PANEL_DATA,
AlarmAssigneeSelectPanelComponent,
AlarmAssigneeSelectPanelData
} from '@home/components/alarm/alarm-assignee-select-panel.component';
2023-07-04 19:58:55 +03:00
import { coerceBoolean } from '@shared/decorators/coercion';
import { AlarmAssigneeOption } from '@shared/models/alarm.models';
@Component({
selector: 'tb-alarm-assignee-select',
templateUrl: './alarm-assignee-select.component.html',
styleUrls: ['./alarm-assignee.component.scss'],
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => AlarmAssigneeSelectComponent),
multi: true
}
]
})
export class AlarmAssigneeSelectComponent implements OnInit, ControlValueAccessor {
@Input() disabled: boolean;
2023-07-04 19:58:55 +03:00
@coerceBoolean()
@Input()
inline = false;
@coerceBoolean()
@Input()
userMode = false;
assigneeFormGroup: UntypedFormGroup;
assignee?: User | UserEmailInfo;
2023-07-04 19:58:55 +03:00
assigneeOption?: AlarmAssigneeOption;
private propagateChange = (_: any) => {};
constructor(private utilsService: UtilsService,
private overlay: Overlay,
private fb: UntypedFormBuilder,
private userService: UserService,
private viewContainerRef: ViewContainerRef,
private translateService: TranslateService) {
}
ngOnInit(): void {
this.assigneeFormGroup = this.fb.group({
assignee: [null, []]
});
}
registerOnChange(fn: any): void {
this.propagateChange = fn;
}
registerOnTouched(fn: any): void {
}
setDisabledState(isDisabled: boolean): void {
this.disabled = isDisabled;
if (this.disabled) {
this.assigneeFormGroup.disable({emitEvent: false});
} else {
this.assigneeFormGroup.enable({emitEvent: false});
}
}
2023-07-04 19:58:55 +03:00
writeValue(value?: UserId | AlarmAssigneeOption): void {
let userId: UserId;
if (value && (value as UserId).id) {
userId = value as UserId;
this.assigneeOption = null;
} else {
userId = null;
this.assigneeOption = value ? value as AlarmAssigneeOption : AlarmAssigneeOption.noAssignee;
}
const userObservable = userId ? this.userService.getUser(userId.id, {ignoreErrors: true}).pipe(
catchError(() => of(null))
) : of(null);
userObservable.pipe(
tap((user) => {
this.assignee = user;
}),
map((user) => this.getAssignee(user))
).subscribe((assignee) => {
2023-07-04 19:58:55 +03:00
if (assignee) {
this.assigneeFormGroup.get('assignee').patchValue(assignee, {emitEvent: false});
} else {
if (!this.assigneeOption) {
this.assigneeOption = AlarmAssigneeOption.noAssignee;
}
assignee = this.getAssigneeOption(this.assigneeOption);
this.assigneeFormGroup.get('assignee').patchValue(assignee, {emitEvent: false});
}
});
}
2023-07-04 19:58:55 +03:00
private getAssignee(user?: User| UserEmailInfo): string | null {
if (user) {
return this.getUserDisplayName(user);
} else {
2023-07-04 19:58:55 +03:00
return null;
}
}
private getAssigneeOption(assigneeOption: AlarmAssigneeOption): string {
if (assigneeOption === AlarmAssigneeOption.noAssignee) {
return this.translateService.instant('alarm.assignee-not-set');
2023-07-04 19:58:55 +03:00
} else {
return this.translateService.instant(this.userMode ? 'alarm.assigned-to-me' : 'alarm.assigned-to-current-user');
}
}
private getUserDisplayName(user?: User | UserEmailInfo): string {
let displayName = '';
if ((user?.firstName && user?.firstName.length > 0) ||
(user?.lastName && user?.lastName.length > 0)) {
if (user?.firstName) {
displayName += user?.firstName;
}
if (user?.lastName) {
if (displayName.length > 0) {
displayName += ' ';
}
displayName += user?.lastName;
}
} else {
displayName = user?.email;
}
return displayName;
}
getUserInitials(): string {
let initials = '';
if (this.assignee?.firstName && this.assignee?.firstName.length ||
this.assignee?.lastName && this.assignee?.lastName.length) {
if (this.assignee?.firstName) {
initials += this.assignee?.firstName.charAt(0);
}
if (this.assignee?.lastName) {
initials += this.assignee?.lastName.charAt(0);
}
} else {
initials += this.assignee?.email.charAt(0);
}
return initials.toUpperCase();
}
getAvatarBgColor(): string {
return this.utilsService.stringToHslColor(this.getUserDisplayName(this.assignee), 40, 60);
}
openAlarmAssigneeSelectPanel($event: Event) {
if ($event) {
$event.stopPropagation();
}
if (!this.disabled) {
const target = $event.currentTarget;
const config = new OverlayConfig();
config.backdropClass = 'cdk-overlay-transparent-backdrop';
config.hasBackdrop = true;
const connectedPosition: ConnectedPosition = {
originX: 'center',
originY: 'bottom',
overlayX: 'center',
overlayY: 'top'
};
config.positionStrategy = this.overlay.position().flexibleConnectedTo(target as HTMLElement)
.withPositions([connectedPosition]);
config.width = (target as HTMLElement).offsetWidth;
const overlayRef = this.overlay.create(config);
overlayRef.backdropClick().subscribe(() => {
overlayRef.dispose();
});
const providers: StaticProvider[] = [
{
provide: ALARM_ASSIGNEE_SELECT_PANEL_DATA,
useValue: {
2023-07-04 19:58:55 +03:00
assigneeId: this.assignee?.id?.id,
assigneeOption: this.assigneeOption,
userMode: this.userMode
} as AlarmAssigneeSelectPanelData
},
{
provide: OverlayRef,
useValue: overlayRef
}
];
const injector = Injector.create({parent: this.viewContainerRef.injector, providers});
const component = overlayRef.attach(new ComponentPortal(AlarmAssigneeSelectPanelComponent,
this.viewContainerRef, injector));
component.onDestroy(() => {
if (component.instance.userSelected) {
this.assignee = component.instance.result;
2023-07-04 19:58:55 +03:00
this.assigneeOption = component.instance.optionResult;
if (this.assignee) {
this.assigneeFormGroup.get('assignee').patchValue(this.getAssignee(this.assignee), {emitEvent: false});
this.propagateChange(this.assignee?.id);
} else if (this.assigneeOption) {
this.assigneeFormGroup.get('assignee').patchValue(this.getAssigneeOption(this.assigneeOption), {emitEvent: false});
this.propagateChange(this.assigneeOption);
}
}
});
}
}
}