Merge pull request #935 from pranshuchittora/pranshuchittora/feat/graph-memory-issue

feat: FE memory fixes and UX enhancements
This commit is contained in:
palash-signoz 2022-04-05 10:35:08 +05:30 committed by GitHub
commit a69bc321a9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 47 additions and 137 deletions

View File

@ -0,0 +1,17 @@
import { grey } from '@ant-design/colors';
import { Chart } from 'chart.js';
export const emptyGraph = {
id: 'emptyChart',
afterDraw(chart: Chart): void {
const { height, width, ctx } = chart;
chart.clear();
ctx.save();
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
ctx.font = '1.5rem sans-serif';
ctx.fillStyle = `${grey.primary}`;
ctx.fillText('No data to display', width / 2, height / 2);
ctx.restore();
},
};

View File

@ -0,0 +1,19 @@
/* eslint-disable no-restricted-syntax */
import { ChartData } from 'chart.js';
export const hasData = (data: ChartData): boolean => {
const { datasets = [] } = data;
let hasData = false;
try {
for (const dataset of datasets) {
if (dataset.data.length > 0 && dataset.data.some((item) => item !== 0)) {
hasData = true;
break;
}
}
} catch (error) {
console.error(error);
}
return hasData;
};

View File

@ -27,7 +27,9 @@ import { useSelector } from 'react-redux';
import { AppState } from 'store/reducers';
import AppReducer from 'types/reducer/app';
import { hasData } from './hasData';
import { legend } from './Plugin';
import { emptyGraph } from './Plugin/EmptyGraph';
import { LegendsContainer } from './styles';
import { useXAxisTimeUnit } from './xAxisConfig';
import { getYAxisFormattedValue } from './yAxisConfig';
@ -128,6 +130,7 @@ function Graph({
grid: {
display: true,
color: getGridColor(),
drawTicks: true,
},
adapters: {
date: chartjsAdapter,
@ -180,12 +183,18 @@ function Graph({
}
},
};
const chartHasData = hasData(data);
const chartPlugins = [];
if (chartHasData) {
chartPlugins.push(legend(name, data.datasets.length > 3));
} else {
chartPlugins.push(emptyGraph);
}
lineChartRef.current = new Chart(chartRef.current, {
type,
data,
options,
plugins: [legend(name, data.datasets.length > 3)],
plugins: chartPlugins,
});
}
}, [

View File

@ -1,91 +0,0 @@
import Graph, { GraphOnClickHandler } from 'components/Graph';
import { timePreferance } from 'container/NewWidget/RightContainer/timeItems';
import GetMaxMinTime from 'lib/getMaxMinTime';
import { colors } from 'lib/getRandomColor';
import getStartAndEndTime from 'lib/getStartAndEndTime';
import getTimeString from 'lib/getTimeString';
import React, { useCallback } from 'react';
import { useSelector } from 'react-redux';
import { AppState } from 'store/reducers';
import { Widgets } from 'types/api/dashboard/getAll';
import { GlobalReducer } from 'types/reducer/globalTime';
function EmptyGraph({
selectedTime,
widget,
onClickHandler,
}: EmptyGraphProps): JSX.Element {
const { minTime, maxTime, loading } = useSelector<AppState, GlobalReducer>(
(state) => state.globalTime,
);
const maxMinTime = GetMaxMinTime({
graphType: widget.panelTypes,
maxTime,
minTime,
});
const { end, start } = getStartAndEndTime({
type: selectedTime.enum,
maxTime: maxMinTime.maxTime,
minTime: maxMinTime.minTime,
});
const dateFunction = useCallback(() => {
if (!loading) {
const dates: Date[] = [];
const startString = getTimeString(start);
const endString = getTimeString(end);
const parsedStart = parseInt(startString, 10);
const parsedEnd = parseInt(endString, 10);
let startDate = parsedStart;
const endDate = parsedEnd;
while (endDate >= startDate) {
const newDate = new Date(startDate);
startDate += 20000;
dates.push(newDate);
}
return dates;
}
return [];
}, [start, end, loading]);
const date = dateFunction();
return (
<Graph
name=""
{...{
type: 'line',
onClickHandler,
data: {
datasets: [
{
data: new Array(date?.length).fill(0),
borderColor: colors[0],
showLine: true,
borderWidth: 1.5,
spanGaps: true,
pointRadius: 0,
},
],
labels: date,
},
}}
/>
);
}
interface EmptyGraphProps {
selectedTime: timePreferance;
widget: Widgets;
onClickHandler: GraphOnClickHandler | undefined;
}
export default EmptyGraph;

View File

@ -23,14 +23,12 @@ import { AppState } from 'store/reducers';
import { Widgets } from 'types/api/dashboard/getAll';
import { GlobalReducer } from 'types/reducer/globalTime';
import EmptyGraph from './EmptyGraph';
import { NotFoundContainer, TimeContainer } from './styles';
function FullView({
widget,
fullViewOptions = true,
onClickHandler,
noDataGraph = false,
name,
yAxisUnit,
}: FullViewProps): JSX.Element {
@ -166,38 +164,6 @@ function FullView({
);
}
if (state.loading === false && state.payload.datasets.length === 0) {
return (
<>
{fullViewOptions && (
<TimeContainer>
<TimePreference
{...{
selectedTime,
setSelectedTime,
}}
/>
<Button onClick={onFetchDataHandler} type="primary">
Refresh
</Button>
</TimeContainer>
)}
{noDataGraph ? (
<EmptyGraph
onClickHandler={onClickHandler}
widget={widget}
selectedTime={selectedTime}
/>
) : (
<NotFoundContainer>
<Typography>No Data</Typography>
</NotFoundContainer>
)}
</>
);
}
return (
<>
{fullViewOptions && (
@ -243,7 +209,6 @@ interface FullViewProps {
widget: Widgets;
fullViewOptions?: boolean;
onClickHandler?: GraphOnClickHandler;
noDataGraph?: boolean;
name: string;
yAxisUnit?: string;
}
@ -251,7 +216,6 @@ interface FullViewProps {
FullView.defaultProps = {
fullViewOptions: undefined,
onClickHandler: undefined,
noDataGraph: undefined,
yAxisUnit: undefined,
};

View File

@ -179,7 +179,6 @@ function Application({ getWidget }: DashboardProps): JSX.Element {
<GraphContainer>
<FullView
name="request_per_sec"
noDataGraph
fullViewOptions={false}
onClickHandler={(event, element, chart, data): void => {
onClickhandler(event, element, chart, data, 'Request');
@ -214,7 +213,6 @@ function Application({ getWidget }: DashboardProps): JSX.Element {
<GraphContainer>
<FullView
name="error_percentage_%"
noDataGraph
fullViewOptions={false}
onClickHandler={(ChartEvent, activeElements, chart, data): void => {
onClickhandler(ChartEvent, activeElements, chart, data, 'Error');

View File

@ -17,7 +17,6 @@ function DBCall({ getWidget }: DBCallProps): JSX.Element {
<GraphContainer>
<FullView
name="database_call_rps"
noDataGraph
fullViewOptions={false}
widget={getWidget([
{
@ -37,7 +36,6 @@ function DBCall({ getWidget }: DBCallProps): JSX.Element {
<GraphContainer>
<FullView
name="database_call_avg_duration"
noDataGraph
fullViewOptions={false}
widget={getWidget([
{

View File

@ -21,7 +21,6 @@ function External({ getWidget }: ExternalProps): JSX.Element {
<FullView
name="external_call_error_percentage"
fullViewOptions={false}
noDataGraph
widget={getWidget([
{
query: `max((sum(rate(signoz_external_call_latency_count{service_name="${servicename}", status_code="STATUS_CODE_ERROR"}[1m]) OR rate(signoz_external_call_latency_count{service_name="${servicename}", http_status_code=~"5.."}[1m]) OR vector(0)) by (http_url))*100/sum(rate(signoz_external_call_latency_count{service_name="${servicename}"}[1m])) by (http_url)) < 1000 OR vector(0)`,
@ -40,7 +39,6 @@ function External({ getWidget }: ExternalProps): JSX.Element {
<GraphContainer>
<FullView
name="external_call_duration"
noDataGraph
fullViewOptions={false}
widget={getWidget([
{
@ -62,7 +60,6 @@ function External({ getWidget }: ExternalProps): JSX.Element {
<GraphContainer>
<FullView
name="external_call_rps_by_address"
noDataGraph
fullViewOptions={false}
widget={getWidget([
{
@ -81,7 +78,6 @@ function External({ getWidget }: ExternalProps): JSX.Element {
<GraphTitle>External Call duration(by Address)</GraphTitle>
<GraphContainer>
<FullView
noDataGraph
name="external_call_duration_by_address"
fullViewOptions={false}
widget={getWidget([