Merge pull request #9569 from rusikv/enhancement/alarm-table-widget

Improved usability of bulk operations in alarm widget table
This commit is contained in:
Igor Kulikov 2023-11-07 16:40:06 +02:00 committed by GitHub
commit c7d992155e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 54 additions and 39 deletions

View File

@ -319,9 +319,7 @@ export class AlarmTableConfig extends EntityTableConfig<AlarmInfo, TimePageLink>
if ($event) { if ($event) {
$event.stopPropagation(); $event.stopPropagation();
} }
const unacknowledgedAlarms = alarms.filter(alarm => { const unacknowledgedAlarms = alarms.filter(alarm => !alarm.acknowledged);
return alarm.status === AlarmStatus.CLEARED_UNACK || alarm.status === AlarmStatus.ACTIVE_UNACK;
})
let title = ''; let title = '';
let content = ''; let content = '';
if (!unacknowledgedAlarms.length) { if (!unacknowledgedAlarms.length) {
@ -356,9 +354,7 @@ export class AlarmTableConfig extends EntityTableConfig<AlarmInfo, TimePageLink>
if ($event) { if ($event) {
$event.stopPropagation(); $event.stopPropagation();
} }
const activeAlarms = alarms.filter(alarm => { const activeAlarms = alarms.filter(alarm => !alarm.cleared);
return alarm.status === AlarmStatus.ACTIVE_ACK || alarm.status === AlarmStatus.ACTIVE_UNACK;
})
let title = ''; let title = '';
let content = ''; let content = '';
if (!activeAlarms.length) { if (!activeAlarms.length) {

View File

@ -896,30 +896,37 @@ export class AlarmsTableWidgetComponent extends PageComponent implements OnInit,
$event.stopPropagation(); $event.stopPropagation();
} }
if (this.alarmsDatasource.selection.hasValue()) { if (this.alarmsDatasource.selection.hasValue()) {
const alarmIds = this.alarmsDatasource.selection.selected.filter( const unacknowledgedAlarms = this.alarmsDatasource.selection.selected.filter(
(alarmId) => alarmId !== NULL_UUID alarm => alarm.id.id !== NULL_UUID && !alarm.acknowledged
); );
if (alarmIds.length) { let title = '';
const title = this.translate.instant('alarm.aknowledge-alarms-title', {count: alarmIds.length}); let content = '';
const content = this.translate.instant('alarm.aknowledge-alarms-text', {count: alarmIds.length}); if (!unacknowledgedAlarms.length) {
title = this.translate.instant('alarm.selected-alarms', {count: unacknowledgedAlarms.length});
content = this.translate.instant('alarm.selected-alarms-are-acknowledged');
this.dialogService.alert(
title,
content
).subscribe();
} else {
title = this.translate.instant('alarm.aknowledge-alarms-title', {count: unacknowledgedAlarms.length});
content = this.translate.instant('alarm.aknowledge-alarms-text', {count: unacknowledgedAlarms.length});
this.dialogService.confirm( this.dialogService.confirm(
title, title,
content, content,
this.translate.instant('action.no'), this.translate.instant('action.no'),
this.translate.instant('action.yes') this.translate.instant('action.yes')
).subscribe((res) => { ).subscribe((res) => {
if (res) {
if (res) { if (res) {
const tasks: Observable<AlarmInfo>[] = []; const tasks: Observable<AlarmInfo>[] = [];
for (const alarmId of alarmIds) { for (const alarm of unacknowledgedAlarms) {
tasks.push(this.alarmService.ackAlarm(alarmId)); tasks.push(this.alarmService.ackAlarm(alarm.id.id));
} }
forkJoin(tasks).subscribe(() => { forkJoin(tasks).subscribe(() => {
this.alarmsDatasource.clearSelection(); this.alarmsDatasource.clearSelection();
this.subscription.update(); this.subscription.update();
}); });
} }
}
}); });
} }
} }
@ -952,30 +959,37 @@ export class AlarmsTableWidgetComponent extends PageComponent implements OnInit,
$event.stopPropagation(); $event.stopPropagation();
} }
if (this.alarmsDatasource.selection.hasValue()) { if (this.alarmsDatasource.selection.hasValue()) {
const alarmIds = this.alarmsDatasource.selection.selected.filter( const activeAlarms = this.alarmsDatasource.selection.selected.filter(
(alarmId) => alarmId !== NULL_UUID alarm => alarm.id.id !== NULL_UUID && !alarm.cleared
); );
if (alarmIds.length) { let title = '';
const title = this.translate.instant('alarm.clear-alarms-title', {count: alarmIds.length}); let content = '';
const content = this.translate.instant('alarm.clear-alarms-text', {count: alarmIds.length}); if (!activeAlarms.length) {
title = this.translate.instant('alarm.selected-alarms', {count: activeAlarms.length});
content = this.translate.instant('alarm.selected-alarms-are-cleared');
this.dialogService.alert(
title,
content
).subscribe();
} else {
title = this.translate.instant('alarm.clear-alarms-title', {count: activeAlarms.length});
content = this.translate.instant('alarm.clear-alarms-text', {count: activeAlarms.length});
this.dialogService.confirm( this.dialogService.confirm(
title, title,
content, content,
this.translate.instant('action.no'), this.translate.instant('action.no'),
this.translate.instant('action.yes') this.translate.instant('action.yes')
).subscribe((res) => { ).subscribe((res) => {
if (res) {
if (res) { if (res) {
const tasks: Observable<AlarmInfo>[] = []; const tasks: Observable<AlarmInfo>[] = [];
for (const alarmId of alarmIds) { for (const alarm of activeAlarms) {
tasks.push(this.alarmService.clearAlarm(alarmId)); tasks.push(this.alarmService.clearAlarm(alarm.id.id));
} }
forkJoin(tasks).subscribe(() => { forkJoin(tasks).subscribe(() => {
this.alarmsDatasource.clearSelection(); this.alarmsDatasource.clearSelection();
this.subscription.update(); this.subscription.update();
}); });
} }
}
}); });
} }
} }
@ -1132,7 +1146,8 @@ class AlarmsDatasource implements DataSource<AlarmDataInfo> {
private alarmsSubject = new BehaviorSubject<AlarmDataInfo[]>([]); private alarmsSubject = new BehaviorSubject<AlarmDataInfo[]>([]);
private pageDataSubject = new BehaviorSubject<PageData<AlarmDataInfo>>(emptyPageData<AlarmDataInfo>()); private pageDataSubject = new BehaviorSubject<PageData<AlarmDataInfo>>(emptyPageData<AlarmDataInfo>());
public selection = new SelectionModel<string>(true, [], false); public selection = new SelectionModel<AlarmDataInfo>(true, [], false,
(alarm1: AlarmDataInfo, alarm2: AlarmDataInfo) => alarm1.id.id === alarm2.id.id);
private selectionModeChanged = new EventEmitter<boolean>(); private selectionModeChanged = new EventEmitter<boolean>();
@ -1210,7 +1225,7 @@ class AlarmsDatasource implements DataSource<AlarmDataInfo> {
} }
if (this.selection.hasValue()) { if (this.selection.hasValue()) {
const alarmIds = alarms.map((alarm) => alarm.id.id); const alarmIds = alarms.map((alarm) => alarm.id.id);
const toRemove = this.selection.selected.filter(alarmId => alarmIds.indexOf(alarmId) === -1); const toRemove = this.selection.selected.filter(alarm => alarmIds.indexOf(alarm.id.id) === -1);
this.selection.deselect(...toRemove); this.selection.deselect(...toRemove);
if (this.selection.isEmpty()) { if (this.selection.isEmpty()) {
isEmptySelection = true; isEmptySelection = true;
@ -1284,14 +1299,14 @@ class AlarmsDatasource implements DataSource<AlarmDataInfo> {
toggleSelection(alarm: AlarmDataInfo) { toggleSelection(alarm: AlarmDataInfo) {
const hasValue = this.selection.hasValue(); const hasValue = this.selection.hasValue();
this.selection.toggle(alarm.id.id); this.selection.toggle(alarm);
if (hasValue !== this.selection.hasValue()) { if (hasValue !== this.selection.hasValue()) {
this.onSelectionModeChanged(this.selection.hasValue()); this.onSelectionModeChanged(this.selection.hasValue());
} }
} }
isSelected(alarm: AlarmDataInfo): boolean { isSelected(alarm: AlarmDataInfo): boolean {
return this.selection.isSelected(alarm.id.id); return this.selection.isSelected(alarm);
} }
clearSelection() { clearSelection() {
@ -1312,7 +1327,7 @@ class AlarmsDatasource implements DataSource<AlarmDataInfo> {
} }
} else { } else {
alarms.forEach(row => { alarms.forEach(row => {
this.selection.select(row.id.id); this.selection.select(row);
}); });
if (numSelected === 0) { if (numSelected === 0) {
this.onSelectionModeChanged(true); this.onSelectionModeChanged(true);

View File

@ -102,6 +102,8 @@ export interface Alarm extends BaseData<AlarmId> {
originator: EntityId; originator: EntityId;
severity: AlarmSeverity; severity: AlarmSeverity;
status: AlarmStatus; status: AlarmStatus;
acknowledged: boolean;
cleared: boolean;
startTs: number; startTs: number;
endTs: number; endTs: number;
ackTs: number; ackTs: number;
@ -181,6 +183,8 @@ export const simulatedAlarm: AlarmInfo = {
type: 'TEMPERATURE', type: 'TEMPERATURE',
severity: AlarmSeverity.MAJOR, severity: AlarmSeverity.MAJOR,
status: AlarmStatus.ACTIVE_UNACK, status: AlarmStatus.ACTIVE_UNACK,
acknowledged: false,
cleared: false,
details: { details: {
message: 'Temperature is high!' message: 'Temperature is high!'
}, },