Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added search filters for kafka connect #244 #539

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 66 additions & 7 deletions frontend/src/components/Connect/List/List.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,14 @@ import React from 'react';
import useAppParams from 'lib/hooks/useAppParams';
import { clusterConnectConnectorPath, ClusterNameRoute } from 'lib/paths';
import Table, { TagCell } from 'components/common/NewTable';
import { FullConnectorInfo } from 'generated-sources';
import {
ConnectorState,
ConnectorType,
FullConnectorInfo,
} from 'generated-sources';
import { useConnectors } from 'lib/hooks/api/kafkaConnect';
import { ColumnDef } from '@tanstack/react-table';
import { useNavigate, useSearchParams } from 'react-router-dom';
import { useNavigate } from 'react-router-dom';

import ActionsCell from './ActionsCell';
import TopicsCell from './TopicsCell';
Expand All @@ -14,11 +18,7 @@ import RunningTasksCell from './RunningTasksCell';
const List: React.FC = () => {
const navigate = useNavigate();
const { clusterName } = useAppParams<ClusterNameRoute>();
const [searchParams] = useSearchParams();
const { data: connectors } = useConnectors(
clusterName,
searchParams.get('q') || ''
);
const { data: connectors } = useConnectors(clusterName);

const columns = React.useMemo<ColumnDef<FullConnectorInfo>[]>(
() => [
Expand All @@ -34,6 +34,63 @@ const List: React.FC = () => {
[]
);

const connectorTypeOptions = Object.values(ConnectorType).map((state) => ({
label: state,
value: state,
}));

const connectorStateOptions = Object.values(ConnectorState).map((state) => ({
label: state,
value: state,
}));

const columnSearchPlaceholders: {
id: string;
columnName: string;
placeholder: string;
type: string;
options?: { label: string; value: string }[];
}[] = [
{
id: 'name',
columnName: 'name',
placeholder: 'Search by Name',
type: 'input',
},
{
id: 'connect',
columnName: 'connect',
placeholder: 'Search by Connect',
type: 'input',
},
{
id: 'type',
columnName: 'type',
placeholder: 'Select Type',
type: 'autocomplete',
options: connectorTypeOptions,
},
{
id: 'connectorClass',
columnName: 'connectorClass',
placeholder: 'Search by Plugin',
type: 'input',
},
{
id: 'Topics',
columnName: 'topics',
placeholder: 'Search by Topics',
type: 'multiInput',
},
{
id: 'status_state',
columnName: 'status',
placeholder: 'Select Status',
type: 'autocomplete',
options: connectorStateOptions,
},
];

return (
<Table
data={connectors || []}
Expand All @@ -44,6 +101,8 @@ const List: React.FC = () => {
}
emptyMessage="No connectors found"
setRowId={(originalRow) => `${originalRow.name}-${originalRow.connect}`}
enableColumnSearch
columnSearchPlaceholders={columnSearchPlaceholders}
/>
);
};
Expand Down
5 changes: 0 additions & 5 deletions frontend/src/components/Connect/List/ListPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,9 @@ import React, { Suspense } from 'react';
import useAppParams from 'lib/hooks/useAppParams';
import { ClusterNameRoute, clusterConnectorNewRelativePath } from 'lib/paths';
import ClusterContext from 'components/contexts/ClusterContext';
import Search from 'components/common/Search/Search';
import * as Metrics from 'components/common/Metrics';
import PageHeading from 'components/common/PageHeading/PageHeading';
import Tooltip from 'components/common/Tooltip/Tooltip';
import { ControlPanelWrapper } from 'components/common/ControlPanel/ControlPanel.styled';
import PageLoader from 'components/common/PageLoader/PageLoader';
import { ConnectorState, Action, ResourceType } from 'generated-sources';
import { useConnectors, useConnects } from 'lib/hooks/api/kafkaConnect';
Expand Down Expand Up @@ -81,9 +79,6 @@ const ListPage: React.FC = () => {
</Metrics.Indicator>
</Metrics.Section>
</Metrics.Wrapper>
<ControlPanelWrapper hasInput>
<Search placeholder="Search by Connect Name, Status or Type" />
</ControlPanelWrapper>
<Suspense fallback={<PageLoader />}>
<List />
</Suspense>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ describe('Connectors List', () => {
it('renders', async () => {
renderComponent();
expect(screen.getByRole('table')).toBeInTheDocument();
expect(screen.getAllByRole('row').length).toEqual(3);
expect(screen.getAllByRole('row').length).toEqual(4);
});

it('opens broker when row clicked', async () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,13 +67,6 @@ describe('Connectors List Page', () => {
});
});

it('renders search input', async () => {
await renderComponent();
expect(
screen.getByPlaceholderText('Search by Connect Name, Status or Type')
).toBeInTheDocument();
});

it('renders list', async () => {
await renderComponent();
expect(screen.getByText('Connectors List')).toBeInTheDocument();
Expand Down
2 changes: 2 additions & 0 deletions frontend/src/components/common/Input/Input.styled.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ const INPUT_SIZES = {

export const Wrapper = styled.div`
position: relative;
min-width: 200px;
&:hover {
svg:first-child {
fill: ${({ theme }) => theme.input.icon.hover};
Expand Down Expand Up @@ -52,6 +53,7 @@ export const Input = styled.input<InputProps>(
: '40px'};
width: 100%;
padding-left: ${search ? '36px' : '12px'};
padding-right: 30px;
font-size: 14px;

&::placeholder {
Expand Down
130 changes: 130 additions & 0 deletions frontend/src/components/common/MultiSearch/MultiSearch.styled.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
import styled, { css } from 'styled-components';
import { ComponentProps } from 'react';

export interface InputProps extends ComponentProps<'input'> {
values?: string[];
inputSize?: 'S' | 'M' | 'L';
searchIcon?: boolean;
isFocused?: boolean;
}

const INPUT_SIZES = {
S: 18,
M: 32,
L: 40,
};

export const Wrapper = styled.div<InputProps>(
({ theme: { input } }) => css`
position: relative;
display: flex;
align-items: center;
flex-wrap: wrap;
gap: 8px;
border: 1px solid ${input.borderColor.normal};
padding: 6px 32px 6px 12px;
border-radius: 4px;
min-width: 250px;
background-color: ${input.backgroundColor.normal};

&::placeholder {
color: ${input.color.placeholder.normal};
font-size: 14px;
}

&:hover {
border-color: ${input.borderColor.hover};
}

&:focus {
outline: none;
border-color: ${input.borderColor.focus};
&::placeholder {
color: transparent;
}
}
`
);

export const ValuesContainer = styled.div<InputProps>(
({ isFocused }) => css`
display: flex;
align-items: center;
flex-wrap: ${isFocused ? 'nowrap' : 'wrap'};
gap: 8px;
flex-grow: 1;
`
);

export const Tag = styled.div`
display: flex;
align-items: center;
background-color: ${({ theme }) => theme.tag.backgroundColor.blue};
color: ${({ theme }) => theme.tag.color};
border-radius: 12px;
padding: 2px 0 2px 8px;
font-size: 12px;
`;

export const RemoveButton = styled.button`
background: none;
border: none;
margin-left: 2px;
display: flex;
align-items: center;
cursor: pointer;
color: ${({ theme }) => theme.tag.color};

&:hover {
color: ${({ theme }) => theme.tag.backgroundColor};
}
`;

export const Input = styled.input<InputProps>(
({ theme: { input }, inputSize, values }) => css`
flex-grow: 1;
background-color: ${input.backgroundColor.normal};
border: none;
color: ${input.color.normal};
height: ${inputSize ? `${INPUT_SIZES[inputSize]}px` : '32px'};
font-size: 14px;
box-sizing: border-box;
width: ${values ? `15px` : '32px'};

&::placeholder {
color: ${input.color.placeholder.normal};
font-size: 14px;
}

&:focus {
outline: none;
&::placeholder {
color: transparent;
}
}
`
);

export const IconButtonWrapper = styled.span.attrs(() => ({
role: 'button',
tabIndex: 0,
}))`
position: absolute;
right: 10px;
top: 50%;
transform: translateY(-50%);
display: flex;
align-items: center;
justify-content: center;
&:hover {
cursor: pointer;
}
`;

export const RemainingTagCount = styled.span`
font-size: 14px;
color: ${({ theme }) => theme.input.color.normal};
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
`;
Loading
Loading