useFields.ts 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475
  1. import { lastValueFrom } from 'rxjs';
  2. import { MetricFindValue, SelectableValue } from '@grafana/data';
  3. import {
  4. BucketAggregationType,
  5. isBucketAggregationType,
  6. } from '../components/QueryEditor/BucketAggregationsEditor/aggregations';
  7. import { useDatasource, useRange } from '../components/QueryEditor/ElasticsearchQueryContext';
  8. import {
  9. isMetricAggregationType,
  10. MetricAggregationType,
  11. } from '../components/QueryEditor/MetricAggregationsEditor/aggregations';
  12. type AggregationType = BucketAggregationType | MetricAggregationType;
  13. const getFilter = (type: AggregationType) => {
  14. if (isMetricAggregationType(type)) {
  15. switch (type) {
  16. case 'cardinality':
  17. return [];
  18. case 'top_metrics':
  19. // top_metrics was introduced in 7.7 where `metrics` only supported number:
  20. // https://www.elastic.co/guide/en/elasticsearch/reference/7.7/search-aggregations-metrics-top-metrics.html#_metrics
  21. // TODO: starting from 7.11 it supports ips and keywords as well:
  22. // https://www.elastic.co/guide/en/elasticsearch/reference/7.11/search-aggregations-metrics-top-metrics.html#_metrics
  23. return ['number'];
  24. default:
  25. return ['number'];
  26. }
  27. }
  28. if (isBucketAggregationType(type)) {
  29. switch (type) {
  30. case 'date_histogram':
  31. return ['date'];
  32. case 'geohash_grid':
  33. return ['geo_point'];
  34. case 'histogram':
  35. return ['number'];
  36. default:
  37. return [];
  38. }
  39. }
  40. return [];
  41. };
  42. const toSelectableValue = ({ text }: MetricFindValue): SelectableValue<string> => ({
  43. label: text,
  44. value: text,
  45. });
  46. /**
  47. * Returns a function to query the configured datasource for autocomplete values for the specified aggregation type or data types.
  48. * Each aggregation can be run on different types, for example avg only operates on numeric fields, geohash_grid only on geo_point fields.
  49. * If an aggregation type is provided, the promise will resolve with all fields suitable to be used as a field for the given aggregation.
  50. * If an array of types is providem the promise will resolve with all the fields matching the provided types.
  51. * @param aggregationType the type of aggregation to get fields for
  52. */
  53. export const useFields = (type: AggregationType | string[]) => {
  54. const datasource = useDatasource();
  55. const range = useRange();
  56. const filter = Array.isArray(type) ? type : getFilter(type);
  57. let rawFields: MetricFindValue[];
  58. return async (q?: string) => {
  59. // _mapping doesn't support filtering, we avoid sending a request everytime q changes
  60. if (!rawFields) {
  61. rawFields = await lastValueFrom(datasource.getFields(filter, range));
  62. }
  63. return rawFields.filter(({ text }) => q === undefined || text.includes(q)).map(toSelectableValue);
  64. };
  65. };