Skip to content

Commit 57ede6c

Browse files
committed
FE: Add button for enabling topics fts search
1 parent bf2fce1 commit 57ede6c

File tree

9 files changed

+159
-19
lines changed

9 files changed

+159
-19
lines changed

frontend/src/components/Topics/List/ListPage.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import PageLoader from 'components/common/PageLoader/PageLoader';
1212
import TopicTable from 'components/Topics/List/TopicTable';
1313
import { Action, ResourceType } from 'generated-sources';
1414
import ResourcePageHeading from 'components/common/ResourcePageHeading/ResourcePageHeading';
15+
import Fts from 'components/common/Fts/Fts';
1516

1617
const ListPage: React.FC = () => {
1718
const { isReadOnly } = React.useContext(ClusterContext);
@@ -62,7 +63,10 @@ const ListPage: React.FC = () => {
6263
)}
6364
</ResourcePageHeading>
6465
<ControlPanelWrapper hasInput>
65-
<Search placeholder="Search by Topic Name" />
66+
<Search
67+
placeholder="Search by Topic Name"
68+
actions={<Fts resourceName="topics" />}
69+
/>
6670
<label>
6771
<Switch
6872
name="ShowInternalTopics"

frontend/src/components/Topics/List/TopicTable.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import ClusterContext from 'components/contexts/ClusterContext';
99
import { useTopics } from 'lib/hooks/api/topics';
1010
import { PER_PAGE } from 'lib/constants';
1111
import { useLocalStoragePersister } from 'components/common/NewTable/ColumnResizer/lib';
12+
import useFts from 'components/common/Fts/useFts';
1213

1314
import { TopicTitleCell } from './TopicTitleCell';
1415
import ActionsCell from './ActionsCell';
@@ -18,8 +19,11 @@ const TopicTable: React.FC = () => {
1819
const { clusterName } = useAppParams<{ clusterName: ClusterName }>();
1920
const [searchParams] = useSearchParams();
2021
const { isReadOnly } = React.useContext(ClusterContext);
22+
const { isFtsEnabled } = useFts('topics');
23+
2124
const { data } = useTopics({
2225
clusterName,
26+
fts: isFtsEnabled,
2327
page: Number(searchParams.get('page') || 1),
2428
perPage: Number(searchParams.get('perPage') || PER_PAGE),
2529
search: searchParams.get('q') || undefined,
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import React from 'react';
2+
import FtsIcon from 'components/common/Icons/FtsIcon';
3+
import styled from 'styled-components';
4+
5+
import useFts from './useFts';
6+
7+
export const IconWrapper = styled.span.attrs<{ active: boolean }>(() => ({
8+
role: 'button',
9+
tabIndex: 1,
10+
}))`
11+
display: inline-block;
12+
&:hover {
13+
cursor: pointer;
14+
color: ${({ theme }) => theme.icons.ftsIcon.active};
15+
}
16+
color: ${(props) =>
17+
props.active
18+
? props.theme.icons.ftsIcon.active
19+
: props.theme.icons.ftsIcon.normal};
20+
`;
21+
22+
const Fts = ({ resourceName }: { resourceName: string }) => {
23+
const { handleSwitch, isFtsEnabled } = useFts(resourceName);
24+
25+
return (
26+
<IconWrapper onClick={handleSwitch} active={isFtsEnabled}>
27+
<FtsIcon />
28+
</IconWrapper>
29+
);
30+
};
31+
32+
export default Fts;
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import React from 'react';
2+
import { useSearchParams } from 'react-router-dom';
3+
4+
type FtsAvailableResource = 'topics';
5+
6+
const storageName = 'kafbat-ui_fts';
7+
8+
const useFts = (resourceName: FtsAvailableResource) => {
9+
const [searchParams, setSearchParams] = useSearchParams();
10+
const storageKey = `${storageName}:${resourceName}`;
11+
12+
React.useEffect(() => {
13+
if (!!localStorage.getItem(storageKey) && !searchParams.has('fts')) {
14+
searchParams.set('fts', 'true');
15+
}
16+
setSearchParams(searchParams);
17+
}, []);
18+
19+
const handleSwitch = () => {
20+
if (searchParams.has('fts')) {
21+
localStorage.removeItem(storageKey);
22+
searchParams.delete('fts');
23+
} else {
24+
localStorage.setItem(storageKey, 'true');
25+
searchParams.set('fts', 'true');
26+
}
27+
searchParams.set('page', '1');
28+
setSearchParams(searchParams);
29+
};
30+
31+
return {
32+
handleSwitch,
33+
isFtsEnabled: !!searchParams.get('fts'),
34+
};
35+
};
36+
37+
export default useFts;
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import React from 'react';
2+
3+
const FtsIcon: React.FC = () => {
4+
return (
5+
<svg
6+
fill="currentColor"
7+
width="800px"
8+
height="800px"
9+
viewBox="0 0 56 56"
10+
xmlns="http://www.w3.org/2000/svg"
11+
>
12+
<path
13+
fill="currentColor"
14+
d="M 13.5039 50.9570 L 26.3476 50.9570 C 25.1055 49.9023 24.0508 48.6367 23.2773 47.1836 L 13.7148 47.1836 C 11.3008 47.1836 10.0117 45.9414 10.0117 43.5976 L 10.0117 8.1367 C 10.0117 5.8164 11.2773 4.4805 13.7148 4.4805 L 38.2070 4.4805 C 40.5508 4.4805 41.8867 5.7930 41.8867 8.1367 L 41.8867 28.5742 C 43.3398 29.3476 44.6055 30.3789 45.6602 31.6211 L 45.6602 8.0664 C 45.6602 3.1679 43.2461 .7070 38.3945 .7070 L 13.5039 .7070 C 8.6758 .7070 6.2383 3.1914 6.2383 8.0664 L 6.2383 43.6211 C 6.2383 48.5195 8.6758 50.9570 13.5039 50.9570 Z M 17.0898 14.0430 L 34.8555 14.0430 C 35.6758 14.0430 36.3086 13.3867 36.3086 12.5664 C 36.3086 11.7695 35.6758 11.1601 34.8555 11.1601 L 17.0898 11.1601 C 16.2227 11.1601 15.6133 11.7695 15.6133 12.5664 C 15.6133 13.3867 16.2227 14.0430 17.0898 14.0430 Z M 17.0898 22.2226 L 34.8555 22.2226 C 35.6758 22.2226 36.3086 21.5664 36.3086 20.7461 C 36.3086 19.9492 35.6758 19.3398 34.8555 19.3398 L 17.0898 19.3398 C 16.2227 19.3398 15.6133 19.9492 15.6133 20.7461 C 15.6133 21.5664 16.2227 22.2226 17.0898 22.2226 Z M 35.1367 50.9570 C 37.2461 50.9570 39.2383 50.3476 40.8789 49.2461 L 46.1524 54.5430 C 46.7148 55.0820 47.2305 55.2930 47.8633 55.2930 C 48.9414 55.2930 49.7617 54.4492 49.7617 53.2539 C 49.7617 52.7383 49.5040 52.2226 49.1056 51.8242 L 43.7617 46.4805 C 44.9570 44.7695 45.6602 42.6836 45.6602 40.4336 C 45.6602 34.5976 40.9492 29.8867 35.1367 29.8867 C 29.3242 29.8867 24.5664 34.6445 24.5664 40.4336 C 24.5664 46.2461 29.3242 50.9570 35.1367 50.9570 Z M 35.1367 47.6054 C 31.1524 47.6054 27.9180 44.3945 27.9180 40.4336 C 27.9180 36.5195 31.1524 33.2617 35.1367 33.2617 C 39.0508 33.2617 42.2851 36.5195 42.2851 40.4336 C 42.2851 44.3945 39.0742 47.6054 35.1367 47.6054 Z"
15+
/>
16+
</svg>
17+
);
18+
};
19+
20+
export default FtsIcon;

frontend/src/components/common/Input/Input.tsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ export interface InputProps
1717
label?: React.ReactNode;
1818
hint?: React.ReactNode;
1919
clearIcon?: React.ReactNode;
20-
20+
actions?: React.ReactNode;
2121
// Some may only accept integer, like `Number of Partitions`
2222
// some may accept decimal
2323
integerOnly?: boolean;
@@ -113,6 +113,7 @@ const Input = React.forwardRef<HTMLInputElement, InputProps>((props, ref) => {
113113
label,
114114
hint,
115115
clearIcon,
116+
actions,
116117
...rest
117118
} = props;
118119

@@ -187,7 +188,8 @@ const Input = React.forwardRef<HTMLInputElement, InputProps>((props, ref) => {
187188
ref={ref}
188189
{...inputOptions}
189190
/>
190-
{clearIcon}
191+
{search && clearIcon}
192+
{actions}
191193

192194
{withError && isHookFormField && (
193195
<S.FormError>
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import styled from 'styled-components';
2+
3+
export const Actions = styled.div`
4+
position: absolute;
5+
display: flex;
6+
align-items: center;
7+
top: 8px;
8+
right: 8px;
9+
gap: 8px;
10+
11+
svg:first-child {
12+
position: initial;
13+
height: 16px;
14+
width: 16px;
15+
fill: ${({ theme }) => theme.input.icon.color};
16+
}
17+
svg:last-child {
18+
position: initial;
19+
height: 16px;
20+
width: 16px;
21+
}
22+
`;
23+
24+
export const IconButtonWrapper = styled.span.attrs(() => ({
25+
role: 'button',
26+
tabIndex: 0,
27+
}))`
28+
display: inline-block;
29+
&:hover {
30+
cursor: pointer;
31+
}
32+
`;

frontend/src/components/common/Search/Search.tsx

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,25 @@
1-
import React, { ComponentRef, useEffect, useRef } from 'react';
1+
import React, { ComponentRef, ReactNode, useEffect, useRef } from 'react';
22
import { useDebouncedCallback } from 'use-debounce';
33
import Input from 'components/common/Input/Input';
44
import { useSearchParams } from 'react-router-dom';
55
import CloseCircleIcon from 'components/common/Icons/CloseCircleIcon';
6-
import styled from 'styled-components';
6+
7+
import * as S from './Search.styled';
78

89
interface SearchProps {
910
placeholder?: string;
1011
disabled?: boolean;
1112
onChange?: (value: string) => void;
1213
value?: string;
14+
extraActions?: ReactNode;
1315
}
1416

15-
const IconButtonWrapper = styled.span.attrs(() => ({
16-
role: 'button',
17-
tabIndex: 0,
18-
}))`
19-
height: 16px !important;
20-
display: inline-block;
21-
&:hover {
22-
cursor: pointer;
23-
}
24-
`;
2517
const Search: React.FC<SearchProps> = ({
2618
placeholder = 'Search',
2719
disabled = false,
2820
value,
2921
onChange,
22+
actions,
3023
}) => {
3124
const [searchParams, setSearchParams] = useSearchParams();
3225
const ref = useRef<ComponentRef<'input'>>(null);
@@ -67,6 +60,8 @@ const Search: React.FC<SearchProps> = ({
6760
}
6861
};
6962

63+
const showClearIcon = searchParams.get('q');
64+
7065
return (
7166
<Input
7267
type="text"
@@ -77,10 +72,16 @@ const Search: React.FC<SearchProps> = ({
7772
disabled={disabled}
7873
ref={ref}
7974
search
80-
clearIcon={
81-
<IconButtonWrapper onClick={clearSearchValue}>
82-
<CloseCircleIcon />
83-
</IconButtonWrapper>
75+
actions={
76+
<S.Actions>
77+
{showClearIcon && (
78+
<S.IconButtonWrapper onClick={clearSearchValue}>
79+
<CloseCircleIcon />
80+
</S.IconButtonWrapper>
81+
)}
82+
83+
{actions}
84+
</S.Actions>
8485
}
8586
/>
8687
);

frontend/src/theme/theme.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -307,6 +307,10 @@ const baseTheme = {
307307
filterIcon: {
308308
normal: Colors.brand[70],
309309
},
310+
ftsIcon: {
311+
normal: Colors.neutral[30],
312+
active: Colors.brand[70],
313+
},
310314
},
311315
textArea: {
312316
borderColor: {
@@ -1539,6 +1543,10 @@ export const darkTheme: ThemeType = {
15391543
normal: Colors.neutral[5],
15401544
},
15411545
menuIcon: Colors.brand[0],
1546+
ftsIcon: {
1547+
normal: Colors.neutral[20],
1548+
active: Colors.brand[70],
1549+
},
15421550
},
15431551
textArea: {
15441552
...baseTheme.textArea,

0 commit comments

Comments
 (0)