ScaleDimensionEditor.tsx 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. import { css } from '@emotion/css';
  2. import React, { FC, useCallback, useMemo } from 'react';
  3. import { GrafanaTheme2, SelectableValue, StandardEditorProps } from '@grafana/data';
  4. import { InlineField, InlineFieldRow, Select, useStyles2 } from '@grafana/ui';
  5. import {
  6. useFieldDisplayNames,
  7. useSelectOptions,
  8. } from '../../../../../packages/grafana-ui/src/components/MatchersUI/utils';
  9. import { validateScaleOptions, validateScaleConfig } from '../scale';
  10. import { ScaleDimensionConfig, ScaleDimensionOptions } from '../types';
  11. import { NumberInput } from './NumberInput';
  12. const fixedValueOption: SelectableValue<string> = {
  13. label: 'Fixed value',
  14. value: '_____fixed_____',
  15. };
  16. export const ScaleDimensionEditor: FC<StandardEditorProps<ScaleDimensionConfig, ScaleDimensionOptions, any>> = (
  17. props
  18. ) => {
  19. const { value, context, onChange, item } = props;
  20. const { settings } = item;
  21. const styles = useStyles2(getStyles);
  22. const fieldName = value?.field;
  23. const isFixed = Boolean(!fieldName);
  24. const names = useFieldDisplayNames(context.data);
  25. const selectOptions = useSelectOptions(names, fieldName, fixedValueOption);
  26. const minMaxStep = useMemo(() => {
  27. return validateScaleOptions(settings);
  28. }, [settings]);
  29. // Validate and update
  30. const validateAndDoChange = useCallback(
  31. (v: ScaleDimensionConfig) => {
  32. // always called with a copy so no need to spread
  33. onChange(validateScaleConfig(v, minMaxStep));
  34. },
  35. [onChange, minMaxStep]
  36. );
  37. const onSelectChange = useCallback(
  38. (selection: SelectableValue<string>) => {
  39. const field = selection.value;
  40. if (field && field !== fixedValueOption.value) {
  41. validateAndDoChange({
  42. ...value,
  43. field,
  44. });
  45. } else {
  46. validateAndDoChange({
  47. ...value,
  48. field: undefined,
  49. });
  50. }
  51. },
  52. [validateAndDoChange, value]
  53. );
  54. const onMinChange = useCallback(
  55. (min?: number) => {
  56. if (min !== undefined) {
  57. validateAndDoChange({
  58. ...value,
  59. min,
  60. });
  61. }
  62. },
  63. [validateAndDoChange, value]
  64. );
  65. const onMaxChange = useCallback(
  66. (max?: number) => {
  67. if (max !== undefined) {
  68. validateAndDoChange({
  69. ...value,
  70. max,
  71. });
  72. }
  73. },
  74. [validateAndDoChange, value]
  75. );
  76. const onValueChange = useCallback(
  77. (fixed?: number) => {
  78. if (fixed !== undefined) {
  79. validateAndDoChange({
  80. ...value,
  81. fixed,
  82. });
  83. }
  84. },
  85. [validateAndDoChange, value]
  86. );
  87. const val = value ?? {};
  88. const selectedOption = isFixed ? fixedValueOption : selectOptions.find((v) => v.value === fieldName);
  89. return (
  90. <>
  91. <div>
  92. <Select
  93. value={selectedOption}
  94. options={selectOptions}
  95. onChange={onSelectChange}
  96. noOptionsMessage="No fields found"
  97. />
  98. </div>
  99. <div className={styles.range}>
  100. {isFixed && (
  101. <InlineFieldRow>
  102. <InlineField label="Value" labelWidth={8} grow={true}>
  103. <NumberInput value={val.fixed} {...minMaxStep} onChange={onValueChange} />
  104. </InlineField>
  105. </InlineFieldRow>
  106. )}
  107. {!isFixed && !minMaxStep.hideRange && (
  108. <>
  109. <InlineFieldRow>
  110. <InlineField label="Min" labelWidth={8} grow={true}>
  111. <NumberInput value={val.min} {...minMaxStep} onChange={onMinChange} />
  112. </InlineField>
  113. </InlineFieldRow>
  114. <InlineFieldRow>
  115. <InlineField label="Max" labelWidth={8} grow={true}>
  116. <NumberInput value={val.max} {...minMaxStep} onChange={onMaxChange} />
  117. </InlineField>
  118. </InlineFieldRow>
  119. </>
  120. )}
  121. </div>
  122. </>
  123. );
  124. };
  125. const getStyles = (theme: GrafanaTheme2) => ({
  126. range: css`
  127. padding-top: 8px;
  128. `,
  129. });