[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;
|
background: #FFFFFF;
|
||||||
cursor: default;
|
cursor: default;
|
||||||
color: #73848C;
|
color: #73848C;
|
||||||
|
padding-right: 18px;
|
||||||
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
.c1 {
|
.c1 {
|
||||||
|
@ -217,6 +219,8 @@ exports[`Tasks view matches snapshot when no tasks 1`] = `
|
||||||
background: #FFFFFF;
|
background: #FFFFFF;
|
||||||
cursor: default;
|
cursor: default;
|
||||||
color: #73848C;
|
color: #73848C;
|
||||||
|
padding-right: 18px;
|
||||||
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
.c1 {
|
.c1 {
|
||||||
|
|
|
@ -12,7 +12,11 @@ import ClusterContext from 'components/contexts/ClusterContext';
|
||||||
import PageLoader from 'components/common/PageLoader/PageLoader';
|
import PageLoader from 'components/common/PageLoader/PageLoader';
|
||||||
import Pagination from 'components/common/Pagination/Pagination';
|
import Pagination from 'components/common/Pagination/Pagination';
|
||||||
import ConfirmationModal from 'components/common/ConfirmationModal/ConfirmationModal';
|
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 TableHeaderCell from 'components/common/table/TableHeaderCell/TableHeaderCell';
|
||||||
import Search from 'components/common/Search/Search';
|
import Search from 'components/common/Search/Search';
|
||||||
import { PER_PAGE } from 'lib/constants';
|
import { PER_PAGE } from 'lib/constants';
|
||||||
|
@ -39,6 +43,7 @@ export interface TopicsListProps {
|
||||||
): void;
|
): void;
|
||||||
search: string;
|
search: string;
|
||||||
orderBy: TopicColumnsToSort | null;
|
orderBy: TopicColumnsToSort | null;
|
||||||
|
sortOrder: SortOrder;
|
||||||
setTopicsSearch(search: string): void;
|
setTopicsSearch(search: string): void;
|
||||||
setTopicsOrderBy(orderBy: TopicColumnsToSort | null): void;
|
setTopicsOrderBy(orderBy: TopicColumnsToSort | null): void;
|
||||||
}
|
}
|
||||||
|
@ -54,6 +59,7 @@ const List: React.FC<TopicsListProps> = ({
|
||||||
clearTopicsMessages,
|
clearTopicsMessages,
|
||||||
search,
|
search,
|
||||||
orderBy,
|
orderBy,
|
||||||
|
sortOrder,
|
||||||
setTopicsSearch,
|
setTopicsSearch,
|
||||||
setTopicsOrderBy,
|
setTopicsOrderBy,
|
||||||
}) => {
|
}) => {
|
||||||
|
@ -69,6 +75,7 @@ const List: React.FC<TopicsListProps> = ({
|
||||||
page,
|
page,
|
||||||
perPage,
|
perPage,
|
||||||
orderBy: orderBy || undefined,
|
orderBy: orderBy || undefined,
|
||||||
|
sortOrder,
|
||||||
search,
|
search,
|
||||||
showInternal,
|
showInternal,
|
||||||
});
|
});
|
||||||
|
@ -78,6 +85,7 @@ const List: React.FC<TopicsListProps> = ({
|
||||||
page,
|
page,
|
||||||
perPage,
|
perPage,
|
||||||
orderBy,
|
orderBy,
|
||||||
|
sortOrder,
|
||||||
search,
|
search,
|
||||||
showInternal,
|
showInternal,
|
||||||
]);
|
]);
|
||||||
|
@ -215,24 +223,32 @@ const List: React.FC<TopicsListProps> = ({
|
||||||
title="Topic Name"
|
title="Topic Name"
|
||||||
orderValue={TopicColumnsToSort.NAME}
|
orderValue={TopicColumnsToSort.NAME}
|
||||||
orderBy={orderBy}
|
orderBy={orderBy}
|
||||||
|
sortOrder={sortOrder}
|
||||||
handleOrderBy={setTopicsOrderBy}
|
handleOrderBy={setTopicsOrderBy}
|
||||||
/>
|
/>
|
||||||
<TableHeaderCell
|
<TableHeaderCell
|
||||||
title="Total Partitions"
|
title="Total Partitions"
|
||||||
orderValue={TopicColumnsToSort.TOTAL_PARTITIONS}
|
orderValue={TopicColumnsToSort.TOTAL_PARTITIONS}
|
||||||
orderBy={orderBy}
|
orderBy={orderBy}
|
||||||
|
sortOrder={sortOrder}
|
||||||
handleOrderBy={setTopicsOrderBy}
|
handleOrderBy={setTopicsOrderBy}
|
||||||
/>
|
/>
|
||||||
<TableHeaderCell
|
<TableHeaderCell
|
||||||
title="Out of sync replicas"
|
title="Out of sync replicas"
|
||||||
orderValue={TopicColumnsToSort.OUT_OF_SYNC_REPLICAS}
|
orderValue={TopicColumnsToSort.OUT_OF_SYNC_REPLICAS}
|
||||||
orderBy={orderBy}
|
orderBy={orderBy}
|
||||||
|
sortOrder={sortOrder}
|
||||||
handleOrderBy={setTopicsOrderBy}
|
handleOrderBy={setTopicsOrderBy}
|
||||||
/>
|
/>
|
||||||
<TableHeaderCell title="Replication Factor" />
|
<TableHeaderCell title="Replication Factor" />
|
||||||
<TableHeaderCell title="Number of messages" />
|
<TableHeaderCell title="Number of messages" />
|
||||||
<TableHeaderCell title="Size" />
|
<TableHeaderCell
|
||||||
<TableHeaderCell />
|
title="Size"
|
||||||
|
orderValue={TopicColumnsToSort.SIZE}
|
||||||
|
orderBy={orderBy}
|
||||||
|
sortOrder={sortOrder}
|
||||||
|
handleOrderBy={setTopicsOrderBy}
|
||||||
|
/>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
|
|
|
@ -15,6 +15,7 @@ import {
|
||||||
getTopicListTotalPages,
|
getTopicListTotalPages,
|
||||||
getTopicsSearch,
|
getTopicsSearch,
|
||||||
getTopicsOrderBy,
|
getTopicsOrderBy,
|
||||||
|
getTopicsSortOrder,
|
||||||
} from 'redux/reducers/topics/selectors';
|
} from 'redux/reducers/topics/selectors';
|
||||||
|
|
||||||
import List from './List';
|
import List from './List';
|
||||||
|
@ -25,6 +26,7 @@ const mapStateToProps = (state: RootState) => ({
|
||||||
totalPages: getTopicListTotalPages(state),
|
totalPages: getTopicListTotalPages(state),
|
||||||
search: getTopicsSearch(state),
|
search: getTopicsSearch(state),
|
||||||
orderBy: getTopicsOrderBy(state),
|
orderBy: getTopicsOrderBy(state),
|
||||||
|
sortOrder: getTopicsSortOrder(state),
|
||||||
});
|
});
|
||||||
|
|
||||||
const mapDispatchToProps = {
|
const mapDispatchToProps = {
|
||||||
|
|
|
@ -13,6 +13,7 @@ import { externalTopicPayload } from 'redux/reducers/topics/__test__/fixtures';
|
||||||
import { ConfirmationModalProps } from 'components/common/ConfirmationModal/ConfirmationModal';
|
import { ConfirmationModalProps } from 'components/common/ConfirmationModal/ConfirmationModal';
|
||||||
import theme from 'theme/theme';
|
import theme from 'theme/theme';
|
||||||
import { ThemeProvider } from 'styled-components';
|
import { ThemeProvider } from 'styled-components';
|
||||||
|
import { SortOrder } from 'generated-sources';
|
||||||
|
|
||||||
jest.mock(
|
jest.mock(
|
||||||
'components/common/ConfirmationModal/ConfirmationModal',
|
'components/common/ConfirmationModal/ConfirmationModal',
|
||||||
|
@ -33,6 +34,7 @@ describe('List', () => {
|
||||||
clearTopicMessages={jest.fn()}
|
clearTopicMessages={jest.fn()}
|
||||||
search=""
|
search=""
|
||||||
orderBy={null}
|
orderBy={null}
|
||||||
|
sortOrder={SortOrder.ASC}
|
||||||
setTopicsSearch={jest.fn()}
|
setTopicsSearch={jest.fn()}
|
||||||
setTopicsOrderBy={jest.fn()}
|
setTopicsOrderBy={jest.fn()}
|
||||||
{...props}
|
{...props}
|
||||||
|
@ -104,6 +106,7 @@ describe('List', () => {
|
||||||
expect(fetchTopicsList).toHaveBeenLastCalledWith({
|
expect(fetchTopicsList).toHaveBeenLastCalledWith({
|
||||||
search: '',
|
search: '',
|
||||||
showInternal: false,
|
showInternal: false,
|
||||||
|
sortOrder: SortOrder.ASC,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
|
import { SortOrder } from 'generated-sources';
|
||||||
import styled, { css } from 'styled-components';
|
import styled, { css } from 'styled-components';
|
||||||
|
|
||||||
interface TitleProps {
|
interface TitleProps {
|
||||||
isOrderable?: boolean;
|
isOrderable?: boolean;
|
||||||
isOrdered?: boolean;
|
isOrdered?: boolean;
|
||||||
|
sortOrder?: SortOrder;
|
||||||
}
|
}
|
||||||
|
|
||||||
const orderableMixin = css(
|
const orderableMixin = css(
|
||||||
|
@ -45,20 +47,48 @@ const orderableMixin = css(
|
||||||
`
|
`
|
||||||
);
|
);
|
||||||
|
|
||||||
const orderedMixin = css(
|
const ASCMixin = css(
|
||||||
({ theme: { table } }) => `
|
({ theme: { table } }) => `
|
||||||
color: ${table.th.color.active};
|
color: ${table.th.color.active};
|
||||||
&::before {
|
cursor: pointer;
|
||||||
border-bottom-color: ${table.th.color.active};
|
|
||||||
}
|
|
||||||
&::after {
|
&::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};
|
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>(
|
export const Title = styled.span<TitleProps>(
|
||||||
({ isOrderable, isOrdered, theme: { table } }) => css`
|
({ isOrderable, isOrdered, sortOrder, theme: { table } }) => css`
|
||||||
font-family: Inter, sans-serif;
|
font-family: Inter, sans-serif;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
|
@ -72,10 +102,14 @@ export const Title = styled.span<TitleProps>(
|
||||||
background: ${table.th.backgroundColor.normal};
|
background: ${table.th.backgroundColor.normal};
|
||||||
cursor: default;
|
cursor: default;
|
||||||
color: ${table.th.color.normal};
|
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 React from 'react';
|
||||||
import { TopicColumnsToSort } from 'generated-sources';
|
import { SortOrder, TopicColumnsToSort } from 'generated-sources';
|
||||||
import * as S from 'components/common/table/TableHeaderCell/TableHeaderCell.styled';
|
import * as S from 'components/common/table/TableHeaderCell/TableHeaderCell.styled';
|
||||||
|
|
||||||
export interface TableHeaderCellProps {
|
export interface TableHeaderCellProps {
|
||||||
|
@ -7,6 +7,7 @@ export interface TableHeaderCellProps {
|
||||||
previewText?: string;
|
previewText?: string;
|
||||||
onPreview?: () => void;
|
onPreview?: () => void;
|
||||||
orderBy?: TopicColumnsToSort | null;
|
orderBy?: TopicColumnsToSort | null;
|
||||||
|
sortOrder?: SortOrder;
|
||||||
orderValue?: TopicColumnsToSort | null;
|
orderValue?: TopicColumnsToSort | null;
|
||||||
handleOrderBy?: (orderBy: TopicColumnsToSort | null) => void;
|
handleOrderBy?: (orderBy: TopicColumnsToSort | null) => void;
|
||||||
}
|
}
|
||||||
|
@ -17,6 +18,7 @@ const TableHeaderCell: React.FC<TableHeaderCellProps> = (props) => {
|
||||||
previewText,
|
previewText,
|
||||||
onPreview,
|
onPreview,
|
||||||
orderBy,
|
orderBy,
|
||||||
|
sortOrder,
|
||||||
orderValue,
|
orderValue,
|
||||||
handleOrderBy,
|
handleOrderBy,
|
||||||
...restProps
|
...restProps
|
||||||
|
@ -38,6 +40,7 @@ const TableHeaderCell: React.FC<TableHeaderCellProps> = (props) => {
|
||||||
};
|
};
|
||||||
const orderableProps = isOrderable && {
|
const orderableProps = isOrderable && {
|
||||||
isOrderable,
|
isOrderable,
|
||||||
|
sortOrder,
|
||||||
onClick: handleOnClick,
|
onClick: handleOnClick,
|
||||||
onKeyDown: handleOnKeyDown,
|
onKeyDown: handleOnKeyDown,
|
||||||
role: 'button',
|
role: 'button',
|
||||||
|
|
|
@ -4,7 +4,7 @@ import { render } from 'lib/testHelpers';
|
||||||
import TableHeaderCell, {
|
import TableHeaderCell, {
|
||||||
TableHeaderCellProps,
|
TableHeaderCellProps,
|
||||||
} from 'components/common/table/TableHeaderCell/TableHeaderCell';
|
} from 'components/common/table/TableHeaderCell/TableHeaderCell';
|
||||||
import { TopicColumnsToSort } from 'generated-sources';
|
import { SortOrder, TopicColumnsToSort } from 'generated-sources';
|
||||||
import theme from 'theme/theme';
|
import theme from 'theme/theme';
|
||||||
import userEvent from '@testing-library/user-event';
|
import userEvent from '@testing-library/user-event';
|
||||||
|
|
||||||
|
@ -50,6 +50,7 @@ describe('TableHeaderCell', () => {
|
||||||
title: testTitle,
|
title: testTitle,
|
||||||
orderBy: TopicColumnsToSort.NAME,
|
orderBy: TopicColumnsToSort.NAME,
|
||||||
orderValue: TopicColumnsToSort.NAME,
|
orderValue: TopicColumnsToSort.NAME,
|
||||||
|
sortOrder: SortOrder.ASC,
|
||||||
handleOrderBy,
|
handleOrderBy,
|
||||||
});
|
});
|
||||||
const columnheader = screen.getByRole('columnheader');
|
const columnheader = screen.getByRole('columnheader');
|
||||||
|
@ -59,7 +60,6 @@ describe('TableHeaderCell', () => {
|
||||||
expect(title).toHaveStyle(`color: ${theme.table.th.color.active};`);
|
expect(title).toHaveStyle(`color: ${theme.table.th.color.active};`);
|
||||||
expect(title).toHaveStyle('cursor: pointer;');
|
expect(title).toHaveStyle('cursor: pointer;');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('renders click on title triggers handler', () => {
|
it('renders click on title triggers handler', () => {
|
||||||
setupComponent({
|
setupComponent({
|
||||||
title: testTitle,
|
title: testTitle,
|
||||||
|
@ -129,6 +129,7 @@ describe('TableHeaderCell', () => {
|
||||||
title: testTitle,
|
title: testTitle,
|
||||||
orderBy: TopicColumnsToSort.NAME,
|
orderBy: TopicColumnsToSort.NAME,
|
||||||
orderValue: TopicColumnsToSort.NAME,
|
orderValue: TopicColumnsToSort.NAME,
|
||||||
|
sortOrder: SortOrder.ASC,
|
||||||
handleOrderBy: jest.fn(),
|
handleOrderBy: jest.fn(),
|
||||||
});
|
});
|
||||||
const columnheader = screen.getByRole('columnheader');
|
const columnheader = screen.getByRole('columnheader');
|
||||||
|
|
|
@ -4,6 +4,7 @@ import {
|
||||||
NewSchemaSubject,
|
NewSchemaSubject,
|
||||||
SchemaSubject,
|
SchemaSubject,
|
||||||
SchemaType,
|
SchemaType,
|
||||||
|
SortOrder,
|
||||||
} from 'generated-sources';
|
} from 'generated-sources';
|
||||||
|
|
||||||
export const clusterStats: ClusterStats = {
|
export const clusterStats: ClusterStats = {
|
||||||
|
@ -42,5 +43,6 @@ export const mockTopicsState = {
|
||||||
messages: [],
|
messages: [],
|
||||||
search: '',
|
search: '',
|
||||||
orderBy: null,
|
orderBy: null,
|
||||||
|
sortOrder: SortOrder.ASC,
|
||||||
consumerGroups: [],
|
consumerGroups: [],
|
||||||
};
|
};
|
||||||
|
|
|
@ -9,6 +9,7 @@ import {
|
||||||
TopicMessage,
|
TopicMessage,
|
||||||
TopicMessageConsuming,
|
TopicMessageConsuming,
|
||||||
TopicMessageSchema,
|
TopicMessageSchema,
|
||||||
|
SortOrder,
|
||||||
} from 'generated-sources';
|
} from 'generated-sources';
|
||||||
|
|
||||||
export type TopicName = Topic['name'];
|
export type TopicName = Topic['name'];
|
||||||
|
@ -53,6 +54,7 @@ export interface TopicsState {
|
||||||
totalPages: number;
|
totalPages: number;
|
||||||
search: string;
|
search: string;
|
||||||
orderBy: TopicColumnsToSort | null;
|
orderBy: TopicColumnsToSort | null;
|
||||||
|
sortOrder: SortOrder;
|
||||||
consumerGroups: ConsumerGroup[];
|
consumerGroups: ConsumerGroup[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,8 @@
|
||||||
import { MessageSchemaSourceEnum, TopicColumnsToSort } from 'generated-sources';
|
import {
|
||||||
|
MessageSchemaSourceEnum,
|
||||||
|
SortOrder,
|
||||||
|
TopicColumnsToSort,
|
||||||
|
} from 'generated-sources';
|
||||||
import {
|
import {
|
||||||
deleteTopicAction,
|
deleteTopicAction,
|
||||||
clearMessagesTopicAction,
|
clearMessagesTopicAction,
|
||||||
|
@ -72,6 +76,7 @@ let state = {
|
||||||
totalPages: 1,
|
totalPages: 1,
|
||||||
search: '',
|
search: '',
|
||||||
orderBy: null,
|
orderBy: null,
|
||||||
|
sortOrder: SortOrder.ASC,
|
||||||
consumerGroups: [],
|
consumerGroups: [],
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -130,6 +135,7 @@ describe('topics reducer', () => {
|
||||||
totalPages: 1,
|
totalPages: 1,
|
||||||
search: '',
|
search: '',
|
||||||
orderBy: null,
|
orderBy: null,
|
||||||
|
sortOrder: SortOrder.ASC,
|
||||||
consumerGroups: [],
|
consumerGroups: [],
|
||||||
};
|
};
|
||||||
expect(
|
expect(
|
||||||
|
|
|
@ -2,7 +2,7 @@ import { Action, TopicsState } from 'redux/interfaces';
|
||||||
import { getType } from 'typesafe-actions';
|
import { getType } from 'typesafe-actions';
|
||||||
import * as actions from 'redux/actions';
|
import * as actions from 'redux/actions';
|
||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
import { TopicColumnsToSort } from 'generated-sources';
|
import { SortOrder, TopicColumnsToSort } from 'generated-sources';
|
||||||
|
|
||||||
export const initialState: TopicsState = {
|
export const initialState: TopicsState = {
|
||||||
byName: {},
|
byName: {},
|
||||||
|
@ -10,6 +10,7 @@ export const initialState: TopicsState = {
|
||||||
totalPages: 1,
|
totalPages: 1,
|
||||||
search: '',
|
search: '',
|
||||||
orderBy: TopicColumnsToSort.NAME,
|
orderBy: TopicColumnsToSort.NAME,
|
||||||
|
sortOrder: SortOrder.ASC,
|
||||||
consumerGroups: [],
|
consumerGroups: [],
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -41,6 +42,10 @@ const reducer = (state = initialState, action: Action): TopicsState => {
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
orderBy: action.payload,
|
orderBy: action.payload,
|
||||||
|
sortOrder:
|
||||||
|
state.orderBy === action.payload && state.sortOrder === SortOrder.ASC
|
||||||
|
? SortOrder.DESC
|
||||||
|
: SortOrder.ASC,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
case getType(actions.fetchTopicMessageSchemaAction.success): {
|
case getType(actions.fetchTopicMessageSchemaAction.success): {
|
||||||
|
|
|
@ -157,6 +157,11 @@ export const getTopicsOrderBy = createSelector(
|
||||||
(state) => state.orderBy
|
(state) => state.orderBy
|
||||||
);
|
);
|
||||||
|
|
||||||
|
export const getTopicsSortOrder = createSelector(
|
||||||
|
topicsState,
|
||||||
|
(state) => state.sortOrder
|
||||||
|
);
|
||||||
|
|
||||||
export const getIsTopicInternal = createSelector(
|
export const getIsTopicInternal = createSelector(
|
||||||
getTopicByName,
|
getTopicByName,
|
||||||
(topic) => !!topic?.internal
|
(topic) => !!topic?.internal
|
||||||
|
|
Loading…
Add table
Reference in a new issue