AddGraphiteFunction.tsx 1.8 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253
  1. import { css, cx } from '@emotion/css';
  2. import React, { useEffect, useMemo, useState } from 'react';
  3. import { GrafanaTheme2, SelectableValue } from '@grafana/data';
  4. import { Button, Segment, useStyles2 } from '@grafana/ui';
  5. import { FuncDefs } from '../gfunc';
  6. import { actions } from '../state/actions';
  7. import { useDispatch } from '../state/context';
  8. import { mapFuncDefsToSelectables } from './helpers';
  9. type Props = {
  10. funcDefs: FuncDefs;
  11. };
  12. export function AddGraphiteFunction({ funcDefs }: Props) {
  13. const dispatch = useDispatch();
  14. const [value, setValue] = useState<SelectableValue<string> | undefined>(undefined);
  15. const styles = useStyles2(getStyles);
  16. const options = useMemo(() => mapFuncDefsToSelectables(funcDefs), [funcDefs]);
  17. // Note: actions.addFunction will add a component that will have a dropdown or input in auto-focus
  18. // (the first param of the function). This auto-focus will cause onBlur() on AddGraphiteFunction's
  19. // Segment component and trigger onChange once again. (why? we call onChange if the user dismissed
  20. // the dropdown, see: SegmentSelect.onCloseMenu for more details). To avoid it we need to wait for
  21. // the Segment to disappear first (hence useEffect) and then dispatch the action that will add new
  22. // components.
  23. useEffect(() => {
  24. if (value?.value !== undefined) {
  25. dispatch(actions.addFunction({ name: value.value }));
  26. setValue(undefined);
  27. }
  28. }, [value, dispatch]);
  29. return (
  30. <Segment
  31. Component={<Button icon="plus" variant="secondary" className={cx(styles.button)} aria-label="Add new function" />}
  32. options={options}
  33. onChange={setValue}
  34. inputMinWidth={150}
  35. />
  36. );
  37. }
  38. function getStyles(theme: GrafanaTheme2) {
  39. return {
  40. button: css`
  41. margin-right: ${theme.spacing(0.5)};
  42. `,
  43. };
  44. }