ListItem.tsx 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  1. import React from 'react';
  2. import cx from 'classnames';
  3. import { NavLink } from 'react-router-dom';
  4. import {
  5. ClusterName,
  6. TopicName,
  7. TopicWithDetailedInfo,
  8. } from 'redux/interfaces';
  9. import DropdownItem from 'components/common/Dropdown/DropdownItem';
  10. import Dropdown from 'components/common/Dropdown/Dropdown';
  11. import ConfirmationModal from 'components/common/ConfirmationModal/ConfirmationModal';
  12. import ClusterContext from 'components/contexts/ClusterContext';
  13. export interface ListItemProps {
  14. topic: TopicWithDetailedInfo;
  15. deleteTopic: (clusterName: ClusterName, topicName: TopicName) => void;
  16. clusterName: ClusterName;
  17. clearTopicMessages(topicName: TopicName, clusterName: ClusterName): void;
  18. }
  19. const ListItem: React.FC<ListItemProps> = ({
  20. topic: { name, internal, partitions },
  21. deleteTopic,
  22. clusterName,
  23. clearTopicMessages,
  24. }) => {
  25. const { isReadOnly } = React.useContext(ClusterContext);
  26. const [isDeleteTopicConfirmationVisible, setDeleteTopicConfirmationVisible] =
  27. React.useState(false);
  28. const outOfSyncReplicas = React.useMemo(() => {
  29. if (partitions === undefined || partitions.length === 0) {
  30. return 0;
  31. }
  32. return partitions.reduce((memo: number, { replicas }) => {
  33. const outOfSync = replicas?.filter(({ inSync }) => !inSync);
  34. return memo + (outOfSync?.length || 0);
  35. }, 0);
  36. }, [partitions]);
  37. const deleteTopicHandler = React.useCallback(() => {
  38. deleteTopic(clusterName, name);
  39. }, [clusterName, name]);
  40. const clearTopicMessagesHandler = React.useCallback(() => {
  41. clearTopicMessages(clusterName, name);
  42. }, [clusterName, name]);
  43. return (
  44. <tr>
  45. <td className="has-text-overflow-ellipsis">
  46. <NavLink
  47. exact
  48. to={`topics/${name}`}
  49. activeClassName="is-active"
  50. className="title is-6"
  51. >
  52. {name}
  53. </NavLink>
  54. </td>
  55. <td>{partitions?.length}</td>
  56. <td>{outOfSyncReplicas}</td>
  57. <td>
  58. <div className={cx('tag', internal ? 'is-light' : 'is-primary')}>
  59. {internal ? 'Internal' : 'External'}
  60. </div>
  61. </td>
  62. <td className="topic-action-block">
  63. {!internal && !isReadOnly ? (
  64. <>
  65. <div className="has-text-right">
  66. <Dropdown
  67. label={
  68. <span className="icon">
  69. <i className="fas fa-cog" />
  70. </span>
  71. }
  72. right
  73. >
  74. <DropdownItem onClick={clearTopicMessagesHandler}>
  75. <span className="has-text-danger">Clear Messages</span>
  76. </DropdownItem>
  77. <DropdownItem
  78. onClick={() => setDeleteTopicConfirmationVisible(true)}
  79. >
  80. <span className="has-text-danger">Remove Topic</span>
  81. </DropdownItem>
  82. </Dropdown>
  83. </div>
  84. <ConfirmationModal
  85. isOpen={isDeleteTopicConfirmationVisible}
  86. onCancel={() => setDeleteTopicConfirmationVisible(false)}
  87. onConfirm={deleteTopicHandler}
  88. >
  89. Are you sure want to remove <b>{name}</b> topic?
  90. </ConfirmationModal>
  91. </>
  92. ) : null}
  93. </td>
  94. </tr>
  95. );
  96. };
  97. export default ListItem;