From 3ca3db256737f14dc4114b620d063596715ec073 Mon Sep 17 00:00:00 2001 From: Amlan Kumar Nandy <45410599+amlannandy@users.noreply.github.com> Date: Mon, 26 May 2025 12:45:21 +0700 Subject: [PATCH] chore: add to alerts/dashboard improvements for one chart per query mode in metrics explorer (#8014) --- .../ExplorerOptions/ExplorerOptionWrapper.tsx | 4 + .../ExplorerOptions.styles.scss | 15 ++ .../ExplorerOptions/ExplorerOptions.tsx | 237 ++++++++++++++---- .../MetricsExplorer/Explorer/Explorer.tsx | 22 +- 4 files changed, 220 insertions(+), 58 deletions(-) diff --git a/frontend/src/container/ExplorerOptions/ExplorerOptionWrapper.tsx b/frontend/src/container/ExplorerOptions/ExplorerOptionWrapper.tsx index a2e0eff9c8..beef5c6686 100644 --- a/frontend/src/container/ExplorerOptions/ExplorerOptionWrapper.tsx +++ b/frontend/src/container/ExplorerOptions/ExplorerOptionWrapper.tsx @@ -14,6 +14,8 @@ function ExplorerOptionWrapper({ isLoading, onExport, sourcepage, + isOneChartPerQuery, + splitedQueries, }: ExplorerOptionsWrapperProps): JSX.Element { const [isExplorerOptionHidden, setIsExplorerOptionHidden] = useState(false); @@ -32,6 +34,8 @@ function ExplorerOptionWrapper({ sourcepage={sourcepage} isExplorerOptionHidden={isExplorerOptionHidden} setIsExplorerOptionHidden={setIsExplorerOptionHidden} + isOneChartPerQuery={isOneChartPerQuery} + splitedQueries={splitedQueries} /> ); } diff --git a/frontend/src/container/ExplorerOptions/ExplorerOptions.styles.scss b/frontend/src/container/ExplorerOptions/ExplorerOptions.styles.scss index 9efc053245..179003da45 100644 --- a/frontend/src/container/ExplorerOptions/ExplorerOptions.styles.scss +++ b/frontend/src/container/ExplorerOptions/ExplorerOptions.styles.scss @@ -8,6 +8,21 @@ display: flex; gap: 16px; background-color: transparent; + + .multi-alert-button, + .multi-dashboard-button { + min-width: 130px; + + .ant-select-selector { + .ant-select-selection-placeholder { + margin-left: 0 !important; + } + + .ant-select-arrow { + display: none !important; + } + } + } } .hide-update { diff --git a/frontend/src/container/ExplorerOptions/ExplorerOptions.tsx b/frontend/src/container/ExplorerOptions/ExplorerOptions.tsx index 3090babe1d..fa4a723f17 100644 --- a/frontend/src/container/ExplorerOptions/ExplorerOptions.tsx +++ b/frontend/src/container/ExplorerOptions/ExplorerOptions.tsx @@ -90,6 +90,8 @@ function ExplorerOptions({ sourcepage, isExplorerOptionHidden = false, setIsExplorerOptionHidden, + isOneChartPerQuery = false, + splitedQueries = [], }: ExplorerOptionsProps): JSX.Element { const [isExport, setIsExport] = useState(false); const [isSaveModalOpen, setIsSaveModalOpen] = useState(false); @@ -99,6 +101,8 @@ function ExplorerOptions({ const history = useHistory(); const ref = useRef(null); const isDarkMode = useIsDarkMode(); + const [queryToExport, setQueryToExport] = useState(null); + const isLogsExplorer = sourcepage === DataSource.LOGS; const isMetricsExplorer = sourcepage === DataSource.METRICS; @@ -149,51 +153,62 @@ function ExplorerOptions({ const { user } = useAppContext(); - const handleConditionalQueryModification = useCallback((): string => { - if ( - query?.builder?.queryData?.[0]?.aggregateOperator !== StringOperators.NOOP - ) { - return JSON.stringify(query); - } + const handleConditionalQueryModification = useCallback( + (defaultQuery: Query | null): string => { + const queryToUse = defaultQuery || query; + if ( + queryToUse?.builder?.queryData?.[0]?.aggregateOperator !== + StringOperators.NOOP + ) { + return JSON.stringify(queryToUse); + } - // Modify aggregateOperator to count, as noop is not supported in alerts - const modifiedQuery = cloneDeep(query); + // Modify aggregateOperator to count, as noop is not supported in alerts + const modifiedQuery = cloneDeep(queryToUse); - modifiedQuery.builder.queryData[0].aggregateOperator = StringOperators.COUNT; + modifiedQuery.builder.queryData[0].aggregateOperator = StringOperators.COUNT; - return JSON.stringify(modifiedQuery); - }, [query]); + return JSON.stringify(modifiedQuery); + }, + [query], + ); - const onCreateAlertsHandler = useCallback(() => { - if (sourcepage === DataSource.TRACES) { - logEvent('Traces Explorer: Create alert', { - panelType, - }); - } else if (isLogsExplorer) { - logEvent('Logs Explorer: Create alert', { - panelType, - }); - } else if (isMetricsExplorer) { - logEvent('Metrics Explorer: Create alert', { - panelType, - }); - } + const onCreateAlertsHandler = useCallback( + (defaultQuery: Query | null) => { + if (sourcepage === DataSource.TRACES) { + logEvent('Traces Explorer: Create alert', { + panelType, + }); + } else if (isLogsExplorer) { + logEvent('Logs Explorer: Create alert', { + panelType, + }); + } else if (isMetricsExplorer) { + logEvent('Metrics Explorer: Create alert', { + panelType, + }); + } - const stringifiedQuery = handleConditionalQueryModification(); + const stringifiedQuery = handleConditionalQueryModification(defaultQuery); - history.push( - `${ROUTES.ALERTS_NEW}?${QueryParams.compositeQuery}=${encodeURIComponent( - stringifiedQuery, - )}`, - ); + history.push( + `${ROUTES.ALERTS_NEW}?${QueryParams.compositeQuery}=${encodeURIComponent( + stringifiedQuery, + )}`, + ); + }, // eslint-disable-next-line react-hooks/exhaustive-deps - }, [handleConditionalQueryModification, history]); + [handleConditionalQueryModification, history], + ); const onCancel = (value: boolean) => (): void => { onModalToggle(value); + if (isOneChartPerQuery) { + setQueryToExport(null); + } }; - const onAddToDashboard = (): void => { + const onAddToDashboard = useCallback((): void => { if (sourcepage === DataSource.TRACES) { logEvent('Traces Explorer: Add to dashboard clicked', { panelType, @@ -208,7 +223,7 @@ function ExplorerOptions({ }); } setIsExport(true); - }; + }, [isLogsExplorer, isMetricsExplorer, panelType, setIsExport, sourcepage]); const { data: viewsData, @@ -616,6 +631,120 @@ function ExplorerOptions({ return 'https://signoz.io/docs/product-features/trace-explorer/?utm_source=product&utm_medium=trace-explorer-toolbar'; }, [isLogsExplorer, isMetricsExplorer]); + const getQueryName = (query: Query): string => { + if (query.builder.queryFormulas.length > 0) { + return `Formula ${query.builder.queryFormulas[0].queryName}`; + } + return `Query ${query.builder.queryData[0].queryName}`; + }; + + const alertButton = useMemo(() => { + if (isOneChartPerQuery) { + const selectLabel = ( + + ); + return ( + + ); + } + return ( + + ); + }, [ + disabled, + isOneChartPerQuery, + onCreateAlertsHandler, + query, + splitedQueries, + ]); + + const dashboardButton = useMemo(() => { + if (isOneChartPerQuery) { + const selectLabel = ( + + ); + return ( + + ); + } + return ( + + ); + }, [disabled, isOneChartPerQuery, onAddToDashboard, splitedQueries]); + return (
{ @@ -719,24 +848,8 @@ function ExplorerOptions({
- - - + {alertButton} + {dashboardButton}
{/* Hide the info icon for metrics explorer until we get the docs link */} @@ -818,9 +931,15 @@ function ExplorerOptions({ destroyOnClose > { + if (isOneChartPerQuery && queryToExport) { + onExport(dashboard, isNewDashboard, queryToExport); + } else { + onExport(dashboard, isNewDashboard); + } + }} />
@@ -829,18 +948,26 @@ function ExplorerOptions({ export interface ExplorerOptionsProps { isLoading?: boolean; - onExport: (dashboard: Dashboard | null, isNewDashboard?: boolean) => void; + onExport: ( + dashboard: Dashboard | null, + isNewDashboard?: boolean, + queryToExport?: Query, + ) => void; query: Query | null; disabled: boolean; sourcepage: DataSource; isExplorerOptionHidden?: boolean; setIsExplorerOptionHidden?: Dispatch>; + isOneChartPerQuery?: boolean; + splitedQueries?: Query[]; } ExplorerOptions.defaultProps = { isLoading: false, isExplorerOptionHidden: false, setIsExplorerOptionHidden: undefined, + isOneChartPerQuery: false, + splitedQueries: [], }; export default ExplorerOptions; diff --git a/frontend/src/container/MetricsExplorer/Explorer/Explorer.tsx b/frontend/src/container/MetricsExplorer/Explorer/Explorer.tsx index eae66505c5..1aed2e567b 100644 --- a/frontend/src/container/MetricsExplorer/Explorer/Explorer.tsx +++ b/frontend/src/container/MetricsExplorer/Explorer/Explorer.tsx @@ -19,6 +19,7 @@ import ErrorBoundaryFallback from 'pages/ErrorBoundaryFallback/ErrorBoundaryFall import { useCallback, useMemo, useState } from 'react'; import { useSearchParams } from 'react-router-dom-v5-compat'; import { Dashboard } from 'types/api/dashboard/getAll'; +import { Query } from 'types/api/queryBuilder/queryBuilderData'; import { DataSource } from 'types/common/queryBuilder'; import { generateExportToDashboardLink } from 'utils/dashboard/generateExportToDashboardLink'; import { v4 as uuid } from 'uuid'; @@ -26,6 +27,7 @@ import { v4 as uuid } from 'uuid'; import QuerySection from './QuerySection'; import TimeSeries from './TimeSeries'; import { ExplorerTabs } from './types'; +import { splitQueryIntoOneChartPerQuery } from './utils'; const ONE_CHART_PER_QUERY_ENABLED_KEY = 'isOneChartPerQueryEnabled'; @@ -75,14 +77,18 @@ function Explorer(): JSX.Element { useShareBuilderUrl(exportDefaultQuery); const handleExport = useCallback( - (dashboard: Dashboard | null): void => { + ( + dashboard: Dashboard | null, + _isNewDashboard?: boolean, + queryToExport?: Query, + ): void => { if (!dashboard) return; const widgetId = uuid(); const updatedDashboard = addEmptyWidgetInDashboardJSONWithQuery( dashboard, - exportDefaultQuery, + queryToExport || exportDefaultQuery, widgetId, PANEL_TYPES.TIME_SERIES, options.selectColumns, @@ -114,7 +120,7 @@ function Explorer(): JSX.Element { return; } const dashboardEditView = generateExportToDashboardLink({ - query: exportDefaultQuery, + query: queryToExport || exportDefaultQuery, panelType: PANEL_TYPES.TIME_SERIES, dashboardId: data.payload?.uuid || '', widgetId, @@ -135,6 +141,14 @@ function Explorer(): JSX.Element { [exportDefaultQuery, notifications, updateDashboard], ); + const splitedQueries = useMemo( + () => + splitQueryIntoOneChartPerQuery( + stagedQuery || initialQueriesMap[DataSource.METRICS], + ), + [stagedQuery], + ); + return ( }>
@@ -190,6 +204,8 @@ function Explorer(): JSX.Element { isLoading={isLoading} sourcepage={DataSource.METRICS} onExport={handleExport} + isOneChartPerQuery={showOneChartPerQuery} + splitedQueries={splitedQueries} /> );