QueryForm.tsx 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  1. import React from 'react';
  2. import { FormError } from 'components/common/Input/Input.styled';
  3. import { ErrorMessage } from '@hookform/error-message';
  4. import { useForm, Controller, useFieldArray } from 'react-hook-form';
  5. import { Button } from 'components/common/Button/Button';
  6. import IconButtonWrapper from 'components/common/Icons/IconButtonWrapper';
  7. import CloseIcon from 'components/common/Icons/CloseIcon';
  8. import { yupResolver } from '@hookform/resolvers/yup';
  9. import yup from 'lib/yupExtended';
  10. import * as S from './QueryForm.styled';
  11. export interface Props {
  12. fetching: boolean;
  13. hasResults: boolean;
  14. handleClearResults: () => void;
  15. handleSSECancel: () => void;
  16. submitHandler: (values: FormValues) => void;
  17. }
  18. export type StreamsPropertiesType = {
  19. key: string;
  20. value: string;
  21. };
  22. export type FormValues = {
  23. ksql: string;
  24. streamsProperties: StreamsPropertiesType[];
  25. };
  26. const streamsPropertiesSchema = yup.object().shape({
  27. key: yup.string().trim(),
  28. value: yup.string().trim(),
  29. });
  30. const validationSchema = yup.object({
  31. ksql: yup.string().trim().required(),
  32. streamsProperties: yup.array().of(streamsPropertiesSchema),
  33. });
  34. const QueryForm: React.FC<Props> = ({
  35. fetching,
  36. hasResults,
  37. handleClearResults,
  38. handleSSECancel,
  39. submitHandler,
  40. }) => {
  41. const {
  42. handleSubmit,
  43. setValue,
  44. control,
  45. formState: { errors },
  46. } = useForm<FormValues>({
  47. mode: 'onTouched',
  48. resolver: yupResolver(validationSchema),
  49. defaultValues: {
  50. ksql: '',
  51. streamsProperties: [{ key: '', value: '' }],
  52. },
  53. });
  54. const { fields, append, remove } = useFieldArray<
  55. FormValues,
  56. 'streamsProperties'
  57. >({
  58. control,
  59. name: 'streamsProperties',
  60. });
  61. return (
  62. <S.QueryWrapper>
  63. <form onSubmit={handleSubmit(submitHandler)}>
  64. <S.KSQLInputsWrapper>
  65. <S.Fieldset aria-labelledby="ksqlLabel">
  66. <S.KSQLInputHeader>
  67. <label id="ksqlLabel">KSQL</label>
  68. <Button
  69. onClick={() => setValue('ksql', '')}
  70. buttonType="primary"
  71. buttonSize="S"
  72. isInverted
  73. >
  74. Clear
  75. </Button>
  76. </S.KSQLInputHeader>
  77. <Controller
  78. control={control}
  79. name="ksql"
  80. render={({ field }) => (
  81. <S.SQLEditor
  82. {...field}
  83. commands={[
  84. {
  85. // commands is array of key bindings.
  86. // name for the key binding.
  87. name: 'commandName',
  88. // key combination used for the command.
  89. bindKey: { win: 'Ctrl-Enter', mac: 'Command-Enter' },
  90. // function to execute when keys are pressed.
  91. exec: () => {
  92. handleSubmit(submitHandler)();
  93. },
  94. },
  95. ]}
  96. readOnly={fetching}
  97. />
  98. )}
  99. />
  100. <FormError>
  101. <ErrorMessage errors={errors} name="ksql" />
  102. </FormError>
  103. </S.Fieldset>
  104. <S.StreamPropertiesContainer>
  105. Stream properties:
  106. {fields.map((item, index) => (
  107. <S.InputsContainer key={item.id}>
  108. <S.StreamPropertiesInputWrapper>
  109. <Controller
  110. control={control}
  111. name={`streamsProperties.${index}.key`}
  112. render={({ field }) => (
  113. <input
  114. {...field}
  115. placeholder="Key"
  116. aria-label="key"
  117. type="text"
  118. />
  119. )}
  120. />
  121. <FormError>
  122. <ErrorMessage
  123. errors={errors}
  124. name={`streamsProperties.${index}.key`}
  125. />
  126. </FormError>
  127. </S.StreamPropertiesInputWrapper>
  128. <S.StreamPropertiesInputWrapper>
  129. <Controller
  130. control={control}
  131. name={`streamsProperties.${index}.value`}
  132. render={({ field }) => (
  133. <input
  134. {...field}
  135. placeholder="Value"
  136. aria-label="value"
  137. type="text"
  138. />
  139. )}
  140. />
  141. <FormError>
  142. <ErrorMessage
  143. errors={errors}
  144. name={`streamsProperties.${index}.value`}
  145. />
  146. </FormError>
  147. </S.StreamPropertiesInputWrapper>
  148. <S.DeleteButtonWrapper onClick={() => remove(index)}>
  149. <IconButtonWrapper aria-label="deleteProperty">
  150. <CloseIcon aria-hidden />
  151. </IconButtonWrapper>
  152. </S.DeleteButtonWrapper>
  153. </S.InputsContainer>
  154. ))}
  155. <Button
  156. type="button"
  157. buttonSize="M"
  158. buttonType="secondary"
  159. onClick={() => append({ key: '', value: '' })}
  160. >
  161. <i className="fas fa-plus" />
  162. Add Stream Property
  163. </Button>
  164. </S.StreamPropertiesContainer>
  165. </S.KSQLInputsWrapper>
  166. <S.KSQLButtons>
  167. <Button
  168. buttonType="primary"
  169. buttonSize="M"
  170. type="submit"
  171. disabled={fetching}
  172. >
  173. Execute
  174. </Button>
  175. <Button
  176. buttonType="secondary"
  177. buttonSize="M"
  178. disabled={!fetching}
  179. onClick={handleSSECancel}
  180. >
  181. Stop query
  182. </Button>
  183. <Button
  184. buttonType="secondary"
  185. buttonSize="M"
  186. disabled={fetching || !hasResults}
  187. onClick={handleClearResults}
  188. >
  189. Clear results
  190. </Button>
  191. </S.KSQLButtons>
  192. </form>
  193. </S.QueryWrapper>
  194. );
  195. };
  196. export default QueryForm;