CSVWaveEditor.tsx 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  1. import React, { PureComponent, useState } from 'react';
  2. import { Button, InlineField, InlineFieldRow, Input } from '@grafana/ui';
  3. import { defaultCSVWaveQuery } from '../constants';
  4. import type { CSVWave } from '../types';
  5. interface WavesProps {
  6. waves?: CSVWave[];
  7. onChange: (waves: CSVWave[]) => void;
  8. }
  9. interface WaveProps {
  10. wave: CSVWave;
  11. index: number;
  12. last: boolean;
  13. onChange: (index: number, wave?: CSVWave) => void;
  14. onAdd: () => void;
  15. }
  16. const CSVWaveEditor = (props: WaveProps) => {
  17. const { wave, last, index, onAdd, onChange } = props;
  18. const [valuesCSV, setValuesCSV] = useState(wave.valuesCSV || '');
  19. const [labels, setLabels] = useState(wave.labels || '');
  20. const [name, setName] = useState(wave.name || '');
  21. const onAction = () => {
  22. if (last) {
  23. onAdd();
  24. } else {
  25. onChange(index, undefined);
  26. }
  27. };
  28. const onValueChange = <K extends keyof CSVWave, V extends CSVWave[K]>(key: K, value: V) => {
  29. onChange(index, { ...wave, [key]: value });
  30. };
  31. const onKeyDown = (evt: React.KeyboardEvent<HTMLInputElement>) => {
  32. if (evt.key === 'Enter') {
  33. onValueChange('valuesCSV', valuesCSV);
  34. }
  35. };
  36. return (
  37. <InlineFieldRow>
  38. <InlineField
  39. label={'Values'}
  40. grow
  41. tooltip="Comma separated values. Each value may be an int, float, or null and must not be empty. Whitespace and trailing commas are removed"
  42. >
  43. <Input
  44. value={valuesCSV}
  45. placeholder={'CSV values'}
  46. onChange={(e) => setValuesCSV(e.currentTarget.value)}
  47. autoFocus={true}
  48. onBlur={() => onValueChange('valuesCSV', valuesCSV)}
  49. onKeyDown={onKeyDown}
  50. />
  51. </InlineField>
  52. <InlineField label={'Step'} tooltip="The number of seconds between datapoints.">
  53. <Input
  54. value={wave.timeStep}
  55. type="number"
  56. placeholder={'60'}
  57. width={10}
  58. onChange={(e) => onValueChange('timeStep', e.currentTarget.valueAsNumber)}
  59. />
  60. </InlineField>
  61. <InlineField label={'Name'}>
  62. <Input
  63. value={name}
  64. placeholder={'name'}
  65. width={10}
  66. onChange={(e) => setName(e.currentTarget.value)}
  67. onBlur={() => onValueChange('name', name)}
  68. />
  69. </InlineField>
  70. <InlineField label={'Labels'}>
  71. <Input
  72. value={labels}
  73. placeholder={'labels'}
  74. width={12}
  75. onChange={(e) => setLabels(e.currentTarget.value)}
  76. onBlur={() => onValueChange('labels', labels)}
  77. />
  78. </InlineField>
  79. <Button icon={last ? 'plus' : 'minus'} variant="secondary" onClick={onAction} />
  80. </InlineFieldRow>
  81. );
  82. };
  83. export class CSVWavesEditor extends PureComponent<WavesProps> {
  84. onChange = (index: number, wave?: CSVWave) => {
  85. let waves = [...(this.props.waves ?? defaultCSVWaveQuery)];
  86. if (wave) {
  87. waves[index] = { ...wave };
  88. } else {
  89. // remove the element
  90. waves.splice(index, 1);
  91. }
  92. this.props.onChange(waves);
  93. };
  94. onAdd = () => {
  95. const waves = [...(this.props.waves ?? defaultCSVWaveQuery)];
  96. waves.push({ ...defaultCSVWaveQuery[0] });
  97. this.props.onChange(waves);
  98. };
  99. render() {
  100. let waves = this.props.waves ?? defaultCSVWaveQuery;
  101. if (!waves.length) {
  102. waves = defaultCSVWaveQuery;
  103. }
  104. return (
  105. <>
  106. {waves.map((wave, index) => (
  107. <CSVWaveEditor
  108. key={`${index}/${wave.valuesCSV}`}
  109. wave={wave}
  110. index={index}
  111. onAdd={this.onAdd}
  112. onChange={this.onChange}
  113. last={index === waves.length - 1}
  114. />
  115. ))}
  116. </>
  117. );
  118. }
  119. }