666: Adding new endpoint with corresponding service method. Also a… (#714)
* (#666): Adding new endpoint with corresponding service method. Also adding search box to kafka connect screen with consuming logic for added endopoint. * Applying feedback: reusing same endpoint and removing '/filtered' version
This commit is contained in:
parent
9770ad47af
commit
51646e786a
14 changed files with 175 additions and 13 deletions
|
@ -4,7 +4,7 @@ services:
|
||||||
|
|
||||||
kafka-ui:
|
kafka-ui:
|
||||||
container_name: kafka-ui
|
container_name: kafka-ui
|
||||||
image: provectuslabs/kafka-ui:master
|
image: kafka-ui:local
|
||||||
ports:
|
ports:
|
||||||
- 8080:8080
|
- 8080:8080
|
||||||
depends_on:
|
depends_on:
|
||||||
|
|
|
@ -63,12 +63,14 @@ public class KafkaConnectController implements KafkaConnectApi {
|
||||||
.map(ResponseEntity::ok);
|
.map(ResponseEntity::ok);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Mono<ResponseEntity<Flux<FullConnectorInfo>>> getAllConnectors(
|
public Mono<ResponseEntity<Flux<FullConnectorInfo>>> getAllConnectors(
|
||||||
String clusterName,
|
String clusterName,
|
||||||
|
String search,
|
||||||
ServerWebExchange exchange
|
ServerWebExchange exchange
|
||||||
) {
|
) {
|
||||||
return Mono.just(ResponseEntity.ok(kafkaConnectService.getAllConnectors(clusterName)));
|
return Mono.just(ResponseEntity.ok(kafkaConnectService.getAllConnectors(clusterName, search)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -23,10 +23,13 @@ import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
|
import java.util.function.Predicate;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.Stream;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.SneakyThrows;
|
import lombok.SneakyThrows;
|
||||||
import lombok.extern.log4j.Log4j2;
|
import lombok.extern.log4j.Log4j2;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.apache.commons.lang3.tuple.Pair;
|
import org.apache.commons.lang3.tuple.Pair;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import reactor.core.publisher.Flux;
|
import reactor.core.publisher.Flux;
|
||||||
|
@ -52,7 +55,7 @@ public class KafkaConnectService {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Flux<FullConnectorInfo> getAllConnectors(String clusterName) {
|
public Flux<FullConnectorInfo> getAllConnectors(final String clusterName, final String search) {
|
||||||
return getConnects(clusterName)
|
return getConnects(clusterName)
|
||||||
.flatMapMany(Function.identity())
|
.flatMapMany(Function.identity())
|
||||||
.flatMap(connect -> getConnectorNames(clusterName, connect))
|
.flatMap(connect -> getConnectorNames(clusterName, connect))
|
||||||
|
@ -87,7 +90,25 @@ public class KafkaConnectService {
|
||||||
.build()
|
.build()
|
||||||
);
|
);
|
||||||
})
|
})
|
||||||
.map(kafkaConnectMapper::fullConnectorInfoFromTuple);
|
.map(kafkaConnectMapper::fullConnectorInfoFromTuple)
|
||||||
|
.filter(matchesSearchTerm(search));
|
||||||
|
}
|
||||||
|
|
||||||
|
private Predicate<FullConnectorInfo> matchesSearchTerm(final String search) {
|
||||||
|
return (connector) -> getSearchValues(connector)
|
||||||
|
.anyMatch(value -> value.contains(
|
||||||
|
StringUtils.defaultString(
|
||||||
|
search,
|
||||||
|
StringUtils.EMPTY)
|
||||||
|
.toUpperCase()));
|
||||||
|
}
|
||||||
|
|
||||||
|
private Stream<String> getSearchValues(FullConnectorInfo fullConnectorInfo) {
|
||||||
|
return Stream.of(
|
||||||
|
fullConnectorInfo.getName(),
|
||||||
|
fullConnectorInfo.getStatus().getState().getValue(),
|
||||||
|
fullConnectorInfo.getType().getValue())
|
||||||
|
.map(String::toUpperCase);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Mono<ConnectorTopics> getConnectorTopics(String clusterName, String connectClusterName,
|
private Mono<ConnectorTopics> getConnectorTopics(String clusterName, String connectClusterName,
|
||||||
|
@ -118,7 +139,7 @@ public class KafkaConnectService {
|
||||||
public Flux<String> getConnectors(String clusterName, String connectName) {
|
public Flux<String> getConnectors(String clusterName, String connectName) {
|
||||||
return getConnectAddress(clusterName, connectName)
|
return getConnectAddress(clusterName, connectName)
|
||||||
.flatMapMany(connect ->
|
.flatMapMany(connect ->
|
||||||
KafkaConnectClients.withBaseUrl(connect).getConnectors()
|
KafkaConnectClients.withBaseUrl(connect).getConnectors(null)
|
||||||
.doOnError(log::error)
|
.doOnError(log::error)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -70,6 +70,73 @@ public class KafkaConnectServiceTests extends AbstractBaseTest {
|
||||||
.expectStatus().isOk();
|
.expectStatus().isOk();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldListAllConnectors() {
|
||||||
|
webTestClient.get()
|
||||||
|
.uri("/api/clusters/{clusterName}/connectors", LOCAL)
|
||||||
|
.exchange()
|
||||||
|
.expectStatus().isOk()
|
||||||
|
.expectBody()
|
||||||
|
.jsonPath(String.format("$[?(@.name == '%s')]", connectorName))
|
||||||
|
.exists();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldFilterByNameConnectors() {
|
||||||
|
webTestClient.get()
|
||||||
|
.uri(
|
||||||
|
"/api/clusters/{clusterName}/connectors?search={search}",
|
||||||
|
LOCAL,
|
||||||
|
connectorName.split("-")[1])
|
||||||
|
.exchange()
|
||||||
|
.expectStatus().isOk()
|
||||||
|
.expectBody()
|
||||||
|
.jsonPath(String.format("$[?(@.name == '%s')]", connectorName))
|
||||||
|
.exists();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldFilterByStatusConnectors() {
|
||||||
|
webTestClient.get()
|
||||||
|
.uri(
|
||||||
|
"/api/clusters/{clusterName}/connectors?search={search}",
|
||||||
|
LOCAL,
|
||||||
|
"running")
|
||||||
|
.exchange()
|
||||||
|
.expectStatus().isOk()
|
||||||
|
.expectBody()
|
||||||
|
.jsonPath(String.format("$[?(@.name == '%s')]", connectorName))
|
||||||
|
.exists();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldFilterByTypeConnectors() {
|
||||||
|
webTestClient.get()
|
||||||
|
.uri(
|
||||||
|
"/api/clusters/{clusterName}/connectors?search={search}",
|
||||||
|
LOCAL,
|
||||||
|
"sink")
|
||||||
|
.exchange()
|
||||||
|
.expectStatus().isOk()
|
||||||
|
.expectBody()
|
||||||
|
.jsonPath(String.format("$[?(@.name == '%s')]", connectorName))
|
||||||
|
.exists();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldNotFilterConnectors() {
|
||||||
|
webTestClient.get()
|
||||||
|
.uri(
|
||||||
|
"/api/clusters/{clusterName}/connectors?search={search}",
|
||||||
|
LOCAL,
|
||||||
|
"something-else")
|
||||||
|
.exchange()
|
||||||
|
.expectStatus().isOk()
|
||||||
|
.expectBody()
|
||||||
|
.jsonPath(String.format("$[?(@.name == '%s')]", connectorName))
|
||||||
|
.doesNotExist();
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void shouldListConnectors() {
|
public void shouldListConnectors() {
|
||||||
webTestClient.get()
|
webTestClient.get()
|
||||||
|
|
|
@ -20,6 +20,12 @@ paths:
|
||||||
- KafkaConnectClient
|
- KafkaConnectClient
|
||||||
summary: get all connectors from Kafka Connect service
|
summary: get all connectors from Kafka Connect service
|
||||||
operationId: getConnectors
|
operationId: getConnectors
|
||||||
|
parameters:
|
||||||
|
- name: search
|
||||||
|
in: query
|
||||||
|
required: false
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
responses:
|
responses:
|
||||||
200:
|
200:
|
||||||
description: OK
|
description: OK
|
||||||
|
|
|
@ -1040,7 +1040,7 @@ paths:
|
||||||
get:
|
get:
|
||||||
tags:
|
tags:
|
||||||
- Kafka Connect
|
- Kafka Connect
|
||||||
summary: get all kafka connectors
|
summary: get filtered kafka connectors
|
||||||
operationId: getAllConnectors
|
operationId: getAllConnectors
|
||||||
parameters:
|
parameters:
|
||||||
- name: clusterName
|
- name: clusterName
|
||||||
|
@ -1048,6 +1048,11 @@ paths:
|
||||||
required: true
|
required: true
|
||||||
schema:
|
schema:
|
||||||
type: string
|
type: string
|
||||||
|
- name: search
|
||||||
|
in: query
|
||||||
|
required: false
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
responses:
|
responses:
|
||||||
200:
|
200:
|
||||||
description: OK
|
description: OK
|
||||||
|
|
|
@ -1,12 +1,13 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Link, useParams } from 'react-router-dom';
|
import { Link, useParams } from 'react-router-dom';
|
||||||
import { Connect, FullConnectorInfo } from 'generated-sources';
|
import { Connect, FullConnectorInfo } from 'generated-sources';
|
||||||
import { ClusterName } from 'redux/interfaces';
|
import { ClusterName, ConnectorSearch } from 'redux/interfaces';
|
||||||
import { clusterConnectorNewPath } from 'lib/paths';
|
import { clusterConnectorNewPath } from 'lib/paths';
|
||||||
import ClusterContext from 'components/contexts/ClusterContext';
|
import ClusterContext from 'components/contexts/ClusterContext';
|
||||||
import Indicator from 'components/common/Dashboard/Indicator';
|
import Indicator from 'components/common/Dashboard/Indicator';
|
||||||
import MetricsWrapper from 'components/common/Dashboard/MetricsWrapper';
|
import MetricsWrapper from 'components/common/Dashboard/MetricsWrapper';
|
||||||
import PageLoader from 'components/common/PageLoader/PageLoader';
|
import PageLoader from 'components/common/PageLoader/PageLoader';
|
||||||
|
import Search from 'components/common/Search/Search';
|
||||||
|
|
||||||
import ListItem from './ListItem';
|
import ListItem from './ListItem';
|
||||||
|
|
||||||
|
@ -17,6 +18,8 @@ export interface ListProps {
|
||||||
connects: Connect[];
|
connects: Connect[];
|
||||||
fetchConnects(clusterName: ClusterName): void;
|
fetchConnects(clusterName: ClusterName): void;
|
||||||
fetchConnectors(clusterName: ClusterName): void;
|
fetchConnectors(clusterName: ClusterName): void;
|
||||||
|
search: string;
|
||||||
|
setConnectorSearch(value: ConnectorSearch): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const List: React.FC<ListProps> = ({
|
const List: React.FC<ListProps> = ({
|
||||||
|
@ -26,6 +29,8 @@ const List: React.FC<ListProps> = ({
|
||||||
areConnectorsFetching,
|
areConnectorsFetching,
|
||||||
fetchConnects,
|
fetchConnects,
|
||||||
fetchConnectors,
|
fetchConnectors,
|
||||||
|
search,
|
||||||
|
setConnectorSearch,
|
||||||
}) => {
|
}) => {
|
||||||
const { isReadOnly } = React.useContext(ClusterContext);
|
const { isReadOnly } = React.useContext(ClusterContext);
|
||||||
const { clusterName } = useParams<{ clusterName: string }>();
|
const { clusterName } = useParams<{ clusterName: string }>();
|
||||||
|
@ -35,6 +40,12 @@ const List: React.FC<ListProps> = ({
|
||||||
fetchConnectors(clusterName);
|
fetchConnectors(clusterName);
|
||||||
}, [fetchConnects, fetchConnectors, clusterName]);
|
}, [fetchConnects, fetchConnectors, clusterName]);
|
||||||
|
|
||||||
|
const handleSearch = (value: string) =>
|
||||||
|
setConnectorSearch({
|
||||||
|
clusterName,
|
||||||
|
search: value,
|
||||||
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<MetricsWrapper>
|
<MetricsWrapper>
|
||||||
|
@ -47,6 +58,14 @@ const List: React.FC<ListProps> = ({
|
||||||
{connects.length}
|
{connects.length}
|
||||||
</Indicator>
|
</Indicator>
|
||||||
|
|
||||||
|
<div className="column">
|
||||||
|
<Search
|
||||||
|
handleSearch={handleSearch}
|
||||||
|
placeholder="Search by Connect Name, Status or Type"
|
||||||
|
value={search}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
{!isReadOnly && (
|
{!isReadOnly && (
|
||||||
<div className="level-item level-right">
|
<div className="level-item level-right">
|
||||||
<Link
|
<Link
|
||||||
|
|
|
@ -3,12 +3,14 @@ import { RootState } from 'redux/interfaces';
|
||||||
import {
|
import {
|
||||||
fetchConnects,
|
fetchConnects,
|
||||||
fetchConnectors,
|
fetchConnectors,
|
||||||
|
setConnectorSearch,
|
||||||
} from 'redux/actions/thunks/connectors';
|
} from 'redux/actions/thunks/connectors';
|
||||||
import {
|
import {
|
||||||
getConnects,
|
getConnects,
|
||||||
getConnectors,
|
getConnectors,
|
||||||
getAreConnectsFetching,
|
getAreConnectsFetching,
|
||||||
getAreConnectorsFetching,
|
getAreConnectorsFetching,
|
||||||
|
getConnectorSearch,
|
||||||
} from 'redux/reducers/connect/selectors';
|
} from 'redux/reducers/connect/selectors';
|
||||||
import List from 'components/Connect/List/List';
|
import List from 'components/Connect/List/List';
|
||||||
|
|
||||||
|
@ -17,11 +19,13 @@ const mapStateToProps = (state: RootState) => ({
|
||||||
areConnectorsFetching: getAreConnectorsFetching(state),
|
areConnectorsFetching: getAreConnectorsFetching(state),
|
||||||
connects: getConnects(state),
|
connects: getConnects(state),
|
||||||
connectors: getConnectors(state),
|
connectors: getConnectors(state),
|
||||||
|
search: getConnectorSearch(state),
|
||||||
});
|
});
|
||||||
|
|
||||||
const mapDispatchToProps = {
|
const mapDispatchToProps = {
|
||||||
fetchConnects,
|
fetchConnects,
|
||||||
fetchConnectors,
|
fetchConnectors,
|
||||||
|
setConnectorSearch,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default connect(mapStateToProps, mapDispatchToProps)(List);
|
export default connect(mapStateToProps, mapDispatchToProps)(List);
|
||||||
|
|
|
@ -31,6 +31,7 @@ describe('Connectors List', () => {
|
||||||
describe('View', () => {
|
describe('View', () => {
|
||||||
const fetchConnects = jest.fn();
|
const fetchConnects = jest.fn();
|
||||||
const fetchConnectors = jest.fn();
|
const fetchConnectors = jest.fn();
|
||||||
|
const setConnectorSearch = jest.fn();
|
||||||
const setupComponent = (
|
const setupComponent = (
|
||||||
props: Partial<ListProps> = {},
|
props: Partial<ListProps> = {},
|
||||||
contextValue: ContextProps = initialValue
|
contextValue: ContextProps = initialValue
|
||||||
|
@ -44,6 +45,8 @@ describe('Connectors List', () => {
|
||||||
connects={[]}
|
connects={[]}
|
||||||
fetchConnects={fetchConnects}
|
fetchConnects={fetchConnects}
|
||||||
fetchConnectors={fetchConnectors}
|
fetchConnectors={fetchConnectors}
|
||||||
|
search=""
|
||||||
|
setConnectorSearch={setConnectorSearch}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
</ClusterContext.Provider>
|
</ClusterContext.Provider>
|
||||||
|
|
|
@ -59,7 +59,8 @@ describe('Thunks', () => {
|
||||||
it('creates GET_CONNECTORS__SUCCESS when fetching connectors', async () => {
|
it('creates GET_CONNECTORS__SUCCESS when fetching connectors', async () => {
|
||||||
fetchMock.getOnce(
|
fetchMock.getOnce(
|
||||||
`/api/clusters/${clusterName}/connectors`,
|
`/api/clusters/${clusterName}/connectors`,
|
||||||
connectorsServerPayload
|
connectorsServerPayload,
|
||||||
|
{ query: { search: '' } }
|
||||||
);
|
);
|
||||||
await store.dispatch(thunks.fetchConnectors(clusterName));
|
await store.dispatch(thunks.fetchConnectors(clusterName));
|
||||||
expect(store.getActions()).toEqual([
|
expect(store.getActions()).toEqual([
|
||||||
|
@ -71,9 +72,10 @@ describe('Thunks', () => {
|
||||||
it('creates GET_CONNECTORS__SUCCESS when fetching connectors in silent mode', async () => {
|
it('creates GET_CONNECTORS__SUCCESS when fetching connectors in silent mode', async () => {
|
||||||
fetchMock.getOnce(
|
fetchMock.getOnce(
|
||||||
`/api/clusters/${clusterName}/connectors`,
|
`/api/clusters/${clusterName}/connectors`,
|
||||||
connectorsServerPayload
|
connectorsServerPayload,
|
||||||
|
{ query: { search: '' } }
|
||||||
);
|
);
|
||||||
await store.dispatch(thunks.fetchConnectors(clusterName, true));
|
await store.dispatch(thunks.fetchConnectors(clusterName, '', true));
|
||||||
expect(store.getActions()).toEqual([
|
expect(store.getActions()).toEqual([
|
||||||
actions.fetchConnectorsAction.success({
|
actions.fetchConnectorsAction.success({
|
||||||
...store.getState().connect,
|
...store.getState().connect,
|
||||||
|
@ -83,7 +85,9 @@ describe('Thunks', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('creates GET_CONNECTORS__FAILURE', async () => {
|
it('creates GET_CONNECTORS__FAILURE', async () => {
|
||||||
fetchMock.getOnce(`/api/clusters/${clusterName}/connectors`, 404);
|
fetchMock.getOnce(`/api/clusters/${clusterName}/connectors`, 404, {
|
||||||
|
query: { search: '' },
|
||||||
|
});
|
||||||
await store.dispatch(thunks.fetchConnectors(clusterName));
|
await store.dispatch(thunks.fetchConnectors(clusterName));
|
||||||
expect(store.getActions()).toEqual([
|
expect(store.getActions()).toEqual([
|
||||||
actions.fetchConnectorsAction.request(),
|
actions.fetchConnectorsAction.request(),
|
||||||
|
|
|
@ -12,6 +12,7 @@ import {
|
||||||
ConnectName,
|
ConnectName,
|
||||||
ConnectorConfig,
|
ConnectorConfig,
|
||||||
ConnectorName,
|
ConnectorName,
|
||||||
|
ConnectorSearch,
|
||||||
FailurePayload,
|
FailurePayload,
|
||||||
PromiseThunkResult,
|
PromiseThunkResult,
|
||||||
} from 'redux/interfaces';
|
} from 'redux/interfaces';
|
||||||
|
@ -39,12 +40,17 @@ export const fetchConnects =
|
||||||
};
|
};
|
||||||
|
|
||||||
export const fetchConnectors =
|
export const fetchConnectors =
|
||||||
(clusterName: ClusterName, silent = false): PromiseThunkResult<void> =>
|
(
|
||||||
|
clusterName: ClusterName,
|
||||||
|
search = '',
|
||||||
|
silent = false
|
||||||
|
): PromiseThunkResult<void> =>
|
||||||
async (dispatch) => {
|
async (dispatch) => {
|
||||||
if (!silent) dispatch(actions.fetchConnectorsAction.request());
|
if (!silent) dispatch(actions.fetchConnectorsAction.request());
|
||||||
try {
|
try {
|
||||||
const connectors = await kafkaConnectApiClient.getAllConnectors({
|
const connectors = await kafkaConnectApiClient.getAllConnectors({
|
||||||
clusterName,
|
clusterName,
|
||||||
|
search,
|
||||||
});
|
});
|
||||||
dispatch(actions.fetchConnectorsAction.success({ connectors }));
|
dispatch(actions.fetchConnectorsAction.success({ connectors }));
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
@ -127,7 +133,7 @@ export const deleteConnector =
|
||||||
connectorName,
|
connectorName,
|
||||||
});
|
});
|
||||||
dispatch(actions.deleteConnectorAction.success({ connectorName }));
|
dispatch(actions.deleteConnectorAction.success({ connectorName }));
|
||||||
dispatch(fetchConnectors(clusterName, true));
|
dispatch(fetchConnectors(clusterName, '', true));
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
const response = await getResponse(error);
|
const response = await getResponse(error);
|
||||||
const alert: FailurePayload = {
|
const alert: FailurePayload = {
|
||||||
|
@ -338,3 +344,14 @@ export const updateConnectorConfig =
|
||||||
}
|
}
|
||||||
return undefined;
|
return undefined;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const setConnectorSearch = (
|
||||||
|
connectorSearch: ConnectorSearch,
|
||||||
|
silent = false
|
||||||
|
): PromiseThunkResult<void> => {
|
||||||
|
return fetchConnectors(
|
||||||
|
connectorSearch.clusterName,
|
||||||
|
connectorSearch.search,
|
||||||
|
silent
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
import { Connect, Connector, FullConnectorInfo, Task } from 'generated-sources';
|
import { Connect, Connector, FullConnectorInfo, Task } from 'generated-sources';
|
||||||
|
|
||||||
|
import { ClusterName } from './cluster';
|
||||||
|
|
||||||
export type ConnectName = Connect['name'];
|
export type ConnectName = Connect['name'];
|
||||||
export type ConnectorName = Connector['name'];
|
export type ConnectorName = Connector['name'];
|
||||||
export type ConnectorConfig = Connector['config'];
|
export type ConnectorConfig = Connector['config'];
|
||||||
|
@ -12,4 +14,10 @@ export interface ConnectState {
|
||||||
tasks: Task[];
|
tasks: Task[];
|
||||||
config: ConnectorConfig | null;
|
config: ConnectorConfig | null;
|
||||||
};
|
};
|
||||||
|
search: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ConnectorSearch {
|
||||||
|
clusterName: ClusterName;
|
||||||
|
search: string;
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,7 @@ export const initialState: ConnectState = {
|
||||||
tasks: [],
|
tasks: [],
|
||||||
config: null,
|
config: null,
|
||||||
},
|
},
|
||||||
|
search: '',
|
||||||
};
|
};
|
||||||
|
|
||||||
const reducer = (state = initialState, action: Action): ConnectState => {
|
const reducer = (state = initialState, action: Action): ConnectState => {
|
||||||
|
|
|
@ -119,3 +119,8 @@ export const getConnectorConfig = createSelector(
|
||||||
getCurrentConnector,
|
getCurrentConnector,
|
||||||
({ config }) => config
|
({ config }) => config
|
||||||
);
|
);
|
||||||
|
|
||||||
|
export const getConnectorSearch = createSelector(
|
||||||
|
connectState,
|
||||||
|
(state) => state.search
|
||||||
|
);
|
||||||
|
|
Loading…
Add table
Reference in a new issue