Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: uplot graph is added and some re-rendering is reduced #3771

Merged
merged 41 commits into from
Nov 15, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
29a6cc0
feat: uplot graph is added and some re-rendering is reduced
palashgdev Oct 19, 2023
2879787
chore: uplot is updated
palashgdev Oct 25, 2023
64474c1
feat: changes for the graph is updated
palashgdev Oct 25, 2023
97ea88d
refactor: added y-axis unit in uplot graph (#3818)
Oct 29, 2023
044970c
feat: uplot points is handled (#3817)
palashgdev Oct 29, 2023
ee56a19
chore: value panel is updated
palashgdev Oct 29, 2023
8030d6a
feat: uplot chart is updated
palashgdev Oct 29, 2023
7927f90
feat: onDrag is updated
palashgdev Oct 29, 2023
c2880ef
feat: data for graph is updated
palashgdev Oct 29, 2023
5a7470c
feat: alert section is fixed
palashgdev Oct 30, 2023
6a061d9
feat: not found is updated
palashgdev Oct 30, 2023
eaa1cee
feat: fix dashboard title section and other uplot parity issues (#3839)
YounixM Oct 31, 2023
cff8081
chore: initial width is updated
palashgdev Oct 31, 2023
915189e
feat: onlcick is updated
palashgdev Oct 31, 2023
923963d
feat: widget full view fixes (#3847)
YounixM Nov 1, 2023
e9bfbaf
feat: show labels in tooltip overlay (#3867)
YounixM Nov 1, 2023
cd12f3d
chore: memo is added
palashgdev Nov 2, 2023
4da4233
feat: toggle is updated
palashgdev Nov 2, 2023
17cce91
fix: Tooltip values is now fixed (#3894)
palashgdev Nov 3, 2023
ac9c30e
feat: resize graph based on the y axis max label length (#3895)
YounixM Nov 3, 2023
0ded916
Merge branch 'develop' into feat/uplot
palashgdev Nov 6, 2023
72dac0b
Merge branch 'develop' into feat/uplot
palashgdev Nov 6, 2023
4f7edd1
chore: build is in progress to fix
palashgdev Nov 6, 2023
bafcacf
[Feat]: Full View (#3896)
Nov 6, 2023
24461ae
feat: use spline renderer to plot curved line graphs, full view impor…
YounixM Nov 7, 2023
dffe14f
fix: add panel issue in dashboard (#3920)
Nov 7, 2023
2d11aa7
fix: update on click plugin opts import path
YounixM Nov 8, 2023
0e49567
feat: replace time series graph in logs explorer and trace explorer w…
YounixM Nov 8, 2023
06769e3
feat: alert threshold is added (#3931)
palashgdev Nov 9, 2023
575ac53
feat: uplot styles are fixed (#3941)
palashgdev Nov 10, 2023
73e7db5
Fix/app dex aligment (#3944)
palashgdev Nov 10, 2023
230870a
Merge branch 'develop' into feat/uplot
palashgdev Nov 10, 2023
7211c42
fix: full view after saving is fixed
palashgdev Nov 10, 2023
9386d5f
feat: css is updated (#3948)
palashgdev Nov 10, 2023
4bf516d
Merge branch 'develop' into feat/uplot
palashgdev Nov 13, 2023
90190aa
feat: on click handler position - factor in the padding on top and left
YounixM Nov 13, 2023
b537255
Merge branch 'develop' into feat/uplot
palashgdev Nov 14, 2023
7b21ff3
fix: timestamp for start and end is updated for view trace (#3966)
palashgdev Nov 15, 2023
80b5559
Merge branch 'develop' into feat/uplot
palashgdev Nov 15, 2023
93d892c
fix: loading over flow is fixed (#3969)
palashgdev Nov 15, 2023
8976330
Merge branch 'develop' into feat/uplot
palashgdev Nov 15, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,6 @@
"react-grid-layout": "^1.3.4",
"react-helmet-async": "1.3.0",
"react-i18next": "^11.16.1",
"react-intersection-observer": "9.4.1",
"react-markdown": "8.0.7",
"react-query": "^3.34.19",
"react-redux": "^7.2.2",
Expand All @@ -102,6 +101,7 @@
"ts-node": "^10.2.1",
"tsconfig-paths-webpack-plugin": "^3.5.1",
"typescript": "^4.0.5",
"uplot": "1.6.26",
"uuid": "^8.3.2",
"web-vitals": "^0.2.4",
"webpack": "5.88.2",
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/components/Graph/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ export type GraphOnClickHandler = (
) => void;

export type ToggleGraphProps = {
toggleGraph(graphIndex: number, isVisible: boolean): void;
toggleGraph(graphIndex: number, isVisible: boolean, reference?: string): void;
};

export type CustomChartOptions = ChartOptions & {
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/components/Graph/yAxisConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ export const getYAxisFormattedValue = (
return `${parseFloat(value)}`;
};

export const getToolTipValue = (value: string, format: string): string => {
export const getToolTipValue = (value: string, format?: string): string => {
try {
return formattedValueToString(
getValueFormat(format)(parseFloat(value), undefined, undefined, undefined),
Expand Down
5 changes: 4 additions & 1 deletion frontend/src/components/TimePreferenceDropDown/index.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { DownOutlined } from '@ant-design/icons';
import { Button, Dropdown } from 'antd';
import TimeItems, {
timePreferance,
Expand Down Expand Up @@ -33,7 +34,9 @@ function TimePreference({
return (
<TextContainer noButtonMargin>
<Dropdown menu={menu}>
<Button>{selectedTime.name}</Button>
<Button>
{selectedTime.name} <DownOutlined />
</Button>
</Dropdown>
</TextContainer>
);
Expand Down
141 changes: 141 additions & 0 deletions frontend/src/components/Uplot/Uplot.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
/* eslint-disable sonarjs/cognitive-complexity */
import './uplot.scss';

import { Typography } from 'antd';
import { ToggleGraphProps } from 'components/Graph/types';
import {
forwardRef,
memo,
useCallback,
useEffect,
useImperativeHandle,
useRef,
} from 'react';
import UPlot from 'uplot';

import { dataMatch, optionsUpdateState } from './utils';

export interface UplotProps {
options: uPlot.Options;
data: uPlot.AlignedData;
onDelete?: (chart: uPlot) => void;
onCreate?: (chart: uPlot) => void;
resetScales?: boolean;
}

const Uplot = forwardRef<ToggleGraphProps | undefined, UplotProps>(
(
{ options, data, onDelete, onCreate, resetScales = true },
ref,
): JSX.Element | null => {
const chartRef = useRef<uPlot | null>(null);
const propOptionsRef = useRef(options);
const targetRef = useRef<HTMLDivElement>(null);
const propDataRef = useRef(data);
const onCreateRef = useRef(onCreate);
const onDeleteRef = useRef(onDelete);

useImperativeHandle(
ref,
(): ToggleGraphProps => ({
toggleGraph(graphIndex: number, isVisible: boolean): void {
chartRef.current?.setSeries(graphIndex, { show: isVisible });
},
}),
);

useEffect(() => {
onCreateRef.current = onCreate;
onDeleteRef.current = onDelete;
});

const destroy = useCallback((chart: uPlot | null) => {
if (chart) {
onDeleteRef.current?.(chart);
chart.destroy();
chartRef.current = null;
}
}, []);

const create = useCallback(() => {
if (targetRef.current === null) return;

// If data is empty, hide cursor
if (data && data[0] && data[0]?.length === 0) {
propOptionsRef.current = {
...propOptionsRef.current,
cursor: { show: false },
};
}

const newChart = new UPlot(
propOptionsRef.current,
propDataRef.current,
targetRef.current,
);

chartRef.current = newChart;
onCreateRef.current?.(newChart);
}, [data]);

useEffect(() => {
create();
return (): void => {
destroy(chartRef.current);
};
}, [create, destroy]);

useEffect(() => {
if (propOptionsRef.current !== options) {
const optionsState = optionsUpdateState(propOptionsRef.current, options);
propOptionsRef.current = options;
if (!chartRef.current || optionsState === 'create') {
destroy(chartRef.current);
create();
} else if (optionsState === 'update') {
chartRef.current.setSize({
width: options.width,
height: options.height,
});
}
}
}, [options, create, destroy]);

useEffect(() => {
if (propDataRef.current !== data) {
if (!chartRef.current) {
propDataRef.current = data;
create();
} else if (!dataMatch(propDataRef.current, data)) {
if (resetScales) {
chartRef.current.setData(data, true);
} else {
chartRef.current.setData(data, false);
chartRef.current.redraw();
}
}
propDataRef.current = data;
}
}, [data, resetScales, create]);

return (
<div className="uplot-graph-container" ref={targetRef}>
{data && data[0] && data[0]?.length === 0 ? (
<div className="not-found">
<Typography>No Data</Typography>
</div>
) : null}
</div>
);
},
);

Uplot.displayName = 'Uplot';

Uplot.defaultProps = {
onDelete: undefined,
onCreate: undefined,
resetScales: true,
};

export default memo(Uplot);
3 changes: 3 additions & 0 deletions frontend/src/components/Uplot/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import Uplot from './Uplot';

export default Uplot;
15 changes: 15 additions & 0 deletions frontend/src/components/Uplot/uplot.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
.not-found {
display: flex;
justify-content: center;
align-items: center;
z-index: 0;
height: 85%;
position: absolute;
left: 50%;
transform: translate(-50%, 0);
}

.uplot-graph-container {
height: 100%;
width: 100%;
}
48 changes: 48 additions & 0 deletions frontend/src/components/Uplot/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import uPlot from 'uplot';

type OptionsUpdateState = 'keep' | 'update' | 'create';

export const optionsUpdateState = (
_lhs: uPlot.Options,
_rhs: uPlot.Options,
): OptionsUpdateState => {
const { width: lhsWidth, height: lhsHeight, ...lhs } = _lhs;
const { width: rhsWidth, height: rhsHeight, ...rhs } = _rhs;

let state: OptionsUpdateState = 'keep';

if (lhsHeight !== rhsHeight || lhsWidth !== rhsWidth) {
state = 'update';
}
if (Object.keys(lhs).length !== Object.keys(rhs).length) {
return 'create';
}
// eslint-disable-next-line no-restricted-syntax
for (const k of Object.keys(lhs)) {
if (!Object.is((lhs as any)[k], (rhs as any)[k])) {
state = 'create';
break;
}
}
return state;
};

export const dataMatch = (
lhs: uPlot.AlignedData,
rhs: uPlot.AlignedData,
): boolean => {
if (lhs.length !== rhs.length) {
return false;
}
return lhs.every((lhsOneSeries, seriesIdx) => {
const rhsOneSeries = rhs[seriesIdx];
if (lhsOneSeries.length !== rhsOneSeries.length) {
return false;
}

// compare each value in the series
return (lhsOneSeries as number[])?.every(
(value, valueIdx) => value === rhsOneSeries[valueIdx],
);
});
};
4 changes: 2 additions & 2 deletions frontend/src/constants/panelTypes.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import Graph from 'components/Graph';
import Uplot from 'components/Uplot';
import GridTableComponent from 'container/GridTableComponent';
import GridValueComponent from 'container/GridValueComponent';

import { PANEL_TYPES } from './queryBuilder';

export const PANEL_TYPES_COMPONENT_MAP = {
[PANEL_TYPES.TIME_SERIES]: Graph,
[PANEL_TYPES.TIME_SERIES]: Uplot,
[PANEL_TYPES.VALUE]: GridValueComponent,
[PANEL_TYPES.TABLE]: GridTableComponent,
[PANEL_TYPES.TRACE]: null,
Expand Down
1 change: 0 additions & 1 deletion frontend/src/constants/theme.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ const themeColors = {
silver: '#BDBDBD',
outrageousOrange: '#FF6633',
roseBud: '#FFB399',
magentaPink: '#FF33FF',
canary: '#FFFF99',
deepSkyBlue: '#00B3E6',
goldTips: '#E6B333',
Expand Down
85 changes: 47 additions & 38 deletions frontend/src/container/FormAlertRules/ChartPreview/index.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
import { InfoCircleOutlined } from '@ant-design/icons';
import { StaticLineProps } from 'components/Graph/types';
import Spinner from 'components/Spinner';
import { initialQueriesMap, PANEL_TYPES } from 'constants/queryBuilder';
import GridPanelSwitch from 'container/GridPanelSwitch';
import { timePreferenceType } from 'container/NewWidget/RightContainer/timeItems';
import { Time } from 'container/TopNav/DateTimeSelection/config';
import { useGetQueryRange } from 'hooks/queryBuilder/useGetQueryRange';
import getChartData from 'lib/getChartData';
import { useMemo } from 'react';
import { useIsDarkMode } from 'hooks/useDarkMode';
import { useResizeObserver } from 'hooks/useDimensions';
import { getUPlotChartOptions } from 'lib/uPlotLib/getUplotChartData';
import { getUPlotChartData } from 'lib/uPlotLib/utils/getChartData';
import { useMemo, useRef } from 'react';
import { useTranslation } from 'react-i18next';
import { useSelector } from 'react-redux';
import { AppState } from 'store/reducers';
Expand Down Expand Up @@ -54,20 +56,6 @@ function ChartPreview({
targetUnit: query?.unit,
});

const staticLine: StaticLineProps | undefined =
threshold !== undefined
? {
yMin: thresholdValue,
yMax: thresholdValue,
borderColor: '#f14',
borderWidth: 1,
lineText: `${t('preview_chart_threshold_label')} (y=${thresholdValue} ${
query?.unit || ''
})`,
textColor: '#f14',
}
: undefined;

const canQuery = useMemo((): boolean => {
if (!query || query == null) {
return false;
Expand Down Expand Up @@ -114,15 +102,36 @@ function ChartPreview({
},
);

const chartDataSet = queryResponse.isError
? null
: getChartData({
queryData: [
{
queryData: queryResponse?.data?.payload?.data?.result ?? [],
},
],
});
const graphRef = useRef<HTMLDivElement>(null);

const chartData = getUPlotChartData(queryResponse?.data?.payload);

const containerDimensions = useResizeObserver(graphRef);

const isDarkMode = useIsDarkMode();

const options = useMemo(
() =>
getUPlotChartOptions({
id: 'alert_legend_widget',
yAxisUnit: query?.unit,
apiResponse: queryResponse?.data?.payload,
dimensions: containerDimensions,
isDarkMode,
thresholdText: `${t(
'preview_chart_threshold_label',
)} (y=${thresholdValue} ${query?.unit || ''})`,
thresholdValue,
}),
[
query?.unit,
queryResponse?.data?.payload,
containerDimensions,
isDarkMode,
t,
thresholdValue,
],
);

return (
<ChartContainer>
Expand All @@ -136,18 +145,18 @@ function ChartPreview({
{queryResponse.isLoading && (
<Spinner size="large" tip="Loading..." height="70vh" />
)}
{chartDataSet && !queryResponse.isError && (
<GridPanelSwitch
panelType={graphType}
title={name}
data={chartDataSet.data}
isStacked
name={name || 'Chart Preview'}
staticLine={staticLine}
panelData={queryResponse.data?.payload.data.newResult.data.result || []}
query={query || initialQueriesMap.metrics}
yAxisUnit={query?.unit}
/>
{chartData && !queryResponse.isError && (
<div ref={graphRef} style={{ height: '100%' }}>
<GridPanelSwitch
options={options}
panelType={graphType}
data={chartData}
name={name || 'Chart Preview'}
panelData={queryResponse.data?.payload.data.newResult.data.result || []}
query={query || initialQueriesMap.metrics}
yAxisUnit={query?.unit}
/>
</div>
)}
</ChartContainer>
);
Expand Down
Loading
Loading