mirror of
https://github.com/SigNoz/signoz.git
synced 2026-05-02 04:59:45 -05:00
fix: handle threshold unit scaling issues (#10020)
This commit is contained in:
committed by
GitHub
parent
e9d66b8094
commit
8cabaafc58
@@ -107,7 +107,6 @@ dist/
|
||||
downloads/
|
||||
eggs/
|
||||
.eggs/
|
||||
lib/
|
||||
lib64/
|
||||
parts/
|
||||
sdist/
|
||||
|
||||
@@ -37,10 +37,7 @@ function ThresholdItem({
|
||||
);
|
||||
if (units.length === 0) {
|
||||
component = (
|
||||
<Tooltip
|
||||
trigger="hover"
|
||||
title="Please select a Y-axis unit for the query first"
|
||||
>
|
||||
<Tooltip trigger="hover" title="No compatible units available">
|
||||
<Select
|
||||
placeholder="Unit"
|
||||
value={threshold.unit ? threshold.unit : null}
|
||||
|
||||
@@ -47,9 +47,17 @@ export function getCategoryByOptionId(id: string): string | undefined {
|
||||
}
|
||||
|
||||
export function getCategorySelectOptionByName(
|
||||
name: string,
|
||||
name: string | undefined,
|
||||
): DefaultOptionType[] {
|
||||
if (!name) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const categories = getYAxisCategories(YAxisSource.ALERTS);
|
||||
if (!categories.length) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return (
|
||||
categories
|
||||
.find((category) => category.name === name)
|
||||
|
||||
@@ -4,3 +4,7 @@
|
||||
gap: 8px;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.rule-unit-selector {
|
||||
width: 150px;
|
||||
}
|
||||
|
||||
@@ -15,8 +15,7 @@ import { DefaultOptionType } from 'antd/es/select';
|
||||
import {
|
||||
getCategoryByOptionId,
|
||||
getCategorySelectOptionByName,
|
||||
} from 'container/NewWidget/RightContainer/alertFomatCategories';
|
||||
import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
|
||||
} from 'container/CreateAlertV2/AlertCondition/utils';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import {
|
||||
AlertDef,
|
||||
@@ -43,10 +42,10 @@ function RuleOptions({
|
||||
setAlertDef,
|
||||
queryCategory,
|
||||
queryOptions,
|
||||
yAxisUnit,
|
||||
}: RuleOptionsProps): JSX.Element {
|
||||
// init namespace for translations
|
||||
const { t } = useTranslation('alerts');
|
||||
const { currentQuery } = useQueryBuilder();
|
||||
|
||||
const { ruleType } = alertDef;
|
||||
|
||||
@@ -365,11 +364,9 @@ function RuleOptions({
|
||||
</InlineSelect>
|
||||
);
|
||||
|
||||
const selectedCategory = getCategoryByOptionId(currentQuery?.unit || '');
|
||||
const selectedCategory = getCategoryByOptionId(yAxisUnit);
|
||||
|
||||
const categorySelectOptions = getCategorySelectOptionByName(
|
||||
selectedCategory?.name,
|
||||
);
|
||||
const categorySelectOptions = getCategorySelectOptionByName(selectedCategory);
|
||||
|
||||
const step3Label = alertDef.alertType === 'METRIC_BASED_ALERT' ? '3' : '2';
|
||||
|
||||
@@ -402,6 +399,7 @@ function RuleOptions({
|
||||
|
||||
<Form.Item noStyle>
|
||||
<Select
|
||||
className="rule-unit-selector"
|
||||
getPopupContainer={popupContainer}
|
||||
allowClear
|
||||
showSearch
|
||||
@@ -515,5 +513,6 @@ interface RuleOptionsProps {
|
||||
setAlertDef: (a: AlertDef) => void;
|
||||
queryCategory: EQueryType;
|
||||
queryOptions: DefaultOptionType[];
|
||||
yAxisUnit: string;
|
||||
}
|
||||
export default RuleOptions;
|
||||
|
||||
@@ -914,6 +914,7 @@ function FormAlertRules({
|
||||
alertDef={alertDef}
|
||||
setAlertDef={setAlertDef}
|
||||
queryOptions={queryOptions}
|
||||
yAxisUnit={yAxisUnit || ''}
|
||||
/>
|
||||
|
||||
{renderBasicInfo()}
|
||||
|
||||
@@ -0,0 +1,132 @@
|
||||
import { UniversalYAxisUnit } from 'components/YAxisUnitSelector/types';
|
||||
import { convertValue, getFormattedUnit } from 'lib/getConvertedValue';
|
||||
|
||||
describe('getFormattedUnit', () => {
|
||||
it('should return the grafana unit for universal unit if it exists', () => {
|
||||
const formattedUnit = getFormattedUnit(UniversalYAxisUnit.KILOBYTES);
|
||||
expect(formattedUnit).toBe('deckbytes');
|
||||
});
|
||||
|
||||
it('should return the unit directly if it is not a universal unit', () => {
|
||||
const formattedUnit = getFormattedUnit('{reason}');
|
||||
expect(formattedUnit).toBe('{reason}');
|
||||
});
|
||||
|
||||
it('should return the universal unit directly if it does not have a grafana equivalent', () => {
|
||||
const formattedUnit = getFormattedUnit(UniversalYAxisUnit.EXABYTES);
|
||||
expect(formattedUnit).toBe(UniversalYAxisUnit.EXABYTES);
|
||||
});
|
||||
});
|
||||
|
||||
describe('convertValue', () => {
|
||||
describe('data', () => {
|
||||
it('should convert bytes (IEC) to kilobytes', () => {
|
||||
expect(
|
||||
convertValue(
|
||||
1000,
|
||||
UniversalYAxisUnit.BYTES_IEC,
|
||||
UniversalYAxisUnit.KILOBYTES,
|
||||
),
|
||||
).toBe(1);
|
||||
});
|
||||
|
||||
it('should convert bytes (SI) to kilobytes', () => {
|
||||
expect(
|
||||
convertValue(1000, UniversalYAxisUnit.BYTES, UniversalYAxisUnit.KILOBYTES),
|
||||
).toBe(1);
|
||||
});
|
||||
|
||||
it('should convert kilobytes to bytes', () => {
|
||||
expect(
|
||||
convertValue(1, UniversalYAxisUnit.KILOBYTES, UniversalYAxisUnit.BYTES),
|
||||
).toBe(1000);
|
||||
});
|
||||
|
||||
it('should convert megabytes to kilobytes', () => {
|
||||
expect(convertValue(1, 'mbytes', 'kbytes')).toBe(1024);
|
||||
});
|
||||
|
||||
it('should convert gigabytes to megabytes', () => {
|
||||
expect(convertValue(1, 'gbytes', 'mbytes')).toBe(1024);
|
||||
});
|
||||
|
||||
it('should convert kilobytes to megabytes', () => {
|
||||
expect(convertValue(1024, 'kbytes', 'mbytes')).toBe(1);
|
||||
});
|
||||
|
||||
it('should convert bits to gigabytes', () => {
|
||||
// 12 GB = 103079215104 bits
|
||||
expect(convertValue(103079215104, 'bits', 'gbytes')).toBe(12);
|
||||
});
|
||||
});
|
||||
|
||||
describe('time', () => {
|
||||
it('should convert milliseconds to seconds', () => {
|
||||
expect(convertValue(1000, 'ms', 's')).toBe(1);
|
||||
});
|
||||
|
||||
it('should convert seconds to milliseconds', () => {
|
||||
expect(convertValue(1, 's', 'ms')).toBe(1000);
|
||||
});
|
||||
|
||||
it('should convert nanoseconds to milliseconds', () => {
|
||||
expect(convertValue(1000000, 'ns', 'ms')).toBe(1);
|
||||
});
|
||||
|
||||
it('should convert seconds to minutes', () => {
|
||||
expect(convertValue(60, 's', 'm')).toBe(1);
|
||||
});
|
||||
|
||||
it('should convert minutes to hours', () => {
|
||||
expect(convertValue(60, 'm', 'h')).toBe(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('data rate', () => {
|
||||
it('should convert bytes/sec to kibibytes/sec', () => {
|
||||
expect(convertValue(1024, 'binBps', 'KiBs')).toBe(1);
|
||||
});
|
||||
|
||||
it('should convert kibibytes/sec to bytes/sec', () => {
|
||||
expect(convertValue(1, 'KiBs', 'binBps')).toBe(1024);
|
||||
});
|
||||
});
|
||||
|
||||
describe('throughput', () => {
|
||||
it('should convert counts per second to counts per minute', () => {
|
||||
expect(convertValue(1, 'cps', 'cpm')).toBe(1 / 60);
|
||||
});
|
||||
|
||||
it('should convert operations per second to operations per minute', () => {
|
||||
expect(convertValue(1, 'ops', 'opm')).toBe(1 / 60);
|
||||
});
|
||||
|
||||
it('should convert counts per minute to counts per second', () => {
|
||||
expect(convertValue(1, 'cpm', 'cps')).toBe(60);
|
||||
});
|
||||
|
||||
it('should convert operations per minute to operations per second', () => {
|
||||
expect(convertValue(1, 'opm', 'ops')).toBe(60);
|
||||
});
|
||||
});
|
||||
|
||||
describe('percent', () => {
|
||||
it('should convert percentunit to percent', () => {
|
||||
expect(convertValue(0.5, 'percentunit', 'percent')).toBe(50);
|
||||
});
|
||||
|
||||
it('should convert percent to percentunit', () => {
|
||||
expect(convertValue(50, 'percent', 'percentunit')).toBe(0.5);
|
||||
});
|
||||
});
|
||||
|
||||
describe('invalid values', () => {
|
||||
it('should return null when currentUnit is invalid', () => {
|
||||
expect(convertValue(100, 'invalidUnit', 'bytes')).toBeNull();
|
||||
});
|
||||
|
||||
it('should return null when targetUnit is invalid', () => {
|
||||
expect(convertValue(100, 'bytes', 'invalidUnit')).toBeNull();
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,3 +1,17 @@
|
||||
import {
|
||||
UniversalUnitToGrafanaUnit,
|
||||
Y_AXIS_UNIT_NAMES,
|
||||
} from 'components/YAxisUnitSelector/constants';
|
||||
import { UniversalYAxisUnit } from 'components/YAxisUnitSelector/types';
|
||||
import { isUniversalUnit } from 'components/YAxisUnitSelector/utils';
|
||||
|
||||
// 1 byte = 8 bits
|
||||
// Or 1 bit = 1/8 bytes
|
||||
const BIT_FACTOR = 1 / 8;
|
||||
|
||||
const DECIMAL_FACTOR = 1000;
|
||||
const BINARY_FACTOR = 1024;
|
||||
|
||||
const unitsMapping = [
|
||||
{
|
||||
label: 'Data',
|
||||
@@ -15,62 +29,132 @@ const unitsMapping = [
|
||||
{
|
||||
label: 'bits(IEC)',
|
||||
value: 'bits',
|
||||
factor: 8, // 1 byte = 8 bits
|
||||
factor: BIT_FACTOR,
|
||||
},
|
||||
{
|
||||
label: 'bits(SI)',
|
||||
value: 'decbits',
|
||||
factor: 8, // 1 byte = 8 bits
|
||||
factor: BIT_FACTOR,
|
||||
},
|
||||
{
|
||||
label: Y_AXIS_UNIT_NAMES[UniversalYAxisUnit.KILOBITS],
|
||||
value: UniversalYAxisUnit.KILOBITS,
|
||||
factor: BIT_FACTOR * DECIMAL_FACTOR,
|
||||
},
|
||||
{
|
||||
label: Y_AXIS_UNIT_NAMES[UniversalYAxisUnit.MEGABITS],
|
||||
value: UniversalYAxisUnit.MEGABITS,
|
||||
factor: BIT_FACTOR * DECIMAL_FACTOR ** 2,
|
||||
},
|
||||
{
|
||||
label: Y_AXIS_UNIT_NAMES[UniversalYAxisUnit.GIGABITS],
|
||||
value: UniversalYAxisUnit.GIGABITS,
|
||||
factor: BIT_FACTOR * DECIMAL_FACTOR ** 3,
|
||||
},
|
||||
{
|
||||
label: Y_AXIS_UNIT_NAMES[UniversalYAxisUnit.TERABITS],
|
||||
value: UniversalYAxisUnit.TERABITS,
|
||||
factor: BIT_FACTOR * DECIMAL_FACTOR ** 4,
|
||||
},
|
||||
{
|
||||
label: Y_AXIS_UNIT_NAMES[UniversalYAxisUnit.PETABITS],
|
||||
value: UniversalYAxisUnit.PETABITS,
|
||||
factor: BIT_FACTOR * DECIMAL_FACTOR ** 5,
|
||||
},
|
||||
{
|
||||
label: Y_AXIS_UNIT_NAMES[UniversalYAxisUnit.EXABITS],
|
||||
value: UniversalYAxisUnit.EXABITS,
|
||||
factor: BIT_FACTOR * DECIMAL_FACTOR ** 6,
|
||||
},
|
||||
{
|
||||
label: Y_AXIS_UNIT_NAMES[UniversalYAxisUnit.ZETTABITS],
|
||||
value: UniversalYAxisUnit.ZETTABITS,
|
||||
factor: BIT_FACTOR * DECIMAL_FACTOR ** 7,
|
||||
},
|
||||
{
|
||||
label: Y_AXIS_UNIT_NAMES[UniversalYAxisUnit.YOTTABITS],
|
||||
value: UniversalYAxisUnit.YOTTABITS,
|
||||
factor: BIT_FACTOR * DECIMAL_FACTOR ** 8,
|
||||
},
|
||||
{
|
||||
label: 'kibibytes',
|
||||
value: 'kbytes',
|
||||
factor: 1024,
|
||||
factor: BINARY_FACTOR,
|
||||
},
|
||||
{
|
||||
label: 'kilobytes',
|
||||
value: 'deckbytes',
|
||||
factor: 1000,
|
||||
factor: DECIMAL_FACTOR,
|
||||
},
|
||||
{
|
||||
label: 'mebibytes',
|
||||
value: 'mbytes',
|
||||
factor: 1024 * 1024,
|
||||
factor: BINARY_FACTOR ** 2,
|
||||
},
|
||||
{
|
||||
label: 'megabytes',
|
||||
value: 'decmbytes',
|
||||
factor: 1000 * 1000,
|
||||
factor: DECIMAL_FACTOR ** 2,
|
||||
},
|
||||
{
|
||||
label: 'gibibytes',
|
||||
value: 'gbytes',
|
||||
factor: 1024 * 1024 * 1024,
|
||||
factor: BINARY_FACTOR ** 3,
|
||||
},
|
||||
{
|
||||
label: 'gigabytes',
|
||||
value: 'decgbytes',
|
||||
factor: 1000 * 1000 * 1000,
|
||||
factor: DECIMAL_FACTOR ** 3,
|
||||
},
|
||||
{
|
||||
label: 'tebibytes',
|
||||
value: 'tbytes',
|
||||
factor: 1024 * 1024 * 1024 * 1024,
|
||||
factor: BINARY_FACTOR ** 4,
|
||||
},
|
||||
{
|
||||
label: 'terabytes',
|
||||
value: 'dectbytes',
|
||||
factor: 1000 * 1000 * 1000 * 1000,
|
||||
factor: DECIMAL_FACTOR ** 4,
|
||||
},
|
||||
{
|
||||
label: 'pebibytes',
|
||||
value: 'pbytes',
|
||||
factor: 1024 * 1024 * 1024 * 1024 * 1024,
|
||||
factor: BINARY_FACTOR ** 5,
|
||||
},
|
||||
{
|
||||
label: 'petabytes',
|
||||
value: 'decpbytes',
|
||||
factor: 1000 * 1000 * 1000 * 1000 * 1000,
|
||||
factor: DECIMAL_FACTOR ** 5,
|
||||
},
|
||||
{
|
||||
label: Y_AXIS_UNIT_NAMES[UniversalYAxisUnit.EXABYTES],
|
||||
value: UniversalYAxisUnit.EXABYTES,
|
||||
factor: DECIMAL_FACTOR ** 6,
|
||||
},
|
||||
{
|
||||
label: Y_AXIS_UNIT_NAMES[UniversalYAxisUnit.EXBIBYTES],
|
||||
value: UniversalYAxisUnit.EXBIBYTES,
|
||||
factor: BINARY_FACTOR ** 6,
|
||||
},
|
||||
{
|
||||
label: Y_AXIS_UNIT_NAMES[UniversalYAxisUnit.ZETTABYTES],
|
||||
value: UniversalYAxisUnit.ZETTABYTES,
|
||||
factor: DECIMAL_FACTOR ** 7,
|
||||
},
|
||||
{
|
||||
label: Y_AXIS_UNIT_NAMES[UniversalYAxisUnit.ZEBIBYTES],
|
||||
value: UniversalYAxisUnit.ZEBIBYTES,
|
||||
factor: BINARY_FACTOR ** 7,
|
||||
},
|
||||
{
|
||||
label: Y_AXIS_UNIT_NAMES[UniversalYAxisUnit.YOTTABYTES],
|
||||
value: UniversalYAxisUnit.YOTTABYTES,
|
||||
factor: DECIMAL_FACTOR ** 8,
|
||||
},
|
||||
{
|
||||
label: Y_AXIS_UNIT_NAMES[UniversalYAxisUnit.YOBIBYTES],
|
||||
value: UniversalYAxisUnit.YOBIBYTES,
|
||||
factor: BINARY_FACTOR ** 8,
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -90,44 +174,103 @@ const unitsMapping = [
|
||||
{
|
||||
label: 'bits/sec(IEC)',
|
||||
value: 'binbps',
|
||||
factor: 8, // 1 byte = 8 bits
|
||||
factor: BIT_FACTOR, // 1 byte = 8 bits
|
||||
},
|
||||
{
|
||||
label: 'bits/sec(SI)',
|
||||
value: 'bps',
|
||||
factor: 8, // 1 byte = 8 bits
|
||||
factor: BIT_FACTOR, // 1 byte = 8 bits
|
||||
},
|
||||
{
|
||||
label: 'kibibytes/sec',
|
||||
value: 'KiBs',
|
||||
factor: 1024,
|
||||
factor: BINARY_FACTOR,
|
||||
},
|
||||
{
|
||||
label: 'kibibits/sec',
|
||||
value: 'Kibits',
|
||||
factor: 8 * 1024, // 1 KiB = 8 Kibits
|
||||
factor: BIT_FACTOR * BINARY_FACTOR, // 1 KiB = 8 Kibits
|
||||
},
|
||||
{
|
||||
label: 'kilobytes/sec',
|
||||
value: 'KBs',
|
||||
factor: 1000,
|
||||
factor: DECIMAL_FACTOR,
|
||||
},
|
||||
{
|
||||
label: 'kilobits/sec',
|
||||
value: 'Kbits',
|
||||
factor: 8 * 1000, // 1 KB = 8 Kbits
|
||||
factor: BIT_FACTOR * DECIMAL_FACTOR, // 1 KB = 8 Kbits
|
||||
},
|
||||
{
|
||||
label: 'mebibytes/sec',
|
||||
value: 'MiBs',
|
||||
factor: 1024 * 1024,
|
||||
factor: BINARY_FACTOR ** 2,
|
||||
},
|
||||
{
|
||||
label: 'mebibits/sec',
|
||||
value: 'Mibits',
|
||||
factor: 8 * 1024 * 1024, // 1 MiB = 8 Mibits
|
||||
factor: BIT_FACTOR * BINARY_FACTOR ** 2, // 1 MiB = 8 Mibits
|
||||
},
|
||||
{
|
||||
label: Y_AXIS_UNIT_NAMES[UniversalYAxisUnit.EXABYTES_SECOND],
|
||||
value: UniversalYAxisUnit.EXABYTES_SECOND,
|
||||
factor: DECIMAL_FACTOR ** 6,
|
||||
},
|
||||
{
|
||||
label: Y_AXIS_UNIT_NAMES[UniversalYAxisUnit.ZETTABYTES_SECOND],
|
||||
value: UniversalYAxisUnit.ZETTABYTES_SECOND,
|
||||
factor: DECIMAL_FACTOR ** 7,
|
||||
},
|
||||
{
|
||||
label: Y_AXIS_UNIT_NAMES[UniversalYAxisUnit.YOTTABYTES_SECOND],
|
||||
value: UniversalYAxisUnit.YOTTABYTES_SECOND,
|
||||
factor: DECIMAL_FACTOR ** 8,
|
||||
},
|
||||
{
|
||||
label: Y_AXIS_UNIT_NAMES[UniversalYAxisUnit.EXBIBYTES_SECOND],
|
||||
value: UniversalYAxisUnit.EXBIBYTES_SECOND,
|
||||
factor: BINARY_FACTOR ** 6,
|
||||
},
|
||||
{
|
||||
label: Y_AXIS_UNIT_NAMES[UniversalYAxisUnit.ZEBIBYTES_SECOND],
|
||||
value: UniversalYAxisUnit.ZEBIBYTES_SECOND,
|
||||
factor: BINARY_FACTOR ** 7,
|
||||
},
|
||||
{
|
||||
label: Y_AXIS_UNIT_NAMES[UniversalYAxisUnit.YOBIBYTES_SECOND],
|
||||
value: UniversalYAxisUnit.YOBIBYTES_SECOND,
|
||||
factor: BINARY_FACTOR ** 8,
|
||||
},
|
||||
{
|
||||
label: Y_AXIS_UNIT_NAMES[UniversalYAxisUnit.EXABITS_SECOND],
|
||||
value: UniversalYAxisUnit.EXABITS_SECOND,
|
||||
factor: BIT_FACTOR * DECIMAL_FACTOR ** 6,
|
||||
},
|
||||
{
|
||||
label: Y_AXIS_UNIT_NAMES[UniversalYAxisUnit.ZETTABITS_SECOND],
|
||||
value: UniversalYAxisUnit.ZETTABITS_SECOND,
|
||||
factor: BIT_FACTOR * DECIMAL_FACTOR ** 7,
|
||||
},
|
||||
{
|
||||
label: Y_AXIS_UNIT_NAMES[UniversalYAxisUnit.YOTTABITS_SECOND],
|
||||
value: UniversalYAxisUnit.YOTTABITS_SECOND,
|
||||
factor: BIT_FACTOR * DECIMAL_FACTOR ** 8,
|
||||
},
|
||||
{
|
||||
label: Y_AXIS_UNIT_NAMES[UniversalYAxisUnit.EXBIBITS_SECOND],
|
||||
value: UniversalYAxisUnit.EXBIBITS_SECOND,
|
||||
factor: BIT_FACTOR * BINARY_FACTOR ** 6,
|
||||
},
|
||||
{
|
||||
label: Y_AXIS_UNIT_NAMES[UniversalYAxisUnit.ZEBIBITS_SECOND],
|
||||
value: UniversalYAxisUnit.ZEBIBITS_SECOND,
|
||||
factor: BIT_FACTOR * BINARY_FACTOR ** 7,
|
||||
},
|
||||
{
|
||||
label: Y_AXIS_UNIT_NAMES[UniversalYAxisUnit.YOBIBITS_SECOND],
|
||||
value: UniversalYAxisUnit.YOBIBITS_SECOND,
|
||||
factor: BIT_FACTOR * BINARY_FACTOR ** 8,
|
||||
},
|
||||
// ... (other options)
|
||||
],
|
||||
},
|
||||
{
|
||||
@@ -268,6 +411,14 @@ function findUnitObject(
|
||||
return unitObj || null;
|
||||
}
|
||||
|
||||
export function getFormattedUnit(unit: string): string {
|
||||
const isUniversalYAxisUnit = isUniversalUnit(unit);
|
||||
if (isUniversalYAxisUnit) {
|
||||
return UniversalUnitToGrafanaUnit[unit as UniversalYAxisUnit] || unit;
|
||||
}
|
||||
return unit;
|
||||
}
|
||||
|
||||
export function convertValue(
|
||||
value: number,
|
||||
currentUnit?: string,
|
||||
@@ -281,8 +432,12 @@ export function convertValue(
|
||||
) {
|
||||
return value;
|
||||
}
|
||||
const currentUnitObj = findUnitObject(currentUnit);
|
||||
const targetUnitObj = findUnitObject(targetUnit);
|
||||
|
||||
const formattedCurrentUnit = getFormattedUnit(currentUnit);
|
||||
const formattedTargetUnit = getFormattedUnit(targetUnit);
|
||||
|
||||
const currentUnitObj = findUnitObject(formattedCurrentUnit);
|
||||
const targetUnitObj = findUnitObject(formattedTargetUnit);
|
||||
|
||||
if (currentUnitObj && targetUnitObj) {
|
||||
const baseValue = value * currentUnitObj.factor;
|
||||
|
||||
Reference in New Issue
Block a user