Skip to content

Commit

Permalink
[#9189] Add apdex-score formula in the apdex-score guide popup
Browse files Browse the repository at this point in the history
  • Loading branch information
binDongKim committed Jan 19, 2023
1 parent 07dec1a commit a9695af
Show file tree
Hide file tree
Showing 19 changed files with 355 additions and 122 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
:host {
display: block;
}

.apdex-score-wrapper {
cursor: pointer;
position: relative;
}

.fa-question-circle {
position: absolute;
top: 1px;
right: 37px;
font-size: 0.6em;
color: var(--icon-default);
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
<pp-apdex-score
[score]="apdexScore">
</pp-apdex-score>
<ng-container *ngIf="apdexScore">
<div class="helper-viewer-exclude apdex-score-wrapper" (click)="onShowHelp($event)">
<pp-apdex-score
[score]="apdexScore">
</pp-apdex-score>
<button class="fas fa-question-circle"></button>
</div>
</ng-container>
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
import { ChangeDetectorRef, Component, OnDestroy, OnInit } from '@angular/core';
import { ChangeDetectorRef, Component, ComponentFactoryResolver, Injector, OnDestroy, OnInit } from '@angular/core';
import { Subject, merge } from 'rxjs';
import { filter, switchMap, tap, map, takeUntil } from 'rxjs/operators';

import { MessageQueueService, MESSAGE_TO, NewUrlStateNotificationService } from 'app/shared/services';
import { ApdexScoreDataService } from './apdex-score-data.service';
import { AnalyticsService, DynamicPopupService, MessageQueueService, MESSAGE_TO, NewUrlStateNotificationService, TRACKED_EVENT_LIST } from 'app/shared/services';
import { IApdexFormulaData, ApdexScoreDataService } from './apdex-score-data.service';
import { ServerMapData } from 'app/core/components/server-map/class/server-map-data.class';
import { HELP_VIEWER_LIST, HelpViewerPopupContainerComponent } from 'app/core/components/help-viewer-popup/help-viewer-popup-container.component';
import { ApdexScoreGuideComponent } from './apdex-score-guide.component';
import { ApdexScoreInteractionService } from './apdex-score-interaction.service';

@Component({
selector: 'pp-apdex-score-container',
Expand All @@ -25,6 +28,11 @@ export class ApdexScoreContainerComponent implements OnInit, OnDestroy {
private messageQueueService: MessageQueueService,
private newUrlStateNotificationService: NewUrlStateNotificationService,
private cd: ChangeDetectorRef,
private injector: Injector,
private analyticsService: AnalyticsService,
private dynamicPopupService: DynamicPopupService,
private componentFactoryResolver: ComponentFactoryResolver,
private apdexScoreInteractionService: ApdexScoreInteractionService
) { }

ngOnInit() {
Expand Down Expand Up @@ -52,8 +60,9 @@ export class ApdexScoreContainerComponent implements OnInit, OnDestroy {
switchMap(({applicationName, serviceTypeCode}: INodeInfo) => {
return this.apdexScoreDataService.getApdexScore({applicationName, serviceTypeCode, from: this.previousRange[0], to: this.previousRange[1]});
})
).subscribe(({apdexScore}: {apdexScore: number}) => {
).subscribe(({apdexScore, apdexFormula: apdexFormulaData}: {apdexScore: number, apdexFormula: IApdexFormulaData}) => {
this.apdexScore = apdexScore;
this.apdexScoreInteractionService.setApdexFormulaData(apdexFormulaData);
this.cd.detectChanges();
});
}
Expand All @@ -62,4 +71,22 @@ export class ApdexScoreContainerComponent implements OnInit, OnDestroy {
this.unsubscribe.next();
this.unsubscribe.complete();
}

onShowHelp($event: MouseEvent): void {
this.analyticsService.trackEvent(TRACKED_EVENT_LIST.CLICK_APDEX_SCORE, HELP_VIEWER_LIST.APDEX_SCORE);
const {left, top, height} = ($event.target as HTMLElement).getBoundingClientRect();

this.dynamicPopupService.openPopup({
data: HELP_VIEWER_LIST.APDEX_SCORE,
template: ApdexScoreGuideComponent,
coord: {
coordX: left,
coordY: top + height / 2
},
component: HelpViewerPopupContainerComponent
}, {
resolver: this.componentFactoryResolver,
injector: this.injector
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@ import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs';

export interface IApdexFormulaData {
satisfiedCount: number;
toleratingCount: number;
totalSamples: number;
}

@Injectable({providedIn: 'root'})
export class ApdexScoreDataService {
private url = 'getApdexScore.pinpoint';
Expand All @@ -10,7 +16,7 @@ export class ApdexScoreDataService {
private http: HttpClient,
) { }

getApdexScore(params: {[key: string]: any}): Observable<{apdexScore: number}> {
return this.http.get<{apdexScore: number}>(this.url, {params});
getApdexScore(params: {[key: string]: any}): Observable<{apdexScore: number, apdexFormula: IApdexFormulaData}> {
return this.http.get<{apdexScore: number, apdexFormula: IApdexFormulaData}>(this.url, {params});
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
:host {
display: block;
}

.title-group {
display: block;
padding: 14px 18px;
height: auto;
border-bottom: 1px solid var(--border-primary);
font-size: 13px;
font-weight: 600;
color: var(--text-primary);
}

.desc-group {
font-size: 12px;
color: var(--text-secondary);
border-bottom: 1px solid var(--border-primary);
padding: 14px 18px 7px 18px;
font-weight: 600;
}

.title-group .title-text {
font-size: 16px;
font-weight: 600;
color: var(--primary);
margin-bottom: 15px;
}

.title-group .title-desc {
font-size: 12px;
color: var(--text-secondary);
}

.contents-group {
padding: 14px 14px;
}

.contents-group .category-title {
font-size: 13px;
font-weight: 600;
color: var(--text-primary);
margin-bottom: 12px;
padding-left: 26px;
}

.contents-group .category-item-list {
display: flex;
padding: 5px 0;
line-height: 20px;
}

.apdex-formula-wrapper {
}

.upper {
display: flex;
justify-content: center;
}

.lower {
display: flex;
justify-content: center;
}

.sign {
padding: 5px;
}

.divider {
display: block;
height: 1px;
border: 0;
border-top: 1px solid #ccc;
margin: 5px 0;
padding: 0;
}

.formula-elem {
padding: 5px;
}

.apdex-score-range {
font-size: 12px;
font-weight: 600;
color: var(--text-primary-lightest);
width: 80px;
display: flex;
align-items: center;
justify-content: center;
margin-right: 5px;
text-align: center;
}

.apdex-score-rank {
font-size: 12px;
color: var(--text-secondary);
flex: 1;
display: flex;
align-items: center;
}

.fas {
font-size: 15px;
margin-right: 3px;
}

.excellent {
color: var(--status-success);
}
.good {
color: var(--status-good);
}
.poor {
color: var(--status-warn);
}
.unacceptable {
color: var(--status-fail);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<div class="desc-wrapper">
<div class="title-group">
<div class="title-text">Apdex Score</div>
<div class="title-desc">
<div class="apdex-formula-wrapper">
<div class="upper">
<div class="formula-elem" title="Satisfied Count">{{apdexFormulaData.satisfiedCount}}</div>
<div class="sign">+ [</div>
<div class="formula-elem" title="Tolerating Count">{{apdexFormulaData.toleratingCount}}</div>
<div class="sign">/</div>
<div class="formula-elem">2</div>
<div class="sign">]</div>
</div>
<hr class="divider"/>
<div class="lower">
<div class="formula-elem" title="Total Samples">{{apdexFormulaData.totalSamples}}</div>
</div>
</div>
</div>
</div>
<div class="contents-group">
<div class="category-title">Score</div>
<div *ngFor="let score of apdexScoreGuide" class="category-item-list">
<span class="apdex-score-range">{{score.range}}</span>
<span class="apdex-score-rank">
<span class="fas" [ngClass]="getIconClass(score.rank)"></span>
<span>{{score.rank | titlecase}}</span>
</span>
</div>
</div>
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { Component, OnInit } from '@angular/core';

import { IApdexFormulaData } from './apdex-score-data.service';
import { ApdexScoreInteractionService } from './apdex-score-interaction.service';
import { APDEX_SCORE_RANK } from './apdex-score-utils';

@Component({
selector: 'pp-apdex-score-guide',
templateUrl: './apdex-score-guide.component.html',
styleUrls: ['./apdex-score-guide.component.css']
})
export class ApdexScoreGuideComponent implements OnInit {
apdexScoreGuide: {range: string, rank: APDEX_SCORE_RANK}[];
apdexFormulaData: IApdexFormulaData;

constructor(
private apdexScoreInteractionService: ApdexScoreInteractionService
) { }

ngOnInit() {
this.apdexScoreGuide = [
{range: '0.94 ~ 1.00', rank: APDEX_SCORE_RANK.EXCELLENT},
{range: '0.85 ~ 0.94', rank: APDEX_SCORE_RANK.GOOD},
{range: '0.7 ~ 0.85', rank: APDEX_SCORE_RANK.FAIR},
{range: '0.5 ~ 0.7', rank: APDEX_SCORE_RANK.POOR},
{range: '< 0.5', rank: APDEX_SCORE_RANK.UNACCEPTABLE},
];

this.apdexScoreInteractionService.onApdexFormulaData$.subscribe((data: IApdexFormulaData) => {
this.apdexFormulaData = data;
});
}

getIconClass(apdexScoreRank: APDEX_SCORE_RANK) {
const iconClass = apdexScoreRank === APDEX_SCORE_RANK.EXCELLENT ? 'fa-smile-beam'
: apdexScoreRank === APDEX_SCORE_RANK.GOOD ? 'fa-smile'
: apdexScoreRank === APDEX_SCORE_RANK.FAIR ? 'fa-meh'
: apdexScoreRank === APDEX_SCORE_RANK.POOR ? 'fa-frown'
: 'fa-angry';

return `${apdexScoreRank} ${iconClass}`;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { Injectable } from '@angular/core';
import { BehaviorSubject, Observable } from 'rxjs';

import { IApdexFormulaData } from './apdex-score-data.service';

@Injectable({providedIn: 'root'})
export class ApdexScoreInteractionService {
private outApdexFormulaData = new BehaviorSubject<IApdexFormulaData>(null);

onApdexFormulaData$: Observable<IApdexFormulaData>;

constructor() {
this.onApdexFormulaData$ = this.outApdexFormulaData.asObservable();
}

setApdexFormulaData(apdexFormulaData: IApdexFormulaData): void {
this.outApdexFormulaData.next(apdexFormulaData);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
export enum APDEX_SCORE_RANK {
EXCELLENT = 'excellent',
GOOD = 'good',
FAIR = 'fair',
POOR = 'poor',
UNACCEPTABLE = 'unacceptable',
}

export function getApdexScoreRank(score: number): string {
return score < 0.5 ? APDEX_SCORE_RANK.UNACCEPTABLE
: score < 0.7 ? APDEX_SCORE_RANK.POOR
: score < 0.85 ? APDEX_SCORE_RANK.FAIR
: score < 0.94 ? APDEX_SCORE_RANK.GOOD
: APDEX_SCORE_RANK.EXCELLENT;
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,7 @@
font-size: 16px;
}

div {
cursor: pointer;
}

.title {
position: relative;
margin-right: 15px;
color: var(--text-primary);
}
Expand All @@ -16,14 +11,6 @@ div {
font-weight: bold;
}

button {
position: absolute;
top: 1px;
right: -6.5px;
font-size: 0.6em;
color: var(--icon-default);
}

.excellent {
color: var(--status-success);
}
Expand All @@ -35,4 +22,4 @@ button {
}
.unacceptable {
color: var(--status-fail);
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,2 @@
<div *ngIf="fixedScore" class="helper-viewer-exclude" (click)="onShowHelp($event)">
<span class="title">
Apdex
<button class="fa fa-question-circle"></button>
</span>
<span class={{getScoreTextClassName()}}>{{ fixedScore }}</span>
</div>
<span class="title">Apdex</span>
<span class="score" [ngClass]="scoreStyleClass">{{fixedScore}}</span>
Loading

0 comments on commit a9695af

Please # to comment.