mirror of
https://github.com/SigNoz/signoz.git
synced 2025-12-23 02:17:11 +00:00
chore: replace y axis unit selector in dashboards
This commit is contained in:
parent
5c22ef773d
commit
9ce228ca13
@ -1,7 +1,7 @@
|
|||||||
import './Explorer.styles.scss';
|
import './Explorer.styles.scss';
|
||||||
|
|
||||||
import * as Sentry from '@sentry/react';
|
import * as Sentry from '@sentry/react';
|
||||||
import { Switch } from 'antd';
|
import { Switch, Tooltip } from 'antd';
|
||||||
import logEvent from 'api/common/logEvent';
|
import logEvent from 'api/common/logEvent';
|
||||||
import { QueryBuilderV2 } from 'components/QueryBuilderV2/QueryBuilderV2';
|
import { QueryBuilderV2 } from 'components/QueryBuilderV2/QueryBuilderV2';
|
||||||
import WarningPopover from 'components/WarningPopover/WarningPopover';
|
import WarningPopover from 'components/WarningPopover/WarningPopover';
|
||||||
@ -25,10 +25,10 @@ import { generateExportToDashboardLink } from 'utils/dashboard/generateExportToD
|
|||||||
import { v4 as uuid } from 'uuid';
|
import { v4 as uuid } from 'uuid';
|
||||||
|
|
||||||
import { MetricsExplorerEventKeys, MetricsExplorerEvents } from '../events';
|
import { MetricsExplorerEventKeys, MetricsExplorerEvents } from '../events';
|
||||||
// import QuerySection from './QuerySection';
|
import MetricDetails from '../MetricDetails/MetricDetails';
|
||||||
import TimeSeries from './TimeSeries';
|
import TimeSeries from './TimeSeries';
|
||||||
import { ExplorerTabs } from './types';
|
import { ExplorerTabs } from './types';
|
||||||
import { splitQueryIntoOneChartPerQuery } from './utils';
|
import { splitQueryIntoOneChartPerQuery, useGetMetricUnits } from './utils';
|
||||||
|
|
||||||
const ONE_CHART_PER_QUERY_ENABLED_KEY = 'isOneChartPerQueryEnabled';
|
const ONE_CHART_PER_QUERY_ENABLED_KEY = 'isOneChartPerQueryEnabled';
|
||||||
|
|
||||||
@ -40,6 +40,31 @@ function Explorer(): JSX.Element {
|
|||||||
currentQuery,
|
currentQuery,
|
||||||
} = useQueryBuilder();
|
} = useQueryBuilder();
|
||||||
const { safeNavigate } = useSafeNavigate();
|
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 [searchParams, setSearchParams] = useSearchParams();
|
||||||
const isOneChartPerQueryEnabled =
|
const isOneChartPerQueryEnabled =
|
||||||
@ -48,7 +73,31 @@ function Explorer(): JSX.Element {
|
|||||||
const [showOneChartPerQuery, toggleShowOneChartPerQuery] = useState(
|
const [showOneChartPerQuery, toggleShowOneChartPerQuery] = useState(
|
||||||
isOneChartPerQueryEnabled,
|
isOneChartPerQueryEnabled,
|
||||||
);
|
);
|
||||||
|
const [disableOneChartPerQuery, toggleDisableOneChartPerQuery] = useState(
|
||||||
|
false,
|
||||||
|
);
|
||||||
const [selectedTab] = useState<ExplorerTabs>(ExplorerTabs.TIME_SERIES);
|
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 => {
|
const handleToggleShowOneChartPerQuery = (): void => {
|
||||||
toggleShowOneChartPerQuery(!showOneChartPerQuery);
|
toggleShowOneChartPerQuery(!showOneChartPerQuery);
|
||||||
@ -68,15 +117,20 @@ function Explorer(): JSX.Element {
|
|||||||
[updateAllQueriesOperators],
|
[updateAllQueriesOperators],
|
||||||
);
|
);
|
||||||
|
|
||||||
const exportDefaultQuery = useMemo(
|
const exportDefaultQuery = useMemo(() => {
|
||||||
() =>
|
const query = updateAllQueriesOperators(
|
||||||
updateAllQueriesOperators(
|
|
||||||
currentQuery || initialQueriesMap[DataSource.METRICS],
|
currentQuery || initialQueriesMap[DataSource.METRICS],
|
||||||
PANEL_TYPES.TIME_SERIES,
|
PANEL_TYPES.TIME_SERIES,
|
||||||
DataSource.METRICS,
|
DataSource.METRICS,
|
||||||
),
|
|
||||||
[currentQuery, updateAllQueriesOperators],
|
|
||||||
);
|
);
|
||||||
|
if (yAxisUnit) {
|
||||||
|
return {
|
||||||
|
...query,
|
||||||
|
unit: yAxisUnit,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return query;
|
||||||
|
}, [currentQuery, updateAllQueriesOperators, yAxisUnit]);
|
||||||
|
|
||||||
useShareBuilderUrl({ defaultValue: defaultQuery });
|
useShareBuilderUrl({ defaultValue: defaultQuery });
|
||||||
|
|
||||||
@ -90,8 +144,16 @@ function Explorer(): JSX.Element {
|
|||||||
|
|
||||||
const widgetId = uuid();
|
const widgetId = uuid();
|
||||||
|
|
||||||
|
let query = queryToExport || exportDefaultQuery;
|
||||||
|
if (yAxisUnit) {
|
||||||
|
query = {
|
||||||
|
...query,
|
||||||
|
unit: yAxisUnit,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
const dashboardEditView = generateExportToDashboardLink({
|
const dashboardEditView = generateExportToDashboardLink({
|
||||||
query: queryToExport || exportDefaultQuery,
|
query,
|
||||||
panelType: PANEL_TYPES.TIME_SERIES,
|
panelType: PANEL_TYPES.TIME_SERIES,
|
||||||
dashboardId: dashboard.id,
|
dashboardId: dashboard.id,
|
||||||
widgetId,
|
widgetId,
|
||||||
@ -99,7 +161,7 @@ function Explorer(): JSX.Element {
|
|||||||
|
|
||||||
safeNavigate(dashboardEditView);
|
safeNavigate(dashboardEditView);
|
||||||
},
|
},
|
||||||
[exportDefaultQuery, safeNavigate],
|
[exportDefaultQuery, safeNavigate, yAxisUnit],
|
||||||
);
|
);
|
||||||
|
|
||||||
const splitedQueries = useMemo(
|
const splitedQueries = useMemo(
|
||||||
@ -129,11 +191,17 @@ function Explorer(): JSX.Element {
|
|||||||
<div className="explore-header">
|
<div className="explore-header">
|
||||||
<div className="explore-header-left-actions">
|
<div className="explore-header-left-actions">
|
||||||
<span>1 chart/query</span>
|
<span>1 chart/query</span>
|
||||||
|
<Tooltip
|
||||||
|
open={disableOneChartPerQuery ? undefined : false}
|
||||||
|
title="One chart per query cannot be disabled for multiple queries with different units."
|
||||||
|
>
|
||||||
<Switch
|
<Switch
|
||||||
checked={showOneChartPerQuery}
|
checked={showOneChartPerQuery}
|
||||||
onChange={handleToggleShowOneChartPerQuery}
|
onChange={handleToggleShowOneChartPerQuery}
|
||||||
|
disabled={disableOneChartPerQuery}
|
||||||
size="small"
|
size="small"
|
||||||
/>
|
/>
|
||||||
|
</Tooltip>
|
||||||
</div>
|
</div>
|
||||||
<div className="explore-header-right-actions">
|
<div className="explore-header-right-actions">
|
||||||
{!isEmpty(warning) && <WarningPopover warningData={warning} />}
|
{!isEmpty(warning) && <WarningPopover warningData={warning} />}
|
||||||
@ -174,6 +242,15 @@ function Explorer(): JSX.Element {
|
|||||||
<TimeSeries
|
<TimeSeries
|
||||||
showOneChartPerQuery={showOneChartPerQuery}
|
showOneChartPerQuery={showOneChartPerQuery}
|
||||||
setWarning={setWarning}
|
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 */}
|
{/* TODO: Enable once we have resolved all related metrics issues */}
|
||||||
@ -190,6 +267,14 @@ function Explorer(): JSX.Element {
|
|||||||
isOneChartPerQuery={false}
|
isOneChartPerQuery={false}
|
||||||
splitedQueries={splitedQueries}
|
splitedQueries={splitedQueries}
|
||||||
/>
|
/>
|
||||||
|
{isMetricDetailsOpen && (
|
||||||
|
<MetricDetails
|
||||||
|
metricName={metricNames[0]}
|
||||||
|
isOpen={isMetricDetailsOpen}
|
||||||
|
onClose={(): void => setIsMetricDetailsOpen(false)}
|
||||||
|
isModalTimeSelection={false}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
</Sentry.ErrorBoundary>
|
</Sentry.ErrorBoundary>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
import { MetricDetails } from 'api/metricsExplorer/getMetricDetails';
|
||||||
import { RelatedMetric } from 'api/metricsExplorer/getRelatedMetrics';
|
import { RelatedMetric } from 'api/metricsExplorer/getRelatedMetrics';
|
||||||
import { Dispatch, SetStateAction } from 'react';
|
import { Dispatch, SetStateAction } from 'react';
|
||||||
import { UseQueryResult } from 'react-query';
|
import { UseQueryResult } from 'react-query';
|
||||||
@ -12,6 +13,15 @@ export enum ExplorerTabs {
|
|||||||
export interface TimeSeriesProps {
|
export interface TimeSeriesProps {
|
||||||
showOneChartPerQuery: boolean;
|
showOneChartPerQuery: boolean;
|
||||||
setWarning: Dispatch<SetStateAction<Warning | undefined>>;
|
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 {
|
export interface RelatedMetricsProps {
|
||||||
|
|||||||
@ -139,7 +139,7 @@ function MetricDetails({
|
|||||||
icon={<Crosshair size={18} />}
|
icon={<Crosshair size={18} />}
|
||||||
onClick={(): void => {
|
onClick={(): void => {
|
||||||
if (metric?.name) {
|
if (metric?.name) {
|
||||||
openInspectModal(metric.name);
|
openInspectModal?.(metric.name);
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
data-testid="inspect-metric-button"
|
data-testid="inspect-metric-button"
|
||||||
|
|||||||
@ -11,7 +11,7 @@ export interface MetricDetailsProps {
|
|||||||
isOpen: boolean;
|
isOpen: boolean;
|
||||||
metricName: string | null;
|
metricName: string | null;
|
||||||
isModalTimeSelection: boolean;
|
isModalTimeSelection: boolean;
|
||||||
openInspectModal: (metricName: string) => void;
|
openInspectModal?: (metricName: string) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface DashboardsAndAlertsPopoverProps {
|
export interface DashboardsAndAlertsPopoverProps {
|
||||||
|
|||||||
@ -190,7 +190,8 @@
|
|||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
}
|
}
|
||||||
|
|
||||||
.y-axis-unit-selector {
|
.y-axis-unit-selector,
|
||||||
|
.y-axis-unit-selector-v2 {
|
||||||
margin-top: 16px;
|
margin-top: 16px;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
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 {
|
.soft-min-max {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|||||||
@ -0,0 +1,23 @@
|
|||||||
|
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,
|
||||||
|
}: {
|
||||||
|
defaultValue: string;
|
||||||
|
onSelect: OnSelectType;
|
||||||
|
fieldLabel: string;
|
||||||
|
}): JSX.Element {
|
||||||
|
return (
|
||||||
|
<div className="y-axis-unit-selector-v2">
|
||||||
|
<Typography.Text className="heading">{fieldLabel}</Typography.Text>
|
||||||
|
<YAxisUnitSelectorComponent value={defaultValue} onChange={onSelect} />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default YAxisUnitSelectorV2;
|
||||||
@ -63,7 +63,7 @@ import LegendColors from './LegendColors/LegendColors';
|
|||||||
import ThresholdSelector from './Threshold/ThresholdSelector';
|
import ThresholdSelector from './Threshold/ThresholdSelector';
|
||||||
import { ThresholdProps } from './Threshold/types';
|
import { ThresholdProps } from './Threshold/types';
|
||||||
import { timePreferance } from './timeItems';
|
import { timePreferance } from './timeItems';
|
||||||
import YAxisUnitSelector from './YAxisUnitSelector';
|
import YAxisUnitSelector from './YAxisUnitSelectorV2';
|
||||||
|
|
||||||
const { TextArea } = Input;
|
const { TextArea } = Input;
|
||||||
const { Option } = Select;
|
const { Option } = Select;
|
||||||
@ -347,7 +347,6 @@ function RightContainer({
|
|||||||
{allowYAxisUnit && (
|
{allowYAxisUnit && (
|
||||||
<YAxisUnitSelector
|
<YAxisUnitSelector
|
||||||
onSelect={setYAxisUnit}
|
onSelect={setYAxisUnit}
|
||||||
value={yAxisUnit || ''}
|
|
||||||
fieldLabel={
|
fieldLabel={
|
||||||
selectedGraphType === PanelDisplay.VALUE ||
|
selectedGraphType === PanelDisplay.VALUE ||
|
||||||
selectedGraphType === PanelDisplay.PIE
|
selectedGraphType === PanelDisplay.PIE
|
||||||
|
|||||||
@ -49,6 +49,7 @@ import {
|
|||||||
import { Props } from 'types/api/dashboard/update';
|
import { Props } from 'types/api/dashboard/update';
|
||||||
import { IField } from 'types/api/logs/fields';
|
import { IField } from 'types/api/logs/fields';
|
||||||
import { MetricRangePayloadProps } from 'types/api/metrics/getQueryRange';
|
import { MetricRangePayloadProps } from 'types/api/metrics/getQueryRange';
|
||||||
|
import { Query } from 'types/api/queryBuilder/queryBuilderData';
|
||||||
import { EQueryType } from 'types/common/dashboard';
|
import { EQueryType } from 'types/common/dashboard';
|
||||||
import { DataSource } from 'types/common/queryBuilder';
|
import { DataSource } from 'types/common/queryBuilder';
|
||||||
import { GlobalReducer } from 'types/reducer/globalTime';
|
import { GlobalReducer } from 'types/reducer/globalTime';
|
||||||
@ -301,6 +302,19 @@ function NewWidget({
|
|||||||
contextLinks,
|
contextLinks,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const compositeQuery = query.get('compositeQuery');
|
||||||
|
if (compositeQuery) {
|
||||||
|
try {
|
||||||
|
const decoded = decodeURIComponent(compositeQuery);
|
||||||
|
const parsedQuery = JSON.parse(decoded) as Query;
|
||||||
|
setYAxisUnit(parsedQuery.unit || 'none');
|
||||||
|
} catch (error) {
|
||||||
|
setYAxisUnit('none');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [query]);
|
||||||
|
|
||||||
const closeModal = (): void => {
|
const closeModal = (): void => {
|
||||||
setSaveModal(false);
|
setSaveModal(false);
|
||||||
setDiscardModal(false);
|
setDiscardModal(false);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user