소스 검색

Refactor topic creation

Azat Belgibayev 3 년 전
부모
커밋
cdad47cc2c

+ 46 - 26
kafka-ui-react-app/src/components/Topics/New/New.tsx

@@ -1,40 +1,61 @@
 import React from 'react';
-import { ClusterName, TopicName, TopicFormDataRaw } from 'redux/interfaces';
+import {
+  ClusterName,
+  TopicName,
+  TopicFormDataRaw,
+  FailurePayload,
+} from 'redux/interfaces';
 import { useForm, FormProvider } from 'react-hook-form';
 import Breadcrumb from 'components/common/Breadcrumb/Breadcrumb';
-import { clusterTopicsPath } from 'lib/paths';
+import { clusterTopicPath, clusterTopicsPath } from 'lib/paths';
 import TopicForm from 'components/Topics/shared/Form/TopicForm';
+import {
+  formatTopicCreation,
+  topicsApiClient,
+  createTopicAction,
+} from 'redux/actions';
+import { useDispatch } from 'react-redux';
+import { getResponse } from 'lib/errorHandling';
+import { useHistory, useParams } from 'react-router';
 
-interface Props {
+interface RouterParams {
   clusterName: ClusterName;
-  isTopicCreated: boolean;
-  createTopic: (clusterName: ClusterName, form: TopicFormDataRaw) => void;
+}
+
+interface Props {
   redirectToTopicPath: (clusterName: ClusterName, topicName: TopicName) => void;
-  resetUploadedState: () => void;
 }
 
-const New: React.FC<Props> = ({
-  clusterName,
-  isTopicCreated,
-  createTopic,
-  redirectToTopicPath,
-}) => {
+const New: React.FC<Props> = () => {
   const methods = useForm<TopicFormDataRaw>();
-  const [isSubmitting, setIsSubmitting] = React.useState<boolean>(false);
+  const { clusterName } = useParams<RouterParams>();
+  const history = useHistory();
+  const dispatch = useDispatch();
 
-  React.useEffect(() => {
-    if (isSubmitting && isTopicCreated) {
-      const { name } = methods.getValues();
-      redirectToTopicPath(clusterName, name);
-    }
-  }, [isSubmitting, isTopicCreated, redirectToTopicPath, clusterName, methods]);
+  const redirectToTopicPath = React.useCallback(
+    (topicName) => {
+      history.push(clusterTopicPath(clusterName, topicName));
+    },
+    [clusterName]
+  );
 
   const onSubmit = async (data: TopicFormDataRaw) => {
-    // TODO: need to fix loader. After success loading the first time, we won't wait for creation any more, because state is
-    // loaded, and we will try to get entity immediately after pressing the button, and we will receive null
-    // going to object page on the second creation. Setting of isSubmitting after createTopic is a workaround, need to tweak loader logic
-    createTopic(clusterName, data);
-    setIsSubmitting(true); // Keep this action after createTopic to prevent redirect before create.
+    try {
+      await topicsApiClient.createTopic({
+        clusterName,
+        topicCreation: formatTopicCreation(data),
+      });
+
+      redirectToTopicPath(data.name);
+    } catch (error) {
+      const response = await getResponse(error);
+      const alert: FailurePayload = {
+        subject: ['schema', data.name].join('-'),
+        title: `Schema ${data.name}`,
+        response,
+      };
+      dispatch(createTopicAction.failure({ alert }));
+    }
   };
 
   return (
@@ -52,10 +73,9 @@ const New: React.FC<Props> = ({
       </div>
 
       <div className="box">
-        {/* eslint-disable react/jsx-props-no-spreading */}
         <FormProvider {...methods}>
           <TopicForm
-            isSubmitting={isSubmitting}
+            isSubmitting={methods.formState.isSubmitting}
             onSubmit={methods.handleSubmit(onSubmit)}
           />
         </FormProvider>

+ 0 - 48
kafka-ui-react-app/src/components/Topics/New/NewContainer.ts

@@ -1,48 +0,0 @@
-import { connect } from 'react-redux';
-import {
-  RootState,
-  ClusterName,
-  TopicName,
-  Action,
-  TopicFormDataRaw,
-} from 'redux/interfaces';
-import { withRouter, RouteComponentProps } from 'react-router-dom';
-import { createTopic, createTopicAction } from 'redux/actions';
-import { getTopicCreated } from 'redux/reducers/topics/selectors';
-import { clusterTopicPath } from 'lib/paths';
-import { ThunkDispatch } from 'redux-thunk';
-
-import New from './New';
-
-interface RouteProps {
-  clusterName: ClusterName;
-}
-
-type OwnProps = RouteComponentProps<RouteProps>;
-
-const mapStateToProps = (
-  state: RootState,
-  {
-    match: {
-      params: { clusterName },
-    },
-  }: OwnProps
-) => ({
-  clusterName,
-  isTopicCreated: getTopicCreated(state),
-});
-
-const mapDispatchToProps = (
-  dispatch: ThunkDispatch<RootState, undefined, Action>,
-  { history }: OwnProps
-) => ({
-  createTopic: (clusterName: ClusterName, form: TopicFormDataRaw) => {
-    dispatch(createTopic(clusterName, form));
-  },
-  redirectToTopicPath: (clusterName: ClusterName, topicName: TopicName) => {
-    history.push(clusterTopicPath(clusterName, topicName));
-  },
-  resetUploadedState: () => dispatch(createTopicAction.failure({})),
-});
-
-export default withRouter(connect(mapStateToProps, mapDispatchToProps)(New));

+ 2 - 6
kafka-ui-react-app/src/components/Topics/Topics.tsx

@@ -8,7 +8,7 @@ import {
 
 import ListContainer from './List/ListContainer';
 import TopicContainer from './Topic/TopicContainer';
-import NewContainer from './New/NewContainer';
+import New from './New/New';
 
 const Topics: React.FC = () => (
   <Switch>
@@ -17,11 +17,7 @@ const Topics: React.FC = () => (
       path={clusterTopicsPath(':clusterName')}
       component={ListContainer}
     />
-    <Route
-      exact
-      path={clusterTopicNewPath(':clusterName')}
-      component={NewContainer}
-    />
+    <Route exact path={clusterTopicNewPath(':clusterName')} component={New} />
     <Route
       path={clusterTopicPath(':clusterName', ':topicName')}
       component={TopicContainer}

+ 1 - 1
kafka-ui-react-app/src/redux/actions/thunks/topics.ts

@@ -161,7 +161,7 @@ const topicReducer = (
   };
 };
 
-const formatTopicCreation = (form: TopicFormDataRaw): TopicCreation => {
+export const formatTopicCreation = (form: TopicFormDataRaw): TopicCreation => {
   const {
     name,
     partitions,

+ 1 - 1
kafka-ui-react-app/src/redux/reducers/topics/selectors.ts

@@ -156,7 +156,7 @@ export const getTopicsOrderBy = createSelector(
 
 export const getIsTopicInternal = createSelector(
   getTopicByName,
-  ({ internal }) => !!internal
+  (topic) => !!topic?.internal
 );
 
 export const getTopicConsumerGroups = createSelector(