[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>
This commit is contained in:
parent
529cd0bd6e
commit
4eaf8ea2c6
12 changed files with 101 additions and 18 deletions
|
@ -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 {
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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 = {
|
||||
|
|
|
@ -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,
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -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};
|
||||
}
|
||||
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 && orderableMixin}
|
||||
${isOrderable && !isOrdered && orderableMixin}
|
||||
|
||||
${isOrderable && isOrdered && orderedMixin}
|
||||
${isOrderable && isOrdered && sortOrder === SortOrder.ASC && ASCMixin}
|
||||
|
||||
${isOrderable && isOrdered && sortOrder === SortOrder.DESC && DESCMixin}
|
||||
`
|
||||
);
|
||||
|
||||
|
|
|
@ -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',
|
||||
|
|
|
@ -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');
|
||||
|
|
|
@ -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: [],
|
||||
};
|
||||
|
|
|
@ -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[];
|
||||
}
|
||||
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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): {
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Add table
Reference in a new issue