diff --git a/web/src/main/angular/src/app/core/components/agent-info/agent-info-container.component.ts b/web/src/main/angular/src/app/core/components/agent-info/agent-info-container.component.ts
index f6e87b25ef07..6104814a9f98 100644
--- a/web/src/main/angular/src/app/core/components/agent-info/agent-info-container.component.ts
+++ b/web/src/main/angular/src/app/core/components/agent-info/agent-info-container.component.ts
@@ -46,7 +46,8 @@ export class AgentInfoContainerComponent implements OnInit, OnDestroy {
this.connectStore();
this.inspectorPageService.sourceForAgentInfo$.pipe(
takeUntil(this.unsubscribe),
- tap(() => this.showLoading = true),
+ filter(Boolean),
+ // tap(() => this.showLoading = true),
switchMap(({agentId, selectedTime}: ISourceForAgentInfo) => {
this.lastRequestParam = [agentId, selectedTime];
return this.agentInfoDataService.getData(agentId, selectedTime).pipe(
@@ -70,6 +71,7 @@ export class AgentInfoContainerComponent implements OnInit, OnDestroy {
ngOnDestroy() {
this.unsubscribe.next();
this.unsubscribe.complete();
+ this.inspectorPageService.reset('agentInfo');
}
private connectStore(): void {
diff --git a/web/src/main/angular/src/app/core/components/configuration-agent-statistic/configuration-agent-statistic-container.component.ts b/web/src/main/angular/src/app/core/components/configuration-agent-statistic/configuration-agent-statistic-container.component.ts
index 910263d06300..79274f836aac 100644
--- a/web/src/main/angular/src/app/core/components/configuration-agent-statistic/configuration-agent-statistic-container.component.ts
+++ b/web/src/main/angular/src/app/core/components/configuration-agent-statistic/configuration-agent-statistic-container.component.ts
@@ -2,7 +2,7 @@ import { Component, OnInit, OnDestroy, ComponentFactoryResolver, Injector } from
import { TranslateService } from '@ngx-translate/core';
import { Subject, forkJoin, Observable } from 'rxjs';
import * as moment from 'moment-timezone';
-import { map, tap } from 'rxjs/operators';
+import { map, takeUntil, tap } from 'rxjs/operators';
import { StoreHelperService, AnalyticsService, TRACKED_EVENT_LIST, DynamicPopupService } from 'app/shared/services';
import { AgentStatisticDataService } from './agent-statistic-data.service';
@@ -78,7 +78,9 @@ export class ConfigurationAgentStatisticContainerComponent implements OnInit, On
}
this.showProcessing();
- this.agentStatisticDataService.getData().subscribe((agentList: IAgentList) => {
+ this.agentStatisticDataService.getData().pipe(
+ takeUntil(this.unsubscribe)
+ ).subscribe((agentList: IAgentList) => {
this.storeHelperService.dispatch(new Actions.UpdateAdminAgentList(agentList));
this.hideProcessing();
}, (error: IServerError) => {
diff --git a/web/src/main/angular/src/app/core/components/inspector-chart/agent-data-source-chart-container.component.ts b/web/src/main/angular/src/app/core/components/inspector-chart/agent-data-source-chart-container.component.ts
index 59e69dd60a92..9a16b10c205e 100644
--- a/web/src/main/angular/src/app/core/components/inspector-chart/agent-data-source-chart-container.component.ts
+++ b/web/src/main/angular/src/app/core/components/inspector-chart/agent-data-source-chart-container.component.ts
@@ -73,6 +73,7 @@ export class AgentDataSourceChartContainerComponent implements OnInit, OnDestroy
ngOnDestroy() {
this.unsubscribe.next();
this.unsubscribe.complete();
+ this.inspectorPageService.reset('chart');
}
private initI18nText(): void {
@@ -151,7 +152,8 @@ export class AgentDataSourceChartContainerComponent implements OnInit, OnDestroy
private initChartData(): void {
this.inspectorPageService.sourceForChart$.pipe(
takeUntil(this.unsubscribe),
- tap(() => this.activeLayer = Layer.LOADING),
+ filter(Boolean),
+ // tap(() => this.activeLayer = Layer.LOADING),
tap(({range}: ISourceForChart) => this.previousRange = range),
switchMap(({range}: ISourceForChart) => {
return this.inspectorChartDataService.getData(range).pipe(
diff --git a/web/src/main/angular/src/app/core/components/inspector-chart/application-data-source-chart-container.component.ts b/web/src/main/angular/src/app/core/components/inspector-chart/application-data-source-chart-container.component.ts
index 72a24a70d745..30d6e45d20af 100644
--- a/web/src/main/angular/src/app/core/components/inspector-chart/application-data-source-chart-container.component.ts
+++ b/web/src/main/angular/src/app/core/components/inspector-chart/application-data-source-chart-container.component.ts
@@ -62,6 +62,7 @@ export class ApplicationDataSourceChartContainerComponent implements OnInit, OnD
ngOnDestroy() {
this.unsubscribe.next();
this.unsubscribe.complete();
+ this.inspectorPageService.reset('chart');
}
private initI18nText(): void {
@@ -100,7 +101,8 @@ export class ApplicationDataSourceChartContainerComponent implements OnInit, OnD
private initChartData(): void {
this.inspectorPageService.sourceForChart$.pipe(
takeUntil(this.unsubscribe),
- tap(() => this.activeLayer = Layer.LOADING),
+ filter(Boolean),
+ // tap(() => this.activeLayer = Layer.LOADING),
tap(({range}: ISourceForChart) => this.previousRange = range),
switchMap(({range}: ISourceForChart) => {
return this.inspectorChartDataService.getData(range).pipe(
diff --git a/web/src/main/angular/src/app/core/components/inspector-chart/inspector-chart-container.component.ts b/web/src/main/angular/src/app/core/components/inspector-chart/inspector-chart-container.component.ts
index 65dca9ee9382..69d1f60942b2 100644
--- a/web/src/main/angular/src/app/core/components/inspector-chart/inspector-chart-container.component.ts
+++ b/web/src/main/angular/src/app/core/components/inspector-chart/inspector-chart-container.component.ts
@@ -88,6 +88,7 @@ export class InspectorChartContainerComponent implements OnInit, OnDestroy {
ngOnDestroy() {
this.unsubscribe.next();
this.unsubscribe.complete();
+ this.inspectorPageService.reset('chart');
}
private initI18nText(): void {
@@ -136,7 +137,8 @@ export class InspectorChartContainerComponent implements OnInit, OnDestroy {
private initChartData(): void {
this.inspectorPageService.sourceForChart$.pipe(
takeUntil(this.unsubscribe),
- tap(() => this.activeLayer = Layer.LOADING),
+ filter(Boolean),
+ // tap(() => this.activeLayer = Layer.LOADING),
tap(({range}: ISourceForChart) => this.previousRange = range),
switchMap(({range}: ISourceForChart) => {
return this.chartContainer.getData(range).pipe(
diff --git a/web/src/main/angular/src/app/core/components/metric/metric-container.component.ts b/web/src/main/angular/src/app/core/components/metric/metric-container.component.ts
index 0c37e58ac92d..146038df04d0 100644
--- a/web/src/main/angular/src/app/core/components/metric/metric-container.component.ts
+++ b/web/src/main/angular/src/app/core/components/metric/metric-container.component.ts
@@ -70,7 +70,7 @@ export class MetricContainerComponent implements OnInit, OnDestroy {
filter((urlService: NewUrlStateNotificationService) => {
return !this.chartConfig || (urlService.isValueChanged(UrlPathId.PERIOD) || urlService.isValueChanged(UrlPathId.END_TIME));
}),
- tap(() => this.activeLayer = Layer.LOADING),
+ // tap(() => this.activeLayer = Layer.LOADING),
switchMap((urlService: NewUrlStateNotificationService) => {
const hostGroupName = urlService.getPathValue(UrlPathId.HOST_GROUP);
const hostName = urlService.getPathValue(UrlPathId.HOST);
diff --git a/web/src/main/angular/src/app/core/components/server-and-agent-list/server-and-agent-list-container.component.css b/web/src/main/angular/src/app/core/components/server-and-agent-list/server-and-agent-list-container.component.css
index f09a3ba168b9..57401af7535b 100644
--- a/web/src/main/angular/src/app/core/components/server-and-agent-list/server-and-agent-list-container.component.css
+++ b/web/src/main/angular/src/app/core/components/server-and-agent-list/server-and-agent-list-container.component.css
@@ -1,6 +1,6 @@
:host {
display: block;
- height: calc(100% - 41px); /* 41px: title height */
+ height: calc(100% - 40px); /* 40px: title height */
}
.guide-text {
@@ -21,6 +21,52 @@
gap: 7px;
}
+.list-wrapper {
+ width: 100%;
+ position: relative;
+ height: calc(100% - 48px - 32px); /* search area(48px) + sort area(32px) */
+}
+
+.sort-option-wrapper {
+ display: flex;
+ align-items: center;;
+ width: 100%;
+ height: 32px;
+ padding:0px 15px 8px;
+ border-bottom: 1px solid var(--border-primary);
+ gap: 2px;
+}
+
+.sort-label {
+ font-size: 12px;
+ color: var(--text-secondary);
+}
+
+.sort-option-list-wrapper {
+ flex: 1;
+ display: flex;
+ /* gap: 5px; */
+}
+
+.sort-option {
+ font-size: 12px;
+ color: var(--text-secondary);
+ padding: 3px 6px;
+ border-radius: 3px;
+ cursor: pointer;
+}
+
+.sort-option:hover {
+ /* background: var(--background-hover-default); */
+ /* font-weight: bold; */
+ color: var(--primary);
+}
+
+.sort-option.active {
+ font-weight: bold;
+ color: var(--primary);
+}
+
.search-input-wrapper {
flex: 1;
height: 100%;
@@ -56,7 +102,7 @@
font-size: 12px;
}
-.fa-question-circle {
+.fas {
color: var(--icon-default);
font-size: 18px;
}
diff --git a/web/src/main/angular/src/app/core/components/server-and-agent-list/server-and-agent-list-container.component.html b/web/src/main/angular/src/app/core/components/server-and-agent-list/server-and-agent-list-container.component.html
index 62ceb572c2d2..1ef6c2b89803 100644
--- a/web/src/main/angular/src/app/core/components/server-and-agent-list/server-and-agent-list-container.component.html
+++ b/web/src/main/angular/src/app/core/components/server-and-agent-list/server-and-agent-list-container.component.html
@@ -10,16 +10,29 @@
+
+
Sort by:
+
+
+ {{sortOption.display}}
+
+
+
{{errorMessage ? errorMessage : emptyText$ | async}}
-
-
+
diff --git a/web/src/main/angular/src/app/core/components/server-and-agent-list/server-and-agent-list-container.component.ts b/web/src/main/angular/src/app/core/components/server-and-agent-list/server-and-agent-list-container.component.ts
index 7baa19fffe48..93e381cc119a 100644
--- a/web/src/main/angular/src/app/core/components/server-and-agent-list/server-and-agent-list-container.component.ts
+++ b/web/src/main/angular/src/app/core/components/server-and-agent-list/server-and-agent-list-container.component.ts
@@ -20,6 +20,11 @@ import { ServerAndAgentListDataService } from './server-and-agent-list-data.serv
import { isEmpty, isThatType } from 'app/core/utils/util';
import { HELP_VIEWER_LIST, HelpViewerPopupContainerComponent } from 'app/core/components/help-viewer-popup/help-viewer-popup-container.component';
+export const enum SortOption {
+ ID = 'id',
+ NAME = 'name',
+ RECENT = 'recent'
+}
@Component({
selector: 'pp-server-and-agent-list-container',
templateUrl: './server-and-agent-list-container.component.html',
@@ -28,10 +33,12 @@ import { HELP_VIEWER_LIST, HelpViewerPopupContainerComponent } from 'app/core/co
export class ServerAndAgentListContainerComponent implements OnInit, OnDestroy {
private unsubscribe = new Subject();
private _query = '';
+ private previousParams: {app: string, range: number[]};
+ private cachedData = {} as {[key in SortOption]: IServerAndAgentDataV2[]};
agentId: string;
- serverList: {[key: string]: IServerAndAgentData[]};
- filteredServerList: {[key: string]: IServerAndAgentData[]} = {};
+ serverList: IServerAndAgentDataV2[];
+ filteredServerList: IServerAndAgentDataV2[] = [];
filteredServerKeyList: string[] = [];
funcImagePath: Function;
isEmpty: boolean;
@@ -40,6 +47,15 @@ export class ServerAndAgentListContainerComponent implements OnInit, OnDestroy {
inputPlaceholder$: Observable;
searchUseEnter = false;
SEARCH_MIN_LENGTH = 2;
+ sortOptionList = [
+ {display: 'ID', key: SortOption.ID},
+ {display: 'Name', key: SortOption.NAME},
+ {display: 'Recent', key: SortOption.RECENT}
+ ];
+ selectedSortOptionKey: SortOption;
+
+ useDisable: boolean;
+ showLoading: boolean;
constructor(
private newUrlStateNotificationService: NewUrlStateNotificationService,
@@ -58,17 +74,25 @@ export class ServerAndAgentListContainerComponent implements OnInit, OnDestroy {
ngOnInit() {
this.initI18nText();
this.funcImagePath = this.webAppSettingDataService.getImagePathMakeFunc();
+ this.selectedSortOptionKey = this.webAppSettingDataService.getAgentListSortOption() as SortOption || SortOption.ID;
merge(
this.newUrlStateNotificationService.onUrlStateChange$.pipe(
takeUntil(this.unsubscribe),
tap((urlService: NewUrlStateNotificationService) => {
this.agentId = urlService.getPathValue(UrlPathId.AGENT_ID);
+ const isAppChanged = urlService.isValueChanged(UrlPathId.APPLICATION);
+ const isPeriodChanged = urlService.isValueChanged(UrlPathId.PERIOD) || urlService.isValueChanged(UrlPathId.END_TIME);
+ const isRealTimeMode = urlService.isRealTimeMode();
+
+ // if (isAppChanged || isPeriodChanged || isRealTimeMode) {
+ if (isAppChanged) {
+ this.filteredServerList = [];
+ this.previousParams = null;
+ this.showLoading = true;
+ }
+
}),
- // TODO: Check valid filter for url
- // filter((urlService: NewUrlStateNotificationService) => {
- // return urlService.isValueChanged(UrlPathId.APPLICATION) || urlService.isValueChanged(UrlPathId.PERIOD) || urlService.isValueChanged(UrlPathId.END_TIME);
- // }),
map((urlService: NewUrlStateNotificationService) => {
if (urlService.isRealTimeMode()) {
const to = urlService.getUrlServerTimeData();
@@ -89,51 +113,55 @@ export class ServerAndAgentListContainerComponent implements OnInit, OnDestroy {
);
}),
pluck('range'),
+ filter(() => this.newUrlStateNotificationService.isRealTimeMode()),
)
).pipe(
- filter(() => this.newUrlStateNotificationService.hasValue(UrlPathId.APPLICATION)), // prevent getting event after the component has been destroyed
+ filter(() => this.newUrlStateNotificationService.hasValue(UrlPathId.APPLICATION)), // prevent from getting event after the component has been destroyed
concatMap((range: number[]) => {
- const appName = (this.newUrlStateNotificationService.getPathValue(UrlPathId.APPLICATION) as IApplication).getApplicationName();
- const requestStartAt = Date.now();
-
- return this.serverAndAgentListDataService.getData(appName, range).pipe(
- filter((res: {[key: string]: IServerAndAgentData[]} | IServerErrorShortFormat) => {
- // TODO: 민우님께 에러구분 여쭤보기. 401이면 AuthService 활용한다? 근데이럼 IS_ACCESS_DENYED 출처 불분명같은 문제가 있지않을까..
- if (isThatType(res, 'errorCode', 'errorMessage')) {
- this.errorMessage = res.errorMessage;
- this.messageQueueService.sendMessage({to: MESSAGE_TO.IS_ACCESS_DENYED, param: true});
- return false;
- } else {
- this.errorMessage = '';
- this.messageQueueService.sendMessage({to: MESSAGE_TO.IS_ACCESS_DENYED, param: false});
- return true;
- }
- }),
- filter((res: {[key: string]: IServerAndAgentData[]}) => {
- if (this.agentId) {
- const filteredList = this.filterServerList(res, this.agentId, ({agentId}: IServerAndAgentData) => this.agentId.toLowerCase() === agentId.toLowerCase());
- const isAgentIdValid = Object.keys(filteredList).length !== 0;
+ const urlService = this.newUrlStateNotificationService;
+ const isAppChanged = urlService.isValueChanged(UrlPathId.APPLICATION);
+ const isPeriodChanged = urlService.isValueChanged(UrlPathId.PERIOD) || urlService.isValueChanged(UrlPathId.END_TIME);
+ const isRealTimeMode = urlService.isRealTimeMode();
- if (isAgentIdValid) {
- return true;
- } else {
- const url = this.newUrlStateNotificationService.isRealTimeMode()
- ? [this.newUrlStateNotificationService.getStartPath(), UrlPathId.REAL_TIME, this.newUrlStateNotificationService.getPathValue(UrlPathId.APPLICATION).getUrlStr()]
- : [
- this.newUrlStateNotificationService.getStartPath(),
- this.newUrlStateNotificationService.getPathValue(UrlPathId.APPLICATION).getUrlStr(),
- this.newUrlStateNotificationService.getPathValue(UrlPathId.PERIOD).getValueWithTime(),
- this.newUrlStateNotificationService.getPathValue(UrlPathId.END_TIME).getEndTime()
- ];
+ const data = this.cachedData[this.selectedSortOptionKey];
- this.urlRouteManagerService.moveOnPage({url});
+ const app = (urlService.getPathValue(UrlPathId.APPLICATION) as IApplication).getApplicationName();
+ const requestStartAt = Date.now();
+ return iif(() => isEmpty(this.filteredServerList) || (isAppChanged || isPeriodChanged || isRealTimeMode),
+ this.serverAndAgentListDataService.getData(app, range, this.selectedSortOptionKey).pipe(
+ tap(() => {
+ this.previousParams = {app, range};
+ this.cachedData = {} as {[key in SortOption]: IServerAndAgentDataV2[]};
+ }),
+ filter((res: IServerAndAgentDataV2[] | IServerErrorShortFormat) => {
+ if (isThatType(res, 'errorCode', 'errorMessage')) {
+ this.errorMessage = res.errorMessage;
+ this.messageQueueService.sendMessage({to: MESSAGE_TO.IS_ACCESS_DENYED, param: true});
return false;
+ } else {
+ this.errorMessage = '';
+ this.messageQueueService.sendMessage({to: MESSAGE_TO.IS_ACCESS_DENYED, param: false});
+ return true;
}
- } else {
- return true;
- }
- }),
+ }),
+ catchError((error: IServerError) => {
+ this.dynamicPopupService.openPopup({
+ data: {
+ title: 'Error',
+ contents: error
+ },
+ component: ServerErrorPopupContainerComponent
+ }, {
+ resolver: this.componentFactoryResolver,
+ injector: this.injector
+ });
+
+ return EMPTY;
+ })
+ ),
+ of(data)
+ ).pipe(
tap(() => {
const responseArriveAt = Date.now();
const deltaT = responseArriveAt - requestStartAt;
@@ -148,27 +176,16 @@ export class ServerAndAgentListContainerComponent implements OnInit, OnDestroy {
}
});
}),
- catchError((error: IServerError) => {
- this.dynamicPopupService.openPopup({
- data: {
- title: 'Error',
- contents: error
- },
- component: ServerErrorPopupContainerComponent
- }, {
- resolver: this.componentFactoryResolver,
- injector: this.injector
- });
-
- return EMPTY;
- })
- );
- }),
- ).subscribe((data: {[key: string]: IServerAndAgentData[]}) => {
- this.serverList = data;
- this.filteredServerList = this.filterServerList(data, this.query);
- this.filteredServerKeyList = Object.keys(this.filteredServerList).sort();
+ )
+ })
+ ).subscribe((data: IServerAndAgentDataV2[]) => {
+ this.serverList = this.cachedData[this.selectedSortOptionKey] = data;
+ this.filteredServerList = this.filterServerList(this.serverList, this.query);
+ this.filteredServerKeyList = this.filteredServerList.map(({groupName}: IServerAndAgentDataV2) => groupName).sort();
this.isEmpty = isEmpty(this.filteredServerList);
+
+ this.useDisable = false;
+ this.showLoading = false;
});
}
@@ -201,20 +218,19 @@ export class ServerAndAgentListContainerComponent implements OnInit, OnDestroy {
];
this.urlRouteManagerService.moveOnPage({url});
- this.analyticsService.trackEvent(TRACKED_EVENT_LIST.SELECT_AGENT_ON_THE_LIST);
}
- private filterServerList(serverList: {[key: string]: IServerAndAgentData[]}, query: string, predi?: (data: IServerAndAgentData) => boolean): {[key: string]: IServerAndAgentData[]} {
- const filterCallback = predi ? predi : ({agentId, agentName}: IServerAndAgentData) => {
+ private filterServerList(serverList: IServerAndAgentDataV2[], query: string, predi?: (data: IAgentDataV2) => boolean): IServerAndAgentDataV2[] {
+ const filterCallback = predi ? predi : ({agentId, agentName}: IAgentDataV2) => {
return agentId.toLowerCase().includes(query.toLowerCase()) || (agentName && agentName.toLowerCase().includes(query.toLowerCase()));
};
return query === '' ? serverList
- : Object.entries(serverList).reduce((acc: {[key: string]: IServerAndAgentData[]}, [key, serverAndAgentDataList]: [string, IServerAndAgentData[]]) => {
- const matchedList = serverAndAgentDataList.filter(filterCallback);
-
- return isEmpty(matchedList) ? acc : {...acc, [key]: matchedList};
- }, {} as {[key: string]: IServerAndAgentData[]});
+ : serverList.reduce((acc: IServerAndAgentDataV2[], {groupName, instancesList}: IServerAndAgentDataV2) => {
+ const matchedList = instancesList.filter(filterCallback);
+
+ return isEmpty(matchedList) ? acc : [...acc, {groupName, instancesList: matchedList}]
+ }, []);
}
private set query(query: string) {
@@ -256,4 +272,55 @@ export class ServerAndAgentListContainerComponent implements OnInit, OnDestroy {
injector: this.injector
});
}
+
+ isActiveSortOption(optionKey: SortOption): boolean {
+ return optionKey === this.selectedSortOptionKey;
+ }
+
+ onSelectSortOption(optionKey: SortOption): void {
+ if (optionKey === this.selectedSortOptionKey || this.showLoading) {
+ return;
+ }
+
+ const {app, range} = this.previousParams;
+
+ of(optionKey).pipe(
+ switchMap((optionKey: SortOption) => {
+ if (Boolean(this.cachedData[optionKey])) {
+ return of(this.cachedData[optionKey]);
+ } else {
+ this.useDisable = true;
+ this.showLoading = true;
+
+ return this.serverAndAgentListDataService.getData(app, range, optionKey).pipe(
+ tap((data: IServerAndAgentDataV2[]) => {
+ this.useDisable = false;
+ this.showLoading = false;
+ this.serverList = this.cachedData[optionKey] = data;
+ }),
+ catchError((error: IServerError) => {
+ this.dynamicPopupService.openPopup({
+ data: {
+ title: 'Error',
+ contents: error
+ },
+ component: ServerErrorPopupContainerComponent
+ }, {
+ resolver: this.componentFactoryResolver,
+ injector: this.injector
+ });
+
+ return EMPTY;
+ })
+ );
+ }
+ })
+ ).subscribe((data: IServerAndAgentDataV2[]) => {
+ this.filteredServerList = this.filterServerList(data, this.query);
+ this.filteredServerKeyList = this.filteredServerList.map(({groupName}: IServerAndAgentDataV2) => groupName).sort();
+ this.isEmpty = isEmpty(this.filteredServerList);
+ this.selectedSortOptionKey = optionKey;
+ this.webAppSettingDataService.setAgentListSortOption(optionKey);
+ });
+ }
}
diff --git a/web/src/main/angular/src/app/core/components/server-and-agent-list/server-and-agent-list-data.service.ts b/web/src/main/angular/src/app/core/components/server-and-agent-list/server-and-agent-list-data.service.ts
index 6895e10a15e5..aaac26c4ae34 100644
--- a/web/src/main/angular/src/app/core/components/server-and-agent-list/server-and-agent-list-data.service.ts
+++ b/web/src/main/angular/src/app/core/components/server-and-agent-list/server-and-agent-list-data.service.ts
@@ -2,21 +2,36 @@ import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';
+import { SortOption } from './server-and-agent-list-container.component';
+
+
+const enum SortOptionParamKey {
+ ID = 'AGENT_ID_ASC',
+ NAME = 'AGENT_NAME_ASC',
+ RECENT = 'RECENT'
+}
@Injectable()
export class ServerAndAgentListDataService {
- private url = 'getAgentList.pinpoint';
+ private url = 'agents/search-application.pinpoint';
constructor(
private http: HttpClient,
) {}
- getData(applicationName: string, range: number[]): Observable<{[key: string]: IServerAndAgentData[]}> {
- return this.http.get<{[key: string]: IServerAndAgentData[]}>(this.url, this.makeRequestOptionsArgs(applicationName, range));
+ getData(applicationName: string, range: number[], sortOption: SortOption): Observable {
+ return this.http.get(this.url, this.makeRequestOptionsArgs(applicationName, range, sortOption));
}
- private makeRequestOptionsArgs(application: string, [from, to]: number[]): object {
+ private makeRequestOptionsArgs(application: string, [from, to]: number[], sortOption: SortOption): object {
return {
- params: { application, from, to }
+ params: {
+ application,
+ from,
+ to,
+ sortBy: sortOption === SortOption.ID ? SortOptionParamKey.ID
+ : sortOption === SortOption.NAME ? SortOptionParamKey.NAME
+ : SortOptionParamKey.RECENT
+ }
};
}
}
diff --git a/web/src/main/angular/src/app/core/components/server-and-agent-list/server-and-agent-list.component.css b/web/src/main/angular/src/app/core/components/server-and-agent-list/server-and-agent-list.component.css
index f6049116b904..cc2c1de05dc0 100644
--- a/web/src/main/angular/src/app/core/components/server-and-agent-list/server-and-agent-list.component.css
+++ b/web/src/main/angular/src/app/core/components/server-and-agent-list/server-and-agent-list.component.css
@@ -1,7 +1,6 @@
:host {
display: block;
- /* height: 100%; */
- height: calc(100% - 48px);
+ height: 100%;
overflow-y: auto;
font-size: 13px;
}
diff --git a/web/src/main/angular/src/app/core/components/server-and-agent-list/server-and-agent-list.component.html b/web/src/main/angular/src/app/core/components/server-and-agent-list/server-and-agent-list.component.html
index ba41f0949864..31e3469198f8 100644
--- a/web/src/main/angular/src/app/core/components/server-and-agent-list/server-and-agent-list.component.html
+++ b/web/src/main/angular/src/app/core/components/server-and-agent-list/server-and-agent-list.component.html
@@ -1,16 +1,16 @@
- -
-
+
-
+
- {{serverName}}
+ {{server.groupName}}
-
+
-
- -
+
+ -
- {{agent.agentId}}
+ {{getAgentLabel(agent)}}
diff --git a/web/src/main/angular/src/app/core/components/server-and-agent-list/server-and-agent-list.component.ts b/web/src/main/angular/src/app/core/components/server-and-agent-list/server-and-agent-list.component.ts
index e9f9fc2252af..f9590912eb06 100644
--- a/web/src/main/angular/src/app/core/components/server-and-agent-list/server-and-agent-list.component.ts
+++ b/web/src/main/angular/src/app/core/components/server-and-agent-list/server-and-agent-list.component.ts
@@ -1,5 +1,8 @@
import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core';
import { trigger, state, style, animate, transition } from '@angular/animations';
+
+import { SortOption } from './server-and-agent-list-container.component';
+
@Component({
selector: 'pp-server-and-agent-list',
templateUrl: './server-and-agent-list.component.html',
@@ -46,8 +49,9 @@ export class ServerAndAgentListComponent implements OnInit {
return this._serverKeyList;
}
- @Input() serverList: {[key: string]: IServerAndAgentData[]};
+ @Input() serverList: IServerAndAgentDataV2[];
@Input() agentId: string;
+ @Input() selectedSortOptionKey: SortOption
@Output() outSelectAgent = new EventEmitter();
private _serverKeyList: string[];
@@ -91,4 +95,15 @@ export class ServerAndAgentListComponent implements OnInit {
return el.classList.contains('active');
});
}
+
+ getAgentLabel({agentId, agentName}: IServerAndAgentData): string {
+ switch (this.selectedSortOptionKey) {
+ case SortOption.ID:
+ case SortOption.RECENT:
+ default:
+ return agentName ? `${agentId} (${agentName})` : `${agentId} (N/A)`;
+ case SortOption.NAME:
+ return agentName ? agentName : `N/A (${agentId})`;
+ }
+ }
}
diff --git a/web/src/main/angular/src/app/core/components/timeline-command-group/timeline-command-group-container.component.ts b/web/src/main/angular/src/app/core/components/timeline-command-group/timeline-command-group-container.component.ts
index 99277449ed18..712d48698af8 100644
--- a/web/src/main/angular/src/app/core/components/timeline-command-group/timeline-command-group-container.component.ts
+++ b/web/src/main/angular/src/app/core/components/timeline-command-group/timeline-command-group-container.component.ts
@@ -28,6 +28,7 @@ export class TimelineCommandGroupContainerComponent implements OnInit, OnDestroy
ngOnDestroy() {
this.unsubscribe.next();
this.unsubscribe.complete();
+ this.inspectorPageService.reset('timelineCommand');
}
private connectStore(): void {
@@ -37,7 +38,8 @@ export class TimelineCommandGroupContainerComponent implements OnInit, OnDestroy
// this.storeHelperService.getInspectorTimelineSelectedTime(this.unsubscribe).pipe(filter((time: number) => time !== 0))
this.inspectorPageService.sourceForTimelineCommand$.pipe(
takeUntil(this.unsubscribe),
- pluck('selectedTime')
+ filter(Boolean),
+ pluck('selectedTime'),
)
).pipe(
map(([dateFormat, timezone, pointingTime]: [string, string, number]) => {
diff --git a/web/src/main/angular/src/app/core/components/timeline/agent-inspector-timeline-container.component.ts b/web/src/main/angular/src/app/core/components/timeline/agent-inspector-timeline-container.component.ts
index f742c828a4de..01b165780ad7 100644
--- a/web/src/main/angular/src/app/core/components/timeline/agent-inspector-timeline-container.component.ts
+++ b/web/src/main/angular/src/app/core/components/timeline/agent-inspector-timeline-container.component.ts
@@ -1,6 +1,6 @@
import { Component, OnInit, OnDestroy, ViewChild, ComponentFactoryResolver, Injector } from '@angular/core';
import { Subject, Observable, EMPTY } from 'rxjs';
-import { map, switchMap, takeUntil, catchError } from 'rxjs/operators';
+import { map, switchMap, takeUntil, catchError, filter } from 'rxjs/operators';
import { StoreHelperService, NewUrlStateNotificationService, AnalyticsService, DynamicPopupService, TRACKED_EVENT_LIST, MessageQueueService, MESSAGE_TO } from 'app/shared/services';
import { ITimelineEventSegment, TimelineUIEvent } from './class';
@@ -71,6 +71,7 @@ export class AgentInspectorTimelineContainerComponent implements OnInit, OnDestr
this.inspectorPageService.sourceForTimeline$.pipe(
takeUntil(this.unsubscribe),
+ filter(Boolean),
map(({timelineInfo, agentId}: ISourceForTimeline) => {
const {range, selectionRange, selectedTime} = timelineInfo;
@@ -107,6 +108,7 @@ export class AgentInspectorTimelineContainerComponent implements OnInit, OnDestr
ngOnDestroy() {
this.unsubscribe.next();
this.unsubscribe.complete();
+ this.inspectorPageService.reset('timeline');
}
private connectStore(): void {
this.timezone$ = this.storeHelperService.getTimezone(this.unsubscribe);
diff --git a/web/src/main/angular/src/app/core/components/timeline/application-inspector-timeline-container.component.ts b/web/src/main/angular/src/app/core/components/timeline/application-inspector-timeline-container.component.ts
index 5cddb865d307..0e8185c1c485 100644
--- a/web/src/main/angular/src/app/core/components/timeline/application-inspector-timeline-container.component.ts
+++ b/web/src/main/angular/src/app/core/components/timeline/application-inspector-timeline-container.component.ts
@@ -1,6 +1,6 @@
import { Component, OnInit, OnDestroy, ViewChild } from '@angular/core';
import { Subject, Observable } from 'rxjs';
-import { takeUntil } from 'rxjs/operators';
+import { filter, takeUntil } from 'rxjs/operators';
import { StoreHelperService, AnalyticsService, TRACKED_EVENT_LIST, MessageQueueService, MESSAGE_TO } from 'app/shared/services';
import { ITimelineEventSegment, TimelineUIEvent } from './class';
@@ -61,6 +61,7 @@ export class ApplicationInspectorTimelineContainerComponent implements OnInit, O
this.inspectorPageService.sourceForTimeline$.pipe(
takeUntil(this.unsubscribe),
+ filter(Boolean),
).subscribe(({timelineInfo: {range, selectionRange, selectedTime}}: ISourceForTimeline) => {
this.timelineStartTime = range[0];
this.timelineEndTime = range[1];
@@ -87,6 +88,7 @@ export class ApplicationInspectorTimelineContainerComponent implements OnInit, O
ngOnDestroy() {
this.unsubscribe.next();
this.unsubscribe.complete();
+ this.inspectorPageService.reset('timeline');
}
private connectStore(): void {
this.timezone$ = this.storeHelperService.getTimezone(this.unsubscribe);
diff --git a/web/src/main/angular/src/app/core/components/url-statistic-chart/url-statistic-chart-container.component.ts b/web/src/main/angular/src/app/core/components/url-statistic-chart/url-statistic-chart-container.component.ts
index 6d8d814660d4..8616254db0b9 100644
--- a/web/src/main/angular/src/app/core/components/url-statistic-chart/url-statistic-chart-container.component.ts
+++ b/web/src/main/angular/src/app/core/components/url-statistic-chart/url-statistic-chart-container.component.ts
@@ -99,7 +99,7 @@ export class UrlStatisticChartContainerComponent implements OnInit, OnDestroy {
const agentId = urlService.getPathValue(UrlPathId.AGENT_ID) || '';
const params = this.previousParams = {from, to, applicationName, agentId, uri};
- this.activeLayer = Layer.LOADING;
+ // this.activeLayer = Layer.LOADING;
return this.urlStatisticChartDataService.getData(params).pipe(
map(({timestamp, metricValueGroups}: IUrlStatChartData) => {
this.cachedData[uri] = {timestamp, metricValues: metricValueGroups[0].metricValues};
diff --git a/web/src/main/angular/src/app/routes/inspector-page/inspector-page.service.ts b/web/src/main/angular/src/app/routes/inspector-page/inspector-page.service.ts
index dc88eccd3504..18397d0633f5 100644
--- a/web/src/main/angular/src/app/routes/inspector-page/inspector-page.service.ts
+++ b/web/src/main/angular/src/app/routes/inspector-page/inspector-page.service.ts
@@ -1,5 +1,5 @@
import { Injectable } from '@angular/core';
-import { Observable, Subject, BehaviorSubject } from 'rxjs';
+import { Observable, Subject, ReplaySubject } from 'rxjs';
import {
NewUrlStateNotificationService,
@@ -30,10 +30,14 @@ export interface ISourceForTimelineCommand {
@Injectable()
export class InspectorPageService {
- private sourceForTimeline = new Subject();
- private sourceForAgentInfo = new Subject();
- private sourceForChart = new Subject();
- private sourceForTimelineCommand = new Subject();
+ // private sourceForTimeline = new Subject();
+ // private sourceForAgentInfo = new Subject();
+ // private sourceForChart = new Subject();
+ // private sourceForTimelineCommand = new Subject();
+ private sourceForTimeline = new ReplaySubject(1);
+ private sourceForAgentInfo = new ReplaySubject(1);
+ private sourceForChart = new ReplaySubject(1);
+ private sourceForTimelineCommand = new ReplaySubject(1);
private timelineInfo: ITimelineInfo;
private agentId: string;
@@ -54,6 +58,23 @@ export class InspectorPageService {
this.sourceForTimelineCommand$ = this.sourceForTimelineCommand.asObservable();
}
+ reset(id: string): void {
+ switch(id) {
+ case 'timelineCommand':
+ this.sourceForTimelineCommand.next(null);
+ break;
+ case 'timeline':
+ this.sourceForTimeline.next(null);
+ break;
+ case 'chart':
+ this.sourceForChart.next(null);
+ break;
+ case 'agentInfo':
+ this.sourceForAgentInfo.next(null);
+ break;
+ }
+ }
+
activate(unsubscribe: Subject): void {
this.messageQueueService.receiveMessage(unsubscribe, MESSAGE_TO.AGENT_LIST_VALID).subscribe(({range, now, agentId}: {range: number[], now: number, agentId: string}) => {
this.agentId = agentId;
diff --git a/web/src/main/angular/src/app/shared/services/web-app-setting-data.service.ts b/web/src/main/angular/src/app/shared/services/web-app-setting-data.service.ts
index 2ea876deb848..7441914edf6c 100644
--- a/web/src/main/angular/src/app/shared/services/web-app-setting-data.service.ts
+++ b/web/src/main/angular/src/app/shared/services/web-app-setting-data.service.ts
@@ -35,6 +35,7 @@ export class WebAppSettingDataService {
LANGUAGE: 'language',
THEME: 'theme',
SIDE_NAV_BAR_SCALE: 'sideNavigationBarScale',
+ AGENT_LIST_SORT_OPTION: 'agentListSortOption'
};
private IMAGE_PATH = './assets/img/';
private IMAGE_EXT = '.png';
@@ -308,4 +309,10 @@ export class WebAppSettingDataService {
getUrlStatFieldNameList(): string[] {
return this.componentDefaultSettingDataService.getUrlStatFieldNameList();
}
+ setAgentListSortOption(sortOption: string): void {
+ this.localStorageService.set(WebAppSettingDataService.KEYS.AGENT_LIST_SORT_OPTION, sortOption);
+ }
+ getAgentListSortOption(): string {
+ return this.localStorageService.get(WebAppSettingDataService.KEYS.AGENT_LIST_SORT_OPTION);
+ }
}