Skip to content

Commit

Permalink
[issues-211] - Clearing up messages from a topic (#378)
Browse files Browse the repository at this point in the history
Co-authored-by: mbovtryuk <mbovtryuk@provectus.com>
  • Loading branch information
TEDMykhailo and MBovtriukProvectus committed Apr 22, 2021
1 parent ca4b3f1 commit c86c955
Show file tree
Hide file tree
Showing 15 changed files with 252 additions and 46 deletions.
7 changes: 7 additions & 0 deletions kafka-ui-react-app/src/components/Topics/List/List.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@ interface Props {
totalPages: number;
fetchTopicsList(props: FetchTopicsListParams): void;
deleteTopic(topicName: TopicName, clusterName: ClusterName): void;
clearTopicMessages(
topicName: TopicName,
clusterName: ClusterName,
partitions?: number[]
): void;
}

const List: React.FC<Props> = ({
Expand All @@ -30,6 +35,7 @@ const List: React.FC<Props> = ({
totalPages,
fetchTopicsList,
deleteTopic,
clearTopicMessages,
}) => {
const { isReadOnly } = React.useContext(ClusterContext);
const { clusterName } = useParams<{ clusterName: ClusterName }>();
Expand Down Expand Up @@ -99,6 +105,7 @@ const List: React.FC<Props> = ({
key={topic.name}
topic={topic}
deleteTopic={deleteTopic}
clearTopicMessages={clearTopicMessages}
/>
))}
{items.length === 0 && (
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
import { connect } from 'react-redux';
import { RootState } from 'redux/interfaces';
import { fetchTopicsList, deleteTopic } from 'redux/actions';
import {
fetchTopicsList,
deleteTopic,
clearTopicMessages,
} from 'redux/actions';
import {
getTopicList,
getExternalTopicList,
Expand All @@ -19,6 +23,7 @@ const mapStateToProps = (state: RootState) => ({
const mapDispatchToProps = {
fetchTopicsList,
deleteTopic,
clearTopicMessages,
};

export default connect(mapStateToProps, mapDispatchToProps)(List);
9 changes: 9 additions & 0 deletions kafka-ui-react-app/src/components/Topics/List/ListItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,14 @@ export interface ListItemProps {
topic: TopicWithDetailedInfo;
deleteTopic: (clusterName: ClusterName, topicName: TopicName) => void;
clusterName: ClusterName;
clearTopicMessages(topicName: TopicName, clusterName: ClusterName): void;
}

const ListItem: React.FC<ListItemProps> = ({
topic: { name, internal, partitions },
deleteTopic,
clusterName,
clearTopicMessages,
}) => {
const [
isDeleteTopicConfirmationVisible,
Expand All @@ -41,6 +43,10 @@ const ListItem: React.FC<ListItemProps> = ({
deleteTopic(clusterName, name);
}, [clusterName, name]);

const clearTopicMessagesHandler = React.useCallback(() => {
clearTopicMessages(clusterName, name);
}, [clusterName, name]);

return (
<tr>
<td className="has-text-overflow-ellipsis">
Expand Down Expand Up @@ -70,6 +76,9 @@ const ListItem: React.FC<ListItemProps> = ({
}
right
>
<DropdownItem onClick={clearTopicMessagesHandler}>
<span className="has-text-danger">Clear Messages</span>
</DropdownItem>
<DropdownItem
onClick={() => setDeleteTopicConfirmationVisible(true)}
>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ describe('List', () => {
totalPages={1}
fetchTopicsList={jest.fn()}
deleteTopic={jest.fn()}
clearTopicMessages={jest.fn()}
/>
</ClusterContext.Provider>
</StaticRouter>
Expand All @@ -49,6 +50,7 @@ describe('List', () => {
totalPages={1}
fetchTopicsList={jest.fn()}
deleteTopic={jest.fn()}
clearTopicMessages={jest.fn()}
/>
</ClusterContext.Provider>
</StaticRouter>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import ListItem, { ListItemProps } from '../ListItem';

const mockDelete = jest.fn();
const clusterName = 'local';
const mockDeleteMessages = jest.fn();

jest.mock(
'components/common/ConfirmationModal/ConfirmationModal',
Expand All @@ -21,14 +22,25 @@ describe('ListItem', () => {
topic={internalTopicPayload}
deleteTopic={mockDelete}
clusterName={clusterName}
clearTopicMessages={mockDeleteMessages}
{...props}
/>
);

it('triggers the deleting messages when clicked on the delete messages button', () => {
const component = shallow(setupComponent());
component.find('DropdownItem').at(0).simulate('click');
expect(mockDeleteMessages).toBeCalledTimes(1);
expect(mockDeleteMessages).toBeCalledWith(
clusterName,
internalTopicPayload.name
);
});

it('triggers the deleteTopic when clicked on the delete button', () => {
const wrapper = shallow(setupComponent());
expect(wrapper.find('mock-ConfirmationModal').prop('isOpen')).toBeFalsy();
wrapper.find('DropdownItem').last().simulate('click');
wrapper.find('DropdownItem').at(1).simulate('click');
const modal = wrapper.find('mock-ConfirmationModal');
expect(modal.prop('isOpen')).toBeTruthy();
modal.simulate('confirm');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,15 @@ interface Props extends Topic, TopicDetails {
clusterName: ClusterName;
topicName: TopicName;
deleteTopic: (clusterName: ClusterName, topicName: TopicName) => void;
clearTopicMessages(clusterName: ClusterName, topicName: TopicName): void;
}

const Details: React.FC<Props> = ({ clusterName, topicName, deleteTopic }) => {
const Details: React.FC<Props> = ({
clusterName,
topicName,
deleteTopic,
clearTopicMessages,
}) => {
const history = useHistory();
const { isReadOnly } = React.useContext(ClusterContext);
const [
Expand All @@ -33,6 +39,10 @@ const Details: React.FC<Props> = ({ clusterName, topicName, deleteTopic }) => {
history.push(clusterTopicsPath(clusterName));
}, [clusterName, topicName]);

const clearTopicMessagesHandler = React.useCallback(() => {
clearTopicMessages(clusterName, topicName);
}, [clusterName, topicName]);

return (
<div className="box">
<nav className="navbar" role="navigation">
Expand Down Expand Up @@ -66,6 +76,13 @@ const Details: React.FC<Props> = ({ clusterName, topicName, deleteTopic }) => {
<div className="buttons">
{!isReadOnly && (
<>
<button
type="button"
className="button is-danger"
onClick={clearTopicMessagesHandler}
>
Clear All Messages
</button>
<button
className="button is-danger"
type="button"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { connect } from 'react-redux';
import { ClusterName, RootState, TopicName } from 'redux/interfaces';
import { withRouter, RouteComponentProps } from 'react-router-dom';
import { deleteTopic } from 'redux/actions';
import { deleteTopic, clearTopicMessages } from 'redux/actions';

import Details from './Details';

interface RouteProps {
Expand All @@ -25,6 +26,7 @@ const mapStateToProps = (

const mapDispatchToProps = {
deleteTopic,
clearTopicMessages,
};

export default withRouter(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,21 @@
import React from 'react';
import { Topic, TopicDetails } from 'generated-sources';
import { ClusterName, TopicName } from 'redux/interfaces';
import Dropdown from 'components/common/Dropdown/Dropdown';
import DropdownItem from 'components/common/Dropdown/DropdownItem';
import MetricsWrapper from 'components/common/Dashboard/MetricsWrapper';
import Indicator from 'components/common/Dashboard/Indicator';
import BytesFormatted from 'components/common/BytesFormatted/BytesFormatted';

interface Props extends Topic, TopicDetails {}
interface Props extends Topic, TopicDetails {
clusterName: ClusterName;
topicName: TopicName;
clearTopicMessages(
clusterName: ClusterName,
topicName: TopicName,
partitions?: number[]
): void;
}

const Overview: React.FC<Props> = ({
partitions,
Expand All @@ -16,6 +27,9 @@ const Overview: React.FC<Props> = ({
replicationFactor,
segmentSize,
segmentCount,
clusterName,
topicName,
clearTopicMessages,
}) => (
<>
<MetricsWrapper>
Expand Down Expand Up @@ -43,28 +57,45 @@ const Overview: React.FC<Props> = ({
<Indicator label="Segment count">{segmentCount}</Indicator>
</MetricsWrapper>
<div className="box">
<div className="table-container">
<table className="table is-striped is-fullwidth">
<thead>
<tr>
<th>Partition ID</th>
<th>Broker leader</th>
<th>Min offset</th>
<th>Max offset</th>
<table className="table is-striped is-fullwidth">
<thead>
<tr>
<th>Partition ID</th>
<th>Broker leader</th>
<th>Min offset</th>
<th>Max offset</th>
<th> </th>
</tr>
</thead>
<tbody>
{partitions?.map(({ partition, leader, offsetMin, offsetMax }) => (
<tr key={`partition-list-item-key-${partition}`}>
<td>{partition}</td>
<td>{leader}</td>
<td>{offsetMin}</td>
<td>{offsetMax}</td>
<td className="has-text-right">
<Dropdown
label={
<span className="icon">
<i className="fas fa-cog" />
</span>
}
right
>
<DropdownItem
onClick={() =>
clearTopicMessages(clusterName, topicName, [partition])
}
>
<span className="has-text-danger">Clear Messages</span>
</DropdownItem>
</Dropdown>
</td>
</tr>
</thead>
<tbody>
{partitions?.map(({ partition, leader, offsetMin, offsetMax }) => (
<tr key={`partition-list-item-key-${partition}`}>
<td>{partition}</td>
<td>{leader}</td>
<td>{offsetMin}</td>
<td>{offsetMax}</td>
</tr>
))}
</tbody>
</table>
</div>
))}
</tbody>
</table>
</div>
</>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { connect } from 'react-redux';
import { RootState, TopicName, ClusterName } from 'redux/interfaces';
import { getTopicByName } from 'redux/reducers/topics/selectors';
import { withRouter, RouteComponentProps } from 'react-router-dom';
import { clearTopicMessages } from 'redux/actions';
import Overview from './Overview';

interface RouteProps {
Expand All @@ -15,11 +16,19 @@ const mapStateToProps = (
state: RootState,
{
match: {
params: { topicName },
params: { topicName, clusterName },
},
}: OwnProps
) => ({
...getTopicByName(state, topicName),
topicName,
clusterName,
});

export default withRouter(connect(mapStateToProps)(Overview));
const mapDispatchToProps = {
clearTopicMessages,
};

export default withRouter(
connect(mapStateToProps, mapDispatchToProps)(Overview)
);
22 changes: 22 additions & 0 deletions kafka-ui-react-app/src/redux/actions/__test__/actions.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -109,4 +109,26 @@ describe('Actions', () => {
});
});
});

describe('clearMessagesTopicAction', () => {
it('creates a REQUEST action', () => {
expect(actions.clearMessagesTopicAction.request()).toEqual({
type: 'CLEAR_TOPIC_MESSAGES__REQUEST',
});
});

it('creates a SUCCESS action', () => {
expect(actions.clearMessagesTopicAction.success('topic')).toEqual({
type: 'CLEAR_TOPIC_MESSAGES__SUCCESS',
payload: 'topic',
});
});

it('creates a FAILURE action', () => {
expect(actions.clearMessagesTopicAction.failure({})).toEqual({
type: 'CLEAR_TOPIC_MESSAGES__FAILURE',
payload: {},
});
});
});
});
Loading

0 comments on commit c86c955

Please sign in to comment.