mirror of
https://git.mirrors.martin98.com/https://github.com/SigNoz/signoz
synced 2025-08-14 23:45:55 +08:00
[Feat]: Uplot Threshold in Time Series. (#3974)
* refactor: resolve merge conflict * refactor: added support to value conversion * refactor: linter fixes * refactor: build fixes
This commit is contained in:
parent
58ccbdbec4
commit
9333fdcd0b
@ -118,10 +118,18 @@ function ChartPreview({
|
|||||||
apiResponse: queryResponse?.data?.payload,
|
apiResponse: queryResponse?.data?.payload,
|
||||||
dimensions: containerDimensions,
|
dimensions: containerDimensions,
|
||||||
isDarkMode,
|
isDarkMode,
|
||||||
thresholdText: `${t(
|
thresholds: [
|
||||||
|
{
|
||||||
|
index: '0', // no impact
|
||||||
|
keyIndex: 0,
|
||||||
|
moveThreshold: (): void => {},
|
||||||
|
selectedGraph: PANEL_TYPES.TIME_SERIES, // no impact
|
||||||
|
thresholdValue,
|
||||||
|
thresholdLabel: `${t(
|
||||||
'preview_chart_threshold_label',
|
'preview_chart_threshold_label',
|
||||||
)} (y=${thresholdValue} ${query?.unit || ''})`,
|
)} (y=${thresholdValue} ${query?.unit || ''})`,
|
||||||
thresholdValue,
|
},
|
||||||
|
],
|
||||||
}),
|
}),
|
||||||
[
|
[
|
||||||
query?.unit,
|
query?.unit,
|
||||||
|
@ -113,6 +113,7 @@ function FullView({
|
|||||||
onDragSelect,
|
onDragSelect,
|
||||||
graphsVisibilityStates,
|
graphsVisibilityStates,
|
||||||
setGraphsVisibilityStates,
|
setGraphsVisibilityStates,
|
||||||
|
thresholds: widget.thresholds,
|
||||||
});
|
});
|
||||||
|
|
||||||
setChartOptions(newChartOptions);
|
setChartOptions(newChartOptions);
|
||||||
|
@ -108,10 +108,12 @@ function GridCardGraph({
|
|||||||
onDragSelect,
|
onDragSelect,
|
||||||
yAxisUnit: widget?.yAxisUnit,
|
yAxisUnit: widget?.yAxisUnit,
|
||||||
onClickHandler,
|
onClickHandler,
|
||||||
|
thresholds: widget.thresholds,
|
||||||
}),
|
}),
|
||||||
[
|
[
|
||||||
widget?.id,
|
widget?.id,
|
||||||
widget?.yAxisUnit,
|
widget?.yAxisUnit,
|
||||||
|
widget.thresholds,
|
||||||
queryResponse.data?.payload,
|
queryResponse.data?.payload,
|
||||||
containerDimensions,
|
containerDimensions,
|
||||||
isDarkMode,
|
isDarkMode,
|
||||||
|
@ -61,6 +61,7 @@ function WidgetGraph({
|
|||||||
dimensions: containerDimensions,
|
dimensions: containerDimensions,
|
||||||
isDarkMode,
|
isDarkMode,
|
||||||
onDragSelect,
|
onDragSelect,
|
||||||
|
thresholds,
|
||||||
fillSpans,
|
fillSpans,
|
||||||
}),
|
}),
|
||||||
[
|
[
|
||||||
@ -70,6 +71,7 @@ function WidgetGraph({
|
|||||||
containerDimensions,
|
containerDimensions,
|
||||||
isDarkMode,
|
isDarkMode,
|
||||||
onDragSelect,
|
onDragSelect,
|
||||||
|
thresholds,
|
||||||
fillSpans,
|
fillSpans,
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
@ -1,7 +1,16 @@
|
|||||||
import './Threshold.styles.scss';
|
import './Threshold.styles.scss';
|
||||||
|
|
||||||
import { CheckOutlined, DeleteOutlined, EditOutlined } from '@ant-design/icons';
|
import { CheckOutlined, DeleteOutlined, EditOutlined } from '@ant-design/icons';
|
||||||
import { Card, Divider, InputNumber, Select, Space, Typography } from 'antd';
|
import {
|
||||||
|
Card,
|
||||||
|
Divider,
|
||||||
|
Input,
|
||||||
|
InputNumber,
|
||||||
|
Select,
|
||||||
|
Space,
|
||||||
|
Typography,
|
||||||
|
} from 'antd';
|
||||||
|
import { PANEL_TYPES } from 'constants/queryBuilder';
|
||||||
import { useIsDarkMode } from 'hooks/useDarkMode';
|
import { useIsDarkMode } from 'hooks/useDarkMode';
|
||||||
import { useRef, useState } from 'react';
|
import { useRef, useState } from 'react';
|
||||||
import { useDrag, useDrop, XYCoord } from 'react-dnd';
|
import { useDrag, useDrop, XYCoord } from 'react-dnd';
|
||||||
@ -24,6 +33,8 @@ function Threshold({
|
|||||||
setThresholds,
|
setThresholds,
|
||||||
keyIndex,
|
keyIndex,
|
||||||
moveThreshold,
|
moveThreshold,
|
||||||
|
selectedGraph,
|
||||||
|
thresholdLabel = '',
|
||||||
}: ThresholdProps): JSX.Element {
|
}: ThresholdProps): JSX.Element {
|
||||||
const [isEditMode, setIsEditMode] = useState<boolean>(isEditEnabled);
|
const [isEditMode, setIsEditMode] = useState<boolean>(isEditEnabled);
|
||||||
const [operator, setOperator] = useState<string | number>(
|
const [operator, setOperator] = useState<string | number>(
|
||||||
@ -35,6 +46,7 @@ function Threshold({
|
|||||||
const [format, setFormat] = useState<ThresholdProps['thresholdFormat']>(
|
const [format, setFormat] = useState<ThresholdProps['thresholdFormat']>(
|
||||||
thresholdFormat,
|
thresholdFormat,
|
||||||
);
|
);
|
||||||
|
const [label, setLabel] = useState<string>(thresholdLabel);
|
||||||
|
|
||||||
const isDarkMode = useIsDarkMode();
|
const isDarkMode = useIsDarkMode();
|
||||||
|
|
||||||
@ -54,6 +66,7 @@ function Threshold({
|
|||||||
thresholdOperator: operator as ThresholdProps['thresholdOperator'],
|
thresholdOperator: operator as ThresholdProps['thresholdOperator'],
|
||||||
thresholdUnit: unit,
|
thresholdUnit: unit,
|
||||||
thresholdValue: value,
|
thresholdValue: value,
|
||||||
|
thresholdLabel: label,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
return threshold;
|
return threshold;
|
||||||
@ -148,6 +161,11 @@ function Threshold({
|
|||||||
|
|
||||||
const opacity = isDragging ? 0 : 1;
|
const opacity = isDragging ? 0 : 1;
|
||||||
drag(drop(ref));
|
drag(drop(ref));
|
||||||
|
const handleLabelChange = (
|
||||||
|
event: React.ChangeEvent<HTMLInputElement>,
|
||||||
|
): void => {
|
||||||
|
setLabel(event.target.value);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
@ -178,19 +196,31 @@ function Threshold({
|
|||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<Space>
|
<Space>
|
||||||
|
{selectedGraph === PANEL_TYPES.TIME_SERIES && (
|
||||||
|
<>
|
||||||
|
<Typography.Text>Label</Typography.Text>
|
||||||
|
{isEditMode ? (
|
||||||
|
<Input defaultValue={label} onChange={handleLabelChange} />
|
||||||
|
) : (
|
||||||
|
<ShowCaseValue width="180px" value={label} />
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
{selectedGraph === PANEL_TYPES.VALUE && (
|
||||||
|
<>
|
||||||
<Typography.Text>If value is</Typography.Text>
|
<Typography.Text>If value is</Typography.Text>
|
||||||
{isEditMode ? (
|
{isEditMode ? (
|
||||||
<Select
|
<Select
|
||||||
style={{ maxWidth: '73px', backgroundColor: '#141414' }}
|
style={{ minWidth: '73px' }}
|
||||||
bordered={false}
|
|
||||||
defaultValue={operator}
|
defaultValue={operator}
|
||||||
options={operatorOptions}
|
options={operatorOptions}
|
||||||
onChange={handleOperatorChange}
|
onChange={handleOperatorChange}
|
||||||
showSearch
|
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<ShowCaseValue width="49px" value={operator} />
|
<ShowCaseValue width="49px" value={operator} />
|
||||||
)}
|
)}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
</Space>
|
</Space>
|
||||||
</div>
|
</div>
|
||||||
<div className="threshold-units-selector">
|
<div className="threshold-units-selector">
|
||||||
@ -228,18 +258,17 @@ function Threshold({
|
|||||||
) : (
|
) : (
|
||||||
<ShowCaseValue width="100px" value={<CustomColor color={color} />} />
|
<ShowCaseValue width="100px" value={<CustomColor color={color} />} />
|
||||||
)}
|
)}
|
||||||
{isEditMode ? (
|
{isEditMode && selectedGraph === PANEL_TYPES.VALUE ? (
|
||||||
|
<>
|
||||||
<Select
|
<Select
|
||||||
style={{ maxWidth: '100px', backgroundColor: '#141414' }}
|
style={{ minWidth: '100px' }}
|
||||||
bordered={false}
|
|
||||||
defaultValue={format}
|
defaultValue={format}
|
||||||
options={showAsOptions}
|
options={showAsOptions}
|
||||||
onChange={handlerFormatChange}
|
onChange={handlerFormatChange}
|
||||||
showSearch
|
|
||||||
/>
|
/>
|
||||||
) : (
|
|
||||||
<ShowCaseValue width="100px" value={format} />
|
<ShowCaseValue width="100px" value={format} />
|
||||||
)}
|
</>
|
||||||
|
) : null}
|
||||||
</Space>
|
</Space>
|
||||||
</Space>
|
</Space>
|
||||||
</div>
|
</div>
|
||||||
@ -255,6 +284,7 @@ Threshold.defaultProps = {
|
|||||||
thresholdUnit: undefined,
|
thresholdUnit: undefined,
|
||||||
thresholdColor: undefined,
|
thresholdColor: undefined,
|
||||||
thresholdFormat: undefined,
|
thresholdFormat: undefined,
|
||||||
|
thresholdLabel: undefined,
|
||||||
isEditEnabled: false,
|
isEditEnabled: false,
|
||||||
thresholdDeleteHandler: undefined,
|
thresholdDeleteHandler: undefined,
|
||||||
};
|
};
|
||||||
|
@ -13,6 +13,7 @@ function ThresholdSelector({
|
|||||||
thresholds,
|
thresholds,
|
||||||
setThresholds,
|
setThresholds,
|
||||||
yAxisUnit,
|
yAxisUnit,
|
||||||
|
selectedGraph,
|
||||||
}: ThresholdSelectorProps): JSX.Element {
|
}: ThresholdSelectorProps): JSX.Element {
|
||||||
const moveThreshold = useCallback(
|
const moveThreshold = useCallback(
|
||||||
(dragIndex: number, hoverIndex: number) => {
|
(dragIndex: number, hoverIndex: number) => {
|
||||||
@ -42,6 +43,7 @@ function ThresholdSelector({
|
|||||||
thresholdValue: 0,
|
thresholdValue: 0,
|
||||||
moveThreshold,
|
moveThreshold,
|
||||||
keyIndex: thresholds.length,
|
keyIndex: thresholds.length,
|
||||||
|
selectedGraph,
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
};
|
};
|
||||||
@ -71,6 +73,8 @@ function ThresholdSelector({
|
|||||||
setThresholds={setThresholds}
|
setThresholds={setThresholds}
|
||||||
keyIndex={idx}
|
keyIndex={idx}
|
||||||
moveThreshold={moveThreshold}
|
moveThreshold={moveThreshold}
|
||||||
|
selectedGraph={selectedGraph}
|
||||||
|
thresholdLabel={threshold.thresholdLabel}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
<Button className="threshold-selector-button" onClick={addThresholdHandler}>
|
<Button className="threshold-selector-button" onClick={addThresholdHandler}>
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import { PANEL_TYPES } from 'constants/queryBuilder';
|
||||||
import { Dispatch, ReactNode, SetStateAction } from 'react';
|
import { Dispatch, ReactNode, SetStateAction } from 'react';
|
||||||
|
|
||||||
type ThresholdOperators = '>' | '<' | '>=' | '<=' | '=';
|
type ThresholdOperators = '>' | '<' | '>=' | '<=' | '=';
|
||||||
@ -12,8 +13,10 @@ export type ThresholdProps = {
|
|||||||
thresholdColor?: string;
|
thresholdColor?: string;
|
||||||
thresholdFormat?: 'Text' | 'Background';
|
thresholdFormat?: 'Text' | 'Background';
|
||||||
isEditEnabled?: boolean;
|
isEditEnabled?: boolean;
|
||||||
|
thresholdLabel?: string;
|
||||||
setThresholds?: Dispatch<SetStateAction<ThresholdProps[]>>;
|
setThresholds?: Dispatch<SetStateAction<ThresholdProps[]>>;
|
||||||
moveThreshold: (dragIndex: number, hoverIndex: number) => void;
|
moveThreshold: (dragIndex: number, hoverIndex: number) => void;
|
||||||
|
selectedGraph: PANEL_TYPES;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type ShowCaseValueProps = {
|
export type ShowCaseValueProps = {
|
||||||
@ -29,4 +32,5 @@ export type ThresholdSelectorProps = {
|
|||||||
yAxisUnit: string;
|
yAxisUnit: string;
|
||||||
thresholds: ThresholdProps[];
|
thresholds: ThresholdProps[];
|
||||||
setThresholds: Dispatch<SetStateAction<ThresholdProps[]>>;
|
setThresholds: Dispatch<SetStateAction<ThresholdProps[]>>;
|
||||||
|
selectedGraph: PANEL_TYPES;
|
||||||
};
|
};
|
||||||
|
@ -182,6 +182,7 @@ function RightContainer({
|
|||||||
thresholds={thresholds}
|
thresholds={thresholds}
|
||||||
setThresholds={setThresholds}
|
setThresholds={setThresholds}
|
||||||
yAxisUnit={yAxisUnit}
|
yAxisUnit={yAxisUnit}
|
||||||
|
selectedGraph={selectedGraph}
|
||||||
/>
|
/>
|
||||||
</Container>
|
</Container>
|
||||||
);
|
);
|
||||||
|
283
frontend/src/lib/getConvertedValue.ts
Normal file
283
frontend/src/lib/getConvertedValue.ts
Normal file
@ -0,0 +1,283 @@
|
|||||||
|
const unitsMapping = [
|
||||||
|
{
|
||||||
|
label: 'Data',
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
label: 'bytes(IEC)',
|
||||||
|
value: 'bytes',
|
||||||
|
factor: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'bytes(SI)',
|
||||||
|
value: 'decbytes',
|
||||||
|
factor: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'bits(IEC)',
|
||||||
|
value: 'bits',
|
||||||
|
factor: 8, // 1 byte = 8 bits
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'bits(SI)',
|
||||||
|
value: 'decbits',
|
||||||
|
factor: 8, // 1 byte = 8 bits
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'kibibytes',
|
||||||
|
value: 'kbytes',
|
||||||
|
factor: 1024,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'kilobytes',
|
||||||
|
value: 'deckbytes',
|
||||||
|
factor: 1000,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'mebibytes',
|
||||||
|
value: 'mbytes',
|
||||||
|
factor: 1024 * 1024,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'megabytes',
|
||||||
|
value: 'decmbytes',
|
||||||
|
factor: 1000 * 1000,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'gibibytes',
|
||||||
|
value: 'gbytes',
|
||||||
|
factor: 1024 * 1024 * 1024,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'gigabytes',
|
||||||
|
value: 'decgbytes',
|
||||||
|
factor: 1000 * 1000 * 1000,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'tebibytes',
|
||||||
|
value: 'tbytes',
|
||||||
|
factor: 1024 * 1024 * 1024 * 1024,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'terabytes',
|
||||||
|
value: 'dectbytes',
|
||||||
|
factor: 1000 * 1000 * 1000 * 1000,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'pebibytes',
|
||||||
|
value: 'pbytes',
|
||||||
|
factor: 1024 * 1024 * 1024 * 1024 * 1024,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'petabytes',
|
||||||
|
value: 'decpbytes',
|
||||||
|
factor: 1000 * 1000 * 1000 * 1000 * 1000,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'DataRate',
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
label: 'bytes/sec(IEC)',
|
||||||
|
value: 'binBps',
|
||||||
|
factor: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'bytes/sec(SI)',
|
||||||
|
value: 'Bps',
|
||||||
|
factor: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'bits/sec(IEC)',
|
||||||
|
value: 'binbps',
|
||||||
|
factor: 8, // 1 byte = 8 bits
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'bits/sec(SI)',
|
||||||
|
value: 'bps',
|
||||||
|
factor: 8, // 1 byte = 8 bits
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'kibibytes/sec',
|
||||||
|
value: 'KiBs',
|
||||||
|
factor: 1024,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'kibibits/sec',
|
||||||
|
value: 'Kibits',
|
||||||
|
factor: 8 * 1024, // 1 KiB = 8 Kibits
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'kilobytes/sec',
|
||||||
|
value: 'KBs',
|
||||||
|
factor: 1000,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'kilobits/sec',
|
||||||
|
value: 'Kbits',
|
||||||
|
factor: 8 * 1000, // 1 KB = 8 Kbits
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'mebibytes/sec',
|
||||||
|
value: 'MiBs',
|
||||||
|
factor: 1024 * 1024,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'mebibits/sec',
|
||||||
|
value: 'Mibits',
|
||||||
|
factor: 8 * 1024 * 1024, // 1 MiB = 8 Mibits
|
||||||
|
},
|
||||||
|
// ... (other options)
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Time',
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
label: 'nanoseconds (ns)',
|
||||||
|
value: 'ns',
|
||||||
|
factor: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'microseconds (µs)',
|
||||||
|
value: 'µs',
|
||||||
|
factor: 1000, // 1 ms = 1000 µs
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'milliseconds (ms)',
|
||||||
|
value: 'ms',
|
||||||
|
factor: 1000 * 1000, // 1 s = 1000 ms
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'seconds (s)',
|
||||||
|
value: 's',
|
||||||
|
factor: 1000 * 1000 * 1000, // 1 s = 1000 ms
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'minutes (m)',
|
||||||
|
value: 'm',
|
||||||
|
factor: 60 * 1000 * 1000 * 1000, // 1 m = 60 s
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'hours (h)',
|
||||||
|
value: 'h',
|
||||||
|
factor: 60 * 60 * 1000 * 1000 * 1000, // 1 h = 60 m
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'days (d)',
|
||||||
|
value: 'd',
|
||||||
|
factor: 24 * 60 * 60 * 1000 * 1000 * 1000, // 1 d = 24 h
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Throughput',
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
label: 'counts/sec (cps)',
|
||||||
|
value: 'cps',
|
||||||
|
factor: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'ops/sec (ops)',
|
||||||
|
value: 'ops',
|
||||||
|
factor: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'requests/sec (reqps)',
|
||||||
|
value: 'reqps',
|
||||||
|
factor: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'reads/sec (rps)',
|
||||||
|
value: 'rps',
|
||||||
|
factor: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'writes/sec (wps)',
|
||||||
|
value: 'wps',
|
||||||
|
factor: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'I/O operations/sec (iops)',
|
||||||
|
value: 'iops',
|
||||||
|
factor: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'counts/min (cpm)',
|
||||||
|
value: 'cpm',
|
||||||
|
factor: 60, // 1 cpm = 60 cps
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'ops/min (opm)',
|
||||||
|
value: 'opm',
|
||||||
|
factor: 60, // 1 opm = 60 ops
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'reads/min (rpm)',
|
||||||
|
value: 'rpm',
|
||||||
|
factor: 60, // 1 rpm = 60 rps
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'writes/min (wpm)',
|
||||||
|
value: 'wpm',
|
||||||
|
factor: 60, // 1 wpm = 60 wps
|
||||||
|
},
|
||||||
|
// ... (other options)
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Miscellaneous',
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
label: 'Percent (0.0-1.0)',
|
||||||
|
value: 'percentunit',
|
||||||
|
factor: 1,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Boolean',
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
label: 'True / False',
|
||||||
|
value: 'bool',
|
||||||
|
factor: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Yes / No',
|
||||||
|
value: 'bool_yes_no',
|
||||||
|
factor: 1,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
function findUnitObject(
|
||||||
|
unitValue: string,
|
||||||
|
): { label: string; value: string; factor: number } | null {
|
||||||
|
const unitObj = unitsMapping
|
||||||
|
.map((category) => category.options.find((unit) => unit.value === unitValue))
|
||||||
|
.find(Boolean);
|
||||||
|
|
||||||
|
return unitObj || null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function convertValue(
|
||||||
|
value: number,
|
||||||
|
currentUnit: string,
|
||||||
|
targetUnit: string,
|
||||||
|
): number | null {
|
||||||
|
if (targetUnit === 'none') {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
const currentUnitObj = findUnitObject(currentUnit);
|
||||||
|
const targetUnitObj = findUnitObject(targetUnit);
|
||||||
|
|
||||||
|
if (currentUnitObj && targetUnitObj) {
|
||||||
|
const baseValue = value * currentUnitObj.factor;
|
||||||
|
|
||||||
|
return baseValue / targetUnitObj.factor;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
@ -4,7 +4,9 @@
|
|||||||
import './uPlotLib.styles.scss';
|
import './uPlotLib.styles.scss';
|
||||||
|
|
||||||
import { FullViewProps } from 'container/GridCardLayout/GridCard/FullView/types';
|
import { FullViewProps } from 'container/GridCardLayout/GridCard/FullView/types';
|
||||||
|
import { ThresholdProps } from 'container/NewWidget/RightContainer/Threshold/types';
|
||||||
import { Dimensions } from 'hooks/useDimensions';
|
import { Dimensions } from 'hooks/useDimensions';
|
||||||
|
import { convertValue } from 'lib/getConvertedValue';
|
||||||
import _noop from 'lodash-es/noop';
|
import _noop from 'lodash-es/noop';
|
||||||
import { MetricRangePayloadProps } from 'types/api/metrics/getQueryRange';
|
import { MetricRangePayloadProps } from 'types/api/metrics/getQueryRange';
|
||||||
import uPlot from 'uplot';
|
import uPlot from 'uplot';
|
||||||
@ -24,6 +26,7 @@ interface GetUPlotChartOptions {
|
|||||||
onClickHandler?: OnClickPluginOpts['onClick'];
|
onClickHandler?: OnClickPluginOpts['onClick'];
|
||||||
graphsVisibilityStates?: boolean[];
|
graphsVisibilityStates?: boolean[];
|
||||||
setGraphsVisibilityStates?: FullViewProps['setGraphsVisibilityStates'];
|
setGraphsVisibilityStates?: FullViewProps['setGraphsVisibilityStates'];
|
||||||
|
thresholds?: ThresholdProps[];
|
||||||
thresholdValue?: number;
|
thresholdValue?: number;
|
||||||
thresholdText?: string;
|
thresholdText?: string;
|
||||||
fillSpans?: boolean;
|
fillSpans?: boolean;
|
||||||
@ -39,8 +42,7 @@ export const getUPlotChartOptions = ({
|
|||||||
onClickHandler = _noop,
|
onClickHandler = _noop,
|
||||||
graphsVisibilityStates,
|
graphsVisibilityStates,
|
||||||
setGraphsVisibilityStates,
|
setGraphsVisibilityStates,
|
||||||
thresholdValue,
|
thresholds,
|
||||||
thresholdText,
|
|
||||||
fillSpans,
|
fillSpans,
|
||||||
}: GetUPlotChartOptions): uPlot.Options => ({
|
}: GetUPlotChartOptions): uPlot.Options => ({
|
||||||
id,
|
id,
|
||||||
@ -86,13 +88,22 @@ export const getUPlotChartOptions = ({
|
|||||||
hooks: {
|
hooks: {
|
||||||
draw: [
|
draw: [
|
||||||
(u): void => {
|
(u): void => {
|
||||||
if (thresholdValue) {
|
thresholds?.forEach((threshold) => {
|
||||||
|
if (threshold.thresholdValue !== undefined) {
|
||||||
const { ctx } = u;
|
const { ctx } = u;
|
||||||
ctx.save();
|
ctx.save();
|
||||||
|
|
||||||
const yPos = u.valToPos(thresholdValue, 'y', true);
|
const yPos = u.valToPos(
|
||||||
|
convertValue(
|
||||||
|
threshold.thresholdValue,
|
||||||
|
threshold.thresholdUnit,
|
||||||
|
yAxisUnit,
|
||||||
|
),
|
||||||
|
'y',
|
||||||
|
true,
|
||||||
|
);
|
||||||
|
|
||||||
ctx.strokeStyle = 'red';
|
ctx.strokeStyle = threshold.thresholdColor || 'red';
|
||||||
ctx.lineWidth = 2;
|
ctx.lineWidth = 2;
|
||||||
ctx.setLineDash([10, 5]);
|
ctx.setLineDash([10, 5]);
|
||||||
|
|
||||||
@ -107,16 +118,17 @@ export const getUPlotChartOptions = ({
|
|||||||
ctx.stroke();
|
ctx.stroke();
|
||||||
|
|
||||||
// Text configuration
|
// Text configuration
|
||||||
if (thresholdText) {
|
if (threshold.thresholdLabel) {
|
||||||
const text = thresholdText;
|
const text = threshold.thresholdLabel;
|
||||||
const textX = plotRight - ctx.measureText(text).width - 20;
|
const textX = plotRight - ctx.measureText(text).width - 20;
|
||||||
const textY = yPos - 15;
|
const textY = yPos - 15;
|
||||||
ctx.fillStyle = 'red';
|
ctx.fillStyle = threshold.thresholdColor || 'red';
|
||||||
ctx.fillText(text, textX, textY);
|
ctx.fillText(text, textX, textY);
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.restore();
|
ctx.restore();
|
||||||
}
|
}
|
||||||
|
});
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
setSelect: [
|
setSelect: [
|
||||||
|
Loading…
x
Reference in New Issue
Block a user