Skip to content

Commit 971ae00

Browse files
committed
[pinpoint-apm#12240] Apply feedbacks of heatmap
1 parent ee4e367 commit 971ae00

File tree

10 files changed

+87
-69
lines changed

10 files changed

+87
-69
lines changed

web-frontend/src/main/v3/packages/ui/src/atoms/serverMap.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { atom } from 'jotai';
22
import {
3+
EXPERIMENTAL_CONFIG_KEYS,
34
FilteredMapType as FilteredMap,
45
GetResponseTimeHistogram,
56
GetServerMap,
@@ -68,3 +69,7 @@ export const currentServerAgentIdAtom = atom<string | undefined>((get) => {
6869
});
6970

7071
export const realtimeDateRanage = atom<{ from: Date; to: Date } | undefined>(undefined);
72+
73+
export const serverMapChartTypeAtom = atom<'scatter' | 'heatmap'>(
74+
window?.localStorage?.getItem(EXPERIMENTAL_CONFIG_KEYS.ENABLE_HEATMAP) ? 'heatmap' : 'scatter',
75+
);

web-frontend/src/main/v3/packages/ui/src/components/Heatmap/core/HeatmapChart.tsx

Lines changed: 55 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,12 @@ import {
1515
} from 'echarts/components';
1616
// 등록
1717
echarts.use([
18-
CanvasRenderer, // 캔버스 렌더링
19-
HeatmapChartEcharts, // 히트맵 차트
20-
GridComponent, // 기본 그리드
21-
TooltipComponent, // 마우스 오버 툴팁
22-
VisualMapComponent, // 색상 범례
23-
GraphicComponent, // 커스텀 그래픽 (선, 박스 등)
18+
CanvasRenderer, // 캔버스 렌더링
19+
HeatmapChartEcharts, // 히트맵 차트
20+
GridComponent, // 기본 그리드
21+
TooltipComponent, // 마우스 오버 툴팁
22+
VisualMapComponent, // 색상 범례
23+
GraphicComponent, // 커스텀 그래픽 (선, 박스 등)
2424
]);
2525

2626
type DataValue = [string, string, number];
@@ -148,7 +148,6 @@ const HeatmapChart = React.forwardRef(
148148
});
149149
});
150150

151-
152151
const xAxisData = heatmapData?.map((row) => String(row.timestamp)) || [];
153152
const yAxisData =
154153
heatmapData?.[heatmapData?.length - 1].cellDataList
@@ -160,6 +159,7 @@ const HeatmapChart = React.forwardRef(
160159

161160
chartInstanceRef.current.setOption({
162161
grid: {
162+
show: true,
163163
left: setting.yMax.toString().length * 10,
164164
right: '16px',
165165
top: '20px',
@@ -180,7 +180,7 @@ const HeatmapChart = React.forwardRef(
180180
yAxis: {
181181
type: 'category',
182182
data: yAxisData,
183-
offset: 1,
183+
offset: 0.5,
184184
axisLabel: {
185185
interval: (index: number, value: string) => {
186186
if (yAxisData.length <= 5) {
@@ -228,6 +228,10 @@ const HeatmapChart = React.forwardRef(
228228
inRange: {
229229
color: [colors.green[100], colors.green[900]],
230230
},
231+
handleStyle: {
232+
borderColor: colors.gray[300],
233+
borderWidth: 2,
234+
},
231235
},
232236
{
233237
id: 'fail',
@@ -249,6 +253,10 @@ const HeatmapChart = React.forwardRef(
249253
inRange: {
250254
color: [colors.red[100], colors.red[900]],
251255
},
256+
handleStyle: {
257+
borderColor: colors.gray[300],
258+
borderWidth: 2,
259+
},
252260
},
253261
{
254262
id: 'cover',
@@ -312,7 +320,7 @@ const HeatmapChart = React.forwardRef(
312320
left: 0,
313321
top: 0,
314322
shape: { r: 6 },
315-
style: { fill: '#34D399' }
323+
style: { fill: '#34D399' },
316324
},
317325
{
318326
type: 'text',
@@ -322,8 +330,8 @@ const HeatmapChart = React.forwardRef(
322330
text: 'Success',
323331
fontSize: 14,
324332
fill: '#6B7280',
325-
fontFamily: 'sans-serif'
326-
}
333+
fontFamily: 'sans-serif',
334+
},
327335
},
328336
{
329337
type: 'text',
@@ -334,10 +342,10 @@ const HeatmapChart = React.forwardRef(
334342
fontSize: 18,
335343
fontWeight: 'bold',
336344
fill: '#111827',
337-
fontFamily: 'sans-serif'
338-
}
339-
}
340-
]
345+
fontFamily: 'sans-serif',
346+
},
347+
},
348+
],
341349
},
342350
{
343351
type: 'group',
@@ -349,7 +357,7 @@ const HeatmapChart = React.forwardRef(
349357
left: 0,
350358
top: 0,
351359
shape: { r: 6 },
352-
style: { fill: '#EF4444' }
360+
style: { fill: '#EF4444' },
353361
},
354362
{
355363
type: 'text',
@@ -359,8 +367,8 @@ const HeatmapChart = React.forwardRef(
359367
text: 'Failed',
360368
fontSize: 14,
361369
fill: '#6B7280',
362-
fontFamily: 'sans-serif'
363-
}
370+
fontFamily: 'sans-serif',
371+
},
364372
},
365373
{
366374
type: 'text',
@@ -371,11 +379,11 @@ const HeatmapChart = React.forwardRef(
371379
fontSize: 18,
372380
fontWeight: 'bold',
373381
fill: '#111827',
374-
fontFamily: 'sans-serif'
375-
}
376-
}
377-
]
378-
}
382+
fontFamily: 'sans-serif',
383+
},
384+
},
385+
],
386+
},
379387
],
380388
series: [
381389
{
@@ -472,8 +480,29 @@ const HeatmapChart = React.forwardRef(
472480
});
473481
}, [startCell, endCell]);
474482

483+
const timeGap = React.useMemo(() => {
484+
try {
485+
if (!data) {
486+
return 0;
487+
}
488+
489+
const { heatmapData } = data;
490+
const firstTimestamp = heatmapData?.[0]?.timestamp;
491+
const secondTimestamp = heatmapData?.[1]?.timestamp;
492+
493+
return Math.abs(Number(firstTimestamp) - Number(secondTimestamp)) || 0;
494+
} catch (err) {
495+
return 0;
496+
}
497+
}, [data]);
498+
475499
const handleDragEnd = React.useCallback(() => {
476-
if (!startCell || !endCell) {
500+
if (
501+
!startCell ||
502+
!endCell ||
503+
startCell?.componentType !== 'series' ||
504+
endCell?.componentType !== 'series'
505+
) {
477506
return;
478507
}
479508

@@ -485,7 +514,7 @@ const HeatmapChart = React.forwardRef(
485514
const failRange = (visualMaps as any)?.find((vm: any) => vm.id === 'fail')?.range;
486515

487516
const x1 = Math.min(startX, endX);
488-
const x2 = Math.max(startX, endX);
517+
const x2 = Math.max(startX, endX) + timeGap - 1;
489518

490519
const y1 = Math.max(startY, endY);
491520

@@ -514,7 +543,7 @@ const HeatmapChart = React.forwardRef(
514543
},
515544
checkedLegends,
516545
);
517-
}, [startCell, endCell]);
546+
}, [startCell, endCell, timeGap]);
518547

519548
return (
520549
<div

web-frontend/src/main/v3/packages/ui/src/components/Heatmap/core/HeatmapSetting.tsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import {
1010
FormItem,
1111
FormLabel,
1212
FormMessage,
13+
Separator,
1314
} from '@pinpoint-fe/ui/src/components/ui';
1415
import { useForm } from 'react-hook-form';
1516
import { zodResolver } from '@hookform/resolvers/zod';
@@ -32,7 +33,7 @@ export const DefaultValue = {
3233

3334
const FormSchema = z.object({
3435
yMin: z.coerce.number().min(0),
35-
yMax: z.coerce.number().min(1),
36+
yMax: z.coerce.number().min(200),
3637
visualMapSuccessMax: z.coerce.number().min(1).optional(),
3738
visualMapFailMax: z.coerce.number().min(1).optional(),
3839
});
@@ -116,7 +117,7 @@ export const HeatmapSetting = ({
116117
type="number"
117118
className="w-24 h-7"
118119
onKeyDown={handleKeyDown}
119-
min={1}
120+
min={200}
120121
{...field}
121122
/>
122123
</FormControl>
@@ -126,6 +127,7 @@ export const HeatmapSetting = ({
126127
/>
127128
{isRealtime && (
128129
<>
130+
<Separator />
129131
<FormField
130132
control={form.control}
131133
name="visualMapSuccessMax"

web-frontend/src/main/v3/packages/ui/src/components/Realtime/Realtime.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,22 +19,22 @@ import {
1919
ErrorBoundary,
2020
Heatmap,
2121
ChartTypeButtons,
22-
useServerMapChartType,
2322
} from '..';
2423
import { useServerMapSearchParameters, useTabFocus } from '@pinpoint-fe/ui/src/hooks';
2524
import {
2625
CurrentTarget,
2726
serverMapCurrentTargetAtom,
2827
serverMapCurrentTargetDataAtom,
2928
serverMapDataAtom,
29+
serverMapChartTypeAtom,
3030
} from '@pinpoint-fe/ui/src/atoms';
3131
import { APP_SETTING_KEYS, ApplicationType, GetServerMap } from '@pinpoint-fe/ui/src/constants';
3232
import { getServerImagePath } from '@pinpoint-fe/ui/src/utils';
3333

3434
export interface RealtimeProps {}
3535

3636
export const Realtime = () => {
37-
const [chartType] = useServerMapChartType();
37+
const chartType = useAtomValue(serverMapChartTypeAtom);
3838
const isFocus = useTabFocus();
3939
const containerRef = React.useRef<HTMLDivElement>(null);
4040
const { application } = useServerMapSearchParameters();

web-frontend/src/main/v3/packages/ui/src/components/ServerMap/ChartTypeButtons.tsx

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1-
import { useAtomValue } from 'jotai';
2-
import { Button, useServerMapChartType } from '..';
3-
import { configurationAtom } from '@pinpoint-fe/ui/src/atoms';
1+
import React from 'react';
2+
import { useAtom, useAtomValue } from 'jotai';
3+
import { Button } from '..';
4+
import { configurationAtom, serverMapChartTypeAtom } from '@pinpoint-fe/ui/src/atoms';
45
import { useLocalStorage } from '@pinpoint-fe/ui/src/hooks';
56
import { EXPERIMENTAL_CONFIG_KEYS } from '@pinpoint-fe/ui/src/constants';
67
import { PiChartScatterBold } from 'react-icons/pi';
@@ -13,7 +14,13 @@ export const ChartTypeButtons = () => {
1314
!!configuration?.['experimental.enableHeatmap.value'],
1415
);
1516

16-
const [chartType, setChartType] = useServerMapChartType();
17+
const [chartType, setChartType] = useAtom(serverMapChartTypeAtom);
18+
19+
React.useEffect(() => {
20+
if (!enableHeatmap) {
21+
setChartType('scatter');
22+
}
23+
}, [enableHeatmap]);
1724

1825
if (!enableHeatmap) {
1926
return null;

web-frontend/src/main/v3/packages/ui/src/components/ServerMap/index.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,3 @@ export * from './ServerMapCore';
44
export * from './ServerMapSkeleton';
55
export * from './ServerMapMenu';
66
export * from './ServerMapFetcher';
7-
export * from './useServerMapChartType';

web-frontend/src/main/v3/packages/ui/src/components/ServerMap/useServerMapChartType.ts

Lines changed: 0 additions & 28 deletions
This file was deleted.

web-frontend/src/main/v3/packages/ui/src/constants/locales/en.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@
5555
"SELECT_URL_INFO": "Select a path info below"
5656
},
5757
"SERVER_MAP": {
58-
"SCATTER_CHART_STATIC_WARN": "To view the scatter chart by agent, please switch the heatmap to a scatter chart."
58+
"SCATTER_CHART_STATIC_WARN": "To view the scatter chart by agent,\nplease switch the heatmap to a scatter chart."
5959
},
6060
"TRANSACTION_LIST": {
6161
"SELECT_TRANSACTION": "Select your transaction",

web-frontend/src/main/v3/packages/ui/src/constants/locales/ko.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@
5555
"SELECT_URL_INFO": "아래에서 Path 정보를 선택하세요."
5656
},
5757
"SERVER_MAP": {
58-
"SCATTER_CHART_STATIC_WARN": "Agent별 scatter chart를 보기 위해 heatmap을 scatter chart로 변경해 주세요."
58+
"SCATTER_CHART_STATIC_WARN": "Agent별 scatter chart를 보기 위해\nheatmap을 scatter chart로 변경해 주세요."
5959
},
6060
"TRANSACTION_LIST": {
6161
"SELECT_TRANSACTION": "Transaction을 선택하세요.",

web-frontend/src/main/v3/packages/ui/src/pages/ServerMap.tsx

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import {
2424
currentServerAtom,
2525
scatterDataAtom,
2626
CurrentTarget,
27+
serverMapChartTypeAtom,
2728
} from '@pinpoint-fe/ui/src/atoms';
2829
import {
2930
FilteredMapType as FilteredMap,
@@ -57,7 +58,6 @@ import {
5758
HelpPopover,
5859
ApplicationCombinedListProps,
5960
ChartTypeButtons,
60-
useServerMapChartType,
6161
} from '@pinpoint-fe/ui';
6262
import { Edge, Node } from '@pinpoint-fe/server-map';
6363
import { PiTreeStructureDuotone, PiArrowSquareOut } from 'react-icons/pi';
@@ -89,7 +89,7 @@ export const ServerMapPage = ({
8989
const [openServerViewTransitionEnd, setServerViewTransitionEnd] = React.useState(false);
9090
const [showFilter, setShowFilter] = React.useState(false);
9191
const [filter, setFilter] = React.useState<FilteredMap.FilterState>();
92-
const [chartType] = useServerMapChartType();
92+
const chartType = useAtomValue(serverMapChartTypeAtom);
9393
const [isScatterDataOutdated, setIsScatterDataOutdated] = React.useState(chartType !== 'scatter');
9494
const scatterData = useAtomValue(scatterDataAtom);
9595
const { t } = useTranslation();
@@ -527,8 +527,12 @@ export const ServerMapPage = ({
527527
selectedAgentId={currentServer?.agentId || ''}
528528
/>
529529
{isScatterDataOutdated && (
530-
<div className="absolute top-0 left-0 z-[1000] flex items-center justify-center w-full h-[calc(100%+48px)] bg-background/50 text-center whitespace-normal break-words">
531-
{t('SERVER_MAP.SCATTER_CHART_STATIC_WARN')}
530+
<div className="absolute top-0 left-0 z-[1000] flex flex-col items-center justify-center w-full h-[calc(100%+48px)] bg-background/50 text-center">
531+
{t('SERVER_MAP.SCATTER_CHART_STATIC_WARN')
532+
.split('\n')
533+
.map((txt, i) => (
534+
<p key={i}>{txt}</p>
535+
))}
532536
</div>
533537
)}
534538
</div>

0 commit comments

Comments
 (0)