diff --git a/frontend/src/container/GridCardLayout/GridCard/FullView/index.tsx b/frontend/src/container/GridCardLayout/GridCard/FullView/index.tsx index 184c34e77b..a1dab3d33f 100644 --- a/frontend/src/container/GridCardLayout/GridCard/FullView/index.tsx +++ b/frontend/src/container/GridCardLayout/GridCard/FullView/index.tsx @@ -204,7 +204,7 @@ function FullView({
)} + {allowStackingBarChart && ( +
+ Stack series + setStackedBarChart(checked)} + /> +
+ )} + {allowBucketConfig && (
Number of buckets @@ -312,6 +328,8 @@ interface RightContainerProps { setSelectedTime: Dispatch>; selectedTime: timePreferance; yAxisUnit: string; + stackedBarChart: boolean; + setStackedBarChart: Dispatch>; bucketWidth: number; bucketCount: number; combineHistogram: boolean; diff --git a/frontend/src/container/NewWidget/index.tsx b/frontend/src/container/NewWidget/index.tsx index bc7f5bf1fd..79c9cb9028 100644 --- a/frontend/src/container/NewWidget/index.tsx +++ b/frontend/src/container/NewWidget/index.tsx @@ -126,6 +126,10 @@ function NewWidget({ selectedGraph }: NewWidgetProps): JSX.Element { const [stacked, setStacked] = useState( selectedWidget?.isStacked || false, ); + + const [stackedBarChart, setStackedBarChart] = useState( + selectedWidget?.stackedBarChart || false, + ); const [opacity, setOpacity] = useState(selectedWidget?.opacity || '1'); const [thresholds, setThresholds] = useState( 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} diff --git a/frontend/src/container/PanelWrapper/UplotPanelWrapper.styles.scss b/frontend/src/container/PanelWrapper/UplotPanelWrapper.styles.scss new file mode 100644 index 0000000000..a1ab2e3c9e --- /dev/null +++ b/frontend/src/container/PanelWrapper/UplotPanelWrapper.styles.scss @@ -0,0 +1,4 @@ +.info-text { + margin-top: 8px; + padding: 8px; +} diff --git a/frontend/src/container/PanelWrapper/UplotPanelWrapper.tsx b/frontend/src/container/PanelWrapper/UplotPanelWrapper.tsx index f95d5772af..dc404adabb 100644 --- a/frontend/src/container/PanelWrapper/UplotPanelWrapper.tsx +++ b/frontend/src/container/PanelWrapper/UplotPanelWrapper.tsx @@ -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(); 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 (
- {isFullViewMode && setGraphVisibility && ( + {widget?.stackedBarChart && isFullViewMode && ( + + )} + {isFullViewMode && setGraphVisibility && !widget?.stackedBarChart && ( + >; +} + +/** 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), }; diff --git a/frontend/src/lib/uPlotLib/plugins/tooltipPlugin.ts b/frontend/src/lib/uPlotLib/plugins/tooltipPlugin.ts index 7a5cd64f88..b468f5847a 100644 --- a/frontend/src/lib/uPlotLib/plugins/tooltipPlugin.ts +++ b/frontend/src/lib/uPlotLib/plugins/tooltipPlugin.ts @@ -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 }); diff --git a/frontend/src/lib/uPlotLib/utils/getSeriesData.ts b/frontend/src/lib/uPlotLib/utils/getSeriesData.ts index 92dbbab8bb..e0537e8e9f 100644 --- a/frontend/src/lib/uPlotLib/utils/getSeriesData.ts +++ b/frontend/src/lib/uPlotLib/utils/getSeriesData.ts @@ -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; diff --git a/frontend/src/lib/uPlotLib/utils/getUplotChartData.ts b/frontend/src/lib/uPlotLib/utils/getUplotChartData.ts index d1f5a7ffbc..0effbbe390 100644 --- a/frontend/src/lib/uPlotLib/utils/getUplotChartData.ts +++ b/frontend/src/lib/uPlotLib/utils/getUplotChartData.ts @@ -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), + ]; }; diff --git a/frontend/src/lib/uPlotLib/utils/tests/__mocks__/seriesData.ts b/frontend/src/lib/uPlotLib/utils/tests/__mocks__/seriesData.ts index 2ff063e2ab..5e859a5c6d 100644 --- a/frontend/src/lib/uPlotLib/utils/tests/__mocks__/seriesData.ts +++ b/frontend/src/lib/uPlotLib/utils/tests/__mocks__/seriesData.ts @@ -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: {}, diff --git a/frontend/src/lib/uPlotLib/utils/tests/getSeriesData.test.ts b/frontend/src/lib/uPlotLib/utils/tests/getSeriesData.test.ts index 75ee3c7f58..199df6f540 100644 --- a/frontend/src/lib/uPlotLib/utils/tests/getSeriesData.test.ts +++ b/frontend/src/lib/uPlotLib/utils/tests/getSeriesData.test.ts @@ -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'); }); }); diff --git a/frontend/src/types/api/dashboard/getAll.ts b/frontend/src/types/api/dashboard/getAll.ts index af254e032e..c73884c926 100644 --- a/frontend/src/types/api/dashboard/getAll.ts +++ b/frontend/src/types/api/dashboard/getAll.ts @@ -97,6 +97,7 @@ export interface IBaseWidget { timePreferance: timePreferenceType; stepSize?: number; yAxisUnit?: string; + stackedBarChart?: boolean; bucketCount?: number; bucketWidth?: number; mergeAllActiveQueries?: boolean;