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