New.tsx 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234
  1. import React from 'react';
  2. import {
  3. ClusterName,
  4. CleanupPolicy,
  5. TopicFormData,
  6. TopicName,
  7. } from 'redux/interfaces';
  8. import { useForm, FormContext, ErrorMessage } from 'react-hook-form';
  9. import Breadcrumb from 'components/common/Breadcrumb/Breadcrumb';
  10. import { clusterTopicsPath } from 'lib/paths';
  11. import { TOPIC_NAME_VALIDATION_PATTERN, BYTES_IN_GB } from 'lib/constants';
  12. import CustomParamsContainer from './CustomParams/CustomParamsContainer';
  13. import TimeToRetain from './TimeToRetain';
  14. interface Props {
  15. clusterName: ClusterName;
  16. isTopicCreated: boolean;
  17. createTopic: (clusterName: ClusterName, form: TopicFormData) => void;
  18. redirectToTopicPath: (clusterName: ClusterName, topicName: TopicName) => void;
  19. resetUploadedState: () => void;
  20. }
  21. const New: React.FC<Props> = ({
  22. clusterName,
  23. isTopicCreated,
  24. createTopic,
  25. redirectToTopicPath,
  26. resetUploadedState,
  27. }) => {
  28. const methods = useForm<TopicFormData>();
  29. const [isSubmitting, setIsSubmitting] = React.useState<boolean>(false);
  30. React.useEffect(() => {
  31. if (isSubmitting && isTopicCreated) {
  32. const { name } = methods.getValues();
  33. redirectToTopicPath(clusterName, name);
  34. }
  35. }, [
  36. isSubmitting,
  37. isTopicCreated,
  38. redirectToTopicPath,
  39. clusterName,
  40. methods.getValues,
  41. ]);
  42. const onSubmit = async (data: TopicFormData) => {
  43. // TODO: need to fix loader. After success loading the first time, we won't wait for creation any more, because state is
  44. // loaded, and we will try to get entity immediately after pressing the button, and we will receive null
  45. // going to object page on the second creation. Resetting loaded state is workaround, need to tweak loader logic
  46. resetUploadedState();
  47. setIsSubmitting(true);
  48. createTopic(clusterName, data);
  49. };
  50. return (
  51. <div className="section">
  52. <div className="level">
  53. <div className="level-item level-left">
  54. <Breadcrumb
  55. links={[
  56. { href: clusterTopicsPath(clusterName), label: 'All Topics' },
  57. ]}
  58. >
  59. New Topic
  60. </Breadcrumb>
  61. </div>
  62. </div>
  63. <div className="box">
  64. {/* eslint-disable react/jsx-props-no-spreading */}
  65. <FormContext {...methods}>
  66. <form onSubmit={methods.handleSubmit(onSubmit)}>
  67. <div className="columns">
  68. <div className="column is-three-quarters">
  69. <label className="label">Topic Name *</label>
  70. <input
  71. className="input"
  72. placeholder="Topic Name"
  73. ref={methods.register({
  74. required: 'Topic Name is required.',
  75. pattern: {
  76. value: TOPIC_NAME_VALIDATION_PATTERN,
  77. message: 'Only alphanumeric, _, -, and . allowed',
  78. },
  79. })}
  80. name="name"
  81. autoComplete="off"
  82. disabled={isSubmitting}
  83. />
  84. <p className="help is-danger">
  85. <ErrorMessage errors={methods.errors} name="name" />
  86. </p>
  87. </div>
  88. <div className="column">
  89. <label className="label">Number of partitions *</label>
  90. <input
  91. className="input"
  92. type="number"
  93. placeholder="Number of partitions"
  94. defaultValue="1"
  95. ref={methods.register({
  96. required: 'Number of partitions is required.',
  97. })}
  98. name="partitions"
  99. disabled={isSubmitting}
  100. />
  101. <p className="help is-danger">
  102. <ErrorMessage errors={methods.errors} name="partitions" />
  103. </p>
  104. </div>
  105. </div>
  106. <div className="columns">
  107. <div className="column">
  108. <label className="label">Replication Factor *</label>
  109. <input
  110. className="input"
  111. type="number"
  112. placeholder="Replication Factor"
  113. defaultValue="1"
  114. ref={methods.register({
  115. required: 'Replication Factor is required.',
  116. })}
  117. name="replicationFactor"
  118. disabled={isSubmitting}
  119. />
  120. <p className="help is-danger">
  121. <ErrorMessage
  122. errors={methods.errors}
  123. name="replicationFactor"
  124. />
  125. </p>
  126. </div>
  127. <div className="column">
  128. <label className="label">Min In Sync Replicas *</label>
  129. <input
  130. className="input"
  131. type="number"
  132. placeholder="Replication Factor"
  133. defaultValue="1"
  134. ref={methods.register({
  135. required: 'Min In Sync Replicas is required.',
  136. })}
  137. name="minInSyncReplicas"
  138. disabled={isSubmitting}
  139. />
  140. <p className="help is-danger">
  141. <ErrorMessage
  142. errors={methods.errors}
  143. name="minInSyncReplicas"
  144. />
  145. </p>
  146. </div>
  147. </div>
  148. <div className="columns">
  149. <div className="column is-one-third">
  150. <label className="label">Cleanup policy</label>
  151. <div className="select is-block">
  152. <select
  153. defaultValue={CleanupPolicy.Delete}
  154. name="cleanupPolicy"
  155. ref={methods.register}
  156. disabled={isSubmitting}
  157. >
  158. <option value={CleanupPolicy.Delete}>Delete</option>
  159. <option value={CleanupPolicy.Compact}>Compact</option>
  160. </select>
  161. </div>
  162. </div>
  163. <div className="column is-one-third">
  164. <TimeToRetain isSubmitting={isSubmitting} />
  165. </div>
  166. <div className="column is-one-third">
  167. <label className="label">Max size on disk in GB</label>
  168. <div className="select is-block">
  169. <select
  170. defaultValue={-1}
  171. name="retentionBytes"
  172. ref={methods.register}
  173. disabled={isSubmitting}
  174. >
  175. <option value={-1}>Not Set</option>
  176. <option value={BYTES_IN_GB}>1 GB</option>
  177. <option value={BYTES_IN_GB * 10}>10 GB</option>
  178. <option value={BYTES_IN_GB * 20}>20 GB</option>
  179. <option value={BYTES_IN_GB * 50}>50 GB</option>
  180. </select>
  181. </div>
  182. </div>
  183. </div>
  184. <div className="columns">
  185. <div className="column">
  186. <label className="label">Maximum message size in bytes *</label>
  187. <input
  188. className="input"
  189. type="number"
  190. defaultValue="1000012"
  191. ref={methods.register({
  192. required: 'Maximum message size in bytes is required',
  193. })}
  194. name="maxMessageBytes"
  195. disabled={isSubmitting}
  196. />
  197. <p className="help is-danger">
  198. <ErrorMessage
  199. errors={methods.errors}
  200. name="maxMessageBytes"
  201. />
  202. </p>
  203. </div>
  204. </div>
  205. <CustomParamsContainer isSubmitting={isSubmitting} />
  206. <input
  207. type="submit"
  208. className="button is-primary"
  209. disabled={isSubmitting}
  210. />
  211. </form>
  212. </FormContext>
  213. </div>
  214. </div>
  215. );
  216. };
  217. export default New;