Implement topic deletion

This commit is contained in:
GneyHabub 2021-03-17 15:00:03 +03:00
parent a8ed4ff37f
commit 3fee2214a0
6 changed files with 93 additions and 3 deletions

View file

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

View file

@ -1,14 +1,22 @@
import React from 'react'; import React from 'react';
import cx from 'classnames'; import cx from 'classnames';
import { NavLink } from 'react-router-dom'; import { NavLink } from 'react-router-dom';
import { TopicWithDetailedInfo } from 'redux/interfaces'; import {
ClusterName,
TopicName,
TopicWithDetailedInfo,
} from 'redux/interfaces';
interface ListItemProps { interface ListItemProps {
topic: TopicWithDetailedInfo; topic: TopicWithDetailedInfo;
deleteTopic: (clusterName: ClusterName, topicName: TopicName) => void;
clusterName: ClusterName;
} }
const ListItem: React.FC<ListItemProps> = ({ const ListItem: React.FC<ListItemProps> = ({
topic: { name, internal, partitions }, topic: { name, internal, partitions },
deleteTopic,
clusterName,
}) => { }) => {
const outOfSyncReplicas = React.useMemo(() => { const outOfSyncReplicas = React.useMemo(() => {
if (partitions === undefined || partitions.length === 0) { if (partitions === undefined || partitions.length === 0) {
@ -21,6 +29,10 @@ const ListItem: React.FC<ListItemProps> = ({
}, 0); }, 0);
}, [partitions]); }, [partitions]);
const deleteTopicHandler = () => {
deleteTopic(clusterName, name);
};
return ( return (
<tr> <tr>
<td> <td>
@ -42,6 +54,17 @@ const ListItem: React.FC<ListItemProps> = ({
{internal ? 'Internal' : 'External'} {internal ? 'Internal' : 'External'}
</div> </div>
</td> </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> </tr>
); );
}; };

View file

@ -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)
);

View file

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

View file

@ -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 = ( export const fetchConsumerGroupsList = (
clusterName: ClusterName clusterName: ClusterName
): PromiseThunkResult => async (dispatch) => { ): PromiseThunkResult => async (dispatch) => {

View file

@ -100,6 +100,15 @@ const reducer = (state = initialState, action: Action): TopicsState => {
}; };
case getType(actions.createTopicAction.success): case getType(actions.createTopicAction.success):
return addToTopicList(state, action.payload); 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: default:
return state; return state;
} }