Browse Source

[ISSUE-1512]Added sorting by topics size

* [ISSUE-1512]Added sorting by topics size

* Add sort by Size.Refactoring sort order

* correct a little mistake

* Improve test coverage

* got rid code dupliction

* refactoring

Co-authored-by: ValentinPrischepa <valentin.prischepa@gmail.com>
Co-authored-by: Anton Zorin <ant.zorin@gmail.com>
Co-authored-by: Oleg Shur <workshur@gmail.com>
Zorii4 3 years ago
parent
commit
4eaf8ea2c6

+ 4 - 0
kafka-ui-react-app/src/components/Connect/Details/Tasks/__tests__/__snapshots__/Tasks.spec.tsx.snap

@@ -44,6 +44,8 @@ exports[`Tasks view matches snapshot 1`] = `
   background: #FFFFFF;
   cursor: default;
   color: #73848C;
+  padding-right: 18px;
+  position: relative;
 }
 
 .c1 {
@@ -217,6 +219,8 @@ exports[`Tasks view matches snapshot when no tasks 1`] = `
   background: #FFFFFF;
   cursor: default;
   color: #73848C;
+  padding-right: 18px;
+  position: relative;
 }
 
 .c1 {

+ 19 - 3
kafka-ui-react-app/src/components/Topics/List/List.tsx

@@ -12,7 +12,11 @@ import ClusterContext from 'components/contexts/ClusterContext';
 import PageLoader from 'components/common/PageLoader/PageLoader';
 import Pagination from 'components/common/Pagination/Pagination';
 import ConfirmationModal from 'components/common/ConfirmationModal/ConfirmationModal';
-import { GetTopicsRequest, TopicColumnsToSort } from 'generated-sources';
+import {
+  GetTopicsRequest,
+  SortOrder,
+  TopicColumnsToSort,
+} from 'generated-sources';
 import TableHeaderCell from 'components/common/table/TableHeaderCell/TableHeaderCell';
 import Search from 'components/common/Search/Search';
 import { PER_PAGE } from 'lib/constants';
@@ -39,6 +43,7 @@ export interface TopicsListProps {
   ): void;
   search: string;
   orderBy: TopicColumnsToSort | null;
+  sortOrder: SortOrder;
   setTopicsSearch(search: string): void;
   setTopicsOrderBy(orderBy: TopicColumnsToSort | null): void;
 }
@@ -54,6 +59,7 @@ const List: React.FC<TopicsListProps> = ({
   clearTopicsMessages,
   search,
   orderBy,
+  sortOrder,
   setTopicsSearch,
   setTopicsOrderBy,
 }) => {
@@ -69,6 +75,7 @@ const List: React.FC<TopicsListProps> = ({
       page,
       perPage,
       orderBy: orderBy || undefined,
+      sortOrder,
       search,
       showInternal,
     });
@@ -78,6 +85,7 @@ const List: React.FC<TopicsListProps> = ({
     page,
     perPage,
     orderBy,
+    sortOrder,
     search,
     showInternal,
   ]);
@@ -215,24 +223,32 @@ const List: React.FC<TopicsListProps> = ({
                   title="Topic Name"
                   orderValue={TopicColumnsToSort.NAME}
                   orderBy={orderBy}
+                  sortOrder={sortOrder}
                   handleOrderBy={setTopicsOrderBy}
                 />
                 <TableHeaderCell
                   title="Total Partitions"
                   orderValue={TopicColumnsToSort.TOTAL_PARTITIONS}
                   orderBy={orderBy}
+                  sortOrder={sortOrder}
                   handleOrderBy={setTopicsOrderBy}
                 />
                 <TableHeaderCell
                   title="Out of sync replicas"
                   orderValue={TopicColumnsToSort.OUT_OF_SYNC_REPLICAS}
                   orderBy={orderBy}
+                  sortOrder={sortOrder}
                   handleOrderBy={setTopicsOrderBy}
                 />
                 <TableHeaderCell title="Replication Factor" />
                 <TableHeaderCell title="Number of messages" />
-                <TableHeaderCell title="Size" />
-                <TableHeaderCell />
+                <TableHeaderCell
+                  title="Size"
+                  orderValue={TopicColumnsToSort.SIZE}
+                  orderBy={orderBy}
+                  sortOrder={sortOrder}
+                  handleOrderBy={setTopicsOrderBy}
+                />
               </tr>
             </thead>
             <tbody>

+ 2 - 0
kafka-ui-react-app/src/components/Topics/List/ListContainer.ts

@@ -15,6 +15,7 @@ import {
   getTopicListTotalPages,
   getTopicsSearch,
   getTopicsOrderBy,
+  getTopicsSortOrder,
 } from 'redux/reducers/topics/selectors';
 
 import List from './List';
@@ -25,6 +26,7 @@ const mapStateToProps = (state: RootState) => ({
   totalPages: getTopicListTotalPages(state),
   search: getTopicsSearch(state),
   orderBy: getTopicsOrderBy(state),
+  sortOrder: getTopicsSortOrder(state),
 });
 
 const mapDispatchToProps = {

+ 3 - 0
kafka-ui-react-app/src/components/Topics/List/__tests__/List.spec.tsx

@@ -13,6 +13,7 @@ import { externalTopicPayload } from 'redux/reducers/topics/__test__/fixtures';
 import { ConfirmationModalProps } from 'components/common/ConfirmationModal/ConfirmationModal';
 import theme from 'theme/theme';
 import { ThemeProvider } from 'styled-components';
+import { SortOrder } from 'generated-sources';
 
 jest.mock(
   'components/common/ConfirmationModal/ConfirmationModal',
@@ -33,6 +34,7 @@ describe('List', () => {
         clearTopicMessages={jest.fn()}
         search=""
         orderBy={null}
+        sortOrder={SortOrder.ASC}
         setTopicsSearch={jest.fn()}
         setTopicsOrderBy={jest.fn()}
         {...props}
@@ -104,6 +106,7 @@ describe('List', () => {
       expect(fetchTopicsList).toHaveBeenLastCalledWith({
         search: '',
         showInternal: false,
+        sortOrder: SortOrder.ASC,
       });
     });
 

+ 44 - 10
kafka-ui-react-app/src/components/common/table/TableHeaderCell/TableHeaderCell.styled.ts

@@ -1,8 +1,10 @@
+import { SortOrder } from 'generated-sources';
 import styled, { css } from 'styled-components';
 
 interface TitleProps {
   isOrderable?: boolean;
   isOrdered?: boolean;
+  sortOrder?: SortOrder;
 }
 
 const orderableMixin = css(
@@ -45,20 +47,48 @@ const orderableMixin = css(
   `
 );
 
-const orderedMixin = css(
+const ASCMixin = css(
   ({ theme: { table } }) => `
   color: ${table.th.color.active};
-      &::before {
-        border-bottom-color: ${table.th.color.active};
-      }
-      &::after {
-        border-top-color: ${table.th.color.active};
-      }
+  cursor: pointer;
+
+  &::after {
+    cursor: pointer;
+    border: 4px solid transparent;
+    content: '';
+    display: block;
+    height: 0;
+    right: 5px;
+    top: 50%;
+    position: absolute;
+    border-top-color: ${table.th.color.active};
+    margin-top: 1px;
+  }
+  `
+);
+
+const DESCMixin = css(
+  ({ theme: { table } }) => `
+  color: ${table.th.color.active};
+  cursor: pointer;
+
+  &::before {
+    border: 4px solid transparent;
+    cursor: pointer;
+    content: '';
+    display: block;
+    height: 0;
+    right: 5px;
+    top: 50%;
+    position: absolute;
+    margin-top: -9px;
+    border-bottom-color: ${table.th.color.active};
+  }
   `
 );
 
 export const Title = styled.span<TitleProps>(
-  ({ isOrderable, isOrdered, theme: { table } }) => css`
+  ({ isOrderable, isOrdered, sortOrder, theme: { table } }) => css`
     font-family: Inter, sans-serif;
     font-size: 12px;
     font-style: normal;
@@ -72,10 +102,14 @@ export const Title = styled.span<TitleProps>(
     background: ${table.th.backgroundColor.normal};
     cursor: default;
     color: ${table.th.color.normal};
+    padding-right: 18px;
+    position: relative;
+
+    ${isOrderable && !isOrdered && orderableMixin}
 
-    ${isOrderable && orderableMixin}
+    ${isOrderable && isOrdered && sortOrder === SortOrder.ASC && ASCMixin}
 
-    ${isOrderable && isOrdered && orderedMixin}
+    ${isOrderable && isOrdered && sortOrder === SortOrder.DESC && DESCMixin}
   `
 );
 

+ 4 - 1
kafka-ui-react-app/src/components/common/table/TableHeaderCell/TableHeaderCell.tsx

@@ -1,5 +1,5 @@
 import React from 'react';
-import { TopicColumnsToSort } from 'generated-sources';
+import { SortOrder, TopicColumnsToSort } from 'generated-sources';
 import * as S from 'components/common/table/TableHeaderCell/TableHeaderCell.styled';
 
 export interface TableHeaderCellProps {
@@ -7,6 +7,7 @@ export interface TableHeaderCellProps {
   previewText?: string;
   onPreview?: () => void;
   orderBy?: TopicColumnsToSort | null;
+  sortOrder?: SortOrder;
   orderValue?: TopicColumnsToSort | null;
   handleOrderBy?: (orderBy: TopicColumnsToSort | null) => void;
 }
@@ -17,6 +18,7 @@ const TableHeaderCell: React.FC<TableHeaderCellProps> = (props) => {
     previewText,
     onPreview,
     orderBy,
+    sortOrder,
     orderValue,
     handleOrderBy,
     ...restProps
@@ -38,6 +40,7 @@ const TableHeaderCell: React.FC<TableHeaderCellProps> = (props) => {
   };
   const orderableProps = isOrderable && {
     isOrderable,
+    sortOrder,
     onClick: handleOnClick,
     onKeyDown: handleOnKeyDown,
     role: 'button',

+ 3 - 2
kafka-ui-react-app/src/components/common/table/__tests__/TableHeaderCell.spec.tsx

@@ -4,7 +4,7 @@ import { render } from 'lib/testHelpers';
 import TableHeaderCell, {
   TableHeaderCellProps,
 } from 'components/common/table/TableHeaderCell/TableHeaderCell';
-import { TopicColumnsToSort } from 'generated-sources';
+import { SortOrder, TopicColumnsToSort } from 'generated-sources';
 import theme from 'theme/theme';
 import userEvent from '@testing-library/user-event';
 
@@ -50,6 +50,7 @@ describe('TableHeaderCell', () => {
       title: testTitle,
       orderBy: TopicColumnsToSort.NAME,
       orderValue: TopicColumnsToSort.NAME,
+      sortOrder: SortOrder.ASC,
       handleOrderBy,
     });
     const columnheader = screen.getByRole('columnheader');
@@ -59,7 +60,6 @@ describe('TableHeaderCell', () => {
     expect(title).toHaveStyle(`color: ${theme.table.th.color.active};`);
     expect(title).toHaveStyle('cursor: pointer;');
   });
-
   it('renders click on title triggers handler', () => {
     setupComponent({
       title: testTitle,
@@ -129,6 +129,7 @@ describe('TableHeaderCell', () => {
       title: testTitle,
       orderBy: TopicColumnsToSort.NAME,
       orderValue: TopicColumnsToSort.NAME,
+      sortOrder: SortOrder.ASC,
       handleOrderBy: jest.fn(),
     });
     const columnheader = screen.getByRole('columnheader');

+ 2 - 0
kafka-ui-react-app/src/redux/actions/__test__/fixtures.ts

@@ -4,6 +4,7 @@ import {
   NewSchemaSubject,
   SchemaSubject,
   SchemaType,
+  SortOrder,
 } from 'generated-sources';
 
 export const clusterStats: ClusterStats = {
@@ -42,5 +43,6 @@ export const mockTopicsState = {
   messages: [],
   search: '',
   orderBy: null,
+  sortOrder: SortOrder.ASC,
   consumerGroups: [],
 };

+ 2 - 0
kafka-ui-react-app/src/redux/interfaces/topic.ts

@@ -9,6 +9,7 @@ import {
   TopicMessage,
   TopicMessageConsuming,
   TopicMessageSchema,
+  SortOrder,
 } from 'generated-sources';
 
 export type TopicName = Topic['name'];
@@ -53,6 +54,7 @@ export interface TopicsState {
   totalPages: number;
   search: string;
   orderBy: TopicColumnsToSort | null;
+  sortOrder: SortOrder;
   consumerGroups: ConsumerGroup[];
 }
 

+ 7 - 1
kafka-ui-react-app/src/redux/reducers/topics/__test__/reducer.spec.ts

@@ -1,4 +1,8 @@
-import { MessageSchemaSourceEnum, TopicColumnsToSort } from 'generated-sources';
+import {
+  MessageSchemaSourceEnum,
+  SortOrder,
+  TopicColumnsToSort,
+} from 'generated-sources';
 import {
   deleteTopicAction,
   clearMessagesTopicAction,
@@ -72,6 +76,7 @@ let state = {
   totalPages: 1,
   search: '',
   orderBy: null,
+  sortOrder: SortOrder.ASC,
   consumerGroups: [],
 };
 
@@ -130,6 +135,7 @@ describe('topics reducer', () => {
         totalPages: 1,
         search: '',
         orderBy: null,
+        sortOrder: SortOrder.ASC,
         consumerGroups: [],
       };
       expect(

+ 6 - 1
kafka-ui-react-app/src/redux/reducers/topics/reducer.ts

@@ -2,7 +2,7 @@ import { Action, TopicsState } from 'redux/interfaces';
 import { getType } from 'typesafe-actions';
 import * as actions from 'redux/actions';
 import * as _ from 'lodash';
-import { TopicColumnsToSort } from 'generated-sources';
+import { SortOrder, TopicColumnsToSort } from 'generated-sources';
 
 export const initialState: TopicsState = {
   byName: {},
@@ -10,6 +10,7 @@ export const initialState: TopicsState = {
   totalPages: 1,
   search: '',
   orderBy: TopicColumnsToSort.NAME,
+  sortOrder: SortOrder.ASC,
   consumerGroups: [],
 };
 
@@ -41,6 +42,10 @@ const reducer = (state = initialState, action: Action): TopicsState => {
       return {
         ...state,
         orderBy: action.payload,
+        sortOrder:
+          state.orderBy === action.payload && state.sortOrder === SortOrder.ASC
+            ? SortOrder.DESC
+            : SortOrder.ASC,
       };
     }
     case getType(actions.fetchTopicMessageSchemaAction.success): {

+ 5 - 0
kafka-ui-react-app/src/redux/reducers/topics/selectors.ts

@@ -157,6 +157,11 @@ export const getTopicsOrderBy = createSelector(
   (state) => state.orderBy
 );
 
+export const getTopicsSortOrder = createSelector(
+  topicsState,
+  (state) => state.sortOrder
+);
+
 export const getIsTopicInternal = createSelector(
   getTopicByName,
   (topic) => !!topic?.internal