Skip to content

Commit 29b52f1

Browse files
committed
fix: enhance action sidebar functionality with infinite scroll and loading state management
1 parent 694b643 commit 29b52f1

File tree

8 files changed

+76
-21
lines changed

8 files changed

+76
-21
lines changed

frontend/src/app/incident-response/playbooks/playbook.service.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,4 +40,9 @@ export class PlaybookService {
4040
loadData(request: any){
4141
this.request$.next(request);
4242
}
43+
44+
reset() {
45+
this.request$.next(null);
46+
this.totalItems.next(0);
47+
}
4348
}

frontend/src/app/incident-response/playbooks/playbooks.component.html

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ <h4 class="mb-1 font-weight-semibold text-muted">Start building</h4>
115115
</div>
116116
</div>
117117

118-
<app-utm-spinner class="position-absolute right-50" [height]="'110px'" [loading]="(playbookService.loading$ | async)" [width]="'110px'"
118+
<app-utm-spinner *ngIf="(playbookService.loading$ | async)" class="position-absolute right-50" [height]="'110px'" [loading]="loading" [width]="'110px'"
119119
label="Loading playbooks">
120120
</app-utm-spinner>
121121

@@ -127,7 +127,7 @@ <h4 class="mb-1 font-weight-semibold text-muted">Start building</h4>
127127
[boundaryLinks]="true"
128128
[collectionSize]="totalItems"
129129
[maxSize]="10"
130-
[pageSize]="5"
130+
[pageSize]="itemsPerPage"
131131
[rotate]="true"
132132
[size]="'sm'"></ngb-pagination>
133133

frontend/src/app/incident-response/playbooks/playbooks.component.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import {AfterViewInit, Component, OnInit} from '@angular/core';
1+
import {AfterViewInit, Component, OnDestroy, OnInit} from '@angular/core';
22
import {NgbModal} from '@ng-bootstrap/ng-bootstrap';
33
import {Observable, of} from 'rxjs';
44
import {catchError, finalize, map, tap} from 'rxjs/operators';
@@ -19,7 +19,7 @@ import {NewPlaybookComponent} from "../shared/component/new-playbook/new-playboo
1919
templateUrl: './playbooks.component.html',
2020
styleUrls: ['./playbooks.component.scss']
2121
})
22-
export class PlaybooksComponent implements OnInit, AfterViewInit {
22+
export class PlaybooksComponent implements OnInit, AfterViewInit, OnDestroy {
2323
loading = true;
2424
rules: IncidentRuleType[];
2525
range: TimeFilterType;
@@ -143,4 +143,8 @@ export class PlaybooksComponent implements OnInit, AfterViewInit {
143143
newPlaybook() {
144144
this.modalService.open(NewPlaybookComponent, {size: 'lg', backdrop: 'static', centered: true});
145145
}
146+
147+
ngOnDestroy(): void {
148+
this.playbookService.reset();
149+
}
146150
}

frontend/src/app/incident-response/shared/component/action-builder/action-builder.component.html

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -86,27 +86,26 @@ <h4 class="panel-title m-0">Flow Actions</h4>
8686

8787
<div *ngFor="let action of workflow; let first = first" class="action-wrapper d-flex flex-column w-100">
8888
<!-- Action block -->
89-
<div (click)="openActionSidebar(action)" class="action-block cursor-pointer d-flex flex-column w-100 p-2" style="height: 120px;">
89+
<div class="action-block cursor-pointer d-flex flex-column w-100 p-2" style="height: 120px;">
9090

91-
<div class="d-flex justify-content-between align-items-center w-100 mb-1">
92-
<div class="fw-bold pl-2">{{ action.title }}</div>
91+
<div style="min-height: 37px" class="d-flex justify-content-between align-items-end w-100 mb-1">
92+
<div class="fw-bold action-title">{{ action.title }}</div>
9393
<div class="d-flex align-items-center">
9494
<app-action-conditional
9595
*ngIf="!first"
9696
[option]="action.conditional"
9797
(optionChange)="updateAction(action, $event)">
9898
</app-action-conditional>
99-
<div
100-
class="icon-cross2 font-size-xs cursor-pointer ml-2"
99+
<div style="min-height: 37px" class="d-flex flex-column justify-content-start icon-cross2 font-size-xs cursor-pointer ml-2"
101100
(click)="removeAction(action)">
102101
</div>
103102
</div>
104103
</div>
105104

106-
<div class="d-flex flex-grow-1 align-items-center w-100">
105+
<div (click)="openActionSidebar(action)" class="d-flex flex-grow-1 align-items-center w-100">
107106
<div class="icon-box mr-2" style="margin-right: 8px;"></div>
108107
<div class="d-flex flex-column w-100 justify-content-center">
109-
<div class="card-body pl-2 pr-0 py-2 w-100">
108+
<div class="card-body p-0 pl-2 pb-2 w-100">
110109
<div class="text-muted" style="
111110
display: -webkit-box;
112111
-webkit-line-clamp: 2;

frontend/src/app/incident-response/shared/component/action-builder/action-builder.component.scss

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,5 +141,13 @@
141141
box-shadow: unset;
142142
}
143143

144+
.action-title {
145+
padding-left: 47px;
146+
}
147+
148+
.icon-cross2:before {
149+
color: #495057!important;
150+
}
151+
144152

145153

frontend/src/app/incident-response/shared/component/action-sidebar/action-sidebar.component.html

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,14 @@
1919
</div>
2020

2121

22-
<div class="px-3 pb-3 overflow-auto flex-grow-1">
22+
<div
23+
infiniteScroll
24+
(scrolled)="onScroll()"
25+
[fromRoot]="true"
26+
[infiniteScrollDistance]="1"
27+
[infiniteScrollThrottle]="80"
28+
[scrollWindow]="false"
29+
class="px-3 pb-3 overflow-auto flex-grow-1">
2330
<div *ngFor="let action of actionSidebarService.actionTemplates$ | async"
2431
class="card mb-3 action-block shadow-sm cursor-pointer"
2532
(click)="addToWorkFlow(action)">
@@ -33,7 +40,9 @@
3340
</div>
3441
</div>
3542
</div>
36-
43+
<app-utm-spinner *ngIf="actionSidebarService.loading$ | async as loading"
44+
[loading]="loading" label="Loading actions...">
45+
</app-utm-spinner>
3746
<div class="card mb-3 available-action phantom-action"
3847
(click)="openActionSidebar()">
3948
<div class="card-body d-flex flex-column px-2">

frontend/src/app/incident-response/shared/component/action-sidebar/action-sidebar.component.ts

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Component, OnInit } from '@angular/core';
1+
import {Component, OnDestroy, OnInit} from '@angular/core';
22
import {NgbModal} from '@ng-bootstrap/ng-bootstrap';
33
import {WorkflowActionsService} from '../../services/workflow-actions.service';
44
import {ActionTerminalComponent} from '../action-terminal/action-terminal.component';
@@ -9,11 +9,11 @@ import {ActionSidebarService} from './action-sidebar.service';
99
templateUrl: './action-sidebar.component.html',
1010
styleUrls: ['./action-sidebar.component.scss']
1111
})
12-
export class ActionSidebarComponent implements OnInit {
12+
export class ActionSidebarComponent implements OnInit, OnDestroy {
1313

1414
request = {
1515
page: 0,
16-
size: 25,
16+
size: 5,
1717
'systemOwner.equals': true
1818
};
1919

@@ -53,4 +53,15 @@ export class ActionSidebarComponent implements OnInit {
5353
},
5454
);
5555
}
56+
57+
onScroll() {
58+
this.actionSidebarService.loadData({
59+
...this.request,
60+
size: this.request.size + 10,
61+
});
62+
}
63+
64+
ngOnDestroy() {
65+
this.actionSidebarService.reset();
66+
}
5667
}
Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import {HttpResponse} from '@angular/common/http';
22
import {Injectable} from '@angular/core';
3-
import {BehaviorSubject} from 'rxjs';
4-
import {map, switchMap} from 'rxjs/operators';
3+
import {BehaviorSubject, of} from 'rxjs';
4+
import {catchError, filter, finalize, map, switchMap, tap} from 'rxjs/operators';
5+
import {UtmToastService} from '../../../../shared/alert/utm-toast.service';
56
import {
67
IncidentResponseActionTemplate,
78
IncidentResponseActionTemplateService
@@ -13,18 +14,36 @@ import {
1314
export class ActionSidebarService {
1415

1516
private request = new BehaviorSubject<any>(null);
17+
private loading = new BehaviorSubject<boolean>(false);
18+
1619
request$ = this.request.asObservable();
20+
loading$ = this.loading.asObservable();
1721

1822
actionTemplates$ = this.request$
1923
.pipe(
20-
switchMap((request) => this.incidentResponseActionTemplateService.query(request)),
21-
map((response: HttpResponse<IncidentResponseActionTemplate[]>) => response.body)
24+
filter(request => !!request),
25+
tap(() => this.loading.next(true)),
26+
switchMap((request) => this.incidentResponseActionTemplateService.query(request)
27+
.pipe(
28+
map((response: HttpResponse<IncidentResponseActionTemplate[]>) => response.body),
29+
catchError(() => {
30+
this.toastService.showError('Error', 'Failed to load action templates');
31+
return of([]);
32+
}),
33+
finalize(() => this.loading.next(false))
34+
)
35+
),
2236
);
2337

24-
constructor(private incidentResponseActionTemplateService: IncidentResponseActionTemplateService) {}
38+
constructor(private incidentResponseActionTemplateService: IncidentResponseActionTemplateService,
39+
private toastService: UtmToastService,) {}
2540

2641
loadData(request: any) {
2742
this.request.next(request);
2843
}
2944

45+
reset() {
46+
this.request.next(null);
47+
}
48+
3049
}

0 commit comments

Comments
 (0)