Compare commits
5 Commits
main
...
chore/y-ax
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
be83be94c6 | ||
|
|
a6d7e62b5c | ||
|
|
0961e92ea6 | ||
|
|
9ce228ca13 | ||
|
|
5c22ef773d |
@@ -1,7 +1,11 @@
|
||||
import './styles.scss';
|
||||
|
||||
import { Select } from 'antd';
|
||||
import { WarningFilled } from '@ant-design/icons';
|
||||
import { Color } from '@signozhq/design-tokens';
|
||||
import { Select, Tooltip } from 'antd';
|
||||
import { DefaultOptionType } from 'antd/es/select';
|
||||
import classNames from 'classnames';
|
||||
import { useMemo } from 'react';
|
||||
|
||||
import { UniversalYAxisUnitMappings, Y_AXIS_CATEGORIES } from './constants';
|
||||
import { UniversalYAxisUnit, YAxisUnitSelectorProps } from './types';
|
||||
@@ -12,9 +16,37 @@ function YAxisUnitSelector({
|
||||
onChange,
|
||||
placeholder = 'Please select a unit',
|
||||
loading = false,
|
||||
initialValue,
|
||||
}: YAxisUnitSelectorProps): JSX.Element {
|
||||
const universalUnit = mapMetricUnitToUniversalUnit(value);
|
||||
|
||||
const initialCategory = useMemo(() => {
|
||||
const initialUniversalUnit = mapMetricUnitToUniversalUnit(initialValue);
|
||||
const unit = Y_AXIS_CATEGORIES.find((category) =>
|
||||
category.units.some((unit) => unit.id === initialUniversalUnit),
|
||||
);
|
||||
return unit?.name;
|
||||
}, [initialValue]);
|
||||
|
||||
const currentCategory = useMemo(() => {
|
||||
const currentUniversalUnit = mapMetricUnitToUniversalUnit(value);
|
||||
const unit = Y_AXIS_CATEGORIES.find((category) =>
|
||||
category.units.some((unit) => unit.id === currentUniversalUnit),
|
||||
);
|
||||
return unit?.name;
|
||||
}, [value]);
|
||||
|
||||
const incorrectCategoryMessage = useMemo(() => {
|
||||
if (
|
||||
initialCategory &&
|
||||
currentCategory &&
|
||||
initialCategory !== currentCategory
|
||||
) {
|
||||
return `Incorrect unit selected. Please select a unit from the ${initialCategory} category.`;
|
||||
}
|
||||
return '';
|
||||
}, [initialCategory, currentCategory]);
|
||||
|
||||
const handleSearch = (
|
||||
searchTerm: string,
|
||||
currentOption: DefaultOptionType | undefined,
|
||||
@@ -45,6 +77,16 @@ function YAxisUnitSelector({
|
||||
placeholder={placeholder}
|
||||
filterOption={(input, option): boolean => handleSearch(input, option)}
|
||||
loading={loading}
|
||||
suffixIcon={
|
||||
incorrectCategoryMessage ? (
|
||||
<Tooltip title={incorrectCategoryMessage}>
|
||||
<WarningFilled color={Color.BG_AMBER_500} />
|
||||
</Tooltip>
|
||||
) : null
|
||||
}
|
||||
className={classNames({
|
||||
'warning-state': incorrectCategoryMessage,
|
||||
})}
|
||||
>
|
||||
{Y_AXIS_CATEGORIES.map((category) => (
|
||||
<Select.OptGroup key={category.name} label={category.name}>
|
||||
|
||||
@@ -10,7 +10,9 @@ describe('YAxisUnitSelector', () => {
|
||||
});
|
||||
|
||||
it('renders with default placeholder', () => {
|
||||
render(<YAxisUnitSelector value="" onChange={mockOnChange} />);
|
||||
render(
|
||||
<YAxisUnitSelector value="" onChange={mockOnChange} initialValue="" />,
|
||||
);
|
||||
expect(screen.getByText('Please select a unit')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
@@ -20,13 +22,16 @@ describe('YAxisUnitSelector', () => {
|
||||
value=""
|
||||
onChange={mockOnChange}
|
||||
placeholder="Custom placeholder"
|
||||
initialValue=""
|
||||
/>,
|
||||
);
|
||||
expect(screen.queryByText('Custom placeholder')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('calls onChange when a value is selected', () => {
|
||||
render(<YAxisUnitSelector value="" onChange={mockOnChange} />);
|
||||
render(
|
||||
<YAxisUnitSelector value="" onChange={mockOnChange} initialValue="" />,
|
||||
);
|
||||
const select = screen.getByRole('combobox');
|
||||
|
||||
fireEvent.mouseDown(select);
|
||||
@@ -41,7 +46,9 @@ describe('YAxisUnitSelector', () => {
|
||||
});
|
||||
|
||||
it('filters options based on search input', () => {
|
||||
render(<YAxisUnitSelector value="" onChange={mockOnChange} />);
|
||||
render(
|
||||
<YAxisUnitSelector value="" onChange={mockOnChange} initialValue="" />,
|
||||
);
|
||||
const select = screen.getByRole('combobox');
|
||||
|
||||
fireEvent.mouseDown(select);
|
||||
@@ -52,7 +59,9 @@ describe('YAxisUnitSelector', () => {
|
||||
});
|
||||
|
||||
it('shows all categories and their units', () => {
|
||||
render(<YAxisUnitSelector value="" onChange={mockOnChange} />);
|
||||
render(
|
||||
<YAxisUnitSelector value="" onChange={mockOnChange} initialValue="" />,
|
||||
);
|
||||
const select = screen.getByRole('combobox');
|
||||
|
||||
fireEvent.mouseDown(select);
|
||||
|
||||
@@ -3,3 +3,13 @@
|
||||
width: 220px;
|
||||
}
|
||||
}
|
||||
|
||||
.warning-state {
|
||||
.ant-select-selector {
|
||||
border-color: var(--bg-amber-400) !important;
|
||||
}
|
||||
|
||||
.anticon {
|
||||
color: var(--bg-amber-400) !important;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ export interface YAxisUnitSelectorProps {
|
||||
placeholder?: string;
|
||||
loading?: boolean;
|
||||
disabled?: boolean;
|
||||
initialValue: string;
|
||||
}
|
||||
|
||||
export enum UniversalYAxisUnit {
|
||||
|
||||
@@ -86,6 +86,13 @@
|
||||
}
|
||||
}
|
||||
|
||||
.y-axis-unit-selector-container {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.detection-method-container {
|
||||
margin: 24px 0;
|
||||
|
||||
|
||||
@@ -16,7 +16,6 @@ import {
|
||||
getCategoryByOptionId,
|
||||
getCategorySelectOptionByName,
|
||||
} from 'container/NewWidget/RightContainer/alertFomatCategories';
|
||||
import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
|
||||
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,7 +364,7 @@ function RuleOptions({
|
||||
</InlineSelect>
|
||||
);
|
||||
|
||||
const selectedCategory = getCategoryByOptionId(currentQuery?.unit || '');
|
||||
const selectedCategory = getCategoryByOptionId(yAxisUnit);
|
||||
|
||||
const categorySelectOptions = getCategorySelectOptionByName(
|
||||
selectedCategory?.name,
|
||||
@@ -515,5 +514,6 @@ interface RuleOptionsProps {
|
||||
setAlertDef: (a: AlertDef) => void;
|
||||
queryCategory: EQueryType;
|
||||
queryOptions: DefaultOptionType[];
|
||||
yAxisUnit: string;
|
||||
}
|
||||
export default RuleOptions;
|
||||
|
||||
@@ -6,6 +6,7 @@ import saveAlertApi from 'api/alerts/save';
|
||||
import testAlertApi from 'api/alerts/testAlert';
|
||||
import logEvent from 'api/common/logEvent';
|
||||
import { getInvolvedQueriesInTraceOperator } from 'components/QueryBuilderV2/QueryV2/TraceOperator/utils/utils';
|
||||
import YAxisUnitSelector from 'components/YAxisUnitSelector';
|
||||
import { ALERTS_DATA_SOURCE_MAP } from 'constants/alerts';
|
||||
import { FeatureKeys } from 'constants/features';
|
||||
import { QueryParams } from 'constants/query';
|
||||
@@ -14,7 +15,6 @@ import { REACT_QUERY_KEY } from 'constants/reactQueryKeys';
|
||||
import ROUTES from 'constants/routes';
|
||||
import QueryTypeTag from 'container/NewWidget/LeftContainer/QueryTypeTag';
|
||||
import PlotTag from 'container/NewWidget/LeftContainer/WidgetGraph/PlotTag';
|
||||
import { BuilderUnitsFilter } from 'container/QueryBuilder/filters';
|
||||
import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
|
||||
import { useShareBuilderUrl } from 'hooks/queryBuilder/useShareBuilderUrl';
|
||||
import { useNotifications } from 'hooks/useNotifications';
|
||||
@@ -57,7 +57,7 @@ import {
|
||||
StepHeading,
|
||||
} from './styles';
|
||||
import { usePrefillAlertConditions } from './usePrefillAlertConditions';
|
||||
import { getSelectedQueryOptions } from './utils';
|
||||
import { getSelectedQueryOptions, useGetYAxisUnitFromQuery } from './utils';
|
||||
|
||||
export enum AlertDetectionTypes {
|
||||
THRESHOLD_ALERT = 'threshold_rule',
|
||||
@@ -719,6 +719,8 @@ function FormAlertRules({
|
||||
|
||||
const isAlertNameMissing = !formInstance.getFieldValue('alert');
|
||||
|
||||
const yAxisUnitFromQuery = useGetYAxisUnitFromQuery(stagedQuery);
|
||||
|
||||
const onUnitChangeHandler = (value: string): void => {
|
||||
setYAxisUnit(value);
|
||||
// reset target unit
|
||||
@@ -731,6 +733,10 @@ function FormAlertRules({
|
||||
}));
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
setYAxisUnit(yAxisUnitFromQuery || '');
|
||||
}, [yAxisUnitFromQuery]);
|
||||
|
||||
const isChannelConfigurationValid =
|
||||
alertDef?.broadcastToAll ||
|
||||
(alertDef.preferredChannels && alertDef.preferredChannels.length > 0);
|
||||
@@ -841,10 +847,14 @@ function FormAlertRules({
|
||||
</div>
|
||||
|
||||
<StepContainer>
|
||||
<BuilderUnitsFilter
|
||||
onChange={onUnitChangeHandler}
|
||||
yAxisUnit={yAxisUnit}
|
||||
/>
|
||||
<div className="y-axis-unit-selector-container">
|
||||
<Typography.Text>Y-Axis Unit</Typography.Text>
|
||||
<YAxisUnitSelector
|
||||
initialValue={currentQuery.unit || ''}
|
||||
value={yAxisUnit}
|
||||
onChange={onUnitChangeHandler}
|
||||
/>
|
||||
</div>
|
||||
</StepContainer>
|
||||
|
||||
<div className="steps-container">
|
||||
@@ -884,6 +894,7 @@ function FormAlertRules({
|
||||
alertDef={alertDef}
|
||||
setAlertDef={setAlertDef}
|
||||
queryOptions={queryOptions}
|
||||
yAxisUnit={yAxisUnit}
|
||||
/>
|
||||
|
||||
{renderBasicInfo()}
|
||||
|
||||
@@ -1,14 +1,18 @@
|
||||
import { SelectProps } from 'antd';
|
||||
import { useGetMetricUnits } from 'container/MetricsExplorer/Explorer/utils';
|
||||
import { Time } from 'container/TopNav/DateTimeSelection/config';
|
||||
import getStartEndRangeTime from 'lib/getStartEndRangeTime';
|
||||
import getStep from 'lib/getStep';
|
||||
import { useMemo } from 'react';
|
||||
import {
|
||||
IBuilderFormula,
|
||||
IBuilderQuery,
|
||||
IBuilderTraceOperator,
|
||||
IClickHouseQuery,
|
||||
IPromQLQuery,
|
||||
Query,
|
||||
} from 'types/api/queryBuilder/queryBuilderData';
|
||||
import { DataSource } from 'types/common/queryBuilder';
|
||||
|
||||
// toChartInterval converts eval window to chart selection time interval
|
||||
export const toChartInterval = (evalWindow: string | undefined): Time => {
|
||||
@@ -62,8 +66,40 @@ export const getSelectedQueryOptions = (
|
||||
>,
|
||||
): SelectProps['options'] =>
|
||||
queries
|
||||
.filter((query) => !query.disabled)
|
||||
?.filter((query) => !query.disabled)
|
||||
.map((query) => ({
|
||||
label: 'queryName' in query ? query.queryName : query.name,
|
||||
value: 'queryName' in query ? query.queryName : query.name,
|
||||
}));
|
||||
|
||||
export const useGetYAxisUnitFromQuery = (
|
||||
query: Query | null,
|
||||
): string | null => {
|
||||
const metricNames = useMemo(() => {
|
||||
if (!query) {
|
||||
return [];
|
||||
}
|
||||
return query.builder.queryData.map(
|
||||
(query) => query.aggregateAttribute?.key ?? '',
|
||||
);
|
||||
}, [query]);
|
||||
|
||||
const { units } = useGetMetricUnits(
|
||||
metricNames,
|
||||
query?.builder.queryData[0].dataSource === DataSource.METRICS,
|
||||
);
|
||||
|
||||
return useMemo(() => {
|
||||
if (!query || units.length === 0) {
|
||||
return null;
|
||||
}
|
||||
if (query?.unit) {
|
||||
return query.unit;
|
||||
}
|
||||
const areAllUnitsSame = units.every((unit) => unit === units[0]);
|
||||
if (areAllUnitsSame) {
|
||||
return units[0];
|
||||
}
|
||||
return null;
|
||||
}, [query, units]);
|
||||
};
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import './Explorer.styles.scss';
|
||||
|
||||
import * as Sentry from '@sentry/react';
|
||||
import { Switch } from 'antd';
|
||||
import { Switch, Tooltip } from 'antd';
|
||||
import logEvent from 'api/common/logEvent';
|
||||
import { QueryBuilderV2 } from 'components/QueryBuilderV2/QueryBuilderV2';
|
||||
import WarningPopover from 'components/WarningPopover/WarningPopover';
|
||||
@@ -25,10 +25,10 @@ import { generateExportToDashboardLink } from 'utils/dashboard/generateExportToD
|
||||
import { v4 as uuid } from 'uuid';
|
||||
|
||||
import { MetricsExplorerEventKeys, MetricsExplorerEvents } from '../events';
|
||||
// import QuerySection from './QuerySection';
|
||||
import MetricDetails from '../MetricDetails/MetricDetails';
|
||||
import TimeSeries from './TimeSeries';
|
||||
import { ExplorerTabs } from './types';
|
||||
import { splitQueryIntoOneChartPerQuery } from './utils';
|
||||
import { splitQueryIntoOneChartPerQuery, useGetMetricUnits } from './utils';
|
||||
|
||||
const ONE_CHART_PER_QUERY_ENABLED_KEY = 'isOneChartPerQueryEnabled';
|
||||
|
||||
@@ -40,6 +40,31 @@ function Explorer(): JSX.Element {
|
||||
currentQuery,
|
||||
} = useQueryBuilder();
|
||||
const { safeNavigate } = useSafeNavigate();
|
||||
const [isMetricDetailsOpen, setIsMetricDetailsOpen] = useState(false);
|
||||
|
||||
const metricNames = useMemo(
|
||||
() =>
|
||||
stagedQuery?.builder.queryData.map(
|
||||
(query) => query.aggregateAttribute?.key ?? '',
|
||||
) ?? [],
|
||||
[stagedQuery],
|
||||
);
|
||||
|
||||
const {
|
||||
units,
|
||||
metrics,
|
||||
isLoading: isMetricUnitsLoading,
|
||||
isError: isMetricUnitsError,
|
||||
} = useGetMetricUnits(metricNames);
|
||||
|
||||
const areAllMetricUnitsSame = useMemo(
|
||||
() =>
|
||||
!isMetricUnitsLoading &&
|
||||
!isMetricUnitsError &&
|
||||
units.length > 0 &&
|
||||
units.every((unit) => unit === units[0]),
|
||||
[units, isMetricUnitsLoading, isMetricUnitsError],
|
||||
);
|
||||
|
||||
const [searchParams, setSearchParams] = useSearchParams();
|
||||
const isOneChartPerQueryEnabled =
|
||||
@@ -48,7 +73,31 @@ function Explorer(): JSX.Element {
|
||||
const [showOneChartPerQuery, toggleShowOneChartPerQuery] = useState(
|
||||
isOneChartPerQueryEnabled,
|
||||
);
|
||||
const [disableOneChartPerQuery, toggleDisableOneChartPerQuery] = useState(
|
||||
false,
|
||||
);
|
||||
const [selectedTab] = useState<ExplorerTabs>(ExplorerTabs.TIME_SERIES);
|
||||
const [yAxisUnit, setYAxisUnit] = useState<string>('');
|
||||
|
||||
useEffect(() => {
|
||||
if (units.length === 0) {
|
||||
setYAxisUnit('');
|
||||
} else if (units.length === 1 && units[0] !== '') {
|
||||
setYAxisUnit(units[0]);
|
||||
} else if (areAllMetricUnitsSame && units[0] !== '') {
|
||||
setYAxisUnit(units[0]);
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [JSON.stringify(units), areAllMetricUnitsSame]);
|
||||
|
||||
useEffect(() => {
|
||||
if (units.length > 1 && !areAllMetricUnitsSame) {
|
||||
toggleShowOneChartPerQuery(true);
|
||||
toggleDisableOneChartPerQuery(true);
|
||||
} else {
|
||||
toggleDisableOneChartPerQuery(false);
|
||||
}
|
||||
}, [units, areAllMetricUnitsSame]);
|
||||
|
||||
const handleToggleShowOneChartPerQuery = (): void => {
|
||||
toggleShowOneChartPerQuery(!showOneChartPerQuery);
|
||||
@@ -68,15 +117,20 @@ function Explorer(): JSX.Element {
|
||||
[updateAllQueriesOperators],
|
||||
);
|
||||
|
||||
const exportDefaultQuery = useMemo(
|
||||
() =>
|
||||
updateAllQueriesOperators(
|
||||
currentQuery || initialQueriesMap[DataSource.METRICS],
|
||||
PANEL_TYPES.TIME_SERIES,
|
||||
DataSource.METRICS,
|
||||
),
|
||||
[currentQuery, updateAllQueriesOperators],
|
||||
);
|
||||
const exportDefaultQuery = useMemo(() => {
|
||||
const query = updateAllQueriesOperators(
|
||||
currentQuery || initialQueriesMap[DataSource.METRICS],
|
||||
PANEL_TYPES.TIME_SERIES,
|
||||
DataSource.METRICS,
|
||||
);
|
||||
if (yAxisUnit) {
|
||||
return {
|
||||
...query,
|
||||
unit: yAxisUnit,
|
||||
};
|
||||
}
|
||||
return query;
|
||||
}, [currentQuery, updateAllQueriesOperators, yAxisUnit]);
|
||||
|
||||
useShareBuilderUrl({ defaultValue: defaultQuery });
|
||||
|
||||
@@ -90,8 +144,16 @@ function Explorer(): JSX.Element {
|
||||
|
||||
const widgetId = uuid();
|
||||
|
||||
let query = queryToExport || exportDefaultQuery;
|
||||
if (yAxisUnit) {
|
||||
query = {
|
||||
...query,
|
||||
unit: yAxisUnit,
|
||||
};
|
||||
}
|
||||
|
||||
const dashboardEditView = generateExportToDashboardLink({
|
||||
query: queryToExport || exportDefaultQuery,
|
||||
query,
|
||||
panelType: PANEL_TYPES.TIME_SERIES,
|
||||
dashboardId: dashboard.id,
|
||||
widgetId,
|
||||
@@ -99,7 +161,7 @@ function Explorer(): JSX.Element {
|
||||
|
||||
safeNavigate(dashboardEditView);
|
||||
},
|
||||
[exportDefaultQuery, safeNavigate],
|
||||
[exportDefaultQuery, safeNavigate, yAxisUnit],
|
||||
);
|
||||
|
||||
const splitedQueries = useMemo(
|
||||
@@ -129,11 +191,17 @@ function Explorer(): JSX.Element {
|
||||
<div className="explore-header">
|
||||
<div className="explore-header-left-actions">
|
||||
<span>1 chart/query</span>
|
||||
<Switch
|
||||
checked={showOneChartPerQuery}
|
||||
onChange={handleToggleShowOneChartPerQuery}
|
||||
size="small"
|
||||
/>
|
||||
<Tooltip
|
||||
open={disableOneChartPerQuery ? undefined : false}
|
||||
title="One chart per query cannot be disabled for multiple queries with different units."
|
||||
>
|
||||
<Switch
|
||||
checked={showOneChartPerQuery}
|
||||
onChange={handleToggleShowOneChartPerQuery}
|
||||
disabled={disableOneChartPerQuery}
|
||||
size="small"
|
||||
/>
|
||||
</Tooltip>
|
||||
</div>
|
||||
<div className="explore-header-right-actions">
|
||||
{!isEmpty(warning) && <WarningPopover warningData={warning} />}
|
||||
@@ -174,6 +242,15 @@ function Explorer(): JSX.Element {
|
||||
<TimeSeries
|
||||
showOneChartPerQuery={showOneChartPerQuery}
|
||||
setWarning={setWarning}
|
||||
areAllMetricUnitsSame={areAllMetricUnitsSame}
|
||||
isMetricUnitsLoading={isMetricUnitsLoading}
|
||||
isMetricUnitsError={isMetricUnitsError}
|
||||
metricUnits={units}
|
||||
metricNames={metricNames}
|
||||
metrics={metrics}
|
||||
setIsMetricDetailsOpen={setIsMetricDetailsOpen}
|
||||
yAxisUnit={yAxisUnit}
|
||||
setYAxisUnit={setYAxisUnit}
|
||||
/>
|
||||
)}
|
||||
{/* TODO: Enable once we have resolved all related metrics issues */}
|
||||
@@ -190,6 +267,14 @@ function Explorer(): JSX.Element {
|
||||
isOneChartPerQuery={false}
|
||||
splitedQueries={splitedQueries}
|
||||
/>
|
||||
{isMetricDetailsOpen && (
|
||||
<MetricDetails
|
||||
metricName={metricNames[0]}
|
||||
isOpen={isMetricDetailsOpen}
|
||||
onClose={(): void => setIsMetricDetailsOpen(false)}
|
||||
isModalTimeSelection={false}
|
||||
/>
|
||||
)}
|
||||
</Sentry.ErrorBoundary>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { MetricDetails } from 'api/metricsExplorer/getMetricDetails';
|
||||
import { RelatedMetric } from 'api/metricsExplorer/getRelatedMetrics';
|
||||
import { Dispatch, SetStateAction } from 'react';
|
||||
import { UseQueryResult } from 'react-query';
|
||||
@@ -12,6 +13,15 @@ export enum ExplorerTabs {
|
||||
export interface TimeSeriesProps {
|
||||
showOneChartPerQuery: boolean;
|
||||
setWarning: Dispatch<SetStateAction<Warning | undefined>>;
|
||||
areAllMetricUnitsSame: boolean;
|
||||
isMetricUnitsLoading: boolean;
|
||||
isMetricUnitsError: boolean;
|
||||
metricUnits: string[];
|
||||
metricNames: string[];
|
||||
metrics: (MetricDetails | undefined)[];
|
||||
setIsMetricDetailsOpen: (isOpen: boolean) => void;
|
||||
yAxisUnit: string;
|
||||
setYAxisUnit: (unit: string) => void;
|
||||
}
|
||||
|
||||
export interface RelatedMetricsProps {
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { MetricDetails } from 'api/metricsExplorer/getMetricDetails';
|
||||
import { useGetMultipleMetrics } from 'hooks/metricsExplorer/useGetMultipleMetrics';
|
||||
import { Query } from 'types/api/queryBuilder/queryBuilderData';
|
||||
import { v4 as uuid } from 'uuid';
|
||||
|
||||
@@ -35,3 +37,25 @@ export const splitQueryIntoOneChartPerQuery = (query: Query): Query[] => {
|
||||
|
||||
return queries;
|
||||
};
|
||||
|
||||
export function useGetMetricUnits(
|
||||
metricNames: string[],
|
||||
isEnabled = true,
|
||||
): {
|
||||
isLoading: boolean;
|
||||
units: string[];
|
||||
isError: boolean;
|
||||
metrics: (MetricDetails | undefined)[];
|
||||
} {
|
||||
const metricsData = useGetMultipleMetrics(metricNames, {
|
||||
enabled: metricNames.length > 0 && isEnabled,
|
||||
});
|
||||
return {
|
||||
isLoading: metricsData.some((metric) => metric.isLoading),
|
||||
units: metricsData.map(
|
||||
(metric) => metric.data?.payload?.data?.metadata?.unit ?? '',
|
||||
),
|
||||
metrics: metricsData.map((metric) => metric.data?.payload?.data),
|
||||
isError: metricsData.some((metric) => metric.isError),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -139,7 +139,7 @@ function MetricDetails({
|
||||
icon={<Crosshair size={18} />}
|
||||
onClick={(): void => {
|
||||
if (metric?.name) {
|
||||
openInspectModal(metric.name);
|
||||
openInspectModal?.(metric.name);
|
||||
}
|
||||
}}
|
||||
data-testid="inspect-metric-button"
|
||||
|
||||
@@ -11,7 +11,7 @@ export interface MetricDetailsProps {
|
||||
isOpen: boolean;
|
||||
metricName: string | null;
|
||||
isModalTimeSelection: boolean;
|
||||
openInspectModal: (metricName: string) => void;
|
||||
openInspectModal?: (metricName: string) => void;
|
||||
}
|
||||
|
||||
export interface DashboardsAndAlertsPopoverProps {
|
||||
|
||||
@@ -190,7 +190,8 @@
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.y-axis-unit-selector {
|
||||
.y-axis-unit-selector,
|
||||
.y-axis-unit-selector-v2 {
|
||||
margin-top: 16px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
@@ -223,6 +224,21 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.y-axis-unit-selector-v2 {
|
||||
.y-axis-unit-selector-component {
|
||||
.ant-select {
|
||||
width: 100%;
|
||||
border-radius: 2px;
|
||||
background: var(--bg-ink-300);
|
||||
|
||||
.ant-select-selector {
|
||||
border: 1px solid var(--bg-slate-400);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.soft-min-max {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
import { Typography } from 'antd';
|
||||
import YAxisUnitSelectorComponent from 'components/YAxisUnitSelector';
|
||||
import { Dispatch, SetStateAction } from 'react';
|
||||
|
||||
type OnSelectType = Dispatch<SetStateAction<string>> | ((val: string) => void);
|
||||
function YAxisUnitSelectorV2({
|
||||
defaultValue,
|
||||
onSelect,
|
||||
fieldLabel,
|
||||
initialValue,
|
||||
}: {
|
||||
defaultValue: string;
|
||||
onSelect: OnSelectType;
|
||||
fieldLabel: string;
|
||||
initialValue: string;
|
||||
}): JSX.Element {
|
||||
return (
|
||||
<div className="y-axis-unit-selector-v2">
|
||||
<Typography.Text className="heading">{fieldLabel}</Typography.Text>
|
||||
<YAxisUnitSelectorComponent
|
||||
value={defaultValue}
|
||||
onChange={onSelect}
|
||||
initialValue={initialValue}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default YAxisUnitSelectorV2;
|
||||
@@ -1,4 +1,5 @@
|
||||
import { DefaultOptionType } from 'antd/es/select';
|
||||
import { Y_AXIS_CATEGORIES } from 'components/YAxisUnitSelector/constants';
|
||||
|
||||
import {
|
||||
BooleanFormats,
|
||||
@@ -107,18 +108,53 @@ export const alertsCategory = [
|
||||
|
||||
export const getCategorySelectOptionByName = (
|
||||
name?: CategoryNames | string,
|
||||
): DefaultOptionType[] =>
|
||||
alertsCategory
|
||||
): DefaultOptionType[] => {
|
||||
const newAlertsCategory = Y_AXIS_CATEGORIES.find(
|
||||
(category) => category.name === name,
|
||||
);
|
||||
if (newAlertsCategory) {
|
||||
return newAlertsCategory.units.map((unit) => ({
|
||||
label: unit.name,
|
||||
value: unit.id,
|
||||
}));
|
||||
}
|
||||
|
||||
const oldAlertsCategory = alertsCategory
|
||||
.find((category) => category.name === name)
|
||||
?.formats.map((format) => ({
|
||||
label: format.name,
|
||||
value: format.id,
|
||||
})) || [];
|
||||
}));
|
||||
if (oldAlertsCategory) {
|
||||
return oldAlertsCategory;
|
||||
}
|
||||
|
||||
export const getCategoryByOptionId = (id: string): Category | undefined =>
|
||||
alertsCategory.find((category) =>
|
||||
return [];
|
||||
};
|
||||
|
||||
export const getCategoryByOptionId = (id: string): Category | undefined => {
|
||||
const newAlertsCategory = Y_AXIS_CATEGORIES.find((category) =>
|
||||
category.units.some((unit) => unit.id === id),
|
||||
);
|
||||
if (newAlertsCategory) {
|
||||
return {
|
||||
name: newAlertsCategory.name,
|
||||
formats: newAlertsCategory.units.map((unit) => ({
|
||||
name: unit.name,
|
||||
id: unit.id,
|
||||
})),
|
||||
};
|
||||
}
|
||||
|
||||
const oldAlertsCategory = alertsCategory.find((category) =>
|
||||
category.formats.some((format) => format.id === id),
|
||||
);
|
||||
if (oldAlertsCategory) {
|
||||
return oldAlertsCategory;
|
||||
}
|
||||
|
||||
return undefined;
|
||||
};
|
||||
|
||||
export const isCategoryName = (name: string): name is CategoryNames =>
|
||||
alertsCategory.some((category) => category.name === name);
|
||||
|
||||
@@ -63,7 +63,7 @@ import LegendColors from './LegendColors/LegendColors';
|
||||
import ThresholdSelector from './Threshold/ThresholdSelector';
|
||||
import { ThresholdProps } from './Threshold/types';
|
||||
import { timePreferance } from './timeItems';
|
||||
import YAxisUnitSelector from './YAxisUnitSelector';
|
||||
import YAxisUnitSelector from './YAxisUnitSelectorV2';
|
||||
|
||||
const { TextArea } = Input;
|
||||
const { Option } = Select;
|
||||
@@ -94,6 +94,7 @@ function RightContainer({
|
||||
setSelectedTime,
|
||||
selectedTime,
|
||||
yAxisUnit,
|
||||
initialYAxisUnit,
|
||||
setYAxisUnit,
|
||||
setGraphHandler,
|
||||
thresholds,
|
||||
@@ -346,8 +347,9 @@ function RightContainer({
|
||||
|
||||
{allowYAxisUnit && (
|
||||
<YAxisUnitSelector
|
||||
defaultValue={yAxisUnit}
|
||||
initialValue={initialYAxisUnit || ''}
|
||||
onSelect={setYAxisUnit}
|
||||
value={yAxisUnit || ''}
|
||||
fieldLabel={
|
||||
selectedGraphType === PanelDisplay.VALUE ||
|
||||
selectedGraphType === PanelDisplay.PIE
|
||||
@@ -544,6 +546,7 @@ interface RightContainerProps {
|
||||
setSelectedTime: Dispatch<SetStateAction<timePreferance>>;
|
||||
selectedTime: timePreferance;
|
||||
yAxisUnit: string;
|
||||
initialYAxisUnit: string | undefined;
|
||||
stackedBarChart: boolean;
|
||||
setStackedBarChart: Dispatch<SetStateAction<boolean>>;
|
||||
bucketWidth: number;
|
||||
|
||||
@@ -301,6 +301,12 @@ function NewWidget({
|
||||
contextLinks,
|
||||
]);
|
||||
|
||||
const initialYAxisUnit = useMemo(
|
||||
() => selectedWidget?.yAxisUnit || 'none',
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
[],
|
||||
);
|
||||
|
||||
const closeModal = (): void => {
|
||||
setSaveModal(false);
|
||||
setDiscardModal(false);
|
||||
@@ -821,6 +827,7 @@ function NewWidget({
|
||||
setStackedBarChart={setStackedBarChart}
|
||||
opacity={opacity}
|
||||
yAxisUnit={yAxisUnit}
|
||||
initialYAxisUnit={initialYAxisUnit}
|
||||
columnUnits={columnUnits}
|
||||
setColumnUnits={setColumnUnits}
|
||||
bucketCount={bucketCount}
|
||||
|
||||
35
frontend/src/hooks/metricsExplorer/useGetMultipleMetrics.ts
Normal file
35
frontend/src/hooks/metricsExplorer/useGetMultipleMetrics.ts
Normal file
@@ -0,0 +1,35 @@
|
||||
import {
|
||||
getMetricDetails,
|
||||
MetricDetailsResponse,
|
||||
} from 'api/metricsExplorer/getMetricDetails';
|
||||
import { REACT_QUERY_KEY } from 'constants/reactQueryKeys';
|
||||
import { useQueries, UseQueryOptions, UseQueryResult } from 'react-query';
|
||||
import { ErrorResponse, SuccessResponse } from 'types/api';
|
||||
|
||||
type QueryData = SuccessResponse<MetricDetailsResponse> | ErrorResponse;
|
||||
type QueryResult = UseQueryResult<QueryData, Error>;
|
||||
|
||||
type UseGetMultipleMetrics = (
|
||||
metricNames: string[],
|
||||
options?: UseQueryOptions<QueryData, Error>,
|
||||
headers?: Record<string, string>,
|
||||
) => QueryResult[];
|
||||
|
||||
export const useGetMultipleMetrics: UseGetMultipleMetrics = (
|
||||
metricNames,
|
||||
options,
|
||||
headers,
|
||||
) => {
|
||||
const queries = useQueries(
|
||||
metricNames.map(
|
||||
(metricName) =>
|
||||
({
|
||||
queryKey: [REACT_QUERY_KEY.GET_METRIC_DETAILS, metricName],
|
||||
queryFn: ({ signal }) => getMetricDetails(metricName, signal, headers),
|
||||
...options,
|
||||
} as UseQueryOptions<QueryData, Error>),
|
||||
),
|
||||
);
|
||||
|
||||
return queries as QueryResult[];
|
||||
};
|
||||
@@ -77,6 +77,9 @@ const useCreateAlerts = (
|
||||
queryRangeMutation.mutate(queryPayload, {
|
||||
onSuccess: (data) => {
|
||||
const updatedQuery = mapQueryDataFromApi(data.data.compositeQuery);
|
||||
if (widget?.yAxisUnit) {
|
||||
updatedQuery.unit = widget?.yAxisUnit;
|
||||
}
|
||||
const url = `${ROUTES.ALERTS_NEW}?${
|
||||
QueryParams.compositeQuery
|
||||
}=${encodeURIComponent(JSON.stringify(updatedQuery))}&${
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
import { Y_AXIS_UNIT_NAMES } from 'components/YAxisUnitSelector/constants';
|
||||
import { UniversalYAxisUnit } from 'components/YAxisUnitSelector/types';
|
||||
|
||||
const unitsMapping = [
|
||||
{
|
||||
label: 'Data',
|
||||
@@ -72,6 +75,97 @@ const unitsMapping = [
|
||||
value: 'decpbytes',
|
||||
factor: 1000 * 1000 * 1000 * 1000 * 1000,
|
||||
},
|
||||
// Universal units
|
||||
{
|
||||
label: Y_AXIS_UNIT_NAMES[UniversalYAxisUnit.BYTES],
|
||||
value: UniversalYAxisUnit.BYTES,
|
||||
factor: 1,
|
||||
},
|
||||
{
|
||||
label: Y_AXIS_UNIT_NAMES[UniversalYAxisUnit.KILOBYTES],
|
||||
value: UniversalYAxisUnit.KILOBYTES,
|
||||
factor: 1024,
|
||||
},
|
||||
{
|
||||
label: Y_AXIS_UNIT_NAMES[UniversalYAxisUnit.MEGABYTES],
|
||||
value: UniversalYAxisUnit.MEGABYTES,
|
||||
factor: 1024 * 1024,
|
||||
},
|
||||
{
|
||||
label: Y_AXIS_UNIT_NAMES[UniversalYAxisUnit.GIGABYTES],
|
||||
value: UniversalYAxisUnit.GIGABYTES,
|
||||
factor: 1024 * 1024 * 1024,
|
||||
},
|
||||
{
|
||||
label: Y_AXIS_UNIT_NAMES[UniversalYAxisUnit.TERABYTES],
|
||||
value: UniversalYAxisUnit.TERABYTES,
|
||||
factor: 1024 * 1024 * 1024 * 1024,
|
||||
},
|
||||
{
|
||||
label: Y_AXIS_UNIT_NAMES[UniversalYAxisUnit.PETABYTES],
|
||||
value: UniversalYAxisUnit.PETABYTES,
|
||||
factor: 1024 * 1024 * 1024 * 1024 * 1024,
|
||||
},
|
||||
{
|
||||
label: Y_AXIS_UNIT_NAMES[UniversalYAxisUnit.EXABYTES],
|
||||
value: UniversalYAxisUnit.EXABYTES,
|
||||
factor: 1024 * 1024 * 1024 * 1024 * 1024 * 1024,
|
||||
},
|
||||
{
|
||||
label: Y_AXIS_UNIT_NAMES[UniversalYAxisUnit.ZETTABYTES],
|
||||
value: UniversalYAxisUnit.ZETTABYTES,
|
||||
factor: 1024 * 1024 * 1024 * 1024 * 1024 * 1024 * 1024,
|
||||
},
|
||||
{
|
||||
label: Y_AXIS_UNIT_NAMES[UniversalYAxisUnit.YOTTABYTES],
|
||||
value: UniversalYAxisUnit.YOTTABYTES,
|
||||
factor: 1024 * 1024 * 1024 * 1024 * 1024 * 1024 * 1024 * 1024,
|
||||
},
|
||||
{
|
||||
label: Y_AXIS_UNIT_NAMES[UniversalYAxisUnit.BITS],
|
||||
value: UniversalYAxisUnit.BITS,
|
||||
factor: 8,
|
||||
},
|
||||
{
|
||||
label: Y_AXIS_UNIT_NAMES[UniversalYAxisUnit.KILOBITS],
|
||||
value: UniversalYAxisUnit.KILOBITS,
|
||||
factor: 8 * 1024,
|
||||
},
|
||||
{
|
||||
label: Y_AXIS_UNIT_NAMES[UniversalYAxisUnit.MEGABITS],
|
||||
value: UniversalYAxisUnit.MEGABITS,
|
||||
factor: 8 * 1024 * 1024,
|
||||
},
|
||||
{
|
||||
label: Y_AXIS_UNIT_NAMES[UniversalYAxisUnit.GIGABITS],
|
||||
value: UniversalYAxisUnit.GIGABITS,
|
||||
factor: 8 * 1024 * 1024 * 1024,
|
||||
},
|
||||
{
|
||||
label: Y_AXIS_UNIT_NAMES[UniversalYAxisUnit.TERABITS],
|
||||
value: UniversalYAxisUnit.TERABITS,
|
||||
factor: 8 * 1024 * 1024 * 1024 * 1024,
|
||||
},
|
||||
{
|
||||
label: Y_AXIS_UNIT_NAMES[UniversalYAxisUnit.PETABITS],
|
||||
value: UniversalYAxisUnit.PETABITS,
|
||||
factor: 8 * 1024 * 1024 * 1024 * 1024 * 1024,
|
||||
},
|
||||
{
|
||||
label: Y_AXIS_UNIT_NAMES[UniversalYAxisUnit.EXABITS],
|
||||
value: UniversalYAxisUnit.EXABITS,
|
||||
factor: 8 * 1024 * 1024 * 1024 * 1024 * 1024 * 1024,
|
||||
},
|
||||
{
|
||||
label: Y_AXIS_UNIT_NAMES[UniversalYAxisUnit.ZETTABITS],
|
||||
value: UniversalYAxisUnit.ZETTABITS,
|
||||
factor: 8 * 1024 * 1024 * 1024 * 1024 * 1024 * 1024 * 1024,
|
||||
},
|
||||
{
|
||||
label: Y_AXIS_UNIT_NAMES[UniversalYAxisUnit.YOTTABITS],
|
||||
value: UniversalYAxisUnit.YOTTABITS,
|
||||
factor: 8 * 1024 * 1024 * 1024 * 1024 * 1024 * 1024 * 1024 * 1024,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
@@ -130,6 +224,87 @@ const unitsMapping = [
|
||||
// ... (other options)
|
||||
],
|
||||
},
|
||||
// Universal units for data rate
|
||||
{
|
||||
label: 'Data Rate',
|
||||
options: [
|
||||
{
|
||||
label: Y_AXIS_UNIT_NAMES[UniversalYAxisUnit.BYTES_SECOND],
|
||||
value: UniversalYAxisUnit.BYTES_SECOND,
|
||||
factor: 1,
|
||||
},
|
||||
{
|
||||
label: Y_AXIS_UNIT_NAMES[UniversalYAxisUnit.KILOBYTES_SECOND],
|
||||
value: UniversalYAxisUnit.KILOBYTES_SECOND,
|
||||
factor: 1024,
|
||||
},
|
||||
{
|
||||
label: Y_AXIS_UNIT_NAMES[UniversalYAxisUnit.MEGABYTES_SECOND],
|
||||
value: UniversalYAxisUnit.MEGABYTES_SECOND,
|
||||
factor: 1024 * 1024,
|
||||
},
|
||||
{
|
||||
label: Y_AXIS_UNIT_NAMES[UniversalYAxisUnit.GIGABYTES_SECOND],
|
||||
value: UniversalYAxisUnit.GIGABYTES_SECOND,
|
||||
factor: 1024 * 1024 * 1024,
|
||||
},
|
||||
{
|
||||
label: Y_AXIS_UNIT_NAMES[UniversalYAxisUnit.TERABYTES_SECOND],
|
||||
value: UniversalYAxisUnit.TERABYTES_SECOND,
|
||||
factor: 1024 * 1024 * 1024 * 1024,
|
||||
},
|
||||
{
|
||||
label: Y_AXIS_UNIT_NAMES[UniversalYAxisUnit.PETABYTES_SECOND],
|
||||
value: UniversalYAxisUnit.PETABYTES_SECOND,
|
||||
factor: 1024,
|
||||
},
|
||||
{
|
||||
label: Y_AXIS_UNIT_NAMES[UniversalYAxisUnit.BITS_SECOND],
|
||||
value: UniversalYAxisUnit.BITS_SECOND,
|
||||
factor: 8,
|
||||
},
|
||||
{
|
||||
label: Y_AXIS_UNIT_NAMES[UniversalYAxisUnit.KILOBITS_SECOND],
|
||||
value: UniversalYAxisUnit.KILOBITS_SECOND,
|
||||
factor: 8 * 1024,
|
||||
},
|
||||
{
|
||||
label: Y_AXIS_UNIT_NAMES[UniversalYAxisUnit.MEGABITS_SECOND],
|
||||
value: UniversalYAxisUnit.MEGABITS_SECOND,
|
||||
factor: 8 * 1024 * 1024,
|
||||
},
|
||||
{
|
||||
label: Y_AXIS_UNIT_NAMES[UniversalYAxisUnit.GIGABITS_SECOND],
|
||||
value: UniversalYAxisUnit.GIGABITS_SECOND,
|
||||
factor: 8 * 1024 * 1024 * 1024,
|
||||
},
|
||||
{
|
||||
label: Y_AXIS_UNIT_NAMES[UniversalYAxisUnit.TERABITS_SECOND],
|
||||
value: UniversalYAxisUnit.TERABITS_SECOND,
|
||||
factor: 8 * 1024 * 1024 * 1024 * 1024,
|
||||
},
|
||||
{
|
||||
label: Y_AXIS_UNIT_NAMES[UniversalYAxisUnit.PETABITS_SECOND],
|
||||
value: UniversalYAxisUnit.PETABITS_SECOND,
|
||||
factor: 8 * 1024 * 1024 * 1024 * 1024 * 1024,
|
||||
},
|
||||
{
|
||||
label: Y_AXIS_UNIT_NAMES[UniversalYAxisUnit.EXABITS_SECOND],
|
||||
value: UniversalYAxisUnit.EXABITS_SECOND,
|
||||
factor: 8 * 1024 * 1024 * 1024 * 1024 * 1024 * 1024,
|
||||
},
|
||||
{
|
||||
label: Y_AXIS_UNIT_NAMES[UniversalYAxisUnit.ZETTABITS_SECOND],
|
||||
value: UniversalYAxisUnit.ZETTABITS_SECOND,
|
||||
factor: 8 * 1024 * 1024 * 1024 * 1024 * 1024 * 1024 * 1024,
|
||||
},
|
||||
{
|
||||
label: Y_AXIS_UNIT_NAMES[UniversalYAxisUnit.YOTTABITS_SECOND],
|
||||
value: UniversalYAxisUnit.YOTTABITS_SECOND,
|
||||
factor: 8 * 1024 * 1024 * 1024 * 1024 * 1024 * 1024 * 1024 * 1024,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: 'Time',
|
||||
options: [
|
||||
@@ -223,7 +398,69 @@ const unitsMapping = [
|
||||
value: 'wpm',
|
||||
factor: 60, // 1 wpm = 60 wps
|
||||
},
|
||||
// ... (other options)
|
||||
// Universal units for throughput
|
||||
{
|
||||
label: Y_AXIS_UNIT_NAMES[UniversalYAxisUnit.COUNT_SECOND],
|
||||
value: UniversalYAxisUnit.COUNT_SECOND,
|
||||
factor: 1,
|
||||
},
|
||||
{
|
||||
label: Y_AXIS_UNIT_NAMES[UniversalYAxisUnit.COUNT_MINUTE],
|
||||
value: UniversalYAxisUnit.COUNT_MINUTE,
|
||||
factor: 60,
|
||||
},
|
||||
],
|
||||
},
|
||||
// Universal units for operations
|
||||
{
|
||||
label: 'Operations',
|
||||
options: [
|
||||
{
|
||||
label: Y_AXIS_UNIT_NAMES[UniversalYAxisUnit.OPS_SECOND],
|
||||
value: UniversalYAxisUnit.OPS_SECOND,
|
||||
factor: 60,
|
||||
},
|
||||
{
|
||||
label: Y_AXIS_UNIT_NAMES[UniversalYAxisUnit.OPS_MINUTE],
|
||||
value: UniversalYAxisUnit.OPS_MINUTE,
|
||||
factor: 1,
|
||||
},
|
||||
{
|
||||
label: Y_AXIS_UNIT_NAMES[UniversalYAxisUnit.REQUESTS_SECOND],
|
||||
value: UniversalYAxisUnit.REQUESTS_SECOND,
|
||||
factor: 60,
|
||||
},
|
||||
{
|
||||
label: Y_AXIS_UNIT_NAMES[UniversalYAxisUnit.REQUESTS_MINUTE],
|
||||
value: UniversalYAxisUnit.REQUESTS_MINUTE,
|
||||
factor: 1,
|
||||
},
|
||||
{
|
||||
label: Y_AXIS_UNIT_NAMES[UniversalYAxisUnit.READS_SECOND],
|
||||
value: UniversalYAxisUnit.READS_SECOND,
|
||||
factor: 60,
|
||||
},
|
||||
{
|
||||
label: Y_AXIS_UNIT_NAMES[UniversalYAxisUnit.READS_MINUTE],
|
||||
value: UniversalYAxisUnit.READS_MINUTE,
|
||||
factor: 1,
|
||||
},
|
||||
{
|
||||
label: Y_AXIS_UNIT_NAMES[UniversalYAxisUnit.WRITES_SECOND],
|
||||
value: UniversalYAxisUnit.WRITES_SECOND,
|
||||
factor: 60,
|
||||
},
|
||||
|
||||
{
|
||||
label: Y_AXIS_UNIT_NAMES[UniversalYAxisUnit.WRITES_MINUTE],
|
||||
value: UniversalYAxisUnit.WRITES_MINUTE,
|
||||
factor: 1,
|
||||
},
|
||||
{
|
||||
label: Y_AXIS_UNIT_NAMES[UniversalYAxisUnit.IOOPS_SECOND],
|
||||
value: UniversalYAxisUnit.IOOPS_SECOND,
|
||||
factor: 60,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
|
||||
@@ -740,6 +740,11 @@ export const getUPlotChartOptions = ({
|
||||
isDarkMode,
|
||||
colorMapping,
|
||||
}),
|
||||
axes: getAxes({ isDarkMode, yAxisUnit, panelType, isLogScale }),
|
||||
axes: getAxes({
|
||||
isDarkMode,
|
||||
yAxisUnit,
|
||||
panelType,
|
||||
isLogScale,
|
||||
}),
|
||||
};
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user