Files
grafana/packages/grafana-sql/src/components/visual-query-builder/SelectCustomFunctionParameters.tsx
Zoltán Bedi 85c696c4ad SQL: Add macro support in select case (#88514)
* Feat: timeGroup macro handling in VQB

* Add tests

* Add functions to SQL ds

* Fix lint errors

* Add feature toggle

* Add rendering based on object

* Fix lint

* Fix CI failures

* Fix tests

* Address review comments

* Add docs

* Fix JSX runtime warnings

* Remove docs part that mentions suggest more macros

* Update docs/sources/shared/datasources/sql-query-builder-macros.md

Co-authored-by: Jack Baldry <jack.baldry@grafana.com>

* Add smoke test for this feature

* lint

* Add supported macros to influx

* Add setupTests.ts to include in tsconfig.json

* Import jest-dom instead of setupTests.ts

---------

Co-authored-by: Jack Baldry <jack.baldry@grafana.com>
2024-11-04 17:13:35 +01:00

138 lines
3.7 KiB
TypeScript

import { css } from '@emotion/css';
import { useCallback } from 'react';
import { SelectableValue } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
import { Button, InlineLabel, Input, Stack, useStyles2 } from '@grafana/ui';
import { QueryEditorExpressionType } from '../../expressions';
import { SQLExpression, SQLQuery } from '../../types';
import { getColumnValue } from '../../utils/sql.utils';
import { SelectColumn } from './SelectColumn';
interface Props {
columns: Array<SelectableValue<string>>;
query: SQLQuery;
onSqlChange: (sql: SQLExpression) => void;
onParameterChange: (index: number) => (value?: string) => void;
currentColumnIndex: number;
}
export function SelectCustomFunctionParameters({
columns,
query,
onSqlChange,
onParameterChange,
currentColumnIndex,
}: Props) {
const styles = useStyles2(getStyles);
const macroOrFunction = query.sql?.columns?.[currentColumnIndex];
const addParameter = useCallback(
(index: number) => {
const item = query.sql?.columns?.[index];
if (!item) {
return;
}
item.parameters = item.parameters
? [...item.parameters, { type: QueryEditorExpressionType.FunctionParameter, name: '' }]
: [];
const newSql: SQLExpression = {
...query.sql,
columns: query.sql?.columns?.map((c, i) => (i === index ? item : c)),
};
onSqlChange(newSql);
},
[onSqlChange, query.sql]
);
const removeParameter = useCallback(
(columnIndex: number, index: number) => {
const item = query.sql?.columns?.[columnIndex];
if (!item?.parameters) {
return;
}
item.parameters = item.parameters?.filter((_, i) => i !== index);
const newSql: SQLExpression = {
...query.sql,
columns: query.sql?.columns?.map((c, i) => (i === columnIndex ? item : c)),
};
onSqlChange(newSql);
},
[onSqlChange, query.sql]
);
function renderParameters(columnIndex: number) {
if (!macroOrFunction?.parameters || macroOrFunction.parameters.length <= 1) {
return null;
}
const paramComponents = macroOrFunction.parameters.map((param, index) => {
// Skip the first parameter as it is the column name
if (index === 0) {
return null;
}
return (
<Stack key={index} gap={2}>
<InlineLabel className={styles.label}>,</InlineLabel>
<Input
onChange={(e) => onParameterChange(index)(e.currentTarget.value)}
value={param.name}
aria-label={`Parameter ${index} for column ${columnIndex}`}
data-testid={selectors.components.SQLQueryEditor.selectInputParameter}
addonAfter={
<Button
title="Remove parameter"
type="button"
icon="times"
variant="secondary"
size="md"
onClick={() => removeParameter(columnIndex, index)}
/>
}
/>
</Stack>
);
});
return paramComponents;
}
return (
<>
<InlineLabel className={styles.label}>(</InlineLabel>
<SelectColumn
columns={columns}
onParameterChange={(s) => onParameterChange(0)(s)}
value={getColumnValue(macroOrFunction?.parameters?.[0])}
/>
{renderParameters(currentColumnIndex)}
<Button
type="button"
onClick={() => addParameter(currentColumnIndex)}
variant="secondary"
size="md"
icon="plus"
title="Add parameter"
/>
<InlineLabel className={styles.label}>)</InlineLabel>
</>
);
}
const getStyles = () => {
return {
label: css({
padding: 0,
margin: 0,
width: 'unset',
}),
};
};