diff --git a/frontend/src/container/FormAlertRules/ChartPreview/index.tsx b/frontend/src/container/FormAlertRules/ChartPreview/index.tsx index 9c3effe973..400a6f85be 100644 --- a/frontend/src/container/FormAlertRules/ChartPreview/index.tsx +++ b/frontend/src/container/FormAlertRules/ChartPreview/index.tsx @@ -2,6 +2,7 @@ import { InfoCircleOutlined } from '@ant-design/icons'; import Spinner from 'components/Spinner'; import { initialQueriesMap, PANEL_TYPES } from 'constants/queryBuilder'; import GridPanelSwitch from 'container/GridPanelSwitch'; +import { getFormatNameByOptionId } from 'container/NewWidget/RightContainer/alertFomatCategories'; import { timePreferenceType } from 'container/NewWidget/RightContainer/timeItems'; import { Time } from 'container/TopNav/DateTimeSelection/config'; import { useGetQueryRange } from 'hooks/queryBuilder/useGetQueryRange'; @@ -19,7 +20,7 @@ import { EQueryType } from 'types/common/dashboard'; import { GlobalReducer } from 'types/reducer/globalTime'; import { ChartContainer, FailedMessageContainer } from './styles'; -import { covertIntoDataFormats } from './utils'; +import { getThresholdLabel } from './utils'; export interface ChartPreviewProps { name: string; @@ -50,12 +51,6 @@ function ChartPreview({ (state) => state.globalTime, ); - const thresholdValue = covertIntoDataFormats({ - value: threshold, - sourceUnit: alertDef?.condition.targetUnit, - targetUnit: query?.unit, - }); - const canQuery = useMemo((): boolean => { if (!query || query == null) { return false; @@ -110,6 +105,9 @@ function ChartPreview({ const isDarkMode = useIsDarkMode(); + const optionName = + getFormatNameByOptionId(alertDef?.condition.targetUnit || '') || ''; + const options = useMemo( () => getUPlotChartOptions({ @@ -124,10 +122,16 @@ function ChartPreview({ keyIndex: 0, moveThreshold: (): void => {}, selectedGraph: PANEL_TYPES.TIME_SERIES, // no impact - thresholdValue, + thresholdValue: threshold, thresholdLabel: `${t( 'preview_chart_threshold_label', - )} (y=${thresholdValue} ${query?.unit || ''})`, + )} (y=${getThresholdLabel( + optionName, + threshold, + alertDef?.condition.targetUnit, + query?.unit, + )})`, + thresholdUnit: alertDef?.condition.targetUnit, }, ], }), @@ -136,8 +140,10 @@ function ChartPreview({ queryResponse?.data?.payload, containerDimensions, isDarkMode, + threshold, t, - thresholdValue, + optionName, + alertDef?.condition.targetUnit, ], ); diff --git a/frontend/src/container/FormAlertRules/ChartPreview/utils.ts b/frontend/src/container/FormAlertRules/ChartPreview/utils.ts index dd9406b275..f17a6e3865 100644 --- a/frontend/src/container/FormAlertRules/ChartPreview/utils.ts +++ b/frontend/src/container/FormAlertRules/ChartPreview/utils.ts @@ -51,6 +51,21 @@ export function covertIntoDataFormats({ return Number.isNaN(result) ? 0 : result; } +export const getThresholdLabel = ( + optionName: string, + value: number, + unit?: string, + yAxisUnit?: string, +): string => { + if ( + unit === MiscellaneousFormats.PercentUnit || + yAxisUnit === MiscellaneousFormats.PercentUnit + ) { + return `${value * 100}%`; + } + return `${value} ${optionName}`; +}; + interface IUnit { value: number; sourceUnit?: string; diff --git a/frontend/src/container/NewWidget/RightContainer/alertFomatCategories.ts b/frontend/src/container/NewWidget/RightContainer/alertFomatCategories.ts index b9ad3feb18..09acc57d0a 100644 --- a/frontend/src/container/NewWidget/RightContainer/alertFomatCategories.ts +++ b/frontend/src/container/NewWidget/RightContainer/alertFomatCategories.ts @@ -6,6 +6,8 @@ import { CategoryNames, DataFormats, DataRateFormats, + HelperCategory, + HelperFormat, MiscellaneousFormats, ThroughputFormats, TimeFormats, @@ -119,3 +121,10 @@ export const getCategoryByOptionId = (id: string): Category | undefined => export const isCategoryName = (name: string): name is CategoryNames => alertsCategory.some((category) => category.name === name); + +const allFormats: HelperFormat[] = alertsCategory.flatMap( + (category: HelperCategory) => category.formats, +); + +export const getFormatNameByOptionId = (id: string): string | undefined => + allFormats.find((format) => format.id === id)?.name; diff --git a/frontend/src/container/NewWidget/RightContainer/types.ts b/frontend/src/container/NewWidget/RightContainer/types.ts index 36d4d106ac..26b39cb3d8 100644 --- a/frontend/src/container/NewWidget/RightContainer/types.ts +++ b/frontend/src/container/NewWidget/RightContainer/types.ts @@ -362,3 +362,13 @@ export type Category = { }; export type DataTypeCategories = Category[]; + +export interface HelperFormat { + name: string; + id: string; +} + +export interface HelperCategory { + name: string; + formats: Format[]; +} diff --git a/frontend/src/lib/getConvertedValue.ts b/frontend/src/lib/getConvertedValue.ts index 8ebc2135ba..229b2d2677 100644 --- a/frontend/src/lib/getConvertedValue.ts +++ b/frontend/src/lib/getConvertedValue.ts @@ -265,10 +265,15 @@ function findUnitObject( export function convertValue( value: number, - currentUnit: string, - targetUnit: string, + currentUnit?: string, + targetUnit?: string, ): number | null { - if (targetUnit === 'none') { + if ( + targetUnit === 'none' || + !currentUnit || + !targetUnit || + currentUnit === targetUnit + ) { return value; } const currentUnitObj = findUnitObject(currentUnit); diff --git a/frontend/src/lib/uPlotLib/getUplotChartOptions.ts b/frontend/src/lib/uPlotLib/getUplotChartOptions.ts index 6cb07299bb..3a5ec4b2c6 100644 --- a/frontend/src/lib/uPlotLib/getUplotChartOptions.ts +++ b/frontend/src/lib/uPlotLib/getUplotChartOptions.ts @@ -15,6 +15,7 @@ import onClickPlugin, { OnClickPluginOpts } from './plugins/onClickPlugin'; import tooltipPlugin from './plugins/tooltipPlugin'; import getAxes from './utils/getAxes'; import getSeries from './utils/getSeriesData'; +import { getYAxisScale } from './utils/getYAxisScale'; interface GetUPlotChartOptions { id?: string; @@ -79,7 +80,11 @@ export const getUPlotChartOptions = ({ auto: true, // Automatically adjust scale range }, y: { - auto: true, + ...getYAxisScale( + thresholds, + apiResponse?.data.newResult.data.result, + yAxisUnit, + ), }, }, plugins: [ diff --git a/frontend/src/lib/uPlotLib/utils/getYAxisScale.ts b/frontend/src/lib/uPlotLib/utils/getYAxisScale.ts new file mode 100644 index 0000000000..d8b672b98e --- /dev/null +++ b/frontend/src/lib/uPlotLib/utils/getYAxisScale.ts @@ -0,0 +1,83 @@ +import { ThresholdProps } from 'container/NewWidget/RightContainer/Threshold/types'; +import { convertValue } from 'lib/getConvertedValue'; +import { QueryDataV3 } from 'types/api/widgets/getQuery'; + +function findMinMaxValues(data: QueryDataV3[]): [number, number] { + let min = 0; + let max = 0; + data?.forEach((entry) => { + entry.series?.forEach((series) => { + series.values.forEach((valueObj) => { + const value = parseFloat(valueObj.value); + if (!value) return; + min = Math.min(min, value); + max = Math.max(max, value); + }); + }); + }); + + return [min, max]; +} + +function findMinMaxThresholdValues( + thresholds: ThresholdProps[], + yAxisUnit?: string, +): [number, number] { + let minThresholdValue = 0; + let maxThresholdValue = 0; + + thresholds.forEach((entry) => { + const { thresholdValue, thresholdUnit } = entry; + if (thresholdValue === undefined) return; + minThresholdValue = Math.min( + minThresholdValue, + convertValue(thresholdValue, thresholdUnit, yAxisUnit) || 0, + ); + maxThresholdValue = Math.max( + maxThresholdValue, + convertValue(thresholdValue, thresholdUnit, yAxisUnit) || 0, + ); + }); + + return [minThresholdValue, maxThresholdValue]; +} + +function getRange( + thresholds: ThresholdProps[], + series: QueryDataV3[], + yAxisUnit?: string, +): [number, number] { + const [minThresholdValue, maxThresholdValue] = findMinMaxThresholdValues( + thresholds, + yAxisUnit, + ); + const [minSeriesValue, maxSeriesValue] = findMinMaxValues(series); + + const min = Math.min(minThresholdValue, minSeriesValue); + const max = Math.max(maxThresholdValue, maxSeriesValue); + + return [min, max]; +} + +function areAllSeriesEmpty(series: QueryDataV3[]): boolean { + return series.every((entry) => { + if (!entry.series) return true; + return entry.series.every((series) => series.values.length === 0); + }); +} + +export const getYAxisScale = ( + thresholds?: ThresholdProps[], + series?: QueryDataV3[], + yAxisUnit?: string, +): { + auto: boolean; + range?: [number, number]; +} => { + if (!thresholds || !series) return { auto: true }; + + if (areAllSeriesEmpty(series)) return { auto: true }; + + const [min, max] = getRange(thresholds, series, yAxisUnit); + return { auto: false, range: [min, max] }; +};