SQL Expressions: Update to feature badges (#112795)

* chore: update badge + update logic

* chore: update comment
This commit is contained in:
Alex Spencer
2025-11-04 08:18:15 -08:00
committed by GitHub
parent de512fb02e
commit 84bd99f1c1
2 changed files with 34 additions and 16 deletions
@@ -1,10 +1,10 @@
import { css } from '@emotion/css';
import { useCallback, useEffect, useRef } from 'react';
import { DataSourceApi, GrafanaTheme2, QueryEditorProps } from '@grafana/data';
import { DataSourceApi, FeatureState, GrafanaTheme2, QueryEditorProps } from '@grafana/data';
import { t, Trans } from '@grafana/i18n';
import { reportInteraction } from '@grafana/runtime';
import { Button, IconButton, InlineField, PopoverContent, useStyles2 } from '@grafana/ui';
import { Button, FeatureBadge, IconButton, InlineField, PopoverContent, useStyles2 } from '@grafana/ui';
import { ClassicConditions } from './components/ClassicConditions';
import { ExpressionTypeDropdown } from './components/ExpressionTypeDropdown';
@@ -23,21 +23,33 @@ const labelWidth = 15;
type NonClassicExpressionType = Exclude<ExpressionQueryType, ExpressionQueryType.classic>;
type ExpressionTypeConfigStorage = Partial<Record<NonClassicExpressionType, string>>;
// Help text for each expression type - can be expanded with more detailed content
const getExpressionHelpText = (type: ExpressionQueryType): PopoverContent | string => {
/**
* Get the configuration for an expression type (helper text and feature state).
* @param type - The expression type.
* @returns The configuration for the expression type.
*/
const getExpressionTypeConfig = (
type: ExpressionQueryType
): { helperText: PopoverContent; featureState: FeatureState | undefined } => {
const description = expressionTypes.find(({ value }) => value === type)?.description;
switch (type) {
case ExpressionQueryType.sql:
return (
<Trans i18nKey="expressions.expression-query-editor.helper-text-sql">
Run MySQL-dialect SQL against the tables returned from your data sources. Data source queries (ie
&quot;A&quot;, &quot;B&quot;) are available as tables and referenced by query-name. Fields are available as
columns, as returned from the data source.
</Trans>
);
return {
helperText: (
<Trans i18nKey="expressions.expression-query-editor.helper-text-sql">
Run MySQL-dialect SQL against the tables returned from your data sources. Data source queries (ie
&quot;A&quot;, &quot;B&quot;) are available as tables and referenced by query-name. Fields are available as
columns, as returned from the data source.
</Trans>
),
featureState: FeatureState.preview,
};
default:
return description ?? '';
return {
helperText: description ?? '',
featureState: undefined,
};
}
};
@@ -148,7 +160,7 @@ export function ExpressionQueryEditor(props: ExpressionQueryEditorProps) {
}
};
const helperText = getExpressionHelpText(query.type);
const { helperText, featureState } = getExpressionTypeConfig(query.type);
return (
<div>
@@ -163,7 +175,10 @@ export function ExpressionQueryEditor(props: ExpressionQueryEditorProps) {
</Button>
</ExpressionTypeDropdown>
</InlineField>
{helperText && <IconButton className={styles.infoIcon} name="info-circle" tooltip={helperText} />}
<div className={styles.fieldContainer}>
{featureState && <FeatureBadge featureState={featureState} />}
{helperText && <IconButton name="info-circle" tooltip={helperText} />}
</div>
</div>
{renderExpressionType()}
</div>
@@ -176,7 +191,10 @@ const getStyles = (theme: GrafanaTheme2) => ({
alignItems: 'center',
gap: theme.spacing(1),
}),
infoIcon: css({
fieldContainer: css({
display: 'flex',
alignItems: 'center',
gap: theme.spacing(1),
marginBottom: theme.spacing(0.5), // Align with the select field
}),
});
@@ -37,7 +37,7 @@ const ExpressionMenuItem = memo<ExpressionMenuItemProps>(({ item, onSelect }) =>
<div className={styles.expressionTypeItemContent} data-testid={`expression-type-${value}`}>
<Icon className={styles.icon} name={EXPRESSION_ICON_MAP[value!]} aria-hidden="true" />
{label}
{value === ExpressionQueryType.sql && <FeatureBadge featureState={FeatureState.new} />}
{value === ExpressionQueryType.sql && <FeatureBadge featureState={FeatureState.preview} />}
</div>
<Tooltip placement="right" content={description!}>
<Icon className={styles.infoIcon} name="info-circle" />