Skip to content

Commit d3f740e

Browse files
author
Leshe4ka
committed
topics connectors
1 parent a23fec3 commit d3f740e

File tree

9 files changed

+92
-4
lines changed

9 files changed

+92
-4
lines changed

frontend/src/components/Connect/List/ConnectorsTable/ConnectorsTable.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { FullConnectorInfo } from 'generated-sources';
33
import Table from 'components/common/NewTable';
44
import { useLocalStoragePersister } from 'components/common/NewTable/ColumnResizer/lib';
55
import { useQueryPersister } from 'components/common/NewTable/ColumnFilter';
6+
import { VisibilityState } from '@tanstack/react-table';
67

78
import { connectorsColumns } from './connectorsColumns/columns';
89

@@ -12,11 +13,13 @@ const setRowId = (originalRow: FullConnectorInfo) =>
1213
type ConnectorsTableProps = {
1314
connectors: FullConnectorInfo[];
1415
columnSizingPersistKey?: string;
16+
columnVisibility?: VisibilityState;
1517
};
1618

1719
export const ConnectorsTable = ({
1820
connectors,
1921
columnSizingPersistKey = 'KafkaConnect',
22+
columnVisibility,
2023
}: ConnectorsTableProps) => {
2124
const filterPersister = useQueryPersister(connectorsColumns);
2225
const columnSizingPersister = useLocalStoragePersister(
@@ -33,6 +36,7 @@ export const ConnectorsTable = ({
3336
emptyMessage="No connectors found"
3437
setRowId={setRowId}
3538
filterPersister={filterPersister}
39+
columnVisibility={columnVisibility}
3640
/>
3741
);
3842
};

frontend/src/components/Connect/List/ConnectorsTable/connectorsColumns/cells/ActionsCell.tsx

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import {
77
ResourceType,
88
} from 'generated-sources';
99
import { CellContext } from '@tanstack/react-table';
10-
import { ClusterNameRoute } from 'lib/paths';
10+
import { RouteParamsClusterTopic } from 'lib/paths';
1111
import useAppParams from 'lib/hooks/useAppParams';
1212
import { Dropdown } from 'components/common/Dropdown';
1313
import {
@@ -24,7 +24,7 @@ const ActionsCell: React.FC<CellContext<FullConnectorInfo, unknown>> = ({
2424
row,
2525
}) => {
2626
const { connect, name, status } = row.original;
27-
const { clusterName } = useAppParams<ClusterNameRoute>();
27+
const { clusterName, topicName } = useAppParams<RouteParamsClusterTopic>();
2828
const { isReadOnly } = useContext(ClusterContext);
2929
const mutationsNumber = useIsMutating();
3030
const isMutating = mutationsNumber > 0;
@@ -33,16 +33,19 @@ const ActionsCell: React.FC<CellContext<FullConnectorInfo, unknown>> = ({
3333
clusterName,
3434
connectName: connect,
3535
connectorName: name,
36+
topicName,
3637
});
3738
const stateMutation = useUpdateConnectorState({
3839
clusterName,
3940
connectName: connect,
4041
connectorName: name,
42+
topicName,
4143
});
4244
const resetConnectorOffsetsMutation = useResetConnectorOffsets({
4345
clusterName,
4446
connectName: connect,
4547
connectorName: name,
48+
topicName,
4649
});
4750
const handleDelete = () => {
4851
confirm(
@@ -54,7 +57,7 @@ const ActionsCell: React.FC<CellContext<FullConnectorInfo, unknown>> = ({
5457
}
5558
);
5659
};
57-
// const stateMutation = useUpdateConnectorState(routerProps);
60+
5861
const resumeConnectorHandler = () =>
5962
stateMutation.mutateAsync(ConnectorAction.RESUME);
6063
const restartConnectorHandler = () =>
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import React from 'react';
2+
import { FullConnectorInfo } from 'generated-sources';
3+
import { ConnectorsTable } from 'components/Connect/List/ConnectorsTable/ConnectorsTable';
4+
5+
type ConnectorsProps = {
6+
connectors: FullConnectorInfo[];
7+
};
8+
9+
const Connectors: React.FC<ConnectorsProps> = ({ connectors }) => (
10+
<ConnectorsTable
11+
columnVisibility={{ topics: false }}
12+
connectors={connectors}
13+
columnSizingPersistKey="topic-connectors"
14+
/>
15+
);
16+
17+
export default Connectors;

frontend/src/components/Topics/Topic/Topic.tsx

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import React, { Suspense } from 'react';
22
import { NavLink, Route, Routes, useNavigate } from 'react-router-dom';
33
import {
4+
clusterTopicConnectorsRelativePath,
45
clusterTopicConsumerGroupsRelativePath,
56
clusterTopicEditRelativePath,
67
clusterTopicMessagesRelativePath,
@@ -22,6 +23,7 @@ import {
2223
useClearTopicMessages,
2324
useDeleteTopic,
2425
useRecreateTopic,
26+
useTopicConnectors,
2527
useTopicDetails,
2628
} from 'lib/hooks/api/topics';
2729
import {
@@ -43,6 +45,7 @@ import Settings from './Settings/Settings';
4345
import TopicConsumerGroups from './ConsumerGroups/TopicConsumerGroups';
4446
import Statistics from './Statistics/Statistics';
4547
import Edit from './Edit/Edit';
48+
import Connectors from './Connectors/Connectors';
4649
import SendMessage from './SendMessage/SendMessage';
4750

4851
const Topic: React.FC = () => {
@@ -70,6 +73,10 @@ const Topic: React.FC = () => {
7073
const deleteTopic = useDeleteTopic(clusterName);
7174
const recreateTopic = useRecreateTopic({ clusterName, topicName });
7275
const { data } = useTopicDetails({ clusterName, topicName });
76+
const { data: connectors = [] } = useTopicConnectors({
77+
clusterName,
78+
topicName,
79+
});
7380

7481
const { isReadOnly, isTopicDeletionAllowed } =
7582
React.useContext(ClusterContext);
@@ -84,6 +91,7 @@ const Topic: React.FC = () => {
8491
await clearMessages.mutateAsync(topicName);
8592
};
8693
const canCleanup = data?.cleanUpPolicy === CleanUpPolicy.DELETE;
94+
const isConnectorsAvailable = connectors.length > 0;
8795

8896
return (
8997
<>
@@ -225,6 +233,19 @@ const Topic: React.FC = () => {
225233
>
226234
Statistics
227235
</ActionNavLink>
236+
{isConnectorsAvailable && (
237+
<ActionNavLink
238+
to={clusterTopicConnectorsRelativePath}
239+
className={({ isActive }) => (isActive ? 'is-active' : '')}
240+
permission={{
241+
resource: ResourceType.TOPIC,
242+
action: Action.ANALYSIS_VIEW,
243+
value: topicName,
244+
}}
245+
>
246+
Connectors
247+
</ActionNavLink>
248+
)}
228249
</Navbar>
229250
<TopicActionsProvider openSidebarWithMessage={openSidebarWithMessage}>
230251
<Suspense fallback={<PageLoader />}>
@@ -246,6 +267,12 @@ const Topic: React.FC = () => {
246267
path={clusterTopicStatisticsRelativePath}
247268
element={<Statistics />}
248269
/>
270+
{isConnectorsAvailable && (
271+
<Route
272+
path={clusterTopicConnectorsRelativePath}
273+
element={<Connectors connectors={connectors} />}
274+
/>
275+
)}
249276
<Route path={clusterTopicEditRelativePath} element={<Edit />} />
250277
</Routes>
251278
</Suspense>

frontend/src/components/Topics/Topic/__test__/Topic.spec.tsx

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import {
2121
useDeleteTopic,
2222
useRecreateTopic,
2323
useTopicDetails,
24+
useTopicConnectors,
2425
} from 'lib/hooks/api/topics';
2526

2627
const mockNavigate = jest.fn();
@@ -33,6 +34,7 @@ jest.mock('lib/hooks/api/topics', () => ({
3334
useDeleteTopic: jest.fn(),
3435
useRecreateTopic: jest.fn(),
3536
useClearTopicMessages: jest.fn(),
37+
useTopicConnectors: jest.fn(),
3638
}));
3739

3840
const clearTopicMessages = jest.fn();
@@ -98,6 +100,9 @@ describe('Details', () => {
98100
(useClearTopicMessages as jest.Mock).mockImplementation(() => ({
99101
mutateAsync: clearTopicMessages,
100102
}));
103+
(useTopicConnectors as jest.Mock).mockImplementation(() => ({
104+
data: [],
105+
}));
101106
});
102107
describe('Action Bar', () => {
103108
describe('when it has readonly flag', () => {
@@ -132,7 +137,7 @@ describe('Details', () => {
132137

133138
describe('when clear messages modal is open', () => {
134139
beforeEach(async () => {
135-
await renderComponent();
140+
renderComponent();
136141
const confirmButton = screen.getAllByText('Clear messages')[0];
137142
await userEvent.click(confirmButton);
138143
});

frontend/src/components/common/NewTable/Table.tsx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import type {
66
PaginationState,
77
Row,
88
SortingState,
9+
VisibilityState,
910
} from '@tanstack/react-table';
1011
import {
1112
flexRender,
@@ -61,6 +62,9 @@ export interface TableProps<TData> {
6162
filterPersister?: Persister;
6263
resetPaginationOnFilter?: boolean;
6364

65+
// Columns visibility
66+
columnVisibility?: VisibilityState;
67+
6468
// Placeholder for empty table
6569
emptyMessage?: React.ReactNode;
6670

@@ -158,6 +162,7 @@ function Table<TData>({
158162
setRowId,
159163
filterPersister,
160164
resetPaginationOnFilter = true,
165+
columnVisibility,
161166
}: TableProps<TData>) {
162167
const [searchParams, setSearchParams] = useSearchParams();
163168
const location = useLocation();
@@ -209,6 +214,7 @@ function Table<TData>({
209214
columnFilters: filterPersister?.getPrevState() ?? [],
210215
rowSelection,
211216
columnSizing: columnSizingPersister?.columnSizing ?? {},
217+
columnVisibility,
212218
},
213219
getRowId: (originalRow, index) => {
214220
if (setRowId) {

frontend/src/lib/hooks/api/kafkaConnect.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,17 @@ import {
33
Connector,
44
ConnectorAction,
55
NewConnector,
6+
Topic,
67
} from 'generated-sources';
78
import { kafkaConnectApiClient as api } from 'lib/api';
89
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
910
import { ClusterName } from 'lib/interfaces/cluster';
1011
import { showSuccessAlert } from 'lib/errorHandling';
12+
import { topicKeys } from 'lib/hooks/api/topics';
1113

1214
interface UseConnectorProps {
1315
clusterName: ClusterName;
16+
topicName?: Topic['name'];
1417
connectName: Connect['name'];
1518
connectorName: Connector['name'];
1619
}
@@ -102,6 +105,13 @@ export function useUpdateConnectorState(props: UseConnectorProps) {
102105
Promise.all([
103106
client.invalidateQueries(connectorsKey(props.clusterName)),
104107
client.invalidateQueries(connectorKey(props)),
108+
props.topicName &&
109+
client.invalidateQueries(
110+
topicKeys.connectors({
111+
clusterName: props.clusterName,
112+
topicName: props.topicName,
113+
})
114+
),
105115
]),
106116
}
107117
);

frontend/src/lib/hooks/api/topics.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ import {
1919
TopicCreation,
2020
TopicDetails,
2121
TopicUpdate,
22+
GetTopicConnectorsRequest,
23+
FullConnectorInfo,
2224
} from 'generated-sources';
2325
import { showServerError, showSuccessAlert } from 'lib/errorHandling';
2426
import { ClusterName } from 'lib/interfaces/cluster';
@@ -45,6 +47,8 @@ export const topicKeys = {
4547
[...topicKeys.details(props), 'consumerGroups'] as const,
4648
statistics: (props: GetTopicDetailsRequest) =>
4749
[...topicKeys.details(props), 'statistics'] as const,
50+
connectors: (props: GetTopicConnectorsRequest) =>
51+
[...topicKeys.details(props), 'connectors'] as const,
4852
};
4953

5054
export function useTopics(props: GetTopicsRequest) {
@@ -81,6 +85,17 @@ export function useTopicConsumerGroups(props: GetTopicDetailsRequest) {
8185
);
8286
}
8387

88+
export function useTopicConnectors(
89+
props: GetTopicConnectorsRequest,
90+
queryOptions?: UseQueryOptions<FullConnectorInfo[]>
91+
) {
92+
return useQuery<FullConnectorInfo[]>(
93+
topicKeys.connectors(props),
94+
() => api.getTopicConnectors(props),
95+
queryOptions
96+
);
97+
}
98+
8499
const topicReducer = (
85100
result: TopicFormFormattedParams,
86101
customParam: TopicConfig

frontend/src/lib/paths.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,7 @@ export const clusterTopicSettingsRelativePath = 'settings';
156156
export const clusterTopicMessagesRelativePath = 'messages';
157157
export const clusterTopicConsumerGroupsRelativePath = 'consumer-groups';
158158
export const clusterTopicStatisticsRelativePath = 'statistics';
159+
export const clusterTopicConnectorsRelativePath = 'connectors';
159160
export const clusterTopicEditRelativePath = 'edit';
160161
export const clusterTopicPath = (
161162
clusterName: ClusterName = RouteParams.clusterName,

0 commit comments

Comments
 (0)