feat: added support for bar chart stacking (#5138)

* feat: stacked bars uplot poc

* feat: stacked bars uplot poc

* feat: reverse the legend order

* fix: tooltip

* feat: added bands

* feat: added bands calculation function

* feat: code cleanup and added toggle for stacked and unstacked bars

* feat: minor fixes and better naming

* feat: fix jest test cases

* feat: fix data on view mode of bar chart stacked

* feat: make transulecent colors

* fix: build issues

* fix: legend issues in bar chart edit mode

* feat: added implementation details and refactored code in tooltip plugin

* fix: added missing return statement

* fix: eslint prettier issues

* fix: legend visibility issues on view mode

* fix: legend visibility issues on view mode

* feat: added info text

* fix: add info text only in full view mode

* fix: issue with zero index
This commit is contained in:
Vikrant Gupta 2024-06-10 17:15:30 +05:30 committed by GitHub
parent 6af5aa0253
commit f2aba5035a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
14 changed files with 438 additions and 717 deletions

View File

@ -204,7 +204,7 @@ function FullView({
<div
className={cx('graph-container', {
disabled: isDashboardLocked,
'height-widget': widget?.mergeAllActiveQueries,
'height-widget': widget?.mergeAllActiveQueries || widget?.stackedBarChart,
'list-graph-container': isListView,
})}
ref={fullViewRef}

View File

@ -241,6 +241,24 @@
}
}
.stack-chart {
margin-top: 16px;
display: flex;
justify-content: space-between;
gap: 8px;
.label {
color: var(--bg-vanilla-400);
font-family: 'Space Mono';
font-size: 13px;
font-style: normal;
font-weight: 400;
line-height: 18px; /* 138.462% */
letter-spacing: 0.52px;
text-transform: uppercase;
}
}
.bucket-config {
margin-top: 16px;
display: flex;

View File

@ -132,3 +132,17 @@ export const panelTypeVsColumnUnitPreferences: {
[PANEL_TYPES.HISTOGRAM]: false,
[PANEL_TYPES.EMPTY_WIDGET]: false,
} as const;
export const panelTypeVsStackingChartPreferences: {
[key in PANEL_TYPES]: boolean;
} = {
[PANEL_TYPES.TIME_SERIES]: false,
[PANEL_TYPES.VALUE]: false,
[PANEL_TYPES.TABLE]: false,
[PANEL_TYPES.LIST]: false,
[PANEL_TYPES.PIE]: false,
[PANEL_TYPES.BAR]: true,
[PANEL_TYPES.TRACE]: false,
[PANEL_TYPES.HISTOGRAM]: false,
[PANEL_TYPES.EMPTY_WIDGET]: false,
} as const;

View File

@ -29,6 +29,7 @@ import {
panelTypeVsFillSpan,
panelTypeVsPanelTimePreferences,
panelTypeVsSoftMinMax,
panelTypeVsStackingChartPreferences,
panelTypeVsThreshold,
panelTypeVsYAxisUnit,
} from './constants';
@ -48,6 +49,8 @@ function RightContainer({
selectedGraph,
bucketCount,
bucketWidth,
stackedBarChart,
setStackedBarChart,
setBucketCount,
setBucketWidth,
setSelectedTime,
@ -87,6 +90,8 @@ function RightContainer({
const allowYAxisUnit = panelTypeVsYAxisUnit[selectedGraph];
const allowCreateAlerts = panelTypeVsCreateAlert[selectedGraph];
const allowBucketConfig = panelTypeVsBucketConfig[selectedGraph];
const allowStackingBarChart =
panelTypeVsStackingChartPreferences[selectedGraph];
const allowPanelTimePreference =
panelTypeVsPanelTimePreferences[selectedGraph];
@ -231,6 +236,17 @@ function RightContainer({
</section>
)}
{allowStackingBarChart && (
<section className="stack-chart">
<Typography.Text className="label">Stack series</Typography.Text>
<Switch
checked={stackedBarChart}
size="small"
onChange={(checked): void => setStackedBarChart(checked)}
/>
</section>
)}
{allowBucketConfig && (
<section className="bucket-config">
<Typography.Text className="label">Number of buckets</Typography.Text>
@ -312,6 +328,8 @@ interface RightContainerProps {
setSelectedTime: Dispatch<SetStateAction<timePreferance>>;
selectedTime: timePreferance;
yAxisUnit: string;
stackedBarChart: boolean;
setStackedBarChart: Dispatch<SetStateAction<boolean>>;
bucketWidth: number;
bucketCount: number;
combineHistogram: boolean;

View File

@ -126,6 +126,10 @@ function NewWidget({ selectedGraph }: NewWidgetProps): JSX.Element {
const [stacked, setStacked] = useState<boolean>(
selectedWidget?.isStacked || false,
);
const [stackedBarChart, setStackedBarChart] = useState<boolean>(
selectedWidget?.stackedBarChart || false,
);
const [opacity, setOpacity] = useState<string>(selectedWidget?.opacity || '1');
const [thresholds, setThresholds] = useState<ThresholdProps[]>(
selectedWidget?.thresholds || [],
@ -195,6 +199,7 @@ function NewWidget({ selectedGraph }: NewWidgetProps): JSX.Element {
fillSpans: isFillSpans,
columnUnits,
bucketCount,
stackedBarChart,
bucketWidth,
mergeAllActiveQueries: combineHistogram,
selectedLogFields,
@ -219,6 +224,7 @@ function NewWidget({ selectedGraph }: NewWidgetProps): JSX.Element {
bucketWidth,
bucketCount,
combineHistogram,
stackedBarChart,
]);
const closeModal = (): void => {
@ -307,6 +313,7 @@ function NewWidget({ selectedGraph }: NewWidgetProps): JSX.Element {
opacity: selectedWidget?.opacity || '1',
nullZeroValues: selectedWidget?.nullZeroValues || 'zero',
title: selectedWidget?.title,
stackedBarChart: selectedWidget?.stackedBarChart || false,
yAxisUnit: selectedWidget?.yAxisUnit,
panelTypes: graphType,
query: currentQuery,
@ -332,6 +339,7 @@ function NewWidget({ selectedGraph }: NewWidgetProps): JSX.Element {
opacity: selectedWidget?.opacity || '1',
nullZeroValues: selectedWidget?.nullZeroValues || 'zero',
title: selectedWidget?.title,
stackedBarChart: selectedWidget?.stackedBarChart || false,
yAxisUnit: selectedWidget?.yAxisUnit,
panelTypes: graphType,
query: currentQuery,
@ -532,6 +540,8 @@ function NewWidget({ selectedGraph }: NewWidgetProps): JSX.Element {
setDescription={setDescription}
stacked={stacked}
setStacked={setStacked}
stackedBarChart={stackedBarChart}
setStackedBarChart={setStackedBarChart}
opacity={opacity}
yAxisUnit={yAxisUnit}
columnUnits={columnUnits}

View File

@ -0,0 +1,4 @@
.info-text {
margin-top: 8px;
padding: 8px;
}

View File

@ -1,3 +1,6 @@
import './UplotPanelWrapper.styles.scss';
import { Alert } from 'antd';
import { ToggleGraphProps } from 'components/Graph/types';
import Uplot from 'components/Uplot';
import { PANEL_TYPES } from 'constants/queryBuilder';
@ -8,6 +11,7 @@ import { useIsDarkMode } from 'hooks/useDarkMode';
import { useResizeObserver } from 'hooks/useDimensions';
import { getUPlotChartOptions } from 'lib/uPlotLib/getUplotChartOptions';
import { getUPlotChartData } from 'lib/uPlotLib/utils/getUplotChartData';
import { cloneDeep, isEqual, isUndefined } from 'lodash-es';
import _noop from 'lodash-es/noop';
import { useDashboard } from 'providers/Dashboard/Dashboard';
import { useEffect, useMemo, useRef, useState } from 'react';
@ -35,6 +39,8 @@ function UplotPanelWrapper({
const [maxTimeScale, setMaxTimeScale] = useState<number>();
const { currentQuery } = useQueryBuilder();
const [hiddenGraph, setHiddenGraph] = useState<{ [key: string]: boolean }>();
useEffect(() => {
if (toScrollWidgetId === widget.id) {
graphRef.current?.scrollIntoView({
@ -78,8 +84,26 @@ function UplotPanelWrapper({
const chartData = getUPlotChartData(
queryResponse?.data?.payload,
widget.fillSpans,
widget?.stackedBarChart,
hiddenGraph,
);
useEffect(() => {
if (widget.panelTypes === PANEL_TYPES.BAR && widget?.stackedBarChart) {
const graphV = cloneDeep(graphVisibility)?.slice(1);
const isSomeSelectedLegend = graphV?.some((v) => v === false);
if (isSomeSelectedLegend) {
const hiddenIndex = graphV?.findIndex((v) => v === true);
if (!isUndefined(hiddenIndex) && hiddenIndex !== -1) {
const updatedHiddenGraph = { [hiddenIndex]: true };
if (!isEqual(hiddenGraph, updatedHiddenGraph)) {
setHiddenGraph(updatedHiddenGraph);
}
}
}
}
}, [graphVisibility, hiddenGraph, widget.panelTypes, widget?.stackedBarChart]);
const options = useMemo(
() =>
getUPlotChartOptions({
@ -99,6 +123,9 @@ function UplotPanelWrapper({
setGraphsVisibilityStates: setGraphVisibility,
panelType: selectedGraph || widget.panelTypes,
currentQuery,
stackBarChart: widget?.stackedBarChart,
hiddenGraph,
setHiddenGraph,
}),
[
widget?.id,
@ -107,6 +134,7 @@ function UplotPanelWrapper({
widget.softMax,
widget.softMin,
widget.panelTypes,
widget?.stackedBarChart,
queryResponse.data?.payload,
containerDimensions,
isDarkMode,
@ -118,15 +146,23 @@ function UplotPanelWrapper({
setGraphVisibility,
selectedGraph,
currentQuery,
hiddenGraph,
],
);
return (
<div style={{ height: '100%', width: '100%' }} ref={graphRef}>
<Uplot options={options} data={chartData} ref={lineChartRef} />
{isFullViewMode && setGraphVisibility && (
{widget?.stackedBarChart && isFullViewMode && (
<Alert
message="Selecting multiple legends is currently not supported in case of stacked bar charts"
type="info"
className="info-text"
/>
)}
{isFullViewMode && setGraphVisibility && !widget?.stackedBarChart && (
<GraphManager
data={chartData}
data={getUPlotChartData(queryResponse?.data?.payload, widget.fillSpans)}
name={widget.id}
options={options}
yAxisUnit={widget.yAxisUnit}

View File

@ -10,9 +10,11 @@ import { saveLegendEntriesToLocalStorage } from 'container/GridCardLayout/GridCa
import { ThresholdProps } from 'container/NewWidget/RightContainer/Threshold/types';
import { Dimensions } from 'hooks/useDimensions';
import { convertValue } from 'lib/getConvertedValue';
import { cloneDeep, isUndefined } from 'lodash-es';
import _noop from 'lodash-es/noop';
import { MetricRangePayloadProps } from 'types/api/metrics/getQueryRange';
import { Query } from 'types/api/queryBuilder/queryBuilderData';
import { QueryData, QueryDataV3 } from 'types/api/widgets/getQuery';
import uPlot from 'uplot';
import onClickPlugin, { OnClickPluginOpts } from './plugins/onClickPlugin';
@ -42,6 +44,82 @@ export interface GetUPlotChartOptions {
softMin: number | null;
softMax: number | null;
currentQuery?: Query;
stackBarChart?: boolean;
hiddenGraph?: {
[key: string]: boolean;
};
setHiddenGraph?: Dispatch<
SetStateAction<{
[key: string]: boolean;
}>
>;
}
/** the function converts series A , series B , series C to
* series A , series A + series B , series A + series B + series C
* which helps us to always ensure the bar in the front is always
* of the smallest value.
*/
function getStackedSeries(apiResponse: QueryData[]): QueryData[] {
const series = cloneDeep(apiResponse);
for (let i = series.length - 2; i >= 0; i--) {
const { values } = series[i];
for (let j = 0; j < values.length; j++) {
values[j][1] = String(
parseFloat(values[j][1]) + parseFloat(series[i + 1].values[j][1]),
);
}
series[i].values = values;
}
return series;
}
/** this does the exact same operations as the function above for a different
* response format.
*/
function getStackedSeriesQueryFormat(apiResponse: QueryData[]): QueryData[] {
const series = cloneDeep(apiResponse);
for (let i = series.length - 2; i >= 0; i--) {
const { values } = series[i];
for (let j = 0; j < values.length; j++) {
values[j].value = String(
parseFloat(values[j].value) + parseFloat(series[i + 1].values[j].value),
);
}
series[i].values = values;
}
return series;
}
function getStackedSeriesYAxis(apiResponse: QueryDataV3[]): QueryDataV3[] {
const series = cloneDeep(apiResponse);
for (let i = 0; i < series.length; i++) {
series[i].series = getStackedSeriesQueryFormat(series[i].series);
}
return series;
}
/**
* here we define the different series bands which should get highlighted based
* on cursor hover. basically the to and the from destination of a particular band.
*/
function getBands(series): any[] {
const bands = [];
for (let i = 0; i < series.length; i++) {
bands.push({
series: [i === 0 ? -1 : i, i + 1],
});
}
return bands;
}
export const getUPlotChartOptions = ({
@ -61,9 +139,18 @@ export const getUPlotChartOptions = ({
softMin,
panelType,
currentQuery,
stackBarChart: stackChart,
hiddenGraph,
setHiddenGraph,
}: GetUPlotChartOptions): uPlot.Options => {
const timeScaleProps = getXAxisScale(minTimeScale, maxTimeScale);
const stackBarChart = stackChart && isUndefined(hiddenGraph);
const series = getStackedSeries(apiResponse?.data?.result || []);
const bands = stackBarChart ? getBands(series) : null;
return {
id,
width: dimensions.width,
@ -91,6 +178,7 @@ export const getUPlotChartOptions = ({
},
},
padding: [16, 16, 8, 8],
bands,
scales: {
x: {
spanGaps: true,
@ -99,7 +187,9 @@ export const getUPlotChartOptions = ({
y: {
...getYAxisScale({
thresholds,
series: apiResponse?.data?.newResult?.data?.result || [],
series: stackBarChart
? getStackedSeriesYAxis(apiResponse?.data?.newResult?.data?.result || [])
: apiResponse?.data?.newResult?.data?.result || [],
yAxisUnit,
softMax,
softMin,
@ -107,7 +197,7 @@ export const getUPlotChartOptions = ({
},
},
plugins: [
tooltipPlugin({ apiResponse, yAxisUnit }),
tooltipPlugin({ apiResponse, yAxisUnit, stackBarChart }),
onClickPlugin({
onClick: onClickHandler,
}),
@ -192,6 +282,17 @@ export const getUPlotChartOptions = ({
const seriesArray = Array.from(seriesEls);
seriesArray.forEach((seriesEl, index) => {
seriesEl.addEventListener('click', () => {
if (stackChart) {
setHiddenGraph((prev) => {
if (isUndefined(prev)) {
return { [index]: true };
}
if (prev[index] === true) {
return undefined;
}
return { [index]: true };
});
}
if (graphsVisibilityStates) {
setGraphsVisibilityStates?.((prev) => {
const newGraphVisibilityStates = [...prev];
@ -221,11 +322,16 @@ export const getUPlotChartOptions = ({
],
},
series: getSeries({
apiResponse,
series:
stackBarChart && isUndefined(hiddenGraph)
? series
: apiResponse?.data?.result,
widgetMetaData: apiResponse?.data.result,
graphsVisibilityStates,
panelType,
currentQuery,
stackBarChart,
hiddenGraph,
}),
axes: getAxes(isDarkMode, yAxisUnit),
};

View File

@ -22,6 +22,19 @@ interface UplotTooltipDataProps {
queryName: string;
}
function getTooltipBaseValue(
data: any[],
index: number,
idx: number,
stackBarChart: boolean | undefined,
): any {
if (stackBarChart && index + 1 < data.length) {
return data[index][idx] - data[index + 1][idx];
}
return data[index][idx];
}
const generateTooltipContent = (
seriesList: any[],
data: any[],
@ -31,6 +44,7 @@ const generateTooltipContent = (
isBillingUsageGraphs?: boolean,
isHistogramGraphs?: boolean,
isMergedSeries?: boolean,
stackBarChart?: boolean,
// eslint-disable-next-line sonarjs/cognitive-complexity
): HTMLElement => {
const container = document.createElement('div');
@ -67,7 +81,8 @@ const generateTooltipContent = (
unit = '',
} = seriesList[index - 1] || {};
const value = data[index][idx];
const value = getTooltipBaseValue(data, index, idx, stackBarChart);
const dataIngested = quantity[idx];
const label = isMergedSeries
? ''
@ -201,6 +216,7 @@ type ToolTipPluginProps = {
isBillingUsageGraphs?: boolean;
isHistogramGraphs?: boolean;
isMergedSeries?: boolean;
stackBarChart?: boolean;
};
const tooltipPlugin = ({
@ -209,6 +225,7 @@ const tooltipPlugin = ({
isBillingUsageGraphs,
isHistogramGraphs,
isMergedSeries,
stackBarChart,
}: ToolTipPluginProps): any => {
let over: HTMLElement;
let bound: HTMLElement;
@ -272,6 +289,7 @@ const tooltipPlugin = ({
isBillingUsageGraphs,
isHistogramGraphs,
isMergedSeries,
stackBarChart,
);
overlay.appendChild(content);
placement(overlay, anchor, 'right', 'start', { bound });

View File

@ -2,7 +2,7 @@
import { PANEL_TYPES } from 'constants/queryBuilder';
import { themeColors } from 'constants/theme';
import getLabelName from 'lib/getLabelName';
import { MetricRangePayloadProps } from 'types/api/metrics/getQueryRange';
import { isUndefined } from 'lodash-es';
import { Query } from 'types/api/queryBuilder/queryBuilderData';
import { QueryData } from 'types/api/widgets/getQuery';
@ -28,16 +28,18 @@ const paths = (
};
const getSeries = ({
apiResponse,
series,
widgetMetaData,
graphsVisibilityStates,
panelType,
hiddenGraph,
}: GetSeriesProps): uPlot.Options['series'] => {
const configurations: uPlot.Series[] = [
{ label: 'Timestamp', stroke: 'purple' },
];
const seriesList = apiResponse?.data.result || [];
const seriesList = series || [];
const newGraphVisibilityStates = graphsVisibilityStates?.slice(1);
for (let i = 0; i < seriesList?.length; i += 1) {
@ -64,7 +66,12 @@ const getSeries = ({
panelType && panelType === PANEL_TYPES.BAR
? null
: lineInterpolations.spline,
show: newGraphVisibilityStates ? newGraphVisibilityStates[i] : true,
// eslint-disable-next-line no-nested-ternary
show: newGraphVisibilityStates
? newGraphVisibilityStates[i]
: !isUndefined(hiddenGraph)
? hiddenGraph[i]
: true,
label,
fill: panelType && panelType === PANEL_TYPES.BAR ? `${color}40` : undefined,
stroke: color,
@ -84,11 +91,15 @@ const getSeries = ({
};
export type GetSeriesProps = {
apiResponse?: MetricRangePayloadProps;
series?: QueryData[];
widgetMetaData: QueryData[];
graphsVisibilityStates?: boolean[];
panelType?: PANEL_TYPES;
currentQuery?: Query;
stackBarChart?: boolean;
hiddenGraph?: {
[key: string]: boolean;
};
};
export default getSeries;

View File

@ -1,3 +1,4 @@
import { cloneDeep, isUndefined } from 'lodash-es';
import { MetricRangePayloadProps } from 'types/api/metrics/getQueryRange';
import { QueryData } from 'types/api/widgets/getQuery';
@ -62,9 +63,25 @@ function fillMissingXAxisTimestamps(
);
}
function getStackedSeries(val: any): any {
const series = cloneDeep(val) || [];
for (let i = series.length - 2; i >= 0; i--) {
for (let j = 0; j < series[i].length; j++) {
series[i][j] += series[i + 1][j];
}
}
return series;
}
export const getUPlotChartData = (
apiResponse?: MetricRangePayloadProps,
fillSpans?: boolean,
stackedBarChart?: boolean,
hiddenGraph?: {
[key: string]: boolean;
},
): any[] => {
const seriesList = apiResponse?.data?.result || [];
const timestampArr = getXAxisTimestamps(seriesList);
@ -74,5 +91,10 @@ export const getUPlotChartData = (
fillSpans || false,
);
return [timestampArr, ...yAxisValuesArr];
return [
timestampArr,
...(stackedBarChart && isUndefined(hiddenGraph)
? getStackedSeries(yAxisValuesArr)
: yAxisValuesArr),
];
};

View File

@ -3,360 +3,91 @@ 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',
},
series: [
{
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'],
],
resultType: '',
newResult: {
status: 'success',
data: {
resultType: '',
result: [
{
queryName: 'A',
series: [
{
labels: {},
labelsArray: [],
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: [],
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,
},
],
},
},
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',
},
],
widgetMetaData: [
{
metric: {},
@ -446,360 +177,91 @@ export const seriesBarChartData = {
} 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',
},
series: [
{
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'],
],
resultType: '',
newResult: {
status: 'success',
data: {
resultType: '',
result: [
{
queryName: 'A',
series: [
{
labels: {},
labelsArray: [],
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: [],
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,
},
],
},
},
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',
},
],
widgetMetaData: [
{
metric: {},

View File

@ -27,6 +27,7 @@ describe('Get Series Data', () => {
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

@ -97,6 +97,7 @@ export interface IBaseWidget {
timePreferance: timePreferenceType;
stepSize?: number;
yAxisUnit?: string;
stackedBarChart?: boolean;
bucketCount?: number;
bucketWidth?: number;
mergeAllActiveQueries?: boolean;