diff --git a/client/src/containers/ConsumerGroup/ConsumerGroupDetail/ConsumerGroup.jsx b/client/src/containers/ConsumerGroup/ConsumerGroupDetail/ConsumerGroup.jsx index 3c51dbf10..e940c9b51 100644 --- a/client/src/containers/ConsumerGroup/ConsumerGroupDetail/ConsumerGroup.jsx +++ b/client/src/containers/ConsumerGroup/ConsumerGroupDetail/ConsumerGroup.jsx @@ -123,14 +123,26 @@ class ConsumerGroup extends Component { - {roles.group && roles.group['group/offsets/update'] && ( + {roles.group && (roles.group['group/offsets/delete'] || roles.group['group/offsets/update']) && ( )} diff --git a/client/src/containers/ConsumerGroup/ConsumerGroupDetail/ConsumerGroupOffsetDelete/ConsumerGroupOffsetDelete.jsx b/client/src/containers/ConsumerGroup/ConsumerGroupDetail/ConsumerGroupOffsetDelete/ConsumerGroupOffsetDelete.jsx new file mode 100644 index 000000000..a076fea3c --- /dev/null +++ b/client/src/containers/ConsumerGroup/ConsumerGroupDetail/ConsumerGroupOffsetDelete/ConsumerGroupOffsetDelete.jsx @@ -0,0 +1,127 @@ +import React from 'react'; +import Header from '../../../Header/Header'; +import { + uriConsumerGroup, uriDeleteGroupOffsets, +} from '../../../../utils/endpoints'; +import 'react-toastify/dist/ReactToastify.css'; +import Root from "../../../../components/Root"; +import Table from "../../../../components/Table"; +import constants from "../../../../utils/constants"; +import ConfirmModal from "../../../../components/Modal/ConfirmModal"; +import {toast} from "react-toastify"; + +class ConsumerGroupOffsetDelete extends Root { + state = { + clusterId: '', + consumerGroupId: '', + topicIds: [], + deleteAllOffsetsForTopic: '', + showDeleteModal: false, + deleteMessage: '', + }; + + componentDidMount() { + const {clusterId, consumerGroupId} = this.props.match.params; + + this.setState({clusterId, consumerGroupId}, () => { + this.getTopics(); + }); + } + + async getTopics() { + const { clusterId, consumerGroupId } = this.state; + + let data; + data = await this.getApi(uriConsumerGroup(clusterId, consumerGroupId)); + data = data.data; + + if (data && data.topics) { + this.setState({ topicIds: data.topics.map(topic => ({ topic })) }); + } else { + this.setState({ topicIds: [] }); + } + } + + showDeleteModal = deleteMessage => { + this.setState({ showDeleteModal: true, deleteMessage }); + }; + + closeDeleteModal = () => { + this.setState({ showDeleteModal: false, deleteMessage: '', deleteAllOffsetsForTopic: '' }); + }; + + deleteOffsets = () => { + const { clusterId, consumerGroupId, deleteAllOffsetsForTopic } = this.state; + this.removeApi(uriDeleteGroupOffsets(clusterId, consumerGroupId, deleteAllOffsetsForTopic)) + .then(() => { + toast.success(`Offsets for topic '${deleteAllOffsetsForTopic}' and consumer group '${consumerGroupId}' are deleted`); + this.setState({ showDeleteModal: false, deleteMessage: '', deleteAllOffsetsForTopic: '' }, () => { + this.getTopics(); + }); + }) + .catch(() => { + this.setState({ showDeleteModal: false, deleteMessage: '', deleteAllOffsetsForTopic: '' }); + }); + } + + handleOnDelete(topicId) { + this.setState({ deleteAllOffsetsForTopic: topicId }, () => { + this.showDeleteModal( + + Do you want to delete all offsets of topic: {{topicId}} ? + + ); + }); + } + + render() { + const {consumerGroupId} = this.state; + + return ( +
+
+
+
+
+ + + + } + onDelete={(row) => { + this.handleOnDelete(row.topic) + }} + actions={ + [constants.TABLE_DELETE] + } + /> + + + + ); + } +} + +export default ConsumerGroupOffsetDelete; diff --git a/client/src/containers/ConsumerGroup/ConsumerGroupDetail/ConsumerGroupOffsetDelete/index.js b/client/src/containers/ConsumerGroup/ConsumerGroupDetail/ConsumerGroupOffsetDelete/index.js new file mode 100644 index 000000000..63a690c72 --- /dev/null +++ b/client/src/containers/ConsumerGroup/ConsumerGroupDetail/ConsumerGroupOffsetDelete/index.js @@ -0,0 +1,3 @@ +import ConsumerGroupOffsetDelete from './ConsumerGroupOffsetDelete'; + +export default ConsumerGroupOffsetDelete; diff --git a/client/src/utils/Routes.js b/client/src/utils/Routes.js index d5ba2f6ba..9634d1158 100644 --- a/client/src/utils/Routes.js +++ b/client/src/utils/Routes.js @@ -21,6 +21,7 @@ import Schema from '../containers/Schema/SchemaDetail/Schema'; import SchemaList from '../containers/Schema/SchemaList/SchemaList'; import SchemaCreate from '../containers/Schema/SchemaCreate/SchemaCreate'; import ConsumerGroupUpdate from '../containers/ConsumerGroup/ConsumerGroupDetail/ConsumerGroupUpdate'; +import ConsumerGroupOffsetDelete from '../containers/ConsumerGroup/ConsumerGroupDetail/ConsumerGroupOffsetDelete'; import AclDetails from '../containers/Acl/AclDetail'; import Login from '../containers/Login'; import Settings from '../containers/Settings/Settings'; @@ -185,6 +186,14 @@ class Routes extends Root { )} + {roles && roles.group && roles.group['group/offsets/delete'] && ( + + )} + {roles && roles.group && roles.group['group/offsets/update'] && ( { return `${apiUrl}/${clusterId}/group/${groupId}/offsets`; }; +export const uriDeleteGroupOffsets = (clusterId, groupId, topicName) => { + return `${apiUrl}/${clusterId}/group/${groupId}/topic/${topicName}`; +}; + export const uriAclsList = (clusterId, search) => { let url = `${apiUrl}/${clusterId}/acls`; return search ? `${url}?search=${search}` : url; @@ -343,5 +347,6 @@ export default { uriAclsByPrincipal, uriLiveTail, uriTopicDataSearch, - uriTopicDataDelete + uriTopicDataDelete, + uriDeleteGroupOffsets };
+
+ No offsets found. +
+