Files
grafana/public/app/plugins/datasource/cloudwatch/components/SQLBuilderEditor/SQLGroupBy.tsx
Erik Sundell bab78a9e64 CloudWatch: Add support for AWS Metric Insights (#42487)
* add support for code editor and builder

* refactor cloudwatch migration

* Add tooltip to editor field (#56)

* add tooltip

* add old tooltips

* Bug bash feedback fixes (#58)

* make ASC the default option

* update sql preview whenever sql changes

* don't allow queries without aggregation

* set default value for aggregation

* use new input field

* cleanup

* pr feedback

* prevent unnecessary rerenders

* use frame error instead of main error

* remove not used snapshot

* Use dimension filter in schema picker  (#63)

* use dimension key filter in group by and schema labels

* add dimension filter also to code editor

* add tests

* fix build error

* fix strict error

* remove debug code

* fix annotation editor (#64)

* fix annotation editor

* fix broken test

* revert annotation backend change

* PR feedback (#67)

* pr feedback

* removed dimension filter from group by

* add spacing between common fields and rest

* do not generate deep link for metric queries (#70)

* update docs (#69)

Co-authored-by: Erik Sundell <erik.sundell87@gmail.com>

* fix lint problem caused by merge conflict

Co-authored-by: achatterjee-grafana <70489351+achatterjee-grafana@users.noreply.github.com>
2021-11-30 10:53:31 +01:00

110 lines
3.6 KiB
TypeScript

import { SelectableValue, toOption } from '@grafana/data';
import { Select } from '@grafana/ui';
import React, { useMemo, useState } from 'react';
import { CloudWatchDatasource } from '../../datasource';
import { QueryEditorExpressionType, QueryEditorGroupByExpression, QueryEditorPropertyType } from '../../expressions';
import { useDimensionKeys } from '../../hooks';
import { CloudWatchMetricsQuery } from '../../types';
import AccessoryButton from '../ui/AccessoryButton';
import EditorList from '../ui/EditorList';
import InputGroup from '../ui/InputGroup';
import {
getFlattenedGroupBys,
getMetricNameFromExpression,
getNamespaceFromExpression,
setGroupByField,
setSql,
} from './utils';
interface SQLGroupByProps {
query: CloudWatchMetricsQuery;
datasource: CloudWatchDatasource;
onQueryChange: (query: CloudWatchMetricsQuery) => void;
}
const SQLGroupBy: React.FC<SQLGroupByProps> = ({ query, datasource, onQueryChange }) => {
const sql = query.sql ?? {};
const groupBysFromQuery = useMemo(() => getFlattenedGroupBys(query.sql ?? {}), [query.sql]);
const [items, setItems] = useState<QueryEditorGroupByExpression[]>(groupBysFromQuery);
const namespace = getNamespaceFromExpression(sql.from);
const metricName = getMetricNameFromExpression(sql.select);
const baseOptions = useDimensionKeys(datasource, query.region, namespace, metricName);
const options = useMemo(
// Exclude options we've already selected
() => baseOptions.filter((option) => !groupBysFromQuery.some((v) => v.property.name === option.value)),
[baseOptions, groupBysFromQuery]
);
const onChange = (newItems: Array<Partial<QueryEditorGroupByExpression>>) => {
// As new (empty object) items come in, with need to make sure they have the correct type
const cleaned = newItems.map(
(v): QueryEditorGroupByExpression => ({
type: QueryEditorExpressionType.GroupBy,
property: {
type: QueryEditorPropertyType.String,
name: v.property?.name,
},
})
);
setItems(cleaned);
// Only save complete expressions into the query state;
const completeExpressions = cleaned.filter((v) => v.property?.name);
const groupBy = completeExpressions.length
? {
type: QueryEditorExpressionType.And as const,
expressions: completeExpressions,
}
: undefined;
onQueryChange(setSql(query, { groupBy }));
};
return <EditorList items={items} onChange={onChange} renderItem={makeRenderItem(options)} />;
};
function makeRenderItem(options: Array<SelectableValue<string>>) {
function renderItem(
item: Partial<QueryEditorGroupByExpression>,
onChange: (item: QueryEditorGroupByExpression) => void,
onDelete: () => void
) {
return <GroupByItem options={options} item={item} onChange={onChange} onDelete={onDelete} />;
}
return renderItem;
}
interface GroupByItemProps {
options: Array<SelectableValue<string>>;
item: Partial<QueryEditorGroupByExpression>;
onChange: (item: QueryEditorGroupByExpression) => void;
onDelete: () => void;
}
const GroupByItem: React.FC<GroupByItemProps> = (props) => {
const { options, item, onChange, onDelete } = props;
const fieldName = item.property?.name;
return (
<InputGroup>
<Select
width="auto"
value={fieldName ? toOption(fieldName) : null}
options={options}
allowCustomValue
onChange={({ value }) => value && onChange(setGroupByField(value))}
menuShouldPortal
/>
<AccessoryButton aria-label="remove" icon="times" variant="secondary" onClick={onDelete} />
</InputGroup>
);
};
export default SQLGroupBy;