Browse Source

Implement topic deletion

GneyHabub 4 năm trước cách đây
mục cha
commit
3fee2214a0

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

@@ -4,7 +4,7 @@ import Breadcrumb from 'components/common/Breadcrumb/Breadcrumb';
 import { NavLink } from 'react-router-dom';
 import { clusterTopicNewPath } from 'lib/paths';
 import ClusterContext from 'components/contexts/ClusterContext';
-import ListItem from './ListItem';
+import ListItemContainer from './ListItemContainer';
 
 interface Props {
   clusterName: ClusterName;
@@ -58,11 +58,12 @@ const List: React.FC<Props> = ({ clusterName, topics, externalTopics }) => {
               <th>Total Partitions</th>
               <th>Out of sync replicas</th>
               <th>Type</th>
+              <th> </th>
             </tr>
           </thead>
           <tbody>
             {items.map((topic) => (
-              <ListItem key={topic.id} topic={topic} />
+              <ListItemContainer key={topic.id} topic={topic} />
             ))}
           </tbody>
         </table>

+ 24 - 1
kafka-ui-react-app/src/components/Topics/List/ListItem.tsx

@@ -1,14 +1,22 @@
 import React from 'react';
 import cx from 'classnames';
 import { NavLink } from 'react-router-dom';
-import { TopicWithDetailedInfo } from 'redux/interfaces';
+import {
+  ClusterName,
+  TopicName,
+  TopicWithDetailedInfo,
+} from 'redux/interfaces';
 
 interface ListItemProps {
   topic: TopicWithDetailedInfo;
+  deleteTopic: (clusterName: ClusterName, topicName: TopicName) => void;
+  clusterName: ClusterName;
 }
 
 const ListItem: React.FC<ListItemProps> = ({
   topic: { name, internal, partitions },
+  deleteTopic,
+  clusterName,
 }) => {
   const outOfSyncReplicas = React.useMemo(() => {
     if (partitions === undefined || partitions.length === 0) {
@@ -21,6 +29,10 @@ const ListItem: React.FC<ListItemProps> = ({
     }, 0);
   }, [partitions]);
 
+  const deleteTopicHandler = () => {
+    deleteTopic(clusterName, name);
+  };
+
   return (
     <tr>
       <td>
@@ -42,6 +54,17 @@ const ListItem: React.FC<ListItemProps> = ({
           {internal ? 'Internal' : 'External'}
         </div>
       </td>
+      <td>
+        <button
+          type="button"
+          className="is-small button is-danger"
+          onClick={deleteTopicHandler}
+        >
+          <span className="icon is-small">
+            <i className="far fa-trash-alt" />
+          </span>
+        </button>
+      </td>
     </tr>
   );
 };

+ 35 - 0
kafka-ui-react-app/src/components/Topics/List/ListItemContainer.ts

@@ -0,0 +1,35 @@
+import { connect } from 'react-redux';
+import { RootState, ClusterName, TopicName, Action } from 'redux/interfaces';
+import { withRouter, RouteComponentProps } from 'react-router-dom';
+import { ThunkDispatch } from 'redux-thunk';
+import { deleteTopic } from 'redux/actions';
+import ListItem from './ListItem';
+
+interface RouteProps {
+  clusterName: ClusterName;
+}
+
+type OwnProps = RouteComponentProps<RouteProps>;
+
+const mapStateToProps = (
+  state: RootState,
+  {
+    match: {
+      params: { clusterName },
+    },
+  }: OwnProps
+) => ({
+  clusterName,
+});
+
+const mapDispatchToProps = (
+  dispatch: ThunkDispatch<RootState, undefined, Action>
+) => ({
+  deleteTopic: (clusterName: ClusterName, topicName: TopicName) => {
+    dispatch(deleteTopic(clusterName, topicName));
+  },
+});
+
+export default withRouter(
+  connect(mapStateToProps, mapDispatchToProps)(ListItem)
+);

+ 6 - 0
kafka-ui-react-app/src/redux/actions/actions.ts

@@ -82,6 +82,12 @@ export const updateTopicAction = createAsyncAction(
   'PATCH_TOPIC__FAILURE'
 )<undefined, Topic, undefined>();
 
+export const deleteTopicAction = createAsyncAction(
+  'DELETE_TOPIC__REQUEST',
+  'DELETE_TOPIC__SUCCESS',
+  'DELETE_TOPIC__FAILURE'
+)<undefined, TopicName, undefined>();
+
 export const fetchConsumerGroupsAction = createAsyncAction(
   'GET_CONSUMER_GROUPS__REQUEST',
   'GET_CONSUMER_GROUPS__SUCCESS',

+ 16 - 0
kafka-ui-react-app/src/redux/actions/thunks.ts

@@ -234,6 +234,22 @@ export const updateTopic = (
   }
 };
 
+export const deleteTopic = (
+  clusterName: ClusterName,
+  topicName: TopicName
+): PromiseThunkResult => async (dispatch) => {
+  dispatch(actions.deleteTopicAction.request());
+  try {
+    await topicsApiClient.deleteTopic({
+      clusterName,
+      topicName,
+    });
+    dispatch(actions.deleteTopicAction.success(topicName));
+  } catch (e) {
+    dispatch(actions.deleteTopicAction.failure());
+  }
+};
+
 export const fetchConsumerGroupsList = (
   clusterName: ClusterName
 ): PromiseThunkResult => async (dispatch) => {

+ 9 - 0
kafka-ui-react-app/src/redux/reducers/topics/reducer.ts

@@ -100,6 +100,15 @@ const reducer = (state = initialState, action: Action): TopicsState => {
       };
     case getType(actions.createTopicAction.success):
       return addToTopicList(state, action.payload);
+    case getType(actions.deleteTopicAction.success): {
+      const newState: TopicsState = { ...state };
+      delete newState.byName[action.payload];
+      newState.allNames = newState.allNames.filter(
+        (name) => name !== action.payload
+      );
+      return newState;
+    }
+
     default:
       return state;
   }