Merge pull request #8285 from rusikv/alarm-details-redesign
Alarm details redesign
This commit is contained in:
		
						commit
						a8d0d871e1
					
				@ -23,7 +23,7 @@
 | 
			
		||||
        "dataKeySettingsSchema": "",
 | 
			
		||||
        "settingsDirective": "tb-alarms-table-widget-settings",
 | 
			
		||||
        "dataKeySettingsDirective": "tb-alarms-table-key-settings",
 | 
			
		||||
        "defaultConfig": "{\"timewindow\":{\"realtime\":{\"interval\":1000,\"timewindowMs\":86400000},\"aggregation\":{\"type\":\"NONE\",\"limit\":200}},\"showTitle\":true,\"backgroundColor\":\"rgb(255, 255, 255)\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"4px\",\"settings\":{\"enableSelection\":true,\"enableSearch\":true,\"displayDetails\":true,\"allowAcknowledgment\":true,\"allowClear\":true,\"allowAssign\":true,\"displayComments\":true,\"displayPagination\":true,\"defaultPageSize\":10,\"defaultSortOrder\":\"-createdTime\",\"enableSelectColumnDisplay\":true,\"enableStickyAction\":false,\"enableFilter\":true},\"title\":\"Alarms table\",\"dropShadow\":true,\"enableFullscreen\":true,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400,\"padding\":\"5px 10px 5px 10px\"},\"useDashboardTimewindow\":false,\"showLegend\":false,\"alarmSource\":{\"type\":\"function\",\"dataKeys\":[{\"name\":\"createdTime\",\"type\":\"alarm\",\"label\":\"Created time\",\"color\":\"#2196f3\",\"settings\":{\"useCellStyleFunction\":false,\"cellStyleFunction\":\"\",\"useCellContentFunction\":false,\"cellContentFunction\":\"\"},\"_hash\":0.021092237451093787},{\"name\":\"originator\",\"type\":\"alarm\",\"label\":\"Originator\",\"color\":\"#4caf50\",\"settings\":{\"useCellStyleFunction\":false,\"cellStyleFunction\":\"\",\"useCellContentFunction\":false,\"cellContentFunction\":\"\"},\"_hash\":0.2780007688856758},{\"name\":\"type\",\"type\":\"alarm\",\"label\":\"Type\",\"color\":\"#f44336\",\"settings\":{\"useCellStyleFunction\":false,\"cellStyleFunction\":\"\",\"useCellContentFunction\":false,\"cellContentFunction\":\"\"},\"_hash\":0.7323586880398418},{\"name\":\"severity\",\"type\":\"alarm\",\"label\":\"Severity\",\"color\":\"#ffc107\",\"settings\":{\"useCellStyleFunction\":false,\"useCellContentFunction\":false},\"_hash\":0.09927019860088193},{\"name\":\"status\",\"type\":\"alarm\",\"label\":\"Status\",\"color\":\"#607d8b\",\"settings\":{\"useCellStyleFunction\":false,\"cellStyleFunction\":\"\",\"useCellContentFunction\":false,\"cellContentFunction\":\"\"},\"_hash\":0.6588418951443418},{\"name\":\"assignee\",\"type\":\"alarm\",\"label\":\"Assignee\",\"color\":\"#9c27b0\",\"settings\":{},\"_hash\":0.5008441077416634}],\"entityAliasId\":null,\"name\":\"alarms\"},\"alarmSearchStatus\":\"ANY\",\"alarmsPollingInterval\":5,\"showTitleIcon\":false,\"titleIcon\":\"more_horiz\",\"iconColor\":\"rgba(0, 0, 0, 0.87)\",\"iconSize\":\"24px\",\"titleTooltip\":\"\",\"widgetStyle\":{},\"displayTimewindow\":true,\"actions\":{},\"alarmStatusList\":[],\"alarmSeverityList\":[],\"alarmTypeList\":[],\"searchPropagatedAlarms\":false}"
 | 
			
		||||
        "defaultConfig": "{\"timewindow\":{\"realtime\":{\"interval\":1000,\"timewindowMs\":86400000},\"aggregation\":{\"type\":\"NONE\",\"limit\":200}},\"showTitle\":true,\"backgroundColor\":\"rgb(255, 255, 255)\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"4px\",\"settings\":{\"enableSelection\":true,\"enableSearch\":true,\"displayDetails\":true,\"allowAcknowledgment\":true,\"allowClear\":true,\"allowAssign\":true,\"displayActivity\":true,\"displayPagination\":true,\"defaultPageSize\":10,\"defaultSortOrder\":\"-createdTime\",\"enableSelectColumnDisplay\":true,\"enableStickyAction\":false,\"enableFilter\":true},\"title\":\"Alarms table\",\"dropShadow\":true,\"enableFullscreen\":true,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400,\"padding\":\"5px 10px 5px 10px\"},\"useDashboardTimewindow\":false,\"showLegend\":false,\"alarmSource\":{\"type\":\"function\",\"dataKeys\":[{\"name\":\"createdTime\",\"type\":\"alarm\",\"label\":\"Created time\",\"color\":\"#2196f3\",\"settings\":{\"useCellStyleFunction\":false,\"cellStyleFunction\":\"\",\"useCellContentFunction\":false,\"cellContentFunction\":\"\"},\"_hash\":0.021092237451093787},{\"name\":\"originator\",\"type\":\"alarm\",\"label\":\"Originator\",\"color\":\"#4caf50\",\"settings\":{\"useCellStyleFunction\":false,\"cellStyleFunction\":\"\",\"useCellContentFunction\":false,\"cellContentFunction\":\"\"},\"_hash\":0.2780007688856758},{\"name\":\"type\",\"type\":\"alarm\",\"label\":\"Type\",\"color\":\"#f44336\",\"settings\":{\"useCellStyleFunction\":false,\"cellStyleFunction\":\"\",\"useCellContentFunction\":false,\"cellContentFunction\":\"\"},\"_hash\":0.7323586880398418},{\"name\":\"severity\",\"type\":\"alarm\",\"label\":\"Severity\",\"color\":\"#ffc107\",\"settings\":{\"useCellStyleFunction\":false,\"useCellContentFunction\":false},\"_hash\":0.09927019860088193},{\"name\":\"status\",\"type\":\"alarm\",\"label\":\"Status\",\"color\":\"#607d8b\",\"settings\":{\"useCellStyleFunction\":false,\"cellStyleFunction\":\"\",\"useCellContentFunction\":false,\"cellContentFunction\":\"\"},\"_hash\":0.6588418951443418},{\"name\":\"assignee\",\"type\":\"alarm\",\"label\":\"Assignee\",\"color\":\"#9c27b0\",\"settings\":{},\"_hash\":0.5008441077416634}],\"entityAliasId\":null,\"name\":\"alarms\"},\"alarmSearchStatus\":\"ANY\",\"alarmsPollingInterval\":5,\"showTitleIcon\":false,\"titleIcon\":\"more_horiz\",\"iconColor\":\"rgba(0, 0, 0, 0.87)\",\"iconSize\":\"24px\",\"titleTooltip\":\"\",\"widgetStyle\":{},\"displayTimewindow\":true,\"actions\":{},\"alarmStatusList\":[],\"alarmSeverityList\":[],\"alarmTypeList\":[],\"searchPropagatedAlarms\":false}"
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  ]
 | 
			
		||||
 | 
			
		||||
@ -25,8 +25,7 @@
 | 
			
		||||
  <mat-autocomplete class="tb-assignee-autocomplete"
 | 
			
		||||
                    #userAutocomplete="matAutocomplete"
 | 
			
		||||
                    [displayWith]="displayUserFn"
 | 
			
		||||
                    (optionSelected)="selected($event)"
 | 
			
		||||
                    panelWidth="260px">
 | 
			
		||||
                    (optionSelected)="selected($event)">
 | 
			
		||||
    <mat-option [fxHide]="!assigneeId" [value]="null">
 | 
			
		||||
      <mat-icon class="unassigned-icon">account_circle</mat-icon>
 | 
			
		||||
      <span translate>alarm.unassigned</span>
 | 
			
		||||
 | 
			
		||||
@ -17,7 +17,7 @@
 | 
			
		||||
:host {
 | 
			
		||||
  width: 100%;
 | 
			
		||||
  overflow: auto;
 | 
			
		||||
  background: #fff;
 | 
			
		||||
  background: white;
 | 
			
		||||
  box-shadow: 0px 1px 2px rgba(0, 0, 0, 0.3), 0px 2px 6px 2px rgba(0, 0, 0, 0.15);
 | 
			
		||||
  border-radius: 4px;
 | 
			
		||||
}
 | 
			
		||||
@ -27,7 +27,7 @@
 | 
			
		||||
    padding: 8px;
 | 
			
		||||
    height: 340px;
 | 
			
		||||
    font-size: 14px;
 | 
			
		||||
    background-color: #fff;
 | 
			
		||||
    background-color: white;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  .mat-form-field-appearance-outline .mdc-notched-outline__trailing{
 | 
			
		||||
@ -37,7 +37,6 @@
 | 
			
		||||
  .tb-assignee-autocomplete {
 | 
			
		||||
    &.tb-assignee-autocomplete.mat-mdc-autocomplete-panel {
 | 
			
		||||
      position: relative;
 | 
			
		||||
      left: -8px;
 | 
			
		||||
      margin-top: 8px;
 | 
			
		||||
      box-shadow: none !important;
 | 
			
		||||
    }
 | 
			
		||||
@ -58,17 +57,16 @@
 | 
			
		||||
        align-items: center;
 | 
			
		||||
        margin-right: 8px;
 | 
			
		||||
        border-radius: 50%;
 | 
			
		||||
        background-color: #5cb445;
 | 
			
		||||
        width: 28px;
 | 
			
		||||
        height: 28px;
 | 
			
		||||
        min-width: 28px;
 | 
			
		||||
        min-height: 28px;
 | 
			
		||||
        color: #fff;
 | 
			
		||||
        color: white;
 | 
			
		||||
        font-size: 13px;
 | 
			
		||||
        font-weight: 700
 | 
			
		||||
      }
 | 
			
		||||
      .user-display-name {
 | 
			
		||||
        max-width: 180px;
 | 
			
		||||
        max-width: 80%;
 | 
			
		||||
        overflow: hidden;
 | 
			
		||||
        span {
 | 
			
		||||
          overflow: hidden;
 | 
			
		||||
@ -79,8 +77,8 @@
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
      .mdc-list-item__primary-text {
 | 
			
		||||
        width: 100%;
 | 
			
		||||
        display: flex;
 | 
			
		||||
        justify-content: start;
 | 
			
		||||
        align-items: center;
 | 
			
		||||
        line-height: normal;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
@ -65,6 +65,8 @@ export class AlarmAssigneePanelComponent implements  OnInit, AfterViewInit, OnDe
 | 
			
		||||
 | 
			
		||||
  assigneeId?: string;
 | 
			
		||||
 | 
			
		||||
  reassigned: boolean = false;
 | 
			
		||||
 | 
			
		||||
  selectUserFormGroup: FormGroup;
 | 
			
		||||
 | 
			
		||||
  @ViewChild('userInput', {static: true}) userInput: ElementRef;
 | 
			
		||||
@ -130,12 +132,18 @@ export class AlarmAssigneePanelComponent implements  OnInit, AfterViewInit, OnDe
 | 
			
		||||
 | 
			
		||||
  assign(user: User): void {
 | 
			
		||||
    this.alarmService.assignAlarm(this.alarmId, user.id.id, {ignoreLoading: true}).subscribe(
 | 
			
		||||
      () => this.overlayRef.dispose());
 | 
			
		||||
      () => {
 | 
			
		||||
        this.reassigned = true;
 | 
			
		||||
        this.overlayRef.dispose()
 | 
			
		||||
      });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  unassign(): void {
 | 
			
		||||
    this.alarmService.unassignAlarm(this.alarmId, {ignoreLoading: true}).subscribe(
 | 
			
		||||
      () => this.overlayRef.dispose());
 | 
			
		||||
      () => {
 | 
			
		||||
        this.reassigned = true;
 | 
			
		||||
        this.overlayRef.dispose()
 | 
			
		||||
      });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  fetchUsers(searchText?: string): Observable<Array<UserEmailInfo>> {
 | 
			
		||||
 | 
			
		||||
@ -16,28 +16,15 @@
 | 
			
		||||
 | 
			
		||||
-->
 | 
			
		||||
 | 
			
		||||
<div class="tb-assignee" fxLayout="row" fxLayoutAlign="start center"
 | 
			
		||||
     (click)="openAlarmAssigneePanel($event, alarm)">
 | 
			
		||||
  <span *ngIf="alarm?.assigneeId" class="assigned-container">
 | 
			
		||||
    <span class="user-avatar" [style.backgroundColor]="getAvatarBgColor(alarm.assignee)">
 | 
			
		||||
      {{ getUserInitials(alarm.assignee) }}
 | 
			
		||||
    </span>
 | 
			
		||||
    <span [matTooltip]="getUserDisplayName(alarm.assignee)"
 | 
			
		||||
          matTooltipPosition="above"
 | 
			
		||||
          style="text-overflow: ellipsis">
 | 
			
		||||
      {{ getUserDisplayName(alarm.assignee) }}
 | 
			
		||||
    </span>
 | 
			
		||||
<mat-form-field fxFlex class="mat-block" style="margin-bottom: 25px"
 | 
			
		||||
                (click)="openAlarmAssigneePanel($event, alarm)"
 | 
			
		||||
                subscriptSizing="dynamic">
 | 
			
		||||
  <mat-label translate>alarm.assignee</mat-label>
 | 
			
		||||
  <input matInput readonly [value]="getAssignee()">
 | 
			
		||||
  <span *ngIf="alarm?.assigneeId" matPrefix class="user-avatar"
 | 
			
		||||
        [style.backgroundColor]="getAvatarBgColor(alarm.assignee)">
 | 
			
		||||
    {{ getUserInitials(alarm.assignee) }}
 | 
			
		||||
  </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 fxFlexAlign="flex-end"
 | 
			
		||||
          mat-icon-button
 | 
			
		||||
          matTooltip="{{ 'alarm.assign' | translate }}"
 | 
			
		||||
          matTooltipPosition="above">
 | 
			
		||||
    <mat-icon>
 | 
			
		||||
      keyboard_arrow_down
 | 
			
		||||
    </mat-icon>
 | 
			
		||||
  </button>
 | 
			
		||||
</div>
 | 
			
		||||
  <mat-icon *ngIf="!alarm?.assigneeId" matPrefix class="unassigned-icon">account_circle</mat-icon>
 | 
			
		||||
  <mat-icon matSuffix>arrow_drop_down</mat-icon>
 | 
			
		||||
</mat-form-field>
 | 
			
		||||
 | 
			
		||||
@ -14,36 +14,29 @@
 | 
			
		||||
 * limitations under the License.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
:host {
 | 
			
		||||
  .tb-assignee {
 | 
			
		||||
    cursor: pointer;
 | 
			
		||||
    max-width: 273px;
 | 
			
		||||
 | 
			
		||||
    .assigned-container {
 | 
			
		||||
      overflow: hidden;
 | 
			
		||||
      white-space: nowrap;
 | 
			
		||||
      text-overflow: ellipsis;
 | 
			
		||||
 | 
			
		||||
      .user-avatar {
 | 
			
		||||
        display: inline-flex;
 | 
			
		||||
        justify-content: center;
 | 
			
		||||
        align-items: center;
 | 
			
		||||
        border-radius: 50%;
 | 
			
		||||
        width: 28px;
 | 
			
		||||
        height: 28px;
 | 
			
		||||
        min-width: 28px;
 | 
			
		||||
        min-height: 28px;
 | 
			
		||||
        color: white;
 | 
			
		||||
        font-size: 13px;
 | 
			
		||||
        font-weight: 700;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    .material-icons.unassigned-icon {
 | 
			
		||||
      width: 28px;
 | 
			
		||||
      height: 28px;
 | 
			
		||||
      font-size: 28px;
 | 
			
		||||
      color: rgba(0, 0, 0, 0.38);
 | 
			
		||||
      overflow: visible;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
.user-avatar {
 | 
			
		||||
  display: inline-flex;
 | 
			
		||||
  justify-content: center;
 | 
			
		||||
  align-items: center;
 | 
			
		||||
  border-radius: 50%;
 | 
			
		||||
  width: 28px;
 | 
			
		||||
  height: 28px;
 | 
			
		||||
  min-width: 28px;
 | 
			
		||||
  min-height: 28px;
 | 
			
		||||
  color: white;
 | 
			
		||||
  font-size: 13px;
 | 
			
		||||
  font-weight: 700;
 | 
			
		||||
  margin-left: 12px;
 | 
			
		||||
  margin-right: 20px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.unassigned-icon {
 | 
			
		||||
  width: 28px;
 | 
			
		||||
  height: 28px;
 | 
			
		||||
  font-size: 28px;
 | 
			
		||||
  color: rgba(0, 0, 0, 0.38);
 | 
			
		||||
  overflow: visible;
 | 
			
		||||
  margin-left: 12px;
 | 
			
		||||
  margin-right: 20px;
 | 
			
		||||
  padding: 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -14,17 +14,17 @@
 | 
			
		||||
/// limitations under the License.
 | 
			
		||||
///
 | 
			
		||||
 | 
			
		||||
import {
 | 
			
		||||
  Component, EventEmitter, Injector, Input, Output, StaticProvider, ViewContainerRef
 | 
			
		||||
} from '@angular/core';
 | 
			
		||||
import { Component, EventEmitter, Injector, Input, Output, StaticProvider, ViewContainerRef } from '@angular/core';
 | 
			
		||||
import { UtilsService } from '@core/services/utils.service';
 | 
			
		||||
import { AlarmAssignee, AlarmInfo } from '@shared/models/alarm.models';
 | 
			
		||||
import {
 | 
			
		||||
  ALARM_ASSIGNEE_PANEL_DATA, AlarmAssigneePanelComponent,
 | 
			
		||||
  ALARM_ASSIGNEE_PANEL_DATA,
 | 
			
		||||
  AlarmAssigneePanelComponent,
 | 
			
		||||
  AlarmAssigneePanelData
 | 
			
		||||
} from '@home/components/alarm/alarm-assignee-panel.component';
 | 
			
		||||
import { ConnectedPosition, Overlay, OverlayConfig, OverlayRef } from '@angular/cdk/overlay';
 | 
			
		||||
import { ComponentPortal } from '@angular/cdk/portal';
 | 
			
		||||
import { TranslateService } from '@ngx-translate/core';
 | 
			
		||||
 | 
			
		||||
@Component({
 | 
			
		||||
  selector: 'tb-alarm-assignee',
 | 
			
		||||
@ -35,12 +35,26 @@ export class AlarmAssigneeComponent {
 | 
			
		||||
  @Input()
 | 
			
		||||
  alarm: AlarmInfo;
 | 
			
		||||
 | 
			
		||||
  @Input()
 | 
			
		||||
  allowAssign: boolean;
 | 
			
		||||
 | 
			
		||||
  @Output()
 | 
			
		||||
  alarmReassigned = new EventEmitter<boolean>();
 | 
			
		||||
 | 
			
		||||
  constructor(private utilsService: UtilsService,
 | 
			
		||||
              private overlay: Overlay,
 | 
			
		||||
              private viewContainerRef: ViewContainerRef) {
 | 
			
		||||
              private viewContainerRef: ViewContainerRef,
 | 
			
		||||
              private translateService: TranslateService) {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  getAssignee() {
 | 
			
		||||
    if (this.alarm) {
 | 
			
		||||
      if (this.alarm.assignee) {
 | 
			
		||||
        return this.getUserDisplayName(this.alarm.assignee);
 | 
			
		||||
      } else {
 | 
			
		||||
        return this.translateService.instant('alarm.unassigned');
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  getUserDisplayName(entity: AlarmAssignee) {
 | 
			
		||||
@ -103,39 +117,41 @@ export class AlarmAssigneeComponent {
 | 
			
		||||
    if ($event) {
 | 
			
		||||
      $event.stopPropagation();
 | 
			
		||||
    }
 | 
			
		||||
    const target = $event.target || $event.srcElement || $event.currentTarget;
 | 
			
		||||
    const config = new OverlayConfig();
 | 
			
		||||
    config.backdropClass = 'cdk-overlay-transparent-backdrop';
 | 
			
		||||
    config.hasBackdrop = true;
 | 
			
		||||
    const connectedPosition: ConnectedPosition = {
 | 
			
		||||
      originX: 'end',
 | 
			
		||||
      originY: 'bottom',
 | 
			
		||||
      overlayX: 'end',
 | 
			
		||||
      overlayY: 'top'
 | 
			
		||||
    };
 | 
			
		||||
    config.positionStrategy = this.overlay.position().flexibleConnectedTo(target as HTMLElement)
 | 
			
		||||
      .withPositions([connectedPosition]);
 | 
			
		||||
    config.minWidth = '260px';
 | 
			
		||||
    const overlayRef = this.overlay.create(config);
 | 
			
		||||
    overlayRef.backdropClick().subscribe(() => {
 | 
			
		||||
      overlayRef.dispose();
 | 
			
		||||
    });
 | 
			
		||||
    const providers: StaticProvider[] = [
 | 
			
		||||
      {
 | 
			
		||||
        provide: ALARM_ASSIGNEE_PANEL_DATA,
 | 
			
		||||
        useValue: {
 | 
			
		||||
          alarmId: alarm.id.id,
 | 
			
		||||
          assigneeId: alarm.assigneeId?.id
 | 
			
		||||
        } as AlarmAssigneePanelData
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        provide: OverlayRef,
 | 
			
		||||
        useValue: overlayRef
 | 
			
		||||
      }
 | 
			
		||||
    ];
 | 
			
		||||
    const injector = Injector.create({parent: this.viewContainerRef.injector, providers});
 | 
			
		||||
    overlayRef.attach(new ComponentPortal(AlarmAssigneePanelComponent,
 | 
			
		||||
      this.viewContainerRef, injector)).onDestroy(() => this.alarmReassigned.emit(true));
 | 
			
		||||
    if (this.allowAssign) {
 | 
			
		||||
      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_PANEL_DATA,
 | 
			
		||||
          useValue: {
 | 
			
		||||
            alarmId: alarm.id.id,
 | 
			
		||||
            assigneeId: alarm.assigneeId?.id
 | 
			
		||||
          } as AlarmAssigneePanelData
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
          provide: OverlayRef,
 | 
			
		||||
          useValue: overlayRef
 | 
			
		||||
        }
 | 
			
		||||
      ];
 | 
			
		||||
      const injector = Injector.create({parent: this.viewContainerRef.injector, providers});
 | 
			
		||||
      overlayRef.attach(new ComponentPortal(AlarmAssigneePanelComponent,
 | 
			
		||||
        this.viewContainerRef, injector)).onDestroy(() => this.alarmReassigned.emit(true));
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -17,11 +17,8 @@
 | 
			
		||||
-->
 | 
			
		||||
<div style="min-width: 600px;">
 | 
			
		||||
  <mat-toolbar color="primary">
 | 
			
		||||
    <h2>{{ 'alarm.comments' | translate }}</h2>
 | 
			
		||||
    <span fxFlex></span>
 | 
			
		||||
    <button mat-icon-button
 | 
			
		||||
            (click)="close()"
 | 
			
		||||
            type="button">
 | 
			
		||||
    <button mat-icon-button (click)="close()" type="button">
 | 
			
		||||
      <mat-icon class="material-icons">close</mat-icon>
 | 
			
		||||
    </button>
 | 
			
		||||
  </mat-toolbar>
 | 
			
		||||
@ -29,16 +26,8 @@
 | 
			
		||||
  </mat-progress-bar>
 | 
			
		||||
  <div style="height: 4px;" *ngIf="!(isLoading$ | async)"></div>
 | 
			
		||||
  <div mat-dialog-content style="padding: 0">
 | 
			
		||||
    <tb-alarm-comment #alarmCommentComponent [alarmId]="alarmId"
 | 
			
		||||
                      [commentsHeaderEnabled]="commentsHeaderEnabled">
 | 
			
		||||
    <tb-alarm-comment [alarmId]="alarmId"
 | 
			
		||||
                      [alarmActivityOnly]="true">
 | 
			
		||||
    </tb-alarm-comment>
 | 
			
		||||
  </div>
 | 
			
		||||
  <div mat-dialog-actions fxLayout="row" fxLayoutAlign="end">
 | 
			
		||||
    <button mat-raised-button color="primary"
 | 
			
		||||
            type="button"
 | 
			
		||||
            [disabled]="(isLoading$ | async)"
 | 
			
		||||
            (click)="close()" cdkFocusInitial>
 | 
			
		||||
      {{ 'action.close' | translate }}
 | 
			
		||||
    </button>
 | 
			
		||||
  </div>
 | 
			
		||||
</div>
 | 
			
		||||
 | 
			
		||||
@ -25,7 +25,6 @@ import { AlarmInfo } from '@shared/models/alarm.models';
 | 
			
		||||
export interface AlarmCommentDialogData {
 | 
			
		||||
  alarmId?: string;
 | 
			
		||||
  alarm?: AlarmInfo;
 | 
			
		||||
  commentsHeaderEnabled: boolean;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@Component({
 | 
			
		||||
@ -37,14 +36,11 @@ export class AlarmCommentDialogComponent extends DialogComponent<AlarmCommentDia
 | 
			
		||||
 | 
			
		||||
  alarmId: string;
 | 
			
		||||
 | 
			
		||||
  commentsHeaderEnabled: boolean = false;
 | 
			
		||||
 | 
			
		||||
  constructor(protected store: Store<AppState>,
 | 
			
		||||
              protected router: Router,
 | 
			
		||||
              @Inject(MAT_DIALOG_DATA) public data: AlarmCommentDialogData,
 | 
			
		||||
              public dialogRef: MatDialogRef<AlarmCommentDialogComponent, void>) {
 | 
			
		||||
    super(store, router, dialogRef);
 | 
			
		||||
    this.commentsHeaderEnabled = this.data.commentsHeaderEnabled
 | 
			
		||||
    this.alarmId = this.data.alarmId;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -17,129 +17,147 @@
 | 
			
		||||
-->
 | 
			
		||||
 | 
			
		||||
<div [formGroup]="alarmCommentFormGroup" class="tb-alarm-comments" fxLayout="column">
 | 
			
		||||
  <div class="tb-alarm-comments-header" fxLayout="row" fxLayoutAlign="space-between baseline">
 | 
			
		||||
    <span *ngIf="commentsHeaderEnabled" class="tb-alarm-comments-header-title">
 | 
			
		||||
      {{ 'alarm-comment.comments' | translate }}
 | 
			
		||||
    </span>
 | 
			
		||||
    <div style="margin-left: auto">
 | 
			
		||||
      <button mat-icon-button
 | 
			
		||||
              type="button"
 | 
			
		||||
              (click)="changeSortDirection()"
 | 
			
		||||
              matTooltip="{{ 'alarm-comment.sort-direction' | translate }}"
 | 
			
		||||
              matTooltipPosition="above">
 | 
			
		||||
        <mat-icon class="material-icons">{{ getSortDirectionIcon() }}</mat-icon>
 | 
			
		||||
      </button>
 | 
			
		||||
      <button mat-icon-button
 | 
			
		||||
              type="button"
 | 
			
		||||
              (click)="loadAlarmComments()"
 | 
			
		||||
              matTooltip="{{ 'alarm-comment.refresh' | translate }}"
 | 
			
		||||
              matTooltipPosition="above">
 | 
			
		||||
        <mat-icon class="material-icons">refresh</mat-icon>
 | 
			
		||||
      </button>
 | 
			
		||||
  <div class="header"  [ngClass]="{'activity-only': alarmActivityOnly}">
 | 
			
		||||
    <div class="header-container" fxLayout="row" fxLayoutAlign="space-between center"
 | 
			
		||||
         [ngClass]="{'asc': isDirectionAscending(), 'activity-only': alarmActivityOnly}">
 | 
			
		||||
      <span class="header-title" translate>
 | 
			
		||||
        alarm-activity.activity
 | 
			
		||||
      </span>
 | 
			
		||||
      <div style="margin-left: auto">
 | 
			
		||||
        <button mat-icon-button
 | 
			
		||||
                type="button"
 | 
			
		||||
                (click)="exportAlarmActivity()"
 | 
			
		||||
                matTooltip="{{ 'alarm-activity.export' | translate }}"
 | 
			
		||||
                matTooltipPosition="above">
 | 
			
		||||
          <mat-icon class="material-icons" svgIcon="mdi:file-export"></mat-icon>
 | 
			
		||||
        </button>
 | 
			
		||||
        <button mat-icon-button
 | 
			
		||||
                type="button"
 | 
			
		||||
                (click)="changeSortDirection()"
 | 
			
		||||
                [matTooltip]="getSortDirectionTooltipText()"
 | 
			
		||||
                matTooltipPosition="above">
 | 
			
		||||
          <mat-icon class="material-icons" [svgIcon]="getSortDirectionIcon()"></mat-icon>
 | 
			
		||||
        </button>
 | 
			
		||||
        <button mat-icon-button
 | 
			
		||||
                type="button"
 | 
			
		||||
                (click)="loadAlarmComments()"
 | 
			
		||||
                matTooltip="{{ 'alarm-activity.refresh' | translate }}"
 | 
			
		||||
                matTooltipPosition="above">
 | 
			
		||||
          <mat-icon class="material-icons">refresh</mat-icon>
 | 
			
		||||
        </button>
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
  </div>
 | 
			
		||||
  <div fxLayout="column" fxLayoutGap="32px">
 | 
			
		||||
    <ng-container *ngIf="isDirectionDescending()">
 | 
			
		||||
  <div fxLayout="column">
 | 
			
		||||
    <ng-container *ngIf="!isDirectionAscending()">
 | 
			
		||||
      <ng-container *ngTemplateOutlet="commentInput"></ng-container>
 | 
			
		||||
    </ng-container>
 | 
			
		||||
    <div fxFlex *ngFor="let displayDataElement of displayData; index as i">
 | 
			
		||||
      <div style="margin-left: 38px"
 | 
			
		||||
           *ngIf="displayDataElement.isSystemComment; else userComment">
 | 
			
		||||
        <span class="tb-alarm-comments-system-text"
 | 
			
		||||
              style="margin-right: 8px">
 | 
			
		||||
          {{ displayDataElement.commentText }}
 | 
			
		||||
        </span>
 | 
			
		||||
        <span class="tb-alarm-comments-time">
 | 
			
		||||
          {{ displayDataElement.createdDateAgo }}
 | 
			
		||||
        </span>
 | 
			
		||||
      </div>
 | 
			
		||||
      <ng-template #userComment>
 | 
			
		||||
        <div fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px"
 | 
			
		||||
             *ngIf="!displayDataElement.edit; else commentEditing"
 | 
			
		||||
             (mouseenter)="onCommentMouseEnter(displayDataElement.commentId, i)"
 | 
			
		||||
             (mouseleave)="onCommentMouseLeave(i)">
 | 
			
		||||
          <div fxLayout="row" fxLayoutAlign="center center" fxFlexAlign="start"
 | 
			
		||||
               class="tb-alarm-comments-user-avatar"
 | 
			
		||||
               [style.background-color]="displayDataElement.avatarBgColor">
 | 
			
		||||
            {{ getUserInitials(displayDataElement.displayName) }}
 | 
			
		||||
          </div>
 | 
			
		||||
          <div fxFlex fxLayout="column" fxLayoutGap="5px">
 | 
			
		||||
            <div fxLayout="row" fxLayoutGap="8px" fxLayoutAlign="start center">
 | 
			
		||||
              <span class="tb-alarm-comments-user-name">{{ displayDataElement.displayName }}</span>
 | 
			
		||||
              <span class="tb-alarm-comments-time" *ngIf="displayDataElement.isEdited">
 | 
			
		||||
                edited {{ displayDataElement.editedDateAgo }}
 | 
			
		||||
              </span>
 | 
			
		||||
              <span class="tb-alarm-comments-time" *ngIf="!displayDataElement.isEdited">
 | 
			
		||||
                {{ displayDataElement.createdDateAgo }}
 | 
			
		||||
              </span>
 | 
			
		||||
            </div>
 | 
			
		||||
            <span class="tb-alarm-comments-text">{{ displayDataElement.commentText }}</span>
 | 
			
		||||
          </div>
 | 
			
		||||
          <div fxLayout="row" class="tb-alarm-comments-action-buttons"
 | 
			
		||||
               [ngClass]="{ 'show-buttons': displayDataElement.showActions }">
 | 
			
		||||
            <button mat-icon-button
 | 
			
		||||
                    type="button"
 | 
			
		||||
                    (click)="editComment(displayDataElement.commentId)">
 | 
			
		||||
              <mat-icon class="material-icons">edit</mat-icon>
 | 
			
		||||
            </button>
 | 
			
		||||
            <button mat-icon-button
 | 
			
		||||
                    type="button"
 | 
			
		||||
                    (click)="deleteComment(displayDataElement.commentId)">
 | 
			
		||||
              <mat-icon class="material-icons">delete</mat-icon>
 | 
			
		||||
            </button>
 | 
			
		||||
          </div>
 | 
			
		||||
    <div class="comments-container" fxLayout="column" fxLayoutGap="12px" style="padding: 24px"
 | 
			
		||||
         [ngClass]="{'asc': isDirectionAscending(), 'activity-only': alarmActivityOnly}">
 | 
			
		||||
      <div fxFlex *ngFor="let displayDataElement of displayData; index as i">
 | 
			
		||||
        <div class="system-comment" *ngIf="displayDataElement.isSystemComment; else userComment">
 | 
			
		||||
          <span class="system-text" style="margin-right: 8px">
 | 
			
		||||
            {{ displayDataElement.commentText }}
 | 
			
		||||
          </span>
 | 
			
		||||
          <span class="time" style="padding: 3px"
 | 
			
		||||
                [matTooltip]="displayDataElement.createdTime"
 | 
			
		||||
                matTooltipPosition="right">
 | 
			
		||||
            {{ displayDataElement.createdDateAgo }}
 | 
			
		||||
          </span>
 | 
			
		||||
        </div>
 | 
			
		||||
        <ng-template #commentEditing>
 | 
			
		||||
          <div fxLayoutAlign="row center" fxLayoutGap="8px">
 | 
			
		||||
            <div fxLayout="row" fxLayoutAlign="center center"
 | 
			
		||||
                 class="tb-alarm-comments-user-avatar"
 | 
			
		||||
        <ng-template #userComment>
 | 
			
		||||
          <div class="user-comment" fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px"
 | 
			
		||||
               *ngIf="!displayDataElement.edit; else commentEditing"
 | 
			
		||||
               (mouseenter)="onCommentMouseEnter(displayDataElement.commentId, i)"
 | 
			
		||||
               (mouseleave)="onCommentMouseLeave(i)">
 | 
			
		||||
            <div class="user-avatar" fxLayout="row" fxLayoutAlign="center center" fxFlexAlign="start" fxHide.xs
 | 
			
		||||
                 [style.background-color]="displayDataElement.avatarBgColor">
 | 
			
		||||
              {{ getUserInitials(displayDataElement.displayName) }}
 | 
			
		||||
            </div>
 | 
			
		||||
            <mat-form-field fxFlex appearance="fill" class="mat-block">
 | 
			
		||||
              <textarea matInput
 | 
			
		||||
                        type="text"
 | 
			
		||||
                        placeholder="{{ 'alarm-comment.add' | translate }}"
 | 
			
		||||
                        cdkTextareaAutosize
 | 
			
		||||
                        cdkAutosizeMinRows="1"
 | 
			
		||||
                        cols="1"
 | 
			
		||||
                        formControlName="alarmCommentEdit"
 | 
			
		||||
                        (keyup.enter)="saveEditedComment(displayDataElement.commentId)"
 | 
			
		||||
                        (keydown.enter)="$event.preventDefault()">
 | 
			
		||||
              </textarea>
 | 
			
		||||
              <div matSuffix fxLayout="row">
 | 
			
		||||
                <button mat-icon-button
 | 
			
		||||
                        (click)="cancelEdit(displayDataElement.commentId)"
 | 
			
		||||
                        type="button">
 | 
			
		||||
                  <mat-icon class="material-icons red-button">close</mat-icon>
 | 
			
		||||
                </button>
 | 
			
		||||
                <button mat-icon-button
 | 
			
		||||
                        type="button"
 | 
			
		||||
                        (click)="saveEditedComment(displayDataElement.commentId)">
 | 
			
		||||
                  <mat-icon class="material-icons green-button">check</mat-icon>
 | 
			
		||||
                </button>
 | 
			
		||||
            <div fxFlex fxLayout="column" fxLayoutGap="5px">
 | 
			
		||||
              <div fxLayout="row" fxLayoutGap="8px" fxLayoutAlign="start center">
 | 
			
		||||
                <span class="user-name">{{ displayDataElement.displayName }}</span>
 | 
			
		||||
                <span class="time"
 | 
			
		||||
                      [matTooltip]="displayDataElement.createdTime"
 | 
			
		||||
                      matTooltipPosition="right">
 | 
			
		||||
                  {{ displayDataElement.createdDateAgo }}
 | 
			
		||||
                </span>
 | 
			
		||||
                <span class="time" *ngIf="displayDataElement.isEdited"
 | 
			
		||||
                      matTooltip="{{ displayDataElement.editedDateAgo }} {{ displayDataElement.editedTime }}"
 | 
			
		||||
                      matTooltipPosition="right">
 | 
			
		||||
                  Edited
 | 
			
		||||
                </span>
 | 
			
		||||
              </div>
 | 
			
		||||
            </mat-form-field>
 | 
			
		||||
              <span class="text">{{ displayDataElement.commentText }}</span>
 | 
			
		||||
            </div>
 | 
			
		||||
            <div fxLayout="row" fxLayout.xs="column"  class="action-buttons"
 | 
			
		||||
                 [ngClass]="{ 'show-buttons': displayDataElement.showActions }">
 | 
			
		||||
              <button mat-icon-button
 | 
			
		||||
                      type="button"
 | 
			
		||||
                      (click)="editComment(displayDataElement.commentId)">
 | 
			
		||||
                <mat-icon class="material-icons">edit</mat-icon>
 | 
			
		||||
              </button>
 | 
			
		||||
              <button mat-icon-button
 | 
			
		||||
                      type="button"
 | 
			
		||||
                      (click)="deleteComment(displayDataElement.commentId)">
 | 
			
		||||
                <mat-icon class="material-icons">delete</mat-icon>
 | 
			
		||||
              </button>
 | 
			
		||||
            </div>
 | 
			
		||||
          </div>
 | 
			
		||||
          <ng-template #commentEditing>
 | 
			
		||||
            <div fxLayoutAlign="row center" fxLayoutGap="8px">
 | 
			
		||||
              <div fxLayout="row" fxLayoutAlign="center center"
 | 
			
		||||
                   class="user-avatar"
 | 
			
		||||
                   [style.background-color]="displayDataElement.avatarBgColor">
 | 
			
		||||
                {{ getUserInitials(displayDataElement.displayName) }}
 | 
			
		||||
              </div>
 | 
			
		||||
              <mat-form-field fxFlex class="mat-block tb-appearance-transparent">
 | 
			
		||||
                <textarea matInput
 | 
			
		||||
                          type="text"
 | 
			
		||||
                          placeholder="{{ 'alarm-activity.add' | translate }}"
 | 
			
		||||
                          cdkTextareaAutosize
 | 
			
		||||
                          cdkAutosizeMinRows="1"
 | 
			
		||||
                          cols="1"
 | 
			
		||||
                          formControlName="alarmCommentEdit"
 | 
			
		||||
                          (keyup.enter)="saveEditedComment(displayDataElement.commentId)"
 | 
			
		||||
                          (keydown.enter)="$event.preventDefault()">
 | 
			
		||||
                </textarea>
 | 
			
		||||
                <div matSuffix fxLayout="row">
 | 
			
		||||
                  <button mat-icon-button
 | 
			
		||||
                          (click)="cancelEdit(displayDataElement.commentId)"
 | 
			
		||||
                          type="button">
 | 
			
		||||
                    <mat-icon class="material-icons red-button">close</mat-icon>
 | 
			
		||||
                  </button>
 | 
			
		||||
                  <button mat-icon-button
 | 
			
		||||
                          type="button"
 | 
			
		||||
                          (click)="saveEditedComment(displayDataElement.commentId)">
 | 
			
		||||
                    <mat-icon class="material-icons green-button">check</mat-icon>
 | 
			
		||||
                  </button>
 | 
			
		||||
                </div>
 | 
			
		||||
              </mat-form-field>
 | 
			
		||||
            </div>
 | 
			
		||||
          </ng-template>
 | 
			
		||||
        </ng-template>
 | 
			
		||||
      </ng-template>
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
    <ng-container *ngIf="isDirectionAscending()">
 | 
			
		||||
      <ng-container *ngTemplateOutlet="commentInput"></ng-container>
 | 
			
		||||
    </ng-container>
 | 
			
		||||
  </div>
 | 
			
		||||
  <ng-template #commentInput>
 | 
			
		||||
    <div fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px" fxFlex>
 | 
			
		||||
      <div fxLayout="row" fxLayoutAlign="center center"
 | 
			
		||||
           class="tb-alarm-comments-user-avatar"
 | 
			
		||||
           *ngIf="userDisplayName$ | async; let userDisplayName"
 | 
			
		||||
           [style.background-color]="getCurrentUserBgColor(userDisplayName)">
 | 
			
		||||
        {{ getUserInitials(userDisplayName) }}
 | 
			
		||||
      </div>
 | 
			
		||||
      <mat-form-field appearance="fill" fxFlex class="mat-block">
 | 
			
		||||
    <div style="background-color: white" class="comment-input"
 | 
			
		||||
         [ngClass]="{'newest-first': !isDirectionAscending(), 'oldest-first': isDirectionAscending(), 'activity-only': alarmActivityOnly}">
 | 
			
		||||
      <div fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px" class="inner-wrap">
 | 
			
		||||
        <div fxLayout="row" fxLayoutAlign="center center"
 | 
			
		||||
             class="user-avatar"
 | 
			
		||||
             *ngIf="userDisplayName$ | async; let userDisplayName"
 | 
			
		||||
             [style.background-color]="getCurrentUserBgColor(userDisplayName)">
 | 
			
		||||
          {{ getUserInitials(userDisplayName) }}
 | 
			
		||||
        </div>
 | 
			
		||||
        <mat-form-field fxFlex class="mat-block tb-appearance-transparent">
 | 
			
		||||
          <textarea matInput
 | 
			
		||||
                    type="text"
 | 
			
		||||
                    placeholder="{{ 'alarm-comment.add' | translate }}"
 | 
			
		||||
                    placeholder="{{ 'alarm-activity.add' | translate }}"
 | 
			
		||||
                    cdkTextareaAutosize
 | 
			
		||||
                    cdkAutosizeMinRows="1"
 | 
			
		||||
                    cols="1"
 | 
			
		||||
@ -147,16 +165,17 @@
 | 
			
		||||
                    (keyup.enter)="saveComment()"
 | 
			
		||||
                    (keydown.enter)="$event.preventDefault()">
 | 
			
		||||
          </textarea>
 | 
			
		||||
        <button mat-icon-button
 | 
			
		||||
                type="button"
 | 
			
		||||
                matSuffix
 | 
			
		||||
                *ngIf="getAlarmCommentFormControl().value"
 | 
			
		||||
                (click)="saveComment()">
 | 
			
		||||
          <mat-icon color="primary">
 | 
			
		||||
            send
 | 
			
		||||
          </mat-icon>
 | 
			
		||||
        </button>
 | 
			
		||||
      </mat-form-field>
 | 
			
		||||
          <button mat-icon-button
 | 
			
		||||
                  type="button"
 | 
			
		||||
                  matSuffix
 | 
			
		||||
                  *ngIf="getAlarmCommentFormControl().value"
 | 
			
		||||
                  (click)="saveComment()">
 | 
			
		||||
            <mat-icon color="primary">
 | 
			
		||||
              send
 | 
			
		||||
            </mat-icon>
 | 
			
		||||
          </button>
 | 
			
		||||
        </mat-form-field>
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
  </ng-template>
 | 
			
		||||
</div>
 | 
			
		||||
 | 
			
		||||
@ -13,69 +13,182 @@
 | 
			
		||||
 * See the License for the specific language governing permissions and
 | 
			
		||||
 * limitations under the License.
 | 
			
		||||
 */
 | 
			
		||||
@use '@angular/material' as mat;
 | 
			
		||||
@import '../theme.scss';
 | 
			
		||||
 | 
			
		||||
$primary-color: rgba(mat.get-color-from-palette($tb-primary, 50), 0.4);
 | 
			
		||||
$border: 1px solid mat.get-color-from-palette($tb-primary);
 | 
			
		||||
 | 
			
		||||
:host {
 | 
			
		||||
  .tb-alarm-comments {
 | 
			
		||||
    padding: 16px 24px 24px 24px;
 | 
			
		||||
    background-color: #fafafa;
 | 
			
		||||
    background-color: $primary-color;
 | 
			
		||||
    max-width: 600px;
 | 
			
		||||
    width: 100%;
 | 
			
		||||
 | 
			
		||||
    &-header {
 | 
			
		||||
      background-color: #fafafa;
 | 
			
		||||
    .comment-input {
 | 
			
		||||
      position: sticky;
 | 
			
		||||
      top: -25px;
 | 
			
		||||
      z-index: 1;
 | 
			
		||||
      margin-bottom: 10px;
 | 
			
		||||
 | 
			
		||||
      &-title {
 | 
			
		||||
        color: rgba(0, 0, 0, 0.76);
 | 
			
		||||
        letter-spacing: 0.25px;
 | 
			
		||||
        font-weight: 500;
 | 
			
		||||
      .inner-wrap {
 | 
			
		||||
        border: $border;
 | 
			
		||||
        padding: 0 24px;
 | 
			
		||||
        background-color: $primary-color;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      .mat-icon {
 | 
			
		||||
        color: rgba(0, 0, 0, 0.38);
 | 
			
		||||
      &.oldest-first {
 | 
			
		||||
        bottom: -24px;
 | 
			
		||||
        box-shadow: 0px -4px 12px rgba(0, 0, 0, 0.04);
 | 
			
		||||
 | 
			
		||||
        .inner-wrap {
 | 
			
		||||
          border-radius: 0 0 8px 8px;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        &.activity-only {
 | 
			
		||||
          bottom: -1px;
 | 
			
		||||
 | 
			
		||||
          .inner-wrap {
 | 
			
		||||
            border: none
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      &.newest-first {
 | 
			
		||||
        top: 24px;
 | 
			
		||||
        box-shadow: 0 8px 10px rgba(23, 33, 90, 0.08);
 | 
			
		||||
 | 
			
		||||
        .inner-wrap {
 | 
			
		||||
          border-top: none;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        &.activity-only {
 | 
			
		||||
          top: 48px;
 | 
			
		||||
          box-shadow: 0 8px 10px rgba(23, 33, 90, 0.08);
 | 
			
		||||
 | 
			
		||||
          .inner-wrap {
 | 
			
		||||
            border: none;
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    &-user-avatar {
 | 
			
		||||
    .header {
 | 
			
		||||
      z-index: 1;
 | 
			
		||||
      position: sticky;
 | 
			
		||||
      top: -24px;
 | 
			
		||||
      background-color: white;
 | 
			
		||||
 | 
			
		||||
      &.activity-only {
 | 
			
		||||
        top: 0;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      &-container {
 | 
			
		||||
        padding: 0 24px;
 | 
			
		||||
        background-color: $primary-color;
 | 
			
		||||
        border: $border;
 | 
			
		||||
        border-bottom: none;
 | 
			
		||||
        border-radius: 8px 8px 0px 0px;
 | 
			
		||||
 | 
			
		||||
        &.activity-only {
 | 
			
		||||
          border: none;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        &.asc {
 | 
			
		||||
          border-bottom: $border;
 | 
			
		||||
          box-shadow: 0px 4px 10px rgba(23, 33, 90, 0.08);
 | 
			
		||||
 | 
			
		||||
          &.activity-only {
 | 
			
		||||
            border: none;
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        .header-title {
 | 
			
		||||
          color: rgba(0, 0, 0, 0.76);
 | 
			
		||||
          letter-spacing: 0.25px;
 | 
			
		||||
          font-weight: 500;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        .mat-icon {
 | 
			
		||||
          color: rgba(0, 0, 0, 0.38);
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .comments-container {
 | 
			
		||||
      border: $border;
 | 
			
		||||
      border-top: none;
 | 
			
		||||
      border-radius: 0px 0px 8px 8px;
 | 
			
		||||
 | 
			
		||||
      &.activity-only {
 | 
			
		||||
        border: none;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      &.asc {
 | 
			
		||||
        border-bottom: none;
 | 
			
		||||
        border-radius: unset;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .user-comment {
 | 
			
		||||
      padding: 4px;
 | 
			
		||||
      border-radius: 8px;
 | 
			
		||||
      &:hover {
 | 
			
		||||
        background-color: $primary-color;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .user-avatar {
 | 
			
		||||
      width: 28px;
 | 
			
		||||
      min-width: 28px;
 | 
			
		||||
      height: 28px;
 | 
			
		||||
      min-height: 28px;
 | 
			
		||||
      border-radius: 50%;
 | 
			
		||||
      font-weight: 700;
 | 
			
		||||
      color: #FFFFFF;
 | 
			
		||||
      color: white;
 | 
			
		||||
      font-size: 13px;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    &-user-name {
 | 
			
		||||
    .user-name {
 | 
			
		||||
      font-size: 16px;
 | 
			
		||||
      color: rgba(0, 0, 0, 0.76);
 | 
			
		||||
      font-weight: 500;
 | 
			
		||||
      letter-spacing: 0.25px;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    &-time {
 | 
			
		||||
    .time {
 | 
			
		||||
      font-size: 14px;
 | 
			
		||||
      font-weight: 400;
 | 
			
		||||
      color: rgba(0, 0, 0, 0.38);
 | 
			
		||||
      letter-spacing: 0.2px
 | 
			
		||||
      letter-spacing: 0.2px;
 | 
			
		||||
      border-radius: 16px;
 | 
			
		||||
      padding: 0 3px;
 | 
			
		||||
      &:hover {
 | 
			
		||||
        background: rgba(0, 0, 0, 0.04);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    &-system-text {
 | 
			
		||||
      color: rgba(0, 0, 0, 0.38);
 | 
			
		||||
    .system-comment {
 | 
			
		||||
      margin-left: 38px;
 | 
			
		||||
      @media #{$mat-xs} {
 | 
			
		||||
        margin-left: 0;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .system-text {
 | 
			
		||||
      font-weight: 500;
 | 
			
		||||
      font-size: 14px;
 | 
			
		||||
      letter-spacing: 0.25px;
 | 
			
		||||
      color: rgba(0, 0, 0, 0.38);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    &-text {
 | 
			
		||||
    .text {
 | 
			
		||||
      white-space: pre-line;
 | 
			
		||||
      word-break: break-word;
 | 
			
		||||
      color: rgba(0, 0, 0, 0.54);
 | 
			
		||||
      font-size: 16px;
 | 
			
		||||
      letter-spacing: 0.15px;
 | 
			
		||||
      color: rgba(0, 0, 0, 0.54);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    &-action-buttons {
 | 
			
		||||
    .action-buttons {
 | 
			
		||||
      visibility: hidden;
 | 
			
		||||
      .mat-icon {
 | 
			
		||||
        color: rgba(0, 0, 0, 0.38);
 | 
			
		||||
 | 
			
		||||
@ -30,13 +30,17 @@ import { map } from 'rxjs/operators';
 | 
			
		||||
import { AlarmComment, AlarmCommentInfo, AlarmCommentType } from '@shared/models/alarm.models';
 | 
			
		||||
import { UtilsService } from '@core/services/utils.service';
 | 
			
		||||
import { EntityType } from '@shared/models/entity-type.models';
 | 
			
		||||
import { DatePipe } from '@angular/common';
 | 
			
		||||
import { ImportExportService } from '@home/components/import-export/import-export.service';
 | 
			
		||||
 | 
			
		||||
interface AlarmCommentsDisplayData {
 | 
			
		||||
  commentId?: string,
 | 
			
		||||
  displayName?: string,
 | 
			
		||||
  createdTime: string,
 | 
			
		||||
  createdDateAgo?: string,
 | 
			
		||||
  edit?: boolean,
 | 
			
		||||
  isEdited?: boolean,
 | 
			
		||||
  editedTime?: string;
 | 
			
		||||
  editedDateAgo?: string,
 | 
			
		||||
  showActions?: boolean,
 | 
			
		||||
  commentText?: string,
 | 
			
		||||
@ -54,7 +58,7 @@ export class AlarmCommentComponent implements OnInit {
 | 
			
		||||
  alarmId: string;
 | 
			
		||||
 | 
			
		||||
  @Input()
 | 
			
		||||
  commentsHeaderEnabled: boolean = true;
 | 
			
		||||
  alarmActivityOnly: boolean = false;
 | 
			
		||||
 | 
			
		||||
  authUser: AuthUser;
 | 
			
		||||
 | 
			
		||||
@ -85,7 +89,9 @@ export class AlarmCommentComponent implements OnInit {
 | 
			
		||||
              public fb: FormBuilder,
 | 
			
		||||
              private dialogService: DialogService,
 | 
			
		||||
              public dateAgoPipe: DateAgoPipe,
 | 
			
		||||
              private utilsService: UtilsService) {
 | 
			
		||||
              private utilsService: UtilsService,
 | 
			
		||||
              private datePipe: DatePipe,
 | 
			
		||||
              private importExportService: ImportExportService) {
 | 
			
		||||
 | 
			
		||||
    this.authUser = getCurrentAuthUser(store);
 | 
			
		||||
 | 
			
		||||
@ -110,7 +116,8 @@ export class AlarmCommentComponent implements OnInit {
 | 
			
		||||
        this.alarmComments = pagedData.data;
 | 
			
		||||
        this.displayData.length = 0;
 | 
			
		||||
        for (let alarmComment of pagedData.data) {
 | 
			
		||||
          let displayDataElement: AlarmCommentsDisplayData = {};
 | 
			
		||||
          let displayDataElement = {} as AlarmCommentsDisplayData;
 | 
			
		||||
          displayDataElement.createdTime = this.datePipe.transform(alarmComment.createdTime, 'yyyy-MM-dd HH:mm:ss');
 | 
			
		||||
          displayDataElement.createdDateAgo = this.dateAgoPipe.transform(alarmComment.createdTime);
 | 
			
		||||
          displayDataElement.commentText = alarmComment.comment.text;
 | 
			
		||||
          displayDataElement.isSystemComment = alarmComment.type === AlarmCommentType.SYSTEM;
 | 
			
		||||
@ -119,7 +126,8 @@ export class AlarmCommentComponent implements OnInit {
 | 
			
		||||
            displayDataElement.displayName = this.getUserDisplayName(alarmComment);
 | 
			
		||||
            displayDataElement.edit = false;
 | 
			
		||||
            displayDataElement.isEdited = alarmComment.comment.edited;
 | 
			
		||||
            displayDataElement.editedDateAgo = this.dateAgoPipe.transform(alarmComment.comment.editedOn).toLowerCase();
 | 
			
		||||
            displayDataElement.editedTime = this.datePipe.transform(alarmComment.comment.editedOn, 'yyyy-MM-dd HH:mm:ss');
 | 
			
		||||
            displayDataElement.editedDateAgo = this.dateAgoPipe.transform(alarmComment.comment.editedOn) + '\n';
 | 
			
		||||
            displayDataElement.showActions = false;
 | 
			
		||||
            displayDataElement.isSystemComment = false;
 | 
			
		||||
            displayDataElement.avatarBgColor = this.utilsService.stringToHslColor(displayDataElement.displayName,
 | 
			
		||||
@ -137,6 +145,11 @@ export class AlarmCommentComponent implements OnInit {
 | 
			
		||||
    this.loadAlarmComments();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  exportAlarmActivity() {
 | 
			
		||||
    let fileName = this.translate.instant('alarm.alarm') + '_' + this.translate.instant('alarm-activity.activity');
 | 
			
		||||
    this.importExportService.exportCsv(this.getDataForExport(), fileName.toLowerCase());
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  saveComment(): void {
 | 
			
		||||
    const commentInputValue: string = this.getAlarmCommentFormControl().value;
 | 
			
		||||
    if (commentInputValue) {
 | 
			
		||||
@ -194,7 +207,7 @@ export class AlarmCommentComponent implements OnInit {
 | 
			
		||||
    const alarmCommentInfo: AlarmComment = this.getAlarmCommentById(commentId);
 | 
			
		||||
    const commentText: string = alarmCommentInfo.comment.text;
 | 
			
		||||
    this.dialogService.confirm(
 | 
			
		||||
      this.translate.instant('alarm-comment.delete-alarm-comment'),
 | 
			
		||||
      this.translate.instant('alarm-activity.delete-alarm-comment'),
 | 
			
		||||
      commentText,
 | 
			
		||||
      this.translate.instant('action.cancel'),
 | 
			
		||||
      this.translate.instant('action.delete')).subscribe(
 | 
			
		||||
@ -211,17 +224,19 @@ export class AlarmCommentComponent implements OnInit {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  getSortDirectionIcon() {
 | 
			
		||||
    return this.alarmCommentSortOrder.direction === Direction.DESC ? 'arrow_downward' : 'arrow_upward'
 | 
			
		||||
    return this.alarmCommentSortOrder.direction === Direction.DESC ? 'mdi:sort-descending' : 'mdi:sort-ascending'
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  getSortDirectionTooltipText() {
 | 
			
		||||
    let text = this.alarmCommentSortOrder.direction === Direction.DESC ? 'alarm-activity.newest-first' :
 | 
			
		||||
      'alarm-activity.oldest-first';
 | 
			
		||||
    return this.translate.instant(text);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  isDirectionAscending() {
 | 
			
		||||
    return this.alarmCommentSortOrder.direction === Direction.ASC;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  isDirectionDescending() {
 | 
			
		||||
    return this.alarmCommentSortOrder.direction === Direction.DESC;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  onCommentMouseEnter(commentId: string, displayDataIndex: number): void {
 | 
			
		||||
    if (!this.editMode) {
 | 
			
		||||
      const alarmUserId = this.getAlarmCommentById(commentId).userId.id;
 | 
			
		||||
@ -292,4 +307,19 @@ export class AlarmCommentComponent implements OnInit {
 | 
			
		||||
    return this.displayData.find(commentDisplayData => commentDisplayData.commentId === commentId);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private getDataForExport() {
 | 
			
		||||
    let dataToExport = [];
 | 
			
		||||
    for (let row of this.displayData) {
 | 
			
		||||
      let exportRow = {
 | 
			
		||||
        [this.translate.instant('alarm-activity.author')]: row.isSystemComment ?
 | 
			
		||||
          this.translate.instant('alarm-activity.system') : row.displayName,
 | 
			
		||||
        [this.translate.instant('alarm-activity.created-date')]: row.createdTime,
 | 
			
		||||
        [this.translate.instant('alarm-activity.edited-date')]: row.editedTime,
 | 
			
		||||
        [this.translate.instant('alarm-activity.text')]: row.commentText
 | 
			
		||||
      }
 | 
			
		||||
      dataToExport.push(exportRow)
 | 
			
		||||
    }
 | 
			
		||||
    return dataToExport;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -28,23 +28,13 @@
 | 
			
		||||
  <mat-progress-bar color="warn" mode="indeterminate" *ngIf="isLoading$ | async">
 | 
			
		||||
  </mat-progress-bar>
 | 
			
		||||
  <div style="height: 4px;" *ngIf="!(isLoading$ | async)"></div>
 | 
			
		||||
  <div mat-dialog-content style="padding: 24px 0 0 0">
 | 
			
		||||
    <fieldset [disabled]="isLoading$ | async" style="padding: 0 24px">
 | 
			
		||||
  <div mat-dialog-content>
 | 
			
		||||
    <fieldset [disabled]="isLoading$ | async" style="margin-bottom: 22px">
 | 
			
		||||
      <div fxLayout="row" fxLayoutGap="6px">
 | 
			
		||||
        <mat-form-field fxFlex class="mat-block">
 | 
			
		||||
          <mat-label translate>alarm.originator</mat-label>
 | 
			
		||||
          <input matInput formControlName="originatorName" readonly>
 | 
			
		||||
        </mat-form-field>
 | 
			
		||||
        <mat-form-field fxFlex class="mat-block">
 | 
			
		||||
          <mat-label translate>alarm.created-time</mat-label>
 | 
			
		||||
          <input matInput formControlName="createdTime" readonly>
 | 
			
		||||
        </mat-form-field>
 | 
			
		||||
      </div>
 | 
			
		||||
      <div fxLayout="row" fxLayoutGap="6px">
 | 
			
		||||
        <mat-form-field fxFlex class="mat-block">
 | 
			
		||||
          <mat-label translate>alarm.type</mat-label>
 | 
			
		||||
          <input matInput formControlName="type" readonly>
 | 
			
		||||
        </mat-form-field>
 | 
			
		||||
        <mat-form-field fxFlex class="mat-block">
 | 
			
		||||
          <mat-label translate>alarm.severity</mat-label>
 | 
			
		||||
          <input matInput formControlName="alarmSeverity" readonly
 | 
			
		||||
@ -52,66 +42,50 @@
 | 
			
		||||
        </mat-form-field>
 | 
			
		||||
      </div>
 | 
			
		||||
      <div fxLayout="row" fxLayoutGap="6px">
 | 
			
		||||
        <mat-form-field *ngIf="alarmFormGroup.get('startTime').value" fxFlex class="mat-block">
 | 
			
		||||
          <mat-label translate>alarm.start-time</mat-label>
 | 
			
		||||
          <input matInput formControlName="startTime" readonly>
 | 
			
		||||
        </mat-form-field>
 | 
			
		||||
        <mat-form-field *ngIf="alarmFormGroup.get('duration').value" fxFlex class="mat-block">
 | 
			
		||||
          <mat-label translate>alarm.duration</mat-label>
 | 
			
		||||
          <input matInput formControlName="duration" readonly>
 | 
			
		||||
        </mat-form-field>
 | 
			
		||||
      </div>
 | 
			
		||||
      <div fxLayout="row" fxLayoutGap="6px">
 | 
			
		||||
        <mat-form-field fxFlex class="mat-block">
 | 
			
		||||
          <mat-label translate>alarm.type</mat-label>
 | 
			
		||||
          <input matInput formControlName="type" readonly>
 | 
			
		||||
        </mat-form-field>
 | 
			
		||||
        <mat-form-field fxFlex class="mat-block">
 | 
			
		||||
          <mat-label translate>alarm.status</mat-label>
 | 
			
		||||
          <input matInput formControlName="alarmStatus" readonly>
 | 
			
		||||
        </mat-form-field>
 | 
			
		||||
        <tb-alarm-assignee fxFlex style="padding-top: 9px"
 | 
			
		||||
                           [alarm]="alarm$ | async"
 | 
			
		||||
                           (alarmReassigned)="onReassign()">
 | 
			
		||||
        </tb-alarm-assignee>
 | 
			
		||||
      </div>
 | 
			
		||||
      <mat-expansion-panel class="tb-alarm-details">
 | 
			
		||||
        <mat-expansion-panel-header  fxLayout="row wrap">
 | 
			
		||||
        <mat-expansion-panel-header  fxLayout="row wrap" style="margin-bottom: 8px">
 | 
			
		||||
          <mat-panel-title>
 | 
			
		||||
          </mat-panel-title>
 | 
			
		||||
          <mat-panel-description fxLayoutAlign="end center" fxHide.xs translate>
 | 
			
		||||
            alarm.advanced-info
 | 
			
		||||
          <mat-panel-description fxLayoutAlign="end center" translate>
 | 
			
		||||
            alarm.show-more
 | 
			
		||||
          </mat-panel-description>
 | 
			
		||||
        </mat-expansion-panel-header>
 | 
			
		||||
        <ng-template matExpansionPanelContent>
 | 
			
		||||
          <div fxLayout="row" fxLayoutGap="6px" *ngIf="alarmFormGroup.get('startTime').value ||
 | 
			
		||||
                                 alarmFormGroup.get('endTime').value">
 | 
			
		||||
            <mat-form-field *ngIf="alarmFormGroup.get('startTime').value" fxFlex class="mat-block">
 | 
			
		||||
              <mat-label translate>alarm.start-time</mat-label>
 | 
			
		||||
              <input matInput formControlName="startTime" readonly>
 | 
			
		||||
            </mat-form-field>
 | 
			
		||||
            <mat-form-field *ngIf="alarmFormGroup.get('endTime').value" fxFlex class="mat-block">
 | 
			
		||||
              <mat-label translate>alarm.end-time</mat-label>
 | 
			
		||||
              <input matInput formControlName="endTime" readonly>
 | 
			
		||||
            </mat-form-field>
 | 
			
		||||
            <span fxFlex *ngIf="!alarmFormGroup.get('startTime').value || !alarmFormGroup.get('endTime').value"></span>
 | 
			
		||||
          </div>
 | 
			
		||||
          <div fxLayout="row" fxLayoutGap="6px" *ngIf="alarmFormGroup.get('ackTime').value ||
 | 
			
		||||
                                 alarmFormGroup.get('clearTime').value">
 | 
			
		||||
            <mat-form-field *ngIf="alarmFormGroup.get('ackTime').value" fxFlex class="mat-block">
 | 
			
		||||
              <mat-label translate>alarm.ack-time</mat-label>
 | 
			
		||||
              <input matInput formControlName="ackTime" readonly>
 | 
			
		||||
            </mat-form-field>
 | 
			
		||||
            <mat-form-field *ngIf="alarmFormGroup.get('clearTime').value" fxFlex class="mat-block">
 | 
			
		||||
              <mat-label translate>alarm.clear-time</mat-label>
 | 
			
		||||
              <input matInput formControlName="clearTime" readonly>
 | 
			
		||||
            </mat-form-field>
 | 
			
		||||
            <span fxFlex *ngIf="!alarmFormGroup.get('ackTime').value || !alarmFormGroup.get('clearTime').value"></span>
 | 
			
		||||
          </div>
 | 
			
		||||
          <tb-json-object-edit
 | 
			
		||||
            *ngIf="displayDetails"
 | 
			
		||||
            formControlName="alarmDetails"
 | 
			
		||||
            readonly
 | 
			
		||||
            label="{{ 'alarm.details' | translate }}">
 | 
			
		||||
            label="{{ 'alarm.additional-info' | translate }}">
 | 
			
		||||
          </tb-json-object-edit>
 | 
			
		||||
        </ng-template>
 | 
			
		||||
      </mat-expansion-panel>
 | 
			
		||||
    </fieldset>
 | 
			
		||||
    <tb-alarm-assignee fxFlex [allowAssign]="allowAssign"
 | 
			
		||||
                       [alarm]="alarm$ | async"
 | 
			
		||||
                       (alarmReassigned)="onReassign()">
 | 
			
		||||
    </tb-alarm-assignee>
 | 
			
		||||
    <tb-alarm-comment #alarmCommentComponent [alarmId]="alarmId"></tb-alarm-comment>
 | 
			
		||||
  </div>
 | 
			
		||||
  <div mat-dialog-actions fxLayout="row">
 | 
			
		||||
    <button mat-button color="primary"
 | 
			
		||||
            type="button"
 | 
			
		||||
            [disabled]="(isLoading$ | async)"
 | 
			
		||||
            (click)="close()" cdkFocusInitial>
 | 
			
		||||
      {{ 'action.close' | translate }}
 | 
			
		||||
    </button>
 | 
			
		||||
    <span fxFlex></span>
 | 
			
		||||
    <div fxLayout="row" *ngIf="alarm$ | async; let alarm;" fxLayoutGap="8px">
 | 
			
		||||
      <button *ngIf="allowAcknowledgment && (alarm.status === alarmStatuses.ACTIVE_UNACK ||
 | 
			
		||||
 | 
			
		||||
@ -13,6 +13,7 @@
 | 
			
		||||
 * See the License for the specific language governing permissions and
 | 
			
		||||
 * limitations under the License.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
:host ::ng-deep {
 | 
			
		||||
  .assignee-field {
 | 
			
		||||
    .mat-form-field-label-wrapper {
 | 
			
		||||
 | 
			
		||||
@ -34,6 +34,7 @@ import { tap } from 'rxjs/operators';
 | 
			
		||||
import { DatePipe } from '@angular/common';
 | 
			
		||||
import { TranslateService } from '@ngx-translate/core';
 | 
			
		||||
import { AlarmCommentComponent } from '@home/components/alarm/alarm-comment.component';
 | 
			
		||||
import { MillisecondsToTimeStringPipe } from '@shared/pipe/milliseconds-to-time-string.pipe';
 | 
			
		||||
 | 
			
		||||
export interface AlarmDetailsDialogData {
 | 
			
		||||
  alarmId?: string;
 | 
			
		||||
@ -41,6 +42,7 @@ export interface AlarmDetailsDialogData {
 | 
			
		||||
  allowAcknowledgment: boolean;
 | 
			
		||||
  allowClear: boolean;
 | 
			
		||||
  displayDetails: boolean;
 | 
			
		||||
  allowAssign: boolean;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@Component({
 | 
			
		||||
@ -56,6 +58,7 @@ export class AlarmDetailsDialogComponent extends DialogComponent<AlarmDetailsDia
 | 
			
		||||
  allowAcknowledgment: boolean;
 | 
			
		||||
  allowClear: boolean;
 | 
			
		||||
  displayDetails: boolean;
 | 
			
		||||
  allowAssign: boolean;
 | 
			
		||||
 | 
			
		||||
  loadAlarmSubject = new ReplaySubject<AlarmInfo>();
 | 
			
		||||
  alarm$: Observable<AlarmInfo> = this.loadAlarmSubject.asObservable().pipe(
 | 
			
		||||
@ -72,6 +75,7 @@ export class AlarmDetailsDialogComponent extends DialogComponent<AlarmDetailsDia
 | 
			
		||||
  constructor(protected store: Store<AppState>,
 | 
			
		||||
              protected router: Router,
 | 
			
		||||
              private datePipe: DatePipe,
 | 
			
		||||
              private millisecondsToTimeStringPipe: MillisecondsToTimeStringPipe,
 | 
			
		||||
              private translate: TranslateService,
 | 
			
		||||
              @Inject(MAT_DIALOG_DATA) public data: AlarmDetailsDialogData,
 | 
			
		||||
              private alarmService: AlarmService,
 | 
			
		||||
@ -82,17 +86,15 @@ export class AlarmDetailsDialogComponent extends DialogComponent<AlarmDetailsDia
 | 
			
		||||
    this.allowAcknowledgment = data.allowAcknowledgment;
 | 
			
		||||
    this.allowClear = data.allowClear;
 | 
			
		||||
    this.displayDetails = data.displayDetails;
 | 
			
		||||
    this.allowAssign = data.allowAssign;
 | 
			
		||||
 | 
			
		||||
    this.alarmFormGroup = this.fb.group(
 | 
			
		||||
      {
 | 
			
		||||
        createdTime: [''],
 | 
			
		||||
        originatorName: [''],
 | 
			
		||||
        startTime: [''],
 | 
			
		||||
        endTime: [''],
 | 
			
		||||
        ackTime: [''],
 | 
			
		||||
        clearTime: [''],
 | 
			
		||||
        type: [''],
 | 
			
		||||
        alarmSeverity: [''],
 | 
			
		||||
        startTime: [''],
 | 
			
		||||
        duration: [''],
 | 
			
		||||
        type: [''],
 | 
			
		||||
        alarmStatus: [''],
 | 
			
		||||
        alarmDetails: [null]
 | 
			
		||||
      }
 | 
			
		||||
@ -116,29 +118,25 @@ export class AlarmDetailsDialogComponent extends DialogComponent<AlarmDetailsDia
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  loadAlarmFields(alarm: AlarmInfo) {
 | 
			
		||||
    this.alarmFormGroup.get('createdTime')
 | 
			
		||||
      .patchValue(this.datePipe.transform(alarm.createdTime, 'yyyy-MM-dd HH:mm:ss'));
 | 
			
		||||
    this.alarmFormGroup.get('originatorName')
 | 
			
		||||
      .patchValue(alarm.originatorName);
 | 
			
		||||
      .patchValue(alarm.originatorLabel ? alarm.originatorLabel : alarm.originatorName);
 | 
			
		||||
    this.alarmFormGroup.get('alarmSeverity')
 | 
			
		||||
      .patchValue(this.translate.instant(alarmSeverityTranslations.get(alarm.severity)));
 | 
			
		||||
    if (alarm.startTs) {
 | 
			
		||||
      this.alarmFormGroup.get('startTime')
 | 
			
		||||
        .patchValue(this.datePipe.transform(alarm.startTs, 'yyyy-MM-dd HH:mm:ss'));
 | 
			
		||||
    }
 | 
			
		||||
    if (alarm.endTs) {
 | 
			
		||||
      this.alarmFormGroup.get('endTime')
 | 
			
		||||
        .patchValue(this.datePipe.transform(alarm.endTs, 'yyyy-MM-dd HH:mm:ss'));
 | 
			
		||||
    }
 | 
			
		||||
    if (alarm.ackTs) {
 | 
			
		||||
      this.alarmFormGroup.get('ackTime')
 | 
			
		||||
        .patchValue(this.datePipe.transform(alarm.ackTs, 'yyyy-MM-dd HH:mm:ss'));
 | 
			
		||||
    }
 | 
			
		||||
    if (alarm.clearTs) {
 | 
			
		||||
      this.alarmFormGroup.get('clearTime')
 | 
			
		||||
        .patchValue(this.datePipe.transform(alarm.clearTs, 'yyyy-MM-dd HH:mm:ss'));
 | 
			
		||||
    if (alarm.startTs || alarm.endTs) {
 | 
			
		||||
      let duration = '';
 | 
			
		||||
      if (alarm.startTs && (alarm.status === AlarmStatus.ACTIVE_ACK || alarm.status === AlarmStatus.ACTIVE_UNACK)) {
 | 
			
		||||
        duration = this.millisecondsToTimeStringPipe.transform(Date.now() - alarm.startTs);
 | 
			
		||||
      }
 | 
			
		||||
      if (alarm.endTs && (alarm.status === AlarmStatus.CLEARED_ACK || alarm.status === AlarmStatus.CLEARED_UNACK)) {
 | 
			
		||||
        duration = this.millisecondsToTimeStringPipe.transform(alarm.endTs - alarm.startTs);
 | 
			
		||||
      }
 | 
			
		||||
      this.alarmFormGroup.get('duration').patchValue(duration);
 | 
			
		||||
    }
 | 
			
		||||
    this.alarmFormGroup.get('type').patchValue(alarm.type);
 | 
			
		||||
    this.alarmFormGroup.get('alarmSeverity')
 | 
			
		||||
      .patchValue(this.translate.instant(alarmSeverityTranslations.get(alarm.severity)));
 | 
			
		||||
    this.alarmFormGroup.get('alarmStatus')
 | 
			
		||||
      .patchValue(this.translate.instant(alarmStatusTranslations.get(alarm.status)));
 | 
			
		||||
    this.alarmFormGroup.get('alarmDetails').patchValue(alarm.details);
 | 
			
		||||
 | 
			
		||||
@ -53,7 +53,8 @@ import { Authority } from '@shared/models/authority.enum';
 | 
			
		||||
import { ChangeDetectorRef, Injector, StaticProvider, ViewContainerRef } from '@angular/core';
 | 
			
		||||
import { ConnectedPosition, Overlay, OverlayConfig, OverlayRef } from '@angular/cdk/overlay';
 | 
			
		||||
import {
 | 
			
		||||
  ALARM_ASSIGNEE_PANEL_DATA, AlarmAssigneePanelComponent,
 | 
			
		||||
  ALARM_ASSIGNEE_PANEL_DATA,
 | 
			
		||||
  AlarmAssigneePanelComponent,
 | 
			
		||||
  AlarmAssigneePanelData
 | 
			
		||||
} from '@home/components/alarm/alarm-assignee-panel.component';
 | 
			
		||||
import { ComponentPortal } from '@angular/cdk/portal';
 | 
			
		||||
@ -168,7 +169,7 @@ export class AlarmTableConfig extends EntityTableConfig<AlarmInfo, TimePageLink>
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  showAlarmDetails(entity: AlarmInfo) {
 | 
			
		||||
    const isPermissionWrite = this.authUser.authority !== Authority.CUSTOMER_USER || entity.customerId.id === this.authUser.customerId;
 | 
			
		||||
    const isPermissionWrite = this.authUser.authority !== Authority.CUSTOMER_USER || entity.customerId?.id === this.authUser.customerId;
 | 
			
		||||
    this.dialog.open<AlarmDetailsDialogComponent, AlarmDetailsDialogData, boolean>
 | 
			
		||||
    (AlarmDetailsDialogComponent,
 | 
			
		||||
      {
 | 
			
		||||
@ -179,7 +180,8 @@ export class AlarmTableConfig extends EntityTableConfig<AlarmInfo, TimePageLink>
 | 
			
		||||
          alarm: entity,
 | 
			
		||||
          allowAcknowledgment: isPermissionWrite,
 | 
			
		||||
          allowClear: isPermissionWrite,
 | 
			
		||||
          displayDetails: true
 | 
			
		||||
          displayDetails: true,
 | 
			
		||||
          allowAssign: true
 | 
			
		||||
        }
 | 
			
		||||
      }).afterClosed().subscribe(
 | 
			
		||||
      (res) => {
 | 
			
		||||
@ -281,8 +283,13 @@ export class AlarmTableConfig extends EntityTableConfig<AlarmInfo, TimePageLink>
 | 
			
		||||
      }
 | 
			
		||||
    ];
 | 
			
		||||
    const injector = Injector.create({parent: this.viewContainerRef.injector, providers});
 | 
			
		||||
    overlayRef.attach(new ComponentPortal(AlarmAssigneePanelComponent,
 | 
			
		||||
      this.viewContainerRef, injector)).onDestroy(() => this.updateData());
 | 
			
		||||
    const componentRef = overlayRef.attach(new ComponentPortal(AlarmAssigneePanelComponent,
 | 
			
		||||
      this.viewContainerRef, injector));
 | 
			
		||||
    componentRef.onDestroy(() => {
 | 
			
		||||
      if (componentRef.instance.reassigned) {
 | 
			
		||||
        this.updateData()
 | 
			
		||||
      }
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -14,42 +14,44 @@
 | 
			
		||||
 * limitations under the License.
 | 
			
		||||
 */
 | 
			
		||||
:host ::ng-deep {
 | 
			
		||||
  tb-entities-table.tb-details-mode {
 | 
			
		||||
    .mat-drawer-container {
 | 
			
		||||
      background-color: white;
 | 
			
		||||
      .assignee-cell {
 | 
			
		||||
        display: flex;
 | 
			
		||||
        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;
 | 
			
		||||
            align-items: center;
 | 
			
		||||
            margin-right: 8px;
 | 
			
		||||
            border-radius: 50%;
 | 
			
		||||
            width: 28px;
 | 
			
		||||
            height: 28px;
 | 
			
		||||
            min-width: 28px;
 | 
			
		||||
            min-height: 28px;
 | 
			
		||||
            color: white;
 | 
			
		||||
            font-size: 13px;
 | 
			
		||||
            font-weight: 700;
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
        .material-icons.unassigned-icon {
 | 
			
		||||
  tb-entities-table {
 | 
			
		||||
    &.tb-details-mode {
 | 
			
		||||
      .mat-drawer-container {
 | 
			
		||||
        background-color: white;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    .assignee-cell {
 | 
			
		||||
      display: flex;
 | 
			
		||||
      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;
 | 
			
		||||
          align-items: center;
 | 
			
		||||
          margin-right: 8px;
 | 
			
		||||
          border-radius: 50%;
 | 
			
		||||
          width: 28px;
 | 
			
		||||
          height: 28px;
 | 
			
		||||
          font-size: 28px;
 | 
			
		||||
          margin-right: 8px;
 | 
			
		||||
          color: rgba(0, 0, 0, 0.38);
 | 
			
		||||
          overflow: visible;
 | 
			
		||||
          min-width: 28px;
 | 
			
		||||
          min-height: 28px;
 | 
			
		||||
          color: white;
 | 
			
		||||
          font-size: 13px;
 | 
			
		||||
          font-weight: 700;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
      .material-icons.unassigned-icon {
 | 
			
		||||
        width: 28px;
 | 
			
		||||
        height: 28px;
 | 
			
		||||
        font-size: 28px;
 | 
			
		||||
        margin-right: 8px;
 | 
			
		||||
        color: rgba(0, 0, 0, 0.38);
 | 
			
		||||
        overflow: visible;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -150,6 +150,11 @@ export const ZIP_TYPE: FileType = {
 | 
			
		||||
  extension: 'zip'
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export const CSV_TYPE: FileType = {
 | 
			
		||||
  mimeType: 'attachament/csv',
 | 
			
		||||
  extension: 'csv'
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export function convertCSVToJson(csvdata: string, config: CsvToJsonConfig,
 | 
			
		||||
                                 onError: (messageId: string, params?: any) => void): CsvToJsonResult | number {
 | 
			
		||||
  config = config || {};
 | 
			
		||||
 | 
			
		||||
@ -47,6 +47,7 @@ import { ItemBufferService, WidgetItem } from '@core/services/item-buffer.servic
 | 
			
		||||
import {
 | 
			
		||||
  BulkImportRequest,
 | 
			
		||||
  BulkImportResult,
 | 
			
		||||
  CSV_TYPE,
 | 
			
		||||
  FileType,
 | 
			
		||||
  ImportWidgetResult,
 | 
			
		||||
  JSON_TYPE,
 | 
			
		||||
@ -597,6 +598,35 @@ export class ImportExportService {
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private processCSVCell(cellData: any): any {
 | 
			
		||||
    if (isString(cellData)) {
 | 
			
		||||
      let result = cellData.replace(/"/g, '""');
 | 
			
		||||
      if (result.search(/([",\n])/g) >= 0) {
 | 
			
		||||
        result = `"${result}"`;
 | 
			
		||||
      }
 | 
			
		||||
      return result;
 | 
			
		||||
    }
 | 
			
		||||
    return cellData;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public exportCsv(data: {[key: string]: any}[], filename: string) {
 | 
			
		||||
    let colsHead: string;
 | 
			
		||||
    let colsData: string;
 | 
			
		||||
    if (data && data.length) {
 | 
			
		||||
      colsHead = Object.keys(data[0]).map(key => [this.processCSVCell(key)]).join(';');
 | 
			
		||||
      colsData = data.map(obj => [
 | 
			
		||||
        Object.keys(obj).map(col => [
 | 
			
		||||
          this.processCSVCell(obj[col])
 | 
			
		||||
        ]).join(';')
 | 
			
		||||
      ]).join('\n');
 | 
			
		||||
    } else {
 | 
			
		||||
      colsHead = '';
 | 
			
		||||
      colsData = '';
 | 
			
		||||
    }
 | 
			
		||||
    const csvData = `${colsHead}\n${colsData}`;
 | 
			
		||||
    this.downloadFile(csvData, filename, CSV_TYPE);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public exportText(data: string | Array<string>, filename: string) {
 | 
			
		||||
    let content = data;
 | 
			
		||||
    if (Array.isArray(data)) {
 | 
			
		||||
 | 
			
		||||
@ -143,7 +143,7 @@ interface AlarmsTableWidgetSettings extends TableWidgetSettings {
 | 
			
		||||
  enableSelection: boolean;
 | 
			
		||||
  enableStatusFilter?: boolean;
 | 
			
		||||
  enableFilter: boolean;
 | 
			
		||||
  displayComments: boolean;
 | 
			
		||||
  displayActivity: boolean;
 | 
			
		||||
  displayDetails: boolean;
 | 
			
		||||
  allowAcknowledgment: boolean;
 | 
			
		||||
  allowClear: boolean;
 | 
			
		||||
@ -154,7 +154,7 @@ interface AlarmWidgetActionDescriptor extends TableCellButtonActionDescriptor {
 | 
			
		||||
  details?: boolean;
 | 
			
		||||
  acknowledge?: boolean;
 | 
			
		||||
  clear?: boolean;
 | 
			
		||||
  comments?: boolean;
 | 
			
		||||
  activity?: boolean;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@Component({
 | 
			
		||||
@ -197,7 +197,7 @@ export class AlarmsTableWidgetComponent extends PageComponent implements OnInit,
 | 
			
		||||
 | 
			
		||||
  private alarmsTitlePattern: string;
 | 
			
		||||
 | 
			
		||||
  private displayComments = false;
 | 
			
		||||
  private displayActivity = false;
 | 
			
		||||
  private displayDetails = true;
 | 
			
		||||
  public allowAcknowledgment = true;
 | 
			
		||||
  private allowClear = true;
 | 
			
		||||
@ -335,7 +335,7 @@ export class AlarmsTableWidgetComponent extends PageComponent implements OnInit,
 | 
			
		||||
  private initializeConfig() {
 | 
			
		||||
    this.ctx.widgetActions = [this.searchAction, this.alarmFilterAction, this.columnDisplayAction];
 | 
			
		||||
 | 
			
		||||
    this.displayComments = isDefined(this.settings.displayComments) ? this.settings.displayComments : false;
 | 
			
		||||
    this.displayActivity = isDefined(this.settings.displayActivity) ? this.settings.displayActivity : false;
 | 
			
		||||
    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;
 | 
			
		||||
@ -464,12 +464,12 @@ export class AlarmsTableWidgetComponent extends PageComponent implements OnInit,
 | 
			
		||||
    this.sortOrderProperty = sortColumn ? sortColumn.def : null;
 | 
			
		||||
 | 
			
		||||
    const actionCellDescriptors: AlarmWidgetActionDescriptor[] = [];
 | 
			
		||||
    if (this.displayComments) {
 | 
			
		||||
    if (this.displayActivity) {
 | 
			
		||||
      actionCellDescriptors.push(
 | 
			
		||||
        {
 | 
			
		||||
          displayName: this.translate.instant('alarm-comment.comments'),
 | 
			
		||||
          displayName: this.translate.instant('alarm-activity.activity'),
 | 
			
		||||
          icon: 'comment',
 | 
			
		||||
          comments: true
 | 
			
		||||
          activity: true
 | 
			
		||||
        } as AlarmWidgetActionDescriptor
 | 
			
		||||
      );
 | 
			
		||||
    }
 | 
			
		||||
@ -821,8 +821,8 @@ export class AlarmsTableWidgetComponent extends PageComponent implements OnInit,
 | 
			
		||||
      this.ackAlarm($event, alarm);
 | 
			
		||||
    } else if (actionDescriptor.clear) {
 | 
			
		||||
      this.clearAlarm($event, alarm);
 | 
			
		||||
    } else if (actionDescriptor.comments) {
 | 
			
		||||
      this.openAlarmComments($event, alarm);
 | 
			
		||||
    } else if (actionDescriptor.activity) {
 | 
			
		||||
      this.openAlarmActivity($event, alarm);
 | 
			
		||||
    } else {
 | 
			
		||||
      if ($event) {
 | 
			
		||||
        $event.stopPropagation();
 | 
			
		||||
@ -864,7 +864,8 @@ export class AlarmsTableWidgetComponent extends PageComponent implements OnInit,
 | 
			
		||||
            alarmId: alarm.id.id,
 | 
			
		||||
            allowAcknowledgment: this.allowAcknowledgment,
 | 
			
		||||
            allowClear: this.allowClear,
 | 
			
		||||
            displayDetails: true
 | 
			
		||||
            displayDetails: true,
 | 
			
		||||
            allowAssign: this.allowAssign
 | 
			
		||||
          }
 | 
			
		||||
        }).afterClosed().subscribe(
 | 
			
		||||
        (res) => {
 | 
			
		||||
@ -988,7 +989,7 @@ export class AlarmsTableWidgetComponent extends PageComponent implements OnInit,
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private openAlarmComments($event: Event, alarm: AlarmDataInfo) {
 | 
			
		||||
  private openAlarmActivity($event: Event, alarm: AlarmDataInfo) {
 | 
			
		||||
    if ($event) {
 | 
			
		||||
      $event.stopPropagation();
 | 
			
		||||
    }
 | 
			
		||||
@ -999,8 +1000,7 @@ export class AlarmsTableWidgetComponent extends PageComponent implements OnInit,
 | 
			
		||||
          disableClose: true,
 | 
			
		||||
          panelClass: ['tb-dialog', 'tb-fullscreen-dialog'],
 | 
			
		||||
          data: {
 | 
			
		||||
            alarmId: alarm.id.id,
 | 
			
		||||
            commentsHeaderEnabled: false
 | 
			
		||||
            alarmId: alarm.id.id
 | 
			
		||||
          }
 | 
			
		||||
        }).afterClosed()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -58,8 +58,8 @@
 | 
			
		||||
      </mat-select>
 | 
			
		||||
    </mat-form-field>
 | 
			
		||||
    <section fxLayout="column" fxLayoutGap="8px">
 | 
			
		||||
      <mat-slide-toggle formControlName="displayComments">
 | 
			
		||||
        {{ 'widgets.table.display-alarm-comments' | translate }}
 | 
			
		||||
      <mat-slide-toggle formControlName="displayActivity">
 | 
			
		||||
        {{ 'widgets.table.display-alarm-activity' | translate }}
 | 
			
		||||
      </mat-slide-toggle>
 | 
			
		||||
      <mat-slide-toggle fxFlex formControlName="displayDetails">
 | 
			
		||||
        {{ 'widgets.table.display-alarm-details' | translate }}
 | 
			
		||||
 | 
			
		||||
@ -74,7 +74,7 @@ export class AlarmsTableWidgetSettingsComponent extends WidgetSettingsComponent
 | 
			
		||||
      allowAcknowledgment: [settings.allowAcknowledgment, []],
 | 
			
		||||
      allowClear: [settings.allowClear, []],
 | 
			
		||||
      allowAssign: [settings.allowAssign, []],
 | 
			
		||||
      displayComments: [settings.displayComments, []],
 | 
			
		||||
      displayActivity: [settings.displayActivity, []],
 | 
			
		||||
      displayPagination: [settings.displayPagination, []],
 | 
			
		||||
      defaultPageSize: [settings.defaultPageSize, [Validators.min(1)]],
 | 
			
		||||
      defaultSortOrder: [settings.defaultSortOrder, []],
 | 
			
		||||
 | 
			
		||||
@ -466,6 +466,7 @@
 | 
			
		||||
        "end-time": "End time",
 | 
			
		||||
        "ack-time": "Acknowledged time",
 | 
			
		||||
        "clear-time": "Cleared time",
 | 
			
		||||
        "duration": "Duration",
 | 
			
		||||
        "alarm-severity-list": "Alarm severity list",
 | 
			
		||||
        "any-severity": "Any severity",
 | 
			
		||||
        "severity-critical": "Critical",
 | 
			
		||||
@ -501,15 +502,24 @@
 | 
			
		||||
        "any-type": "Any type",
 | 
			
		||||
        "search-propagated-alarms": "Search propagated alarms",
 | 
			
		||||
        "comments": "Alarm comments",
 | 
			
		||||
        "advanced-info": "Advanced info"
 | 
			
		||||
        "show-more": "Show more",
 | 
			
		||||
        "additional-info": "Additional info"
 | 
			
		||||
    },
 | 
			
		||||
    "alarm-comment": {
 | 
			
		||||
    "alarm-activity": {
 | 
			
		||||
        "add": "Add a comment...",
 | 
			
		||||
        "alarm-comment": "Alarm comment",
 | 
			
		||||
        "comments": "Comments",
 | 
			
		||||
        "delete-alarm-comment": "Do you want to delete this comment?",
 | 
			
		||||
        "refresh": "Refresh",
 | 
			
		||||
        "sort-direction": "Sort direction"
 | 
			
		||||
        "oldest-first": "Oldest first",
 | 
			
		||||
        "newest-first": "Newest first",
 | 
			
		||||
        "activity": "Activity",
 | 
			
		||||
        "export":  "Export to CSV",
 | 
			
		||||
        "author": "Author",
 | 
			
		||||
        "created-date": "Created date",
 | 
			
		||||
        "edited-date": "Edited date",
 | 
			
		||||
        "text": "Text",
 | 
			
		||||
        "system": "System"
 | 
			
		||||
    },
 | 
			
		||||
    "alias": {
 | 
			
		||||
        "add": "Add alias",
 | 
			
		||||
@ -5042,7 +5052,7 @@
 | 
			
		||||
            "display-alarm-details": "Display alarm details",
 | 
			
		||||
            "allow-alarms-ack": "Allow alarms acknowledgment",
 | 
			
		||||
            "allow-alarms-clear": "Allow alarms clear",
 | 
			
		||||
            "display-alarm-comments": "Display alarm comments",
 | 
			
		||||
            "display-alarm-activity": "Display alarm activity",
 | 
			
		||||
            "allow-alarms-assign": "Allow alarms assignment"
 | 
			
		||||
        },
 | 
			
		||||
        "value-source": {
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user