MetricSegment.tsx 2.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061
  1. import { debounce } from 'lodash';
  2. import React, { useCallback, useMemo } from 'react';
  3. import { SelectableValue } from '@grafana/data';
  4. import { SegmentAsync } from '@grafana/ui';
  5. import { actions } from '../state/actions';
  6. import { useDispatch } from '../state/context';
  7. import { getAltSegmentsSelectables } from '../state/providers';
  8. import { GraphiteQueryEditorState } from '../state/store';
  9. import { GraphiteSegment } from '../types';
  10. type Props = {
  11. segment: GraphiteSegment;
  12. metricIndex: number;
  13. state: GraphiteQueryEditorState;
  14. };
  15. /**
  16. * Represents a single metric node in the metric path at the given index. Allows to change the metric name to one of the
  17. * provided options or a custom value.
  18. *
  19. * Options for tag names and metric names are reloaded while user is typing with backend taking care of auto-complete
  20. * (auto-complete cannot be implemented in front-end because backend returns only limited number of entries)
  21. *
  22. * getAltSegmentsSelectables() also returns list of tags for segment with index=0. Once a tag is selected the editor
  23. * enters tag-adding mode (see SeriesSection and GraphiteQueryModel.seriesByTagUsed).
  24. */
  25. export function MetricSegment({ metricIndex, segment, state }: Props) {
  26. const dispatch = useDispatch();
  27. const loadOptions = useCallback(
  28. (value: string | undefined) => {
  29. return getAltSegmentsSelectables(state, metricIndex, value || '');
  30. },
  31. [state, metricIndex]
  32. );
  33. const debouncedLoadOptions = useMemo(() => debounce(loadOptions, 200, { leading: true }), [loadOptions]);
  34. const onSegmentChanged = useCallback(
  35. (selectableValue: SelectableValue<GraphiteSegment | string>) => {
  36. // selectableValue.value is always defined because emptyValues are not allowed in SegmentAsync by default
  37. dispatch(actions.segmentValueChanged({ segment: selectableValue.value!, index: metricIndex }));
  38. },
  39. [dispatch, metricIndex]
  40. );
  41. // segmentValueChanged action will destroy SegmentAsync immediately if a tag is selected. To give time
  42. // for the clean up the action is debounced.
  43. const onSegmentChangedDebounced = useMemo(() => debounce(onSegmentChanged, 100), [onSegmentChanged]);
  44. return (
  45. <SegmentAsync<GraphiteSegment | string>
  46. value={segment.value}
  47. inputMinWidth={150}
  48. allowCustomValue={true}
  49. loadOptions={debouncedLoadOptions}
  50. reloadOptionsOnChange={true}
  51. onChange={onSegmentChangedDebounced}
  52. />
  53. );
  54. }