diff --git a/public/app/features/dashboard-scene/panel-edit/PanelDataPane/PanelDataQueriesTab.tsx b/public/app/features/dashboard-scene/panel-edit/PanelDataPane/PanelDataQueriesTab.tsx index f1660b56772..19a1e3af6c5 100644 --- a/public/app/features/dashboard-scene/panel-edit/PanelDataPane/PanelDataQueriesTab.tsx +++ b/public/app/features/dashboard-scene/panel-edit/PanelDataPane/PanelDataQueriesTab.tsx @@ -18,6 +18,9 @@ import { addQuery } from 'app/core/utils/query'; import { getLastUsedDatasourceFromStorage } from 'app/features/dashboard/utils/dashboard'; import { storeLastUsedDataSourceInLocalStorage } from 'app/features/datasources/components/picker/utils'; import { dataSource as expressionDatasource } from 'app/features/expressions/ExpressionDatasource'; +import { ExpressionTypeDropdown } from 'app/features/expressions/components/ExpressionTypeDropdown'; +import { ExpressionQueryType } from 'app/features/expressions/types'; +import { getDefaults } from 'app/features/expressions/utils/expressionTypes'; import { GroupActionComponents } from 'app/features/query/components/QueryActionComponent'; import { QueryEditorRows } from 'app/features/query/components/QueryEditorRows'; import { QueryGroupTopSection } from 'app/features/query/components/QueryGroup'; @@ -286,9 +289,15 @@ export class PanelDataQueriesTab extends SceneObjectBase { + public onAddExpressionOfType = (type: ExpressionQueryType) => { const queries = this.getQueries(); - this.onQueriesChange(addQuery(queries, expressionDatasource.newQuery())); + // Create base expression query with the specified type + const baseQuery = expressionDatasource.newQuery(); + const queryWithType = { ...baseQuery, type }; + // Apply defaults specific to the expression type + const queryWithDefaults = getDefaults(queryWithType); + + this.onQueriesChange(addQuery(queries, queryWithDefaults)); }; public renderExtraActions() { @@ -316,6 +325,7 @@ export function PanelDataQueriesTabRendered({ model }: SceneComponentProps { // ensure all queries explicitly define a datasource @@ -394,16 +404,11 @@ export function PanelDataQueriesTabRendered({ model }: SceneComponentProps )} {config.expressionsEnabled && model.isExpressionsSupported(dsSettings) && ( - + + )} {model.renderExtraActions()} diff --git a/public/app/features/expressions/ExpressionQueryEditor.tsx b/public/app/features/expressions/ExpressionQueryEditor.tsx index 75261904c60..b1f07c253bb 100644 --- a/public/app/features/expressions/ExpressionQueryEditor.tsx +++ b/public/app/features/expressions/ExpressionQueryEditor.tsx @@ -1,10 +1,12 @@ +import { css } from '@emotion/css'; import { useCallback, useEffect, useRef } from 'react'; -import { DataSourceApi, QueryEditorProps, SelectableValue } from '@grafana/data'; -import { t } from '@grafana/i18n'; -import { InlineField, Select } from '@grafana/ui'; +import { DataSourceApi, GrafanaTheme2, QueryEditorProps } from '@grafana/data'; +import { t, Trans } from '@grafana/i18n'; +import { Button, IconButton, InlineField, PopoverContent, useStyles2 } from '@grafana/ui'; import { ClassicConditions } from './components/ClassicConditions'; +import { ExpressionTypeDropdown } from './components/ExpressionTypeDropdown'; import { Math } from './components/Math'; import { Reduce } from './components/Reduce'; import { Resample } from './components/Resample'; @@ -20,6 +22,24 @@ const labelWidth = 15; type NonClassicExpressionType = Exclude; type ExpressionTypeConfigStorage = Partial>; +// Help text for each expression type - can be expanded with more detailed content +const getExpressionHelpText = (type: ExpressionQueryType): PopoverContent | string => { + const description = expressionTypes.find(({ value }) => value === type)?.description; + + switch (type) { + case ExpressionQueryType.sql: + return ( + + Run MySQL-dialect SQL against the tables returned from your data sources. Data source queries (ie "A", "B") + are available as tables and referenced by query-name. Fields are available as columns, as returned from the + data source. + + ); + default: + return description ?? ''; + } +}; + function useExpressionsCache() { const expressionCache = useRef({}); @@ -62,14 +82,16 @@ export function ExpressionQueryEditor(props: Props) { const { query, queries, onRunQuery, onChange, app } = props; const { getCachedExpression, setCachedExpression } = useExpressionsCache(); + const styles = useStyles2(getStyles); + useEffect(() => { setCachedExpression(query.type, query.expression); }, [query.expression, query.type, setCachedExpression]); const onSelectExpressionType = useCallback( - (item: SelectableValue) => { - const cachedExpression = getCachedExpression(item.value!); - const defaults = getDefaults({ ...query, type: item.value! }); + (value: ExpressionQueryType) => { + const cachedExpression = getCachedExpression(value!); + const defaults = getDefaults({ ...query, type: value! }); onChange({ ...defaults, expression: cachedExpression ?? defaults.expression }); }, @@ -100,17 +122,35 @@ export function ExpressionQueryEditor(props: Props) { } }; - const selected = expressionTypes.find((o) => o.value === query.type); + const helperText = getExpressionHelpText(query.type); return (
- -