Skip to content

Commit 9f37767

Browse files
committed
FE: Clusters as separated page
1 parent 705ef75 commit 9f37767

File tree

17 files changed

+390
-2
lines changed

17 files changed

+390
-2
lines changed

frontend/src/components/ClusterPage/ClusterPage.tsx

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import {
1414
clusterConfigRelativePath,
1515
getNonExactPath,
1616
clusterAclRelativePath,
17+
kafkaConnectsPaths,
1718
} from 'lib/paths';
1819
import ClusterContext from 'components/contexts/ClusterContext';
1920
import PageLoader from 'components/common/PageLoader/PageLoader';
@@ -24,6 +25,9 @@ const Brokers = React.lazy(() => import('components/Brokers/Brokers'));
2425
const Topics = React.lazy(() => import('components/Topics/Topics'));
2526
const Schemas = React.lazy(() => import('components/Schemas/Schemas'));
2627
const Connect = React.lazy(() => import('components/Connect/Connect'));
28+
const KafkaConnectClusters = React.lazy(
29+
() => import('components/KafkaConnectClustersPage/KafkaConnectClustersPage')
30+
);
2731
const KsqlDb = React.lazy(() => import('components/KsqlDb/KsqlDb'));
2832
const ClusterConfigPage = React.lazy(
2933
() => import('components/ClusterPage/ClusterConfigPage')
@@ -88,6 +92,12 @@ const ClusterPage: React.FC = () => {
8892
element={<Connect />}
8993
/>
9094
)}
95+
{contextValue.hasKafkaConnectConfigured && (
96+
<Route
97+
path={getNonExactPath(kafkaConnectsPaths)}
98+
element={<KafkaConnectClusters />}
99+
/>
100+
)}
91101
{contextValue.hasKafkaConnectConfigured && (
92102
<Route
93103
path={getNonExactPath(clusterConnectorsRelativePath)}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import React from 'react';
2+
import ResourcePageHeading from 'components/common/ResourcePageHeading/ResourcePageHeading';
3+
import { Connect } from 'generated-sources';
4+
5+
import List from './ui/List/List';
6+
import Statistics from './ui/Statistics/Statistics';
7+
8+
const connects: Connect[] = [
9+
{
10+
name: 'local',
11+
connectorsCount: 5,
12+
failedConnectorsCount: 0,
13+
tasksCount: 5,
14+
failedTasksCount: 0,
15+
},
16+
{
17+
name: 'Cluster name 2',
18+
connectorsCount: 5,
19+
failedConnectorsCount: 1,
20+
tasksCount: 6,
21+
failedTasksCount: 3,
22+
},
23+
];
24+
25+
const KafkaConnectClustersPage = () => {
26+
return (
27+
<div>
28+
<ResourcePageHeading text="Kafka connect clusters" />
29+
<Statistics connects={connects} />
30+
<List connects={connects} />
31+
</div>
32+
);
33+
};
34+
35+
export default KafkaConnectClustersPage;
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import AlertBadge from 'components/common/AlertBadge/AlertBadge';
2+
import { Connect } from 'generated-sources';
3+
import React from 'react';
4+
5+
type Props = { connect: Connect };
6+
const ConnectorsCell = ({ connect }: Props) => {
7+
const count = connect.connectorsCount ?? 0;
8+
const failedCount = connect.failedConnectorsCount ?? 0;
9+
const text = `${count - failedCount}/${count}`;
10+
11+
if (failedCount > 0) {
12+
return (
13+
<AlertBadge>
14+
<AlertBadge.Content content={text} />
15+
<AlertBadge.Icon />
16+
</AlertBadge>
17+
);
18+
}
19+
20+
return text;
21+
};
22+
export default ConnectorsCell;
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import { CellContext } from '@tanstack/react-table';
2+
import { Connect } from 'generated-sources';
3+
import React from 'react';
4+
5+
type Props = CellContext<Connect, string>;
6+
const NameCell = ({ getValue }: Props) => {
7+
return <div>{getValue()}</div>;
8+
};
9+
export default NameCell;
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import AlertBadge from 'components/common/AlertBadge/AlertBadge';
2+
import { Connect } from 'generated-sources';
3+
import React from 'react';
4+
5+
type Props = { connect: Connect };
6+
const TasksCell = ({ connect }: Props) => {
7+
const count = connect.tasksCount ?? 0;
8+
const failedCount = connect.failedTasksCount ?? 0;
9+
const text = `${count - failedCount}/${count}`;
10+
11+
if (failedCount > 0) {
12+
return (
13+
<AlertBadge>
14+
<AlertBadge.Content content={text} />
15+
<AlertBadge.Icon />
16+
</AlertBadge>
17+
);
18+
}
19+
20+
return (
21+
<div>
22+
{count - failedCount}/{count}
23+
</div>
24+
);
25+
};
26+
export default TasksCell;
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import React from 'react';
2+
import { Connect } from 'generated-sources';
3+
import Table from 'components/common/NewTable';
4+
import useAppParams from 'lib/hooks/useAppParams';
5+
import { ClusterName } from 'lib/interfaces/cluster';
6+
import { useNavigate } from 'react-router-dom';
7+
import { clusterConnectorsPath } from 'lib/paths';
8+
import { createColumnHelper } from '@tanstack/react-table';
9+
10+
import ConnectorsCell from './Cells/ConnectorsCell';
11+
import NameCell from './Cells/NameCell';
12+
import TasksCell from './Cells/TasksCell';
13+
14+
const helper = createColumnHelper<Connect>();
15+
export const columns = [
16+
helper.accessor('name', { cell: NameCell, size: 600 }),
17+
helper.display({
18+
header: 'Connectors',
19+
id: 'connectors',
20+
cell: (props) => <ConnectorsCell connect={props.row.original} />,
21+
size: 100,
22+
}),
23+
helper.display({
24+
header: 'Running tasks',
25+
id: 'tasks',
26+
cell: (props) => <TasksCell connect={props.row.original} />,
27+
size: 100,
28+
}),
29+
];
30+
31+
interface Props {
32+
connects: Connect[];
33+
}
34+
const List = ({ connects }: Props) => {
35+
const navigate = useNavigate();
36+
const { clusterName } = useAppParams<{ clusterName: ClusterName }>();
37+
38+
return (
39+
<Table
40+
data={connects}
41+
columns={columns}
42+
onRowClick={({ original: { name } }) => {
43+
navigate(`${clusterConnectorsPath(clusterName)}?connect=${name}`);
44+
}}
45+
emptyMessage="No kafka connect clusters"
46+
/>
47+
);
48+
};
49+
50+
export default List;
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import styled from 'styled-components';
2+
3+
export const Container = styled.div`
4+
width: 216px;
5+
height: 68px;
6+
border-radius: 12px;
7+
padding: 12px 16px;
8+
background: ${({ theme }) => theme.kafkaConectClusters.statistic.background};
9+
`;
10+
11+
export const Header = styled.span`
12+
font-weight: 500;
13+
font-size: 12px;
14+
line-height: 16px;
15+
color: ${({ theme }) => theme.kafkaConectClusters.statistic.header.color};
16+
`;
17+
export const Footer = styled.div`
18+
display: flex;
19+
justify-content: space-between;
20+
`;
21+
22+
export const Count = styled.div`
23+
font-weight: 500;
24+
font-size: 16px;
25+
line-height: 24px;
26+
color: ${({ theme }) => theme.kafkaConectClusters.statistic.count.color};
27+
`;
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import React from 'react';
2+
import AlertBadge from 'components/common/AlertBadge/AlertBadge';
3+
4+
import * as S from './Statistic.styled';
5+
6+
type Props = {
7+
title: string;
8+
count: number;
9+
warningCount?: number;
10+
};
11+
const Statistic = ({ title, count, warningCount }: Props) => {
12+
return (
13+
<S.Container>
14+
<S.Header>{title}</S.Header>
15+
<S.Footer>
16+
<S.Count>{count}</S.Count>
17+
{warningCount && (
18+
<AlertBadge>
19+
<AlertBadge.Icon />
20+
<AlertBadge.Content content={warningCount} />
21+
</AlertBadge>
22+
)}
23+
</S.Footer>
24+
</S.Container>
25+
);
26+
};
27+
28+
export default Statistic;
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import styled from 'styled-components';
2+
3+
export const Container = styled.div`
4+
padding: 16px;
5+
display: flex;
6+
gap: 4px;
7+
background: ${({ theme }) => theme.kafkaConectClusters.statistics.background};
8+
`;
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import React, { useMemo } from 'react';
2+
import { Connect } from 'generated-sources';
3+
4+
import * as S from './Statistics.styled';
5+
import { computeStatistic } from './models/computeStatistics';
6+
import Statistic from './Statistic/Statistic';
7+
8+
type Props = { connects: Connect[] };
9+
const Statistics = ({ connects }: Props) => {
10+
const statistic = useMemo(() => {
11+
return computeStatistic(connects);
12+
}, [connects]);
13+
return (
14+
<S.Container>
15+
<Statistic title="Clusters" count={statistic.clustersCount} />
16+
<Statistic
17+
title="Connectors"
18+
count={statistic.connectorsCount}
19+
warningCount={statistic.failedConnectorsCount}
20+
/>
21+
<Statistic
22+
title="Tasks"
23+
count={statistic.tasksCount}
24+
warningCount={statistic.failedTasksCount}
25+
/>
26+
</S.Container>
27+
);
28+
};
29+
30+
export default Statistics;

0 commit comments

Comments
 (0)