Feat: Bar chart (#4562)

* feat: added bar panel and configuration for bar chart
This commit is contained in:
Rajat Dabade 2024-02-28 14:56:50 +05:30 committed by GitHub
parent ddaa464d97
commit 9964e3425a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
34 changed files with 1694 additions and 47 deletions

View File

@ -24,7 +24,7 @@ const config: Config.InitialOptions = {
'^(?!.*\\.(js|jsx|mjs|cjs|ts|tsx|css|json)$)': 'jest-preview/transforms/file',
},
transformIgnorePatterns: [
'node_modules/(?!(lodash-es|react-dnd|core-dnd|@react-dnd|dnd-core|react-dnd-html5-backend|axios|@signozhq/design-tokens)/)',
'node_modules/(?!(lodash-es|react-dnd|core-dnd|@react-dnd|dnd-core|react-dnd-html5-backend|axios|@signozhq/design-tokens|d3-interpolate|d3-color)/)',
],
setupFilesAfterEnv: ['<rootDir>jest.setup.ts'],
testPathIgnorePatterns: ['/node_modules/', '/public/'],

View File

@ -0,0 +1,41 @@
import { CSSProperties } from 'react';
function BarIcon({
fillColor,
}: {
fillColor: CSSProperties['color'];
}): JSX.Element {
return (
<svg
width="30"
height="30"
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M8 2H6C4.89543 2 4 2.89543 4 4V16C4 17.1046 4.89543 18 6 18H8C9.10457 18 10 17.1046 10 16V4C10 2.89543 9.10457 2 8 2Z"
stroke={fillColor}
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
/>
<path
d="M18 9H16C14.8954 9 14 9.89543 14 11V16C14 17.1046 14.8954 18 16 18H18C19.1046 18 20 17.1046 20 16V11C20 9.89543 19.1046 9 18 9Z"
stroke={fillColor}
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
/>
<path
d="M22 22H2"
stroke={fillColor}
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
);
}
export default BarIcon;

View File

@ -14,6 +14,7 @@ export const PANEL_TYPES_COMPONENT_MAP = {
[PANEL_TYPES.TRACE]: null,
[PANEL_TYPES.LIST]: LogsPanelComponent,
[PANEL_TYPES.EMPTY_WIDGET]: null,
[PANEL_TYPES.BAR]: Uplot,
} as const;
export const getComponentForPanelType = (
@ -27,6 +28,7 @@ export const getComponentForPanelType = (
[PANEL_TYPES.TRACE]: null,
[PANEL_TYPES.LIST]:
dataSource === DataSource.LOGS ? LogsPanelComponent : TracesTableComponent,
[PANEL_TYPES.BAR]: Uplot,
[PANEL_TYPES.EMPTY_WIDGET]: null,
};

View File

@ -264,6 +264,7 @@ export enum PANEL_TYPES {
TABLE = 'table',
LIST = 'list',
TRACE = 'trace',
BAR = 'bar',
EMPTY_WIDGET = 'EMPTY_WIDGET',
}

View File

@ -19,6 +19,8 @@ import { AlertDef } from 'types/api/alerts/def';
import { Query } from 'types/api/queryBuilder/queryBuilderData';
import { EQueryType } from 'types/common/dashboard';
import { GlobalReducer } from 'types/reducer/globalTime';
import { getGraphType } from 'utils/getGraphType';
import { getSortedSeriesData } from 'utils/getSortedSeriesData';
import { getTimeRange } from 'utils/getTimeRange';
import { ChartContainer, FailedMessageContainer } from './styles';
@ -86,7 +88,7 @@ function ChartPreview({
{
query: query || initialQueriesMap.metrics,
globalSelectedInterval: selectedInterval,
graphType,
graphType: getGraphType(graphType),
selectedTime,
params: {
allowSelectedIntervalForStepGen,
@ -114,6 +116,13 @@ function ChartPreview({
setMaxTimeScale(endTime);
}, [maxTime, minTime, globalSelectedInterval, queryResponse]);
if (queryResponse.data && graphType === PANEL_TYPES.BAR) {
const sortedSeriesData = getSortedSeriesData(
queryResponse.data?.payload.data.result,
);
queryResponse.data.payload.data.result = sortedSeriesData;
}
const chartData = getUPlotChartData(queryResponse?.data?.payload);
const containerDimensions = useResizeObserver(graphRef);
@ -153,6 +162,7 @@ function ChartPreview({
],
softMax: null,
softMin: null,
panelType: graphType,
}),
[
yAxisUnit,
@ -165,6 +175,7 @@ function ChartPreview({
t,
optionName,
alertDef?.condition.targetUnit,
graphType,
],
);

View File

@ -22,6 +22,7 @@ function QuerySection({
setQueryCategory,
alertType,
runQuery,
panelType,
}: QuerySectionProps): JSX.Element {
// init namespace for translations
const { t } = useTranslation('alerts');
@ -44,7 +45,7 @@ function QuerySection({
const renderMetricUI = (): JSX.Element => (
<QueryBuilder
panelType={PANEL_TYPES.TIME_SERIES}
panelType={panelType}
config={{
queryVariant: 'static',
initialDataSource: ALERTS_DATA_SOURCE_MAP[alertType],
@ -196,6 +197,7 @@ interface QuerySectionProps {
setQueryCategory: (n: EQueryType) => void;
alertType: AlertTypes;
runQuery: VoidFunction;
panelType: PANEL_TYPES;
}
export default QuerySection;

View File

@ -10,6 +10,7 @@ import {
import saveAlertApi from 'api/alerts/save';
import testAlertApi from 'api/alerts/testAlert';
import { FeatureKeys } from 'constants/features';
import { QueryParams } from 'constants/query';
import { PANEL_TYPES } from 'constants/queryBuilder';
import ROUTES from 'constants/routes';
import QueryTypeTag from 'container/NewWidget/LeftContainer/QueryTypeTag';
@ -20,6 +21,7 @@ import { useShareBuilderUrl } from 'hooks/queryBuilder/useShareBuilderUrl';
import { updateStepInterval } from 'hooks/queryBuilder/useStepInterval';
import { MESSAGE, useIsFeatureDisabled } from 'hooks/useFeatureFlag';
import { useNotifications } from 'hooks/useNotifications';
import useUrlQuery from 'hooks/useUrlQuery';
import history from 'lib/history';
import { mapQueryDataFromApi } from 'lib/newQueryBuilder/queryBuilderMappers/mapQueryDataFromApi';
import { mapQueryDataToApi } from 'lib/newQueryBuilder/queryBuilderMappers/mapQueryDataToApi';
@ -68,14 +70,23 @@ function FormAlertRules({
GlobalReducer
>((state) => state.globalTime);
const urlQuery = useUrlQuery();
const panelType = urlQuery.get(QueryParams.panelTypes) as PANEL_TYPES | null;
const {
currentQuery,
panelType,
stagedQuery,
handleRunQuery,
handleSetConfig,
initialDataSource,
redirectWithQueryBuilderData,
} = useQueryBuilder();
useEffect(() => {
handleSetConfig(panelType || PANEL_TYPES.TIME_SERIES, initialDataSource);
}, [handleSetConfig, initialDataSource, panelType]);
// use query client
const ruleCache = useQueryClient();
@ -277,7 +288,7 @@ function FormAlertRules({
promQueries: mapQueryDataToApi(currentQuery.promql, 'name').data,
chQueries: mapQueryDataToApi(currentQuery.clickhouse_sql, 'name').data,
queryType: currentQuery.queryType,
panelType: initQuery.panelType,
panelType: panelType || initQuery.panelType,
unit: currentQuery.unit,
},
},
@ -290,6 +301,7 @@ function FormAlertRules({
alertDef,
alertType,
initQuery,
panelType,
]);
const isAlertAvialable = useIsFeatureDisabled(
@ -423,6 +435,7 @@ function FormAlertRules({
selectedInterval={globalSelectedInterval}
alertDef={alertDef}
yAxisUnit={yAxisUnit || ''}
graphType={panelType || PANEL_TYPES.TIME_SERIES}
/>
);
@ -439,6 +452,7 @@ function FormAlertRules({
alertDef={alertDef}
selectedInterval={globalSelectedInterval}
yAxisUnit={yAxisUnit || ''}
graphType={panelType || PANEL_TYPES.TIME_SERIES}
/>
);
@ -495,6 +509,7 @@ function FormAlertRules({
setQueryCategory={onQueryCategoryChange}
alertType={alertType || AlertTypes.METRICS_BASED_ALERT}
runQuery={handleRunQuery}
panelType={panelType || PANEL_TYPES.TIME_SERIES}
/>
<RuleOptions

View File

@ -25,5 +25,6 @@ export const PANEL_TYPES_VS_FULL_VIEW_TABLE: PanelTypeAndGraphManagerVisibilityP
TABLE: false,
LIST: false,
TRACE: false,
BAR: true,
EMPTY_WIDGET: false,
};

View File

@ -25,12 +25,12 @@ import { useSelector } from 'react-redux';
import { AppState } from 'store/reducers';
import { GlobalReducer } from 'types/reducer/globalTime';
import uPlot from 'uplot';
import { getSortedSeriesData } from 'utils/getSortedSeriesData';
import { getTimeRange } from 'utils/getTimeRange';
import { getGraphVisibilityStateOnDataChange } from '../utils';
import { PANEL_TYPES_VS_FULL_VIEW_TABLE } from './contants';
import GraphManager from './GraphManager';
// import GraphManager from './GraphManager';
import { GraphContainer, TimeContainer } from './styles';
import { FullViewProps } from './types';
@ -107,6 +107,13 @@ function FullView({
panelTypeAndGraphManagerVisibility: PANEL_TYPES_VS_FULL_VIEW_TABLE,
});
if (response.data && widget.panelTypes === PANEL_TYPES.BAR) {
const sortedSeriesData = getSortedSeriesData(
response.data?.payload.data.result,
);
response.data.payload.data.result = sortedSeriesData;
}
const chartData = getUPlotChartData(response?.data?.payload, widget.fillSpans);
const isDarkMode = useIsDarkMode();
@ -152,6 +159,7 @@ function FullView({
maxTimeScale,
softMax: widget.softMax === undefined ? null : widget.softMax,
softMin: widget.softMin === undefined ? null : widget.softMin,
panelType: widget.panelTypes,
});
setChartOptions(newChartOptions);

View File

@ -21,6 +21,8 @@ import { useLocation } from 'react-router-dom';
import { UpdateTimeInterval } from 'store/actions';
import { AppState } from 'store/reducers';
import { GlobalReducer } from 'types/reducer/globalTime';
import { getGraphType } from 'utils/getGraphType';
import { getSortedSeriesData } from 'utils/getSortedSeriesData';
import { getTimeRange } from 'utils/getTimeRange';
import EmptyWidget from '../EmptyWidget';
@ -125,7 +127,7 @@ function GridCardGraph({
const queryResponse = useGetQueryRange(
{
selectedTime: widget?.timePreferance,
graphType: widget?.panelTypes,
graphType: getGraphType(widget.panelTypes),
query: updatedQuery,
globalSelectedInterval,
variables: getDashboardVariables(variables),
@ -160,6 +162,13 @@ function GridCardGraph({
setMaxTimeScale(endTime);
}, [maxTime, minTime, globalSelectedInterval, queryResponse]);
if (queryResponse.data && widget.panelTypes === PANEL_TYPES.BAR) {
const sortedSeriesData = getSortedSeriesData(
queryResponse.data?.payload.data.result,
);
queryResponse.data.payload.data.result = sortedSeriesData;
}
const chartData = getUPlotChartData(queryResponse?.data?.payload, fillSpans);
const isDarkMode = useIsDarkMode();
@ -191,6 +200,7 @@ function GridCardGraph({
softMin: widget.softMin === undefined ? null : widget.softMin,
graphsVisibilityStates: graphVisibility,
setGraphsVisibilityStates: setGraphVisibility,
panelType: widget.panelTypes,
}),
[
widget?.id,
@ -207,6 +217,7 @@ function GridCardGraph({
maxTimeScale,
graphVisibility,
setGraphVisibility,
widget.panelTypes,
],
);

View File

@ -58,6 +58,11 @@ const GridPanelSwitch = forwardRef<
selectedTime,
},
[PANEL_TYPES.TRACE]: null,
[PANEL_TYPES.BAR]: {
data,
options,
ref,
},
[PANEL_TYPES.EMPTY_WIDGET]: null,
};

View File

@ -41,5 +41,8 @@ export type PropsTypePropsMap = {
[PANEL_TYPES.TABLE]: GridTableComponentProps;
[PANEL_TYPES.TRACE]: null;
[PANEL_TYPES.LIST]: LogsPanelComponentProps | TracesTableComponentProps;
[PANEL_TYPES.BAR]: UplotProps & {
ref: ForwardedRef<ToggleGraphProps | undefined>;
};
[PANEL_TYPES.EMPTY_WIDGET]: null;
};

View File

@ -120,7 +120,9 @@ function ListAlert({ allAlertRules, refetch }: ListAlertProps): JSX.Element {
history.push(
`${ROUTES.EDIT_ALERTS}?ruleId=${record.id.toString()}&${
QueryParams.compositeQuery
}=${encodeURIComponent(JSON.stringify(compositeQuery))}`,
}=${encodeURIComponent(JSON.stringify(compositeQuery))}&panelTypes=${
record.condition.compositeQuery.panelType
}`,
);
})
.catch(handleError);

View File

@ -9,6 +9,7 @@ export const PANEL_TYPES_INITIAL_QUERY = {
[PANEL_TYPES.TABLE]: initialQueriesMap.metrics,
[PANEL_TYPES.LIST]: initialQueriesMap.logs,
[PANEL_TYPES.TRACE]: initialQueriesMap.traces,
[PANEL_TYPES.BAR]: initialQueriesMap.metrics,
[PANEL_TYPES.EMPTY_WIDGET]: initialQueriesMap.metrics,
};

View File

@ -1,3 +1,4 @@
import BarIcon from 'assets/Dashboard/BarIcon';
import List from 'assets/Dashboard/List';
import TableIcon from 'assets/Dashboard/Table';
import TimeSeriesIcon from 'assets/Dashboard/TimeSeries';
@ -18,6 +19,7 @@ const Items: ItemsProps[] = [
},
{ name: PANEL_TYPES.TABLE, Icon: TableIcon, display: 'Table' },
{ name: PANEL_TYPES.LIST, Icon: List, display: 'List' },
{ name: PANEL_TYPES.BAR, Icon: BarIcon, display: 'Bar' },
];
interface ItemsProps {

View File

@ -5,6 +5,8 @@ import { WidgetGraphProps } from 'container/NewWidget/types';
import { useGetWidgetQueryRange } from 'hooks/queryBuilder/useGetWidgetQueryRange';
import useUrlQuery from 'hooks/useUrlQuery';
import { useDashboard } from 'providers/Dashboard/Dashboard';
import { getGraphType } from 'utils/getGraphType';
import { getSortedSeriesData } from 'utils/getSortedSeriesData';
import { NotFoundContainer } from './styles';
import WidgetGraph from './WidgetGraphs';
@ -31,10 +33,17 @@ function WidgetGraphContainer({
const selectedWidget = widgets.find((e) => e.id === widgetId);
const getWidgetQueryRange = useGetWidgetQueryRange({
graphType: selectedGraph,
graphType: getGraphType(selectedGraph),
selectedTime: selectedTime.enum,
});
if (getWidgetQueryRange.data && selectedGraph === PANEL_TYPES.BAR) {
const sortedSeriesData = getSortedSeriesData(
getWidgetQueryRange.data?.payload.data.result,
);
getWidgetQueryRange.data.payload.data.result = sortedSeriesData;
}
if (selectedWidget === undefined) {
return <Card>Invalid widget</Card>;
}
@ -83,6 +92,7 @@ function WidgetGraphContainer({
selectedLogFields={selectedLogFields}
selectedTracesFields={selectedTracesFields}
selectedTime={selectedTime}
selectedGraph={selectedGraph}
/>
);
}

View File

@ -1,4 +1,5 @@
import { QueryParams } from 'constants/query';
import { PANEL_TYPES } from 'constants/queryBuilder';
import GridPanelSwitch from 'container/GridPanelSwitch';
import { ThresholdProps } from 'container/NewWidget/RightContainer/Threshold/types';
import { timePreferance } from 'container/NewWidget/RightContainer/timeItems';
@ -34,6 +35,7 @@ function WidgetGraph({
selectedLogFields,
selectedTracesFields,
selectedTime,
selectedGraph,
}: WidgetGraphProps): JSX.Element {
const { stagedQuery, currentQuery } = useQueryBuilder();
@ -130,6 +132,7 @@ function WidgetGraph({
maxTimeScale,
softMax,
softMin,
panelType: selectedGraph,
}),
[
widgetId,
@ -144,6 +147,7 @@ function WidgetGraph({
maxTimeScale,
softMax,
softMin,
selectedGraph,
],
);
@ -183,6 +187,7 @@ interface WidgetGraphProps {
selectedLogFields: Widgets['selectedLogFields'];
selectedTracesFields: Widgets['selectedTracesFields'];
selectedTime: timePreferance;
selectedGraph: PANEL_TYPES;
}
export default WidgetGraph;

View File

@ -5,6 +5,7 @@ import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
import useUrlQuery from 'hooks/useUrlQuery';
import { useDashboard } from 'providers/Dashboard/Dashboard';
import { memo } from 'react';
import { getGraphType } from 'utils/getGraphType';
import { WidgetGraphProps } from '../../types';
import PlotTag from './PlotTag';
@ -34,7 +35,7 @@ function WidgetGraph({
const selectedWidget = widgets.find((e) => e.id === widgetId);
const getWidgetQueryRange = useGetWidgetQueryRange({
graphType: selectedGraph,
graphType: getGraphType(selectedGraph),
selectedTime: selectedTime.enum,
});

View File

@ -26,6 +26,7 @@ export const panelTypeVsThreshold: { [key in PANEL_TYPES]: boolean } = {
[PANEL_TYPES.VALUE]: true,
[PANEL_TYPES.TABLE]: true,
[PANEL_TYPES.LIST]: false,
[PANEL_TYPES.BAR]: true,
[PANEL_TYPES.TRACE]: false,
[PANEL_TYPES.EMPTY_WIDGET]: false,
} as const;
@ -35,6 +36,7 @@ export const panelTypeVsSoftMinMax: { [key in PANEL_TYPES]: boolean } = {
[PANEL_TYPES.VALUE]: false,
[PANEL_TYPES.TABLE]: false,
[PANEL_TYPES.LIST]: false,
[PANEL_TYPES.BAR]: true,
[PANEL_TYPES.TRACE]: false,
[PANEL_TYPES.EMPTY_WIDGET]: false,
} as const;
@ -44,6 +46,7 @@ export const panelTypeVsDragAndDrop: { [key in PANEL_TYPES]: boolean } = {
[PANEL_TYPES.VALUE]: true,
[PANEL_TYPES.TABLE]: true,
[PANEL_TYPES.LIST]: false,
[PANEL_TYPES.BAR]: false,
[PANEL_TYPES.TRACE]: false,
[PANEL_TYPES.EMPTY_WIDGET]: false,
} as const;
@ -53,6 +56,7 @@ export const panelTypeVsFillSpan: { [key in PANEL_TYPES]: boolean } = {
[PANEL_TYPES.VALUE]: false,
[PANEL_TYPES.TABLE]: false,
[PANEL_TYPES.LIST]: false,
[PANEL_TYPES.BAR]: false,
[PANEL_TYPES.TRACE]: false,
[PANEL_TYPES.EMPTY_WIDGET]: false,
} as const;
@ -62,6 +66,7 @@ export const panelTypeVsYAxisUnit: { [key in PANEL_TYPES]: boolean } = {
[PANEL_TYPES.VALUE]: true,
[PANEL_TYPES.TABLE]: true,
[PANEL_TYPES.LIST]: false,
[PANEL_TYPES.BAR]: true,
[PANEL_TYPES.TRACE]: false,
[PANEL_TYPES.EMPTY_WIDGET]: false,
} as const;
@ -71,6 +76,7 @@ export const panelTypeVsCreateAlert: { [key in PANEL_TYPES]: boolean } = {
[PANEL_TYPES.VALUE]: true,
[PANEL_TYPES.TABLE]: false,
[PANEL_TYPES.LIST]: false,
[PANEL_TYPES.BAR]: true,
[PANEL_TYPES.TRACE]: false,
[PANEL_TYPES.EMPTY_WIDGET]: false,
} as const;
@ -82,6 +88,7 @@ export const panelTypeVsPanelTimePreferences: {
[PANEL_TYPES.VALUE]: true,
[PANEL_TYPES.TABLE]: true,
[PANEL_TYPES.LIST]: false,
[PANEL_TYPES.BAR]: true,
[PANEL_TYPES.TRACE]: false,
[PANEL_TYPES.EMPTY_WIDGET]: false,
} as const;

View File

@ -46,6 +46,10 @@ export const QueryBuilder = memo(function QueryBuilder({
useEffect(() => {
if (currentDataSource !== initialDataSource || newPanelType !== panelType) {
if (panelType === PANEL_TYPES.BAR) {
handleSetConfig(PANEL_TYPES.BAR, DataSource.METRICS);
return;
}
handleSetConfig(newPanelType, currentDataSource);
}
}, [

View File

@ -14,6 +14,7 @@ import { useSelector } from 'react-redux';
import { AppState } from 'store/reducers';
import { Widgets } from 'types/api/dashboard/getAll';
import { GlobalReducer } from 'types/reducer/globalTime';
import { getGraphType } from 'utils/getGraphType';
const useCreateAlerts = (widget?: Widgets): VoidFunction => {
const queryRangeMutation = useMutation(getQueryRangeFormat);
@ -33,7 +34,7 @@ const useCreateAlerts = (widget?: Widgets): VoidFunction => {
const { queryPayload } = prepareQueryRangePayload({
query: widget.query,
globalSelectedInterval,
graphType: widget.panelTypes,
graphType: getGraphType(widget.panelTypes),
selectedTime: widget.timePreferance,
variables: getDashboardVariables(selectedDashboard?.data.variables),
});
@ -44,7 +45,7 @@ const useCreateAlerts = (widget?: Widgets): VoidFunction => {
history.push(
`${ROUTES.ALERTS_NEW}?${QueryParams.compositeQuery}=${encodeURIComponent(
JSON.stringify(updatedQuery),
)}`,
)}&${QueryParams.panelTypes}=${widget.panelTypes}`,
);
},
onError: () => {

View File

@ -1,3 +1,4 @@
import { PANEL_TYPES } from 'constants/queryBuilder';
import { REACT_QUERY_KEY } from 'constants/reactQueryKeys';
import {
GetMetricQueryRange,
@ -14,6 +15,17 @@ type UseGetQueryRange = (
) => UseQueryResult<SuccessResponse<MetricRangePayloadProps>, Error>;
export const useGetQueryRange: UseGetQueryRange = (requestData, options) => {
const newRequestData: GetQueryResultsProps = useMemo(
() => ({
...requestData,
graphType:
requestData.graphType === PANEL_TYPES.BAR
? PANEL_TYPES.TIME_SERIES
: requestData.graphType,
}),
[requestData],
);
const queryKey = useMemo(() => {
if (options?.queryKey && Array.isArray(options.queryKey)) {
return [...options.queryKey];
@ -23,11 +35,11 @@ export const useGetQueryRange: UseGetQueryRange = (requestData, options) => {
return options.queryKey;
}
return [REACT_QUERY_KEY.GET_QUERY_RANGE, requestData];
}, [options?.queryKey, requestData]);
return [REACT_QUERY_KEY.GET_QUERY_RANGE, newRequestData];
}, [options?.queryKey, newRequestData]);
return useQuery<SuccessResponse<MetricRangePayloadProps>, Error>({
queryFn: async ({ signal }) => GetMetricQueryRange(requestData, signal),
queryFn: async ({ signal }) => GetMetricQueryRange(newRequestData, signal),
...options,
queryKey,
});

View File

@ -4,6 +4,7 @@
/* eslint-disable sonarjs/cognitive-complexity */
import './uPlotLib.styles.scss';
import { PANEL_TYPES } from 'constants/queryBuilder';
import { FullViewProps } from 'container/GridCardLayout/GridCard/FullView/types';
import { ThresholdProps } from 'container/NewWidget/RightContainer/Threshold/types';
import { Dimensions } from 'hooks/useDimensions';
@ -19,11 +20,12 @@ import getSeries from './utils/getSeriesData';
import { getXAxisScale } from './utils/getXAxisScale';
import { getYAxisScale } from './utils/getYAxisScale';
interface GetUPlotChartOptions {
export interface GetUPlotChartOptions {
id?: string;
apiResponse?: MetricRangePayloadProps;
dimensions: Dimensions;
isDarkMode: boolean;
panelType?: PANEL_TYPES;
onDragSelect?: (startTime: number, endTime: number) => void;
yAxisUnit?: string;
onClickHandler?: OnClickPluginOpts['onClick'];
@ -55,6 +57,7 @@ export const getUPlotChartOptions = ({
fillSpans,
softMax,
softMin,
panelType,
}: GetUPlotChartOptions): uPlot.Options => {
const timeScaleProps = getXAxisScale(minTimeScale, maxTimeScale);
@ -209,12 +212,12 @@ export const getUPlotChartOptions = ({
},
],
},
series: getSeries(
series: getSeries({
apiResponse,
apiResponse?.data.result,
widgetMetaData: apiResponse?.data.result,
graphsVisibilityStates,
fillSpans,
),
panelType,
}),
axes: getAxes(isDarkMode, yAxisUnit),
};
};

View File

@ -0,0 +1,15 @@
// Define type annotations for style and interp
export const drawStyles = {
line: 'line',
bars: 'bars',
barsLeft: 'barsLeft',
barsRight: 'barsRight',
points: 'points',
};
export const lineInterpolations = {
linear: 'linear',
stepAfter: 'stepAfter',
stepBefore: 'stepBefore',
spline: 'spline',
};

View File

@ -61,5 +61,4 @@ const getAxes = (isDarkMode: boolean, yAxisUnit?: string): any => [
},
},
];
export default getAxes;

View File

@ -1,30 +1,21 @@
import uPlot from 'uplot';
// Define type annotations for style and interp
export const drawStyles = {
line: 'line',
bars: 'bars',
barsLeft: 'barsLeft',
barsRight: 'barsRight',
points: 'points',
};
import { drawStyles, lineInterpolations } from './constants';
export const lineInterpolations = {
linear: 'linear',
stepAfter: 'stepAfter',
stepBefore: 'stepBefore',
spline: 'spline',
};
const { spline: splinePath } = uPlot.paths;
const { spline: splinePath, bars: barsPath } = uPlot.paths;
const spline = splinePath && splinePath();
const bars = barsPath && barsPath();
const getRenderer = (style: any, interp: any): any => {
if (style === drawStyles.line && interp === lineInterpolations.spline) {
return spline;
}
if (style === drawStyles.bars) {
return bars;
}
return null;
};

View File

@ -1,10 +1,13 @@
/* eslint-disable sonarjs/cognitive-complexity */
import { PANEL_TYPES } from 'constants/queryBuilder';
import { themeColors } from 'constants/theme';
import getLabelName from 'lib/getLabelName';
import { MetricRangePayloadProps } from 'types/api/metrics/getQueryRange';
import { QueryData } from 'types/api/widgets/getQuery';
import { drawStyles, lineInterpolations } from './constants';
import { generateColor } from './generateColor';
import getRenderer, { drawStyles, lineInterpolations } from './getRenderer';
import getRenderer from './getRenderer';
const paths = (
u: any,
@ -23,17 +26,17 @@ const paths = (
return renderer(u, seriesIdx, idx0, idx1, extendGap, buildClip);
};
const getSeries = (
apiResponse?: MetricRangePayloadProps,
widgetMetaData: QueryData[] = [],
graphsVisibilityStates?: boolean[],
): uPlot.Options['series'] => {
const getSeries = ({
apiResponse,
widgetMetaData,
graphsVisibilityStates,
panelType,
}: GetSeriesProps): uPlot.Options['series'] => {
const configurations: uPlot.Series[] = [
{ label: 'Timestamp', stroke: 'purple' },
];
const seriesList = apiResponse?.data.result || [];
const newGraphVisibilityStates = graphsVisibilityStates?.slice(1);
for (let i = 0; i < seriesList?.length; i += 1) {
@ -52,10 +55,17 @@ const getSeries = (
const seriesObj: any = {
paths,
drawStyle: drawStyles.line,
lineInterpolation: lineInterpolations.spline,
drawStyle:
panelType && panelType === PANEL_TYPES.BAR
? drawStyles.bars
: drawStyles.line,
lineInterpolation:
panelType && panelType === PANEL_TYPES.BAR
? null
: lineInterpolations.spline,
show: newGraphVisibilityStates ? newGraphVisibilityStates[i] : true,
label,
fill: panelType && panelType === PANEL_TYPES.BAR ? `${color}40` : undefined,
stroke: color,
width: 2,
spanGaps: true,
@ -72,4 +82,11 @@ const getSeries = (
return configurations;
};
export type GetSeriesProps = {
apiResponse?: MetricRangePayloadProps;
widgetMetaData: QueryData[];
graphsVisibilityStates?: boolean[];
panelType?: PANEL_TYPES;
};
export default getSeries;

View File

@ -0,0 +1,889 @@
import { PANEL_TYPES } from 'constants/queryBuilder';
import { GetSeriesProps } from '../../getSeriesData';
export const seriesBarChartData = {
apiResponse: {
data: {
result: [
{
metric: {},
values: [
[1708683840, '6260'],
[1708683240, '6251'],
[1708683780, '6237'],
[1708683660, '6188'],
[1708683720, '6176'],
[1708683360, '6169'],
[1708683480, '6068'],
[1708683540, '6025'],
[1708683300, '6042'],
[1708683420, '6001'],
[1708683600, '5969'],
[1708683900, '5955'],
[1708683180, '4301'],
],
queryName: 'F1',
legend: 'firstLegend',
},
{
metric: {},
values: [
[1708683240, '3378'],
[1708683300, '3269'],
[1708683360, '3341'],
[1708683420, '3269'],
[1708683480, '3296'],
[1708683540, '3280'],
[1708683600, '3260'],
[1708683660, '3351'],
[1708683720, '3345'],
[1708683780, '3370'],
[1708683840, '3382'],
[1708683900, '3249'],
[1708683960, '212'],
],
queryName: 'A',
legend: 'secondLegend',
},
{
metric: {},
values: [
[1708683840, '2878'],
[1708683240, '2873'],
[1708683780, '2867'],
[1708683660, '2837'],
[1708683720, '2831'],
[1708683360, '2828'],
[1708683300, '2773'],
[1708683480, '2772'],
[1708683540, '2745'],
[1708683420, '2732'],
[1708683180, '2729'],
[1708683600, '2709'],
[1708683900, '2706'],
],
queryName: 'B',
legend: 'thirdLegend',
},
{
metric: {
F2: 'F2',
},
values: [
[1708683840, '504'],
[1708683240, '505'],
[1708683780, '503'],
[1708683660, '514'],
[1708683720, '514'],
[1708683360, '513'],
[1708683480, '524'],
[1708683540, '535'],
[1708683300, '496'],
[1708683420, '537'],
[1708683600, '551'],
[1708683900, '543'],
[1708683180, '-1157'],
],
queryName: 'F2',
legend: 'forthLength',
},
],
resultType: '',
newResult: {
status: 'success',
data: {
resultType: '',
result: [
{
queryName: 'A',
series: [
{
labels: {},
labelsArray: null,
values: [
{
timestamp: 1708683240000,
value: '3378',
},
{
timestamp: 1708683300000,
value: '3269',
},
{
timestamp: 1708683360000,
value: '3341',
},
{
timestamp: 1708683420000,
value: '3269',
},
{
timestamp: 1708683480000,
value: '3296',
},
{
timestamp: 1708683540000,
value: '3280',
},
{
timestamp: 1708683600000,
value: '3260',
},
{
timestamp: 1708683660000,
value: '3351',
},
{
timestamp: 1708683720000,
value: '3345',
},
{
timestamp: 1708683780000,
value: '3370',
},
{
timestamp: 1708683840000,
value: '3382',
},
{
timestamp: 1708683900000,
value: '3249',
},
{
timestamp: 1708683960000,
value: '212',
},
],
},
],
list: null,
},
{
queryName: 'B',
series: [
{
labels: {},
labelsArray: null,
values: [
{
timestamp: 1708683840000,
value: '2878',
},
{
timestamp: 1708683240000,
value: '2873',
},
{
timestamp: 1708683780000,
value: '2867',
},
{
timestamp: 1708683660000,
value: '2837',
},
{
timestamp: 1708683720000,
value: '2831',
},
{
timestamp: 1708683360000,
value: '2828',
},
{
timestamp: 1708683300000,
value: '2773',
},
{
timestamp: 1708683480000,
value: '2772',
},
{
timestamp: 1708683540000,
value: '2745',
},
{
timestamp: 1708683420000,
value: '2732',
},
{
timestamp: 1708683180000,
value: '2729',
},
{
timestamp: 1708683600000,
value: '2709',
},
{
timestamp: 1708683900000,
value: '2706',
},
],
},
],
list: null,
},
{
queryName: 'F2',
series: [
{
labels: {
F2: 'F2',
},
values: [
{
timestamp: 1708683840000,
value: '504',
},
{
timestamp: 1708683240000,
value: '505',
},
{
timestamp: 1708683780000,
value: '503',
},
{
timestamp: 1708683660000,
value: '514',
},
{
timestamp: 1708683720000,
value: '514',
},
{
timestamp: 1708683360000,
value: '513',
},
{
timestamp: 1708683480000,
value: '524',
},
{
timestamp: 1708683540000,
value: '535',
},
{
timestamp: 1708683300000,
value: '496',
},
{
timestamp: 1708683420000,
value: '537',
},
{
timestamp: 1708683600000,
value: '551',
},
{
timestamp: 1708683900000,
value: '543',
},
{
timestamp: 1708683180000,
value: '-1157',
},
],
},
],
list: null,
},
{
queryName: 'F1',
series: [
{
labels: {},
labelsArray: null,
values: [
{
timestamp: 1708683840000,
value: '6260',
},
{
timestamp: 1708683240000,
value: '6251',
},
{
timestamp: 1708683780000,
value: '6237',
},
{
timestamp: 1708683660000,
value: '6188',
},
{
timestamp: 1708683720000,
value: '6176',
},
{
timestamp: 1708683360000,
value: '6169',
},
{
timestamp: 1708683480000,
value: '6068',
},
{
timestamp: 1708683540000,
value: '6025',
},
{
timestamp: 1708683300000,
value: '6042',
},
{
timestamp: 1708683420000,
value: '6001',
},
{
timestamp: 1708683600000,
value: '5969',
},
{
timestamp: 1708683900000,
value: '5955',
},
{
timestamp: 1708683180000,
value: '4301',
},
],
},
],
list: null,
},
],
},
},
},
},
widgetMetaData: [
{
metric: {},
values: [
[1708683840, '6260'],
[1708683240, '6251'],
[1708683780, '6237'],
[1708683660, '6188'],
[1708683720, '6176'],
[1708683360, '6169'],
[1708683480, '6068'],
[1708683540, '6025'],
[1708683300, '6042'],
[1708683420, '6001'],
[1708683600, '5969'],
[1708683900, '5955'],
[1708683180, '4301'],
],
queryName: 'F1',
legend: 'firstLegend',
},
{
metric: {},
values: [
[1708683240, '3378'],
[1708683300, '3269'],
[1708683360, '3341'],
[1708683420, '3269'],
[1708683480, '3296'],
[1708683540, '3280'],
[1708683600, '3260'],
[1708683660, '3351'],
[1708683720, '3345'],
[1708683780, '3370'],
[1708683840, '3382'],
[1708683900, '3249'],
[1708683960, '212'],
],
queryName: 'A',
legend: 'A-A',
},
{
metric: {},
values: [
[1708683840, '2878'],
[1708683240, '2873'],
[1708683780, '2867'],
[1708683660, '2837'],
[1708683720, '2831'],
[1708683360, '2828'],
[1708683300, '2773'],
[1708683480, '2772'],
[1708683540, '2745'],
[1708683420, '2732'],
[1708683180, '2729'],
[1708683600, '2709'],
[1708683900, '2706'],
],
queryName: 'B',
legend: 'B-B',
},
{
metric: {
F2: 'F2',
},
values: [
[1708683840, '504'],
[1708683240, '505'],
[1708683780, '503'],
[1708683660, '514'],
[1708683720, '514'],
[1708683360, '513'],
[1708683480, '524'],
[1708683540, '535'],
[1708683300, '496'],
[1708683420, '537'],
[1708683600, '551'],
[1708683900, '543'],
[1708683180, '-1157'],
],
queryName: 'F2',
legend: 'F2',
},
],
graphsVisibilityStates: [true, true, true, true, true],
panelType: PANEL_TYPES.BAR,
} as GetSeriesProps;
export const seriesLineChartData = {
apiResponse: {
data: {
result: [
{
metric: {},
values: [
[1708683840, '6260'],
[1708683240, '6251'],
[1708683780, '6237'],
[1708683660, '6188'],
[1708683720, '6176'],
[1708683360, '6169'],
[1708683480, '6068'],
[1708683540, '6025'],
[1708683300, '6042'],
[1708683420, '6001'],
[1708683600, '5969'],
[1708683900, '5955'],
[1708683180, '4301'],
],
queryName: 'F1',
legend: 'firstLegend',
},
{
metric: {},
values: [
[1708683240, '3378'],
[1708683300, '3269'],
[1708683360, '3341'],
[1708683420, '3269'],
[1708683480, '3296'],
[1708683540, '3280'],
[1708683600, '3260'],
[1708683660, '3351'],
[1708683720, '3345'],
[1708683780, '3370'],
[1708683840, '3382'],
[1708683900, '3249'],
[1708683960, '212'],
],
queryName: 'A',
legend: 'secondLegend',
},
{
metric: {},
values: [
[1708683840, '2878'],
[1708683240, '2873'],
[1708683780, '2867'],
[1708683660, '2837'],
[1708683720, '2831'],
[1708683360, '2828'],
[1708683300, '2773'],
[1708683480, '2772'],
[1708683540, '2745'],
[1708683420, '2732'],
[1708683180, '2729'],
[1708683600, '2709'],
[1708683900, '2706'],
],
queryName: 'B',
legend: 'thirdLegend',
},
{
metric: {
F2: 'F2',
},
values: [
[1708683840, '504'],
[1708683240, '505'],
[1708683780, '503'],
[1708683660, '514'],
[1708683720, '514'],
[1708683360, '513'],
[1708683480, '524'],
[1708683540, '535'],
[1708683300, '496'],
[1708683420, '537'],
[1708683600, '551'],
[1708683900, '543'],
[1708683180, '-1157'],
],
queryName: 'F2',
legend: 'forthLength',
},
],
resultType: '',
newResult: {
status: 'success',
data: {
resultType: '',
result: [
{
queryName: 'A',
series: [
{
labels: {},
labelsArray: null,
values: [
{
timestamp: 1708683240000,
value: '3378',
},
{
timestamp: 1708683300000,
value: '3269',
},
{
timestamp: 1708683360000,
value: '3341',
},
{
timestamp: 1708683420000,
value: '3269',
},
{
timestamp: 1708683480000,
value: '3296',
},
{
timestamp: 1708683540000,
value: '3280',
},
{
timestamp: 1708683600000,
value: '3260',
},
{
timestamp: 1708683660000,
value: '3351',
},
{
timestamp: 1708683720000,
value: '3345',
},
{
timestamp: 1708683780000,
value: '3370',
},
{
timestamp: 1708683840000,
value: '3382',
},
{
timestamp: 1708683900000,
value: '3249',
},
{
timestamp: 1708683960000,
value: '212',
},
],
},
],
list: null,
},
{
queryName: 'B',
series: [
{
labels: {},
labelsArray: null,
values: [
{
timestamp: 1708683840000,
value: '2878',
},
{
timestamp: 1708683240000,
value: '2873',
},
{
timestamp: 1708683780000,
value: '2867',
},
{
timestamp: 1708683660000,
value: '2837',
},
{
timestamp: 1708683720000,
value: '2831',
},
{
timestamp: 1708683360000,
value: '2828',
},
{
timestamp: 1708683300000,
value: '2773',
},
{
timestamp: 1708683480000,
value: '2772',
},
{
timestamp: 1708683540000,
value: '2745',
},
{
timestamp: 1708683420000,
value: '2732',
},
{
timestamp: 1708683180000,
value: '2729',
},
{
timestamp: 1708683600000,
value: '2709',
},
{
timestamp: 1708683900000,
value: '2706',
},
],
},
],
list: null,
},
{
queryName: 'F2',
series: [
{
labels: {
F2: 'F2',
},
values: [
{
timestamp: 1708683840000,
value: '504',
},
{
timestamp: 1708683240000,
value: '505',
},
{
timestamp: 1708683780000,
value: '503',
},
{
timestamp: 1708683660000,
value: '514',
},
{
timestamp: 1708683720000,
value: '514',
},
{
timestamp: 1708683360000,
value: '513',
},
{
timestamp: 1708683480000,
value: '524',
},
{
timestamp: 1708683540000,
value: '535',
},
{
timestamp: 1708683300000,
value: '496',
},
{
timestamp: 1708683420000,
value: '537',
},
{
timestamp: 1708683600000,
value: '551',
},
{
timestamp: 1708683900000,
value: '543',
},
{
timestamp: 1708683180000,
value: '-1157',
},
],
},
],
list: null,
},
{
queryName: 'F1',
series: [
{
labels: {},
labelsArray: null,
values: [
{
timestamp: 1708683840000,
value: '6260',
},
{
timestamp: 1708683240000,
value: '6251',
},
{
timestamp: 1708683780000,
value: '6237',
},
{
timestamp: 1708683660000,
value: '6188',
},
{
timestamp: 1708683720000,
value: '6176',
},
{
timestamp: 1708683360000,
value: '6169',
},
{
timestamp: 1708683480000,
value: '6068',
},
{
timestamp: 1708683540000,
value: '6025',
},
{
timestamp: 1708683300000,
value: '6042',
},
{
timestamp: 1708683420000,
value: '6001',
},
{
timestamp: 1708683600000,
value: '5969',
},
{
timestamp: 1708683900000,
value: '5955',
},
{
timestamp: 1708683180000,
value: '4301',
},
],
},
],
list: null,
},
],
},
},
},
},
widgetMetaData: [
{
metric: {},
values: [
[1708683840, '6260'],
[1708683240, '6251'],
[1708683780, '6237'],
[1708683660, '6188'],
[1708683720, '6176'],
[1708683360, '6169'],
[1708683480, '6068'],
[1708683540, '6025'],
[1708683300, '6042'],
[1708683420, '6001'],
[1708683600, '5969'],
[1708683900, '5955'],
[1708683180, '4301'],
],
queryName: 'F1',
legend: 'firstLegend',
},
{
metric: {},
values: [
[1708683240, '3378'],
[1708683300, '3269'],
[1708683360, '3341'],
[1708683420, '3269'],
[1708683480, '3296'],
[1708683540, '3280'],
[1708683600, '3260'],
[1708683660, '3351'],
[1708683720, '3345'],
[1708683780, '3370'],
[1708683840, '3382'],
[1708683900, '3249'],
[1708683960, '212'],
],
queryName: 'A',
legend: 'A-A',
},
{
metric: {},
values: [
[1708683840, '2878'],
[1708683240, '2873'],
[1708683780, '2867'],
[1708683660, '2837'],
[1708683720, '2831'],
[1708683360, '2828'],
[1708683300, '2773'],
[1708683480, '2772'],
[1708683540, '2745'],
[1708683420, '2732'],
[1708683180, '2729'],
[1708683600, '2709'],
[1708683900, '2706'],
],
queryName: 'B',
legend: 'B-B',
},
{
metric: {
F2: 'F2',
},
values: [
[1708683840, '504'],
[1708683240, '505'],
[1708683780, '503'],
[1708683660, '514'],
[1708683720, '514'],
[1708683360, '513'],
[1708683480, '524'],
[1708683540, '535'],
[1708683300, '496'],
[1708683420, '537'],
[1708683600, '551'],
[1708683900, '543'],
[1708683180, '-1157'],
],
queryName: 'F2',
legend: 'F2',
},
],
graphsVisibilityStates: [true, true, true, true, true],
panelType: PANEL_TYPES.TIME_SERIES,
} as GetSeriesProps;

View File

@ -0,0 +1,453 @@
import { PANEL_TYPES } from 'constants/queryBuilder';
import { GetUPlotChartOptions } from 'lib/uPlotLib/getUplotChartOptions';
export const inputPropsTimeSeries = {
id: '',
dimensions: {
width: 400,
height: 288,
},
isDarkMode: true,
apiResponse: {
data: {
result: [
{
metric: {
A: 'A',
},
values: [
[1708623120, '122'],
[1708623180, '112'],
[1708623240, '106'],
[1708623300, '106'],
[1708623360, '116'],
[1708623420, '110'],
[1708623480, '110'],
[1708623540, '114'],
[1708623600, '114'],
[1708623660, '118'],
[1708623720, '110'],
[1708623780, '112'],
[1708623840, '116'],
[1708623900, '104'],
[1708623960, '106'],
[1708624020, '120'],
[1708624080, '110'],
[1708624140, '112'],
[1708624200, '110'],
[1708624260, '112'],
[1708624320, '110'],
[1708624380, '112'],
[1708624440, '108'],
[1708624500, '110'],
[1708624560, '114'],
[1708624620, '104'],
[1708624680, '122'],
[1708624740, '112'],
[1708624800, '104'],
[1708624860, '90'],
],
queryName: 'A',
legend: 'A',
},
],
resultType: '',
newResult: {
status: 'success',
data: {
resultType: '',
result: [
{
queryName: 'A',
series: [
{
labels: {
A: 'A',
},
values: [
{
timestamp: 1708623120000,
value: '122',
},
{
timestamp: 1708623180000,
value: '112',
},
{
timestamp: 1708623240000,
value: '106',
},
{
timestamp: 1708623300000,
value: '106',
},
{
timestamp: 1708623360000,
value: '116',
},
{
timestamp: 1708623420000,
value: '110',
},
{
timestamp: 1708623480000,
value: '110',
},
{
timestamp: 1708623540000,
value: '114',
},
{
timestamp: 1708623600000,
value: '114',
},
{
timestamp: 1708623660000,
value: '118',
},
{
timestamp: 1708623720000,
value: '110',
},
{
timestamp: 1708623780000,
value: '112',
},
{
timestamp: 1708623840000,
value: '116',
},
{
timestamp: 1708623900000,
value: '104',
},
{
timestamp: 1708623960000,
value: '106',
},
{
timestamp: 1708624020000,
value: '120',
},
{
timestamp: 1708624080000,
value: '110',
},
{
timestamp: 1708624140000,
value: '112',
},
{
timestamp: 1708624200000,
value: '110',
},
{
timestamp: 1708624260000,
value: '112',
},
{
timestamp: 1708624320000,
value: '110',
},
{
timestamp: 1708624380000,
value: '112',
},
{
timestamp: 1708624440000,
value: '108',
},
{
timestamp: 1708624500000,
value: '110',
},
{
timestamp: 1708624560000,
value: '114',
},
{
timestamp: 1708624620000,
value: '104',
},
{
timestamp: 1708624680000,
value: '122',
},
{
timestamp: 1708624740000,
value: '112',
},
{
timestamp: 1708624800000,
value: '104',
},
{
timestamp: 1708624860000,
value: '90',
},
],
},
],
list: null,
},
],
},
},
},
},
yAxisUnit: 'none',
minTimeScale: 1708623105,
maxTimeScale: 1708624905,
graphsVisibilityStates: [true, true],
thresholds: [],
softMax: null,
softMin: null,
panelType: PANEL_TYPES.TIME_SERIES,
} as GetUPlotChartOptions;
export const inputPropsBar = {
id: '',
dimensions: {
width: 400,
height: 288,
},
isDarkMode: true,
apiResponse: {
data: {
result: [
{
metric: {
A: 'A',
},
values: [
[1708623120, '122'],
[1708623180, '112'],
[1708623240, '106'],
[1708623300, '106'],
[1708623360, '116'],
[1708623420, '110'],
[1708623480, '110'],
[1708623540, '114'],
[1708623600, '114'],
[1708623660, '118'],
[1708623720, '110'],
[1708623780, '112'],
[1708623840, '116'],
[1708623900, '104'],
[1708623960, '106'],
[1708624020, '120'],
[1708624080, '110'],
[1708624140, '112'],
[1708624200, '110'],
[1708624260, '112'],
[1708624320, '110'],
[1708624380, '112'],
[1708624440, '108'],
[1708624500, '110'],
[1708624560, '114'],
[1708624620, '104'],
[1708624680, '122'],
[1708624740, '112'],
[1708624800, '104'],
[1708624860, '90'],
],
queryName: 'A',
legend: 'A',
},
],
resultType: '',
newResult: {
status: 'success',
data: {
resultType: '',
result: [
{
queryName: 'A',
series: [
{
labels: {
A: 'A',
},
values: [
{
timestamp: 1708623120000,
value: '122',
},
{
timestamp: 1708623180000,
value: '112',
},
{
timestamp: 1708623240000,
value: '106',
},
{
timestamp: 1708623300000,
value: '106',
},
{
timestamp: 1708623360000,
value: '116',
},
{
timestamp: 1708623420000,
value: '110',
},
{
timestamp: 1708623480000,
value: '110',
},
{
timestamp: 1708623540000,
value: '114',
},
{
timestamp: 1708623600000,
value: '114',
},
{
timestamp: 1708623660000,
value: '118',
},
{
timestamp: 1708623720000,
value: '110',
},
{
timestamp: 1708623780000,
value: '112',
},
{
timestamp: 1708623840000,
value: '116',
},
{
timestamp: 1708623900000,
value: '104',
},
{
timestamp: 1708623960000,
value: '106',
},
{
timestamp: 1708624020000,
value: '120',
},
{
timestamp: 1708624080000,
value: '110',
},
{
timestamp: 1708624140000,
value: '112',
},
{
timestamp: 1708624200000,
value: '110',
},
{
timestamp: 1708624260000,
value: '112',
},
{
timestamp: 1708624320000,
value: '110',
},
{
timestamp: 1708624380000,
value: '112',
},
{
timestamp: 1708624440000,
value: '108',
},
{
timestamp: 1708624500000,
value: '110',
},
{
timestamp: 1708624560000,
value: '114',
},
{
timestamp: 1708624620000,
value: '104',
},
{
timestamp: 1708624680000,
value: '122',
},
{
timestamp: 1708624740000,
value: '112',
},
{
timestamp: 1708624800000,
value: '104',
},
{
timestamp: 1708624860000,
value: '90',
},
],
},
],
list: null,
},
],
},
},
},
},
yAxisUnit: 'none',
minTimeScale: 1708623105,
maxTimeScale: 1708624905,
graphsVisibilityStates: [true, true],
thresholds: [],
softMax: null,
softMin: null,
panelType: PANEL_TYPES.BAR,
} as GetUPlotChartOptions;
export const seriesDataTimeSeries = [
{
label: 'Timestamp',
stroke: 'purple',
},
{
drawStyle: 'line',
lineInterpolation: 'spline',
show: true,
label: 'A',
stroke: '#6495ED',
width: 2,
spanGaps: true,
points: {
size: 5,
show: false,
stroke: '#6495ED',
},
},
];
export const seriesDataBarChart = [
{
label: 'Timestamp',
stroke: 'purple',
},
{
drawStyle: 'bars',
lineInterpolation: null,
show: true,
label: 'A',
fill: '#6495ED40',
stroke: '#6495ED',
width: 2,
spanGaps: true,
points: {
size: 5,
show: false,
stroke: '#6495ED',
},
},
];

View File

@ -0,0 +1,32 @@
/* eslint-disable @typescript-eslint/ban-ts-comment */
/* eslint-disable @typescript-eslint/explicit-function-return-type */
import getSeries from '../getSeriesData';
import {
seriesBarChartData,
seriesLineChartData,
} from './__mocks__/seriesData';
jest.mock('../getRenderer', () => jest.fn().mockImplementation(() => () => {}));
describe('Get Series Data', () => {
test('Should return series data for uplot chart', () => {
const seriesData = getSeries(seriesBarChartData);
expect(seriesData.length).toBe(5);
expect(seriesData[1].label).toBe('firstLegend');
expect(seriesData[1].show).toBe(true);
expect(seriesData[1].fill).toBe('#C7158540');
expect(seriesData[1].width).toBe(2);
});
test('Should return series drawline bar chart for panel type barchart', () => {
const seriesData = getSeries(seriesBarChartData);
// @ts-ignore
expect(seriesData[1].drawStyle).toBe('bars');
});
test('Should return seris drawline line chart for panel type time series', () => {
const seriesData = getSeries(seriesLineChartData);
// @ts-ignore
expect(seriesData[1].drawStyle).toBe('line');
});
});

View File

@ -0,0 +1,68 @@
/* eslint-disable @typescript-eslint/ban-ts-comment */
import { PANEL_TYPES } from 'constants/queryBuilder';
import { getUPlotChartOptions } from 'lib/uPlotLib/getUplotChartOptions';
import {
inputPropsTimeSeries,
seriesDataBarChart,
seriesDataTimeSeries,
} from './__mocks__/uplotChartOptionsData';
jest.mock('../../plugins/tooltipPlugin', () => jest.fn().mockReturnValue({}));
jest.mock('../getSeriesData', () =>
jest.fn().mockImplementation((props) => {
const { panelType } = props;
if (panelType === PANEL_TYPES.TIME_SERIES) {
return seriesDataTimeSeries;
}
return seriesDataBarChart;
}),
);
describe('getUPlotChartOptions', () => {
test('should return uPlot options', () => {
const options = getUPlotChartOptions(inputPropsTimeSeries);
expect(options.legend?.isolate).toBe(true);
expect(options.width).toBe(inputPropsTimeSeries.dimensions.width);
expect(options.height).toBe(inputPropsTimeSeries.dimensions.height - 30);
expect(options.axes?.length).toBe(2);
expect(options.series[1].label).toBe('A');
});
test('Should return line chart as drawStyle for time series', () => {
const options = getUPlotChartOptions(inputPropsTimeSeries);
// @ts-ignore
expect(options.series[1].drawStyle).toBe('line');
// @ts-ignore
expect(options.series[1].lineInterpolation).toBe('spline');
// @ts-ignore
expect(options.series[1].show).toBe(true);
expect(options.series[1].label).toBe('A');
expect(options.series[1].stroke).toBe('#6495ED');
expect(options.series[1].width).toBe(2);
expect(options.series[1].spanGaps).toBe(true);
// @ts-ignore
expect(options.series[1].points.size).toBe(5);
});
test('should return bar chart as drawStyle for panel type bar', () => {
const options = getUPlotChartOptions({
...inputPropsTimeSeries,
panelType: PANEL_TYPES.BAR,
});
// @ts-ignore
expect(options.series[1].drawStyle).toBe('bars');
// @ts-ignore
expect(options.series[1].lineInterpolation).toBe(null);
// @ts-ignore
expect(options.series[1].show).toBe(true);
expect(options.series[1].label).toBe('A');
expect(options.series[1].fill).toBe('#6495ED40');
expect(options.series[1].stroke).toBe('#6495ED');
expect(options.series[1].width).toBe(2);
expect(options.series[1].spanGaps).toBe(true);
// @ts-ignore
expect(options.series[1].points.size).toBe(5);
});
});

View File

@ -100,7 +100,13 @@ export function QueryBuilderProvider({
null,
);
const [panelType, setPanelType] = useState<PANEL_TYPES | null>(null);
const panelTypeQueryParams = urlQuery.get(
QueryParams.panelTypes,
) as PANEL_TYPES | null;
const [panelType, setPanelType] = useState<PANEL_TYPES | null>(
panelTypeQueryParams,
);
const [currentQuery, setCurrentQuery] = useState<QueryState>(queryState);
const [stagedQuery, setStagedQuery] = useState<Query | null>(null);

View File

@ -0,0 +1,9 @@
import { PANEL_TYPES } from 'constants/queryBuilder';
export const getGraphType = (panelType: PANEL_TYPES): PANEL_TYPES => {
// backend don't support graphType as bar, as we consume time series data, sending graphType as time_series whenever we use bar as panel_type
if (panelType === PANEL_TYPES.BAR) {
return PANEL_TYPES.TIME_SERIES;
}
return panelType;
};

View File

@ -0,0 +1,20 @@
import { QueryData } from 'types/api/widgets/getQuery';
// Sorting the series data in desending matter for plotting cummulative bar chart.
export const getSortedSeriesData = (
result: QueryData[] | undefined,
): QueryData[] => {
const seriesList = result || [];
return seriesList.sort((a, b) => {
if (a.values.length === 0) return 1;
if (b.values.length === 0) return -1;
const avgA =
a.values.reduce((acc, curr) => acc + parseFloat(curr[1]), 0) /
a.values.length;
const avgB =
b.values.reduce((acc, curr) => acc + parseFloat(curr[1]), 0) /
b.values.length;
return avgB - avgA;
});
};