Details.tsx 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. import React from 'react';
  2. import { useNavigate, useSearchParams } from 'react-router-dom';
  3. import useAppParams from 'lib/hooks/useAppParams';
  4. import {
  5. clusterConsumerGroupResetRelativePath,
  6. clusterConsumerGroupsPath,
  7. ClusterGroupParam,
  8. } from 'lib/paths';
  9. import Search from 'components/common/Search/Search';
  10. import ClusterContext from 'components/contexts/ClusterContext';
  11. import PageHeading from 'components/common/PageHeading/PageHeading';
  12. import * as Metrics from 'components/common/Metrics';
  13. import { Tag } from 'components/common/Tag/Tag.styled';
  14. import groupBy from 'lodash/groupBy';
  15. import { Table } from 'components/common/table/Table/Table.styled';
  16. import getTagColor from 'components/common/Tag/getTagColor';
  17. import { Dropdown } from 'components/common/Dropdown';
  18. import { ControlPanelWrapper } from 'components/common/ControlPanel/ControlPanel.styled';
  19. import { Action, ResourceType } from 'generated-sources';
  20. import { ActionDropdownItem } from 'components/common/ActionComponent';
  21. import TableHeaderCell from 'components/common/table/TableHeaderCell/TableHeaderCell';
  22. import {
  23. useConsumerGroupDetails,
  24. useDeleteConsumerGroupMutation,
  25. } from 'lib/hooks/api/consumers';
  26. import ListItem from './ListItem';
  27. const Details: React.FC = () => {
  28. const navigate = useNavigate();
  29. const [searchParams] = useSearchParams();
  30. const searchValue = searchParams.get('q') || '';
  31. const { isReadOnly } = React.useContext(ClusterContext);
  32. const routeParams = useAppParams<ClusterGroupParam>();
  33. const { clusterName, consumerGroupID } = routeParams;
  34. const consumerGroup = useConsumerGroupDetails(routeParams);
  35. const deleteConsumerGroup = useDeleteConsumerGroupMutation(routeParams);
  36. const onDelete = async () => {
  37. await deleteConsumerGroup.mutateAsync();
  38. navigate('../');
  39. };
  40. const onResetOffsets = () => {
  41. navigate(clusterConsumerGroupResetRelativePath);
  42. };
  43. const partitionsByTopic = groupBy(consumerGroup.data?.partitions, 'topic');
  44. const filteredPartitionsByTopic = Object.keys(partitionsByTopic).filter(
  45. (el) => el.includes(searchValue)
  46. );
  47. const currentPartitionsByTopic = searchValue.length
  48. ? filteredPartitionsByTopic
  49. : Object.keys(partitionsByTopic);
  50. const hasAssignedTopics = consumerGroup?.data?.topics !== 0;
  51. return (
  52. <div>
  53. <div>
  54. <PageHeading
  55. text={consumerGroupID}
  56. backTo={clusterConsumerGroupsPath(clusterName)}
  57. backText="Consumers"
  58. >
  59. {!isReadOnly && (
  60. <Dropdown>
  61. <ActionDropdownItem
  62. onClick={onResetOffsets}
  63. permission={{
  64. resource: ResourceType.CONSUMER,
  65. action: Action.RESET_OFFSETS,
  66. value: consumerGroupID,
  67. }}
  68. disabled={!hasAssignedTopics}
  69. >
  70. Reset offset
  71. </ActionDropdownItem>
  72. <ActionDropdownItem
  73. confirm="Are you sure you want to delete this consumer group?"
  74. onClick={onDelete}
  75. danger
  76. permission={{
  77. resource: ResourceType.CONSUMER,
  78. action: Action.DELETE,
  79. value: consumerGroupID,
  80. }}
  81. >
  82. Delete consumer group
  83. </ActionDropdownItem>
  84. </Dropdown>
  85. )}
  86. </PageHeading>
  87. </div>
  88. <Metrics.Wrapper>
  89. <Metrics.Section>
  90. <Metrics.Indicator label="State">
  91. <Tag color={getTagColor(consumerGroup.data?.state)}>
  92. {consumerGroup.data?.state}
  93. </Tag>
  94. </Metrics.Indicator>
  95. <Metrics.Indicator label="Members">
  96. {consumerGroup.data?.members}
  97. </Metrics.Indicator>
  98. <Metrics.Indicator label="Assigned Topics">
  99. {consumerGroup.data?.topics}
  100. </Metrics.Indicator>
  101. <Metrics.Indicator label="Assigned Partitions">
  102. {consumerGroup.data?.partitions?.length}
  103. </Metrics.Indicator>
  104. <Metrics.Indicator label="Coordinator ID">
  105. {consumerGroup.data?.coordinator?.id}
  106. </Metrics.Indicator>
  107. <Metrics.Indicator label="Total lag">
  108. {consumerGroup.data?.consumerLag}
  109. </Metrics.Indicator>
  110. </Metrics.Section>
  111. </Metrics.Wrapper>
  112. <ControlPanelWrapper hasInput style={{ margin: '16px 0 20px' }}>
  113. <Search placeholder="Search by Topic Name" />
  114. </ControlPanelWrapper>
  115. <Table isFullwidth>
  116. <thead>
  117. <tr>
  118. <TableHeaderCell title="Topic" />
  119. <TableHeaderCell title="Consumer Lag" />
  120. </tr>
  121. </thead>
  122. <tbody>
  123. {currentPartitionsByTopic.map((key) => (
  124. <ListItem
  125. clusterName={clusterName}
  126. consumers={partitionsByTopic[key]}
  127. name={key}
  128. key={key}
  129. />
  130. ))}
  131. </tbody>
  132. </Table>
  133. </div>
  134. );
  135. };
  136. export default Details;