Topics sorted alphabetically (#1999)
* Added topics sorting and tests * Sorting topics logic moved to redux, test improved * LocaleCompare replaced with default sort function * Shadow fixed on overview topic page * Code samples fixed in InfoModal * String type removed * Unused import removed * Default JS sort method removed with lodash library sorting method
This commit is contained in:
parent
6d8c6cace0
commit
ad2966f31b
8 changed files with 64 additions and 23 deletions
|
@ -12,6 +12,7 @@ import {
|
||||||
getAreConnectorsFetching,
|
getAreConnectorsFetching,
|
||||||
getConnectorSearch,
|
getConnectorSearch,
|
||||||
getFailedConnectors,
|
getFailedConnectors,
|
||||||
|
getSortedTopics,
|
||||||
getFailedTasks,
|
getFailedTasks,
|
||||||
} from 'redux/reducers/connect/selectors';
|
} from 'redux/reducers/connect/selectors';
|
||||||
import List from 'components/Connect/List/List';
|
import List from 'components/Connect/List/List';
|
||||||
|
@ -21,6 +22,7 @@ const mapStateToProps = (state: RootState) => ({
|
||||||
areConnectorsFetching: getAreConnectorsFetching(state),
|
areConnectorsFetching: getAreConnectorsFetching(state),
|
||||||
connects: getConnects(state),
|
connects: getConnects(state),
|
||||||
failedConnectors: getFailedConnectors(state),
|
failedConnectors: getFailedConnectors(state),
|
||||||
|
sortedTopics: getSortedTopics(state),
|
||||||
failedTasks: getFailedTasks(state),
|
failedTasks: getFailedTasks(state),
|
||||||
connectors: getConnectors(state),
|
connectors: getConnectors(state),
|
||||||
search: getConnectorSearch(state),
|
search: getConnectorSearch(state),
|
||||||
|
|
|
@ -52,6 +52,14 @@ describe('Connectors ListItem', () => {
|
||||||
expect(screen.getAllByRole('cell')[6]).toHaveTextContent('2 of 2');
|
expect(screen.getAllByRole('cell')[6]).toHaveTextContent('2 of 2');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('topics tags are sorted', () => {
|
||||||
|
render(setupWrapper());
|
||||||
|
const getLink = screen.getAllByRole('link');
|
||||||
|
expect(getLink[1]).toHaveTextContent('a');
|
||||||
|
expect(getLink[2]).toHaveTextContent('b');
|
||||||
|
expect(getLink[3]).toHaveTextContent('c');
|
||||||
|
});
|
||||||
|
|
||||||
it('renders item with failed tasks', () => {
|
it('renders item with failed tasks', () => {
|
||||||
render(
|
render(
|
||||||
setupWrapper({
|
setupWrapper({
|
||||||
|
|
|
@ -125,6 +125,16 @@ export const InfoParagraph = styled.p`
|
||||||
color: ${({ theme }) => theme.table.td.color.normal};
|
color: ${({ theme }) => theme.table.td.color.normal};
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
export const InfoCodeSample = styled.pre`
|
||||||
|
background: #f5f5f5;
|
||||||
|
padding: 5px;
|
||||||
|
border: 1px solid #e1e1e1;
|
||||||
|
border-radius: 5px;
|
||||||
|
width: fit-content;
|
||||||
|
margin: 5px 20px;
|
||||||
|
color: #cc0f35;
|
||||||
|
`;
|
||||||
|
|
||||||
export const MessageFilterModal = styled.div`
|
export const MessageFilterModal = styled.div`
|
||||||
height: auto;
|
height: auto;
|
||||||
width: 560px;
|
width: 560px;
|
||||||
|
|
|
@ -26,32 +26,37 @@ const InfoModal: React.FC<InfoModalProps> = ({ toggleIsOpen }) => {
|
||||||
</S.InfoParagraph>
|
</S.InfoParagraph>
|
||||||
<ol aria-label="info-list">
|
<ol aria-label="info-list">
|
||||||
<S.ListItem>
|
<S.ListItem>
|
||||||
`keyAsText != null && keyAsText ~"([Gg])roovy"` - regex for
|
<code>keyAsText != null && keyAsText ~"([Gg])roovy"</code> -
|
||||||
key as a string
|
regex for key as a string
|
||||||
</S.ListItem>
|
</S.ListItem>
|
||||||
<S.ListItem>
|
<S.ListItem>
|
||||||
`value.name == "iS.ListItemax" && value.age > 30` - in
|
<code>
|
||||||
case value is json
|
value.name == "iS.ListItemax" && value.age > 30
|
||||||
|
</code>{' '}
|
||||||
|
- in case value is json
|
||||||
</S.ListItem>
|
</S.ListItem>
|
||||||
<S.ListItem>
|
<S.ListItem>
|
||||||
`value == null && valueAsText != null` - search for values that are
|
<code>value == null && valueAsText != null</code> - search for values
|
||||||
not nulls and are not json
|
that are not nulls and are not json
|
||||||
</S.ListItem>
|
</S.ListItem>
|
||||||
<S.ListItem>
|
<S.ListItem>
|
||||||
`headers.sentBy == "some system" &&
|
<code>
|
||||||
headers["sentAt"] == "2020-01-01"`
|
headers.sentBy == "some system" &&
|
||||||
|
headers["sentAt"] == "2020-01-01"
|
||||||
|
</code>
|
||||||
</S.ListItem>
|
</S.ListItem>
|
||||||
<S.ListItem>multiline filters are also allowed:</S.ListItem>
|
<S.ListItem>multiline filters are also allowed:</S.ListItem>
|
||||||
<S.InfoParagraph>
|
<S.InfoParagraph>
|
||||||
```
|
<S.InfoCodeSample>
|
||||||
<br />
|
<code>
|
||||||
def name = value.name
|
def name = value.name
|
||||||
<br />
|
<br />
|
||||||
def age = value.age
|
def age = value.age
|
||||||
<br />
|
<br />
|
||||||
name == "iliax" && age == 30
|
name == "iliax" && age == 30
|
||||||
<br />
|
<br />
|
||||||
```
|
</code>
|
||||||
|
</S.InfoCodeSample>
|
||||||
</S.InfoParagraph>
|
</S.InfoParagraph>
|
||||||
</ol>
|
</ol>
|
||||||
<S.ButtonContainer>
|
<S.ButtonContainer>
|
||||||
|
|
|
@ -21,7 +21,6 @@ export const IndicatorWrapper = styled.div`
|
||||||
align-items: flex-start;
|
align-items: flex-start;
|
||||||
padding: 12px 16px;
|
padding: 12px 16px;
|
||||||
box-shadow: 3px 3px 3px rgba(0, 0, 0, 0.08);
|
box-shadow: 3px 3px 3px rgba(0, 0, 0, 0.08);
|
||||||
margin: 0 0 3px 0;
|
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
@ -36,10 +35,11 @@ export const IndicatorTitle = styled.div`
|
||||||
|
|
||||||
export const IndicatorsWrapper = styled.div`
|
export const IndicatorsWrapper = styled.div`
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 1px;
|
gap: 2px;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
|
box-shadow: 3px 3px 3px rgba(0, 0, 0, 0.08);
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const SectionTitle = styled.h5`
|
export const SectionTitle = styled.h5`
|
||||||
|
|
|
@ -19,7 +19,7 @@ export const connectorsServerPayload = [
|
||||||
name: 'hdfs-source-connector',
|
name: 'hdfs-source-connector',
|
||||||
connector_class: 'FileStreamSource',
|
connector_class: 'FileStreamSource',
|
||||||
type: ConnectorType.SOURCE,
|
type: ConnectorType.SOURCE,
|
||||||
topics: ['test-topic'],
|
topics: ['a', 'b', 'c'],
|
||||||
status: {
|
status: {
|
||||||
state: ConnectorTaskStatus.RUNNING,
|
state: ConnectorTaskStatus.RUNNING,
|
||||||
workerId: 1,
|
workerId: 1,
|
||||||
|
@ -48,7 +48,7 @@ export const connectors: FullConnectorInfo[] = [
|
||||||
name: 'hdfs-source-connector',
|
name: 'hdfs-source-connector',
|
||||||
connectorClass: 'FileStreamSource',
|
connectorClass: 'FileStreamSource',
|
||||||
type: ConnectorType.SOURCE,
|
type: ConnectorType.SOURCE,
|
||||||
topics: ['test-topic'],
|
topics: ['a', 'b', 'c'],
|
||||||
status: {
|
status: {
|
||||||
state: ConnectorState.RUNNING,
|
state: ConnectorState.RUNNING,
|
||||||
},
|
},
|
||||||
|
@ -75,7 +75,7 @@ export const failedConnectors: FullConnectorInfo[] = [
|
||||||
name: 'hdfs-source-connector',
|
name: 'hdfs-source-connector',
|
||||||
connectorClass: 'FileStreamSource',
|
connectorClass: 'FileStreamSource',
|
||||||
type: ConnectorType.SOURCE,
|
type: ConnectorType.SOURCE,
|
||||||
topics: ['test-topic'],
|
topics: ['a', 'b', 'c'],
|
||||||
status: {
|
status: {
|
||||||
state: ConnectorState.FAILED,
|
state: ConnectorState.FAILED,
|
||||||
},
|
},
|
||||||
|
@ -87,7 +87,7 @@ export const failedConnectors: FullConnectorInfo[] = [
|
||||||
name: 'hdfs2-source-connector',
|
name: 'hdfs2-source-connector',
|
||||||
connectorClass: 'FileStreamSource',
|
connectorClass: 'FileStreamSource',
|
||||||
type: ConnectorType.SINK,
|
type: ConnectorType.SINK,
|
||||||
topics: ['test-topic'],
|
topics: ['a', 'b', 'c'],
|
||||||
status: {
|
status: {
|
||||||
state: ConnectorState.FAILED,
|
state: ConnectorState.FAILED,
|
||||||
},
|
},
|
||||||
|
|
|
@ -83,6 +83,17 @@ describe('Connect selectors', () => {
|
||||||
expect(selectors.getFailedTasks(store.getState())).toEqual(1);
|
expect(selectors.getFailedTasks(store.getState())).toEqual(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('returns sorted topics', () => {
|
||||||
|
store.dispatch({
|
||||||
|
type: fetchConnectors.fulfilled.type,
|
||||||
|
payload: { connectors },
|
||||||
|
});
|
||||||
|
const sortedTopics = selectors.getSortedTopics(store.getState());
|
||||||
|
if (sortedTopics[0] && sortedTopics[0].length > 1) {
|
||||||
|
expect(sortedTopics[0]).toEqual(['a', 'b', 'c']);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
it('returns connector', () => {
|
it('returns connector', () => {
|
||||||
store.dispatch({
|
store.dispatch({
|
||||||
type: fetchConnector.fulfilled.type,
|
type: fetchConnector.fulfilled.type,
|
||||||
|
|
|
@ -6,6 +6,7 @@ import {
|
||||||
ConnectorState,
|
ConnectorState,
|
||||||
FullConnectorInfo,
|
FullConnectorInfo,
|
||||||
} from 'generated-sources';
|
} from 'generated-sources';
|
||||||
|
import { sortBy } from 'lodash';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
deleteConnector,
|
deleteConnector,
|
||||||
|
@ -63,6 +64,10 @@ export const getFailedTasks = createSelector(connectState, ({ connectors }) => {
|
||||||
.reduce((acc: number, value: number) => acc + value, 0);
|
.reduce((acc: number, value: number) => acc + value, 0);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export const getSortedTopics = createSelector(connectState, ({ connectors }) =>
|
||||||
|
connectors.map(({ topics }) => sortBy(topics || []))
|
||||||
|
);
|
||||||
|
|
||||||
const getConnectorFetchingStatus = createFetchingSelector(
|
const getConnectorFetchingStatus = createFetchingSelector(
|
||||||
fetchConnector.typePrefix
|
fetchConnector.typePrefix
|
||||||
);
|
);
|
||||||
|
|
Loading…
Add table
Reference in a new issue