Skip to content
Open
Show file tree
Hide file tree
Changes from 27 commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
844e34e
Impl HeartbeatSerde
Haarolean Sep 25, 2025
496aa43
Impl OffsetSyncSerde
Haarolean Sep 25, 2025
13c951f
Impl CheckpointSerde
Haarolean Sep 25, 2025
c25604b
lint
Haarolean Sep 25, 2025
de52924
Change result type from string to json in appropriate cases
Haarolean Sep 26, 2025
6146073
Impl tests
Haarolean Sep 26, 2025
fc59e6b
Logs
Haarolean Sep 26, 2025
267d52d
Split k/v methods
Haarolean Sep 26, 2025
89ca82c
Upd fields visibility
Haarolean Sep 27, 2025
1ea2aa6
Auto register serdes for well known topic patterns
Haarolean Sep 29, 2025
9c987ef
Simplify serialization
Haarolean Sep 29, 2025
7e25c7c
Reduced duplicate code
germanosin Sep 29, 2025
c5cb67d
Reduced duplicate code
germanosin Sep 29, 2025
40760ca
Reduced duplicate code
germanosin Sep 29, 2025
68a8a26
Reduced duplicate code
germanosin Sep 29, 2025
dfa9cbb
Reduced duplicate code
germanosin Sep 29, 2025
6b2431c
Reduced duplicate code
germanosin Sep 30, 2025
35f6c08
Reduced duplicate code
germanosin Sep 30, 2025
bf2fce1
BE: issue-1333 optional fts
germanosin Oct 2, 2025
57ede6c
FE: Add button for enabling topics fts search
Vixtir Oct 5, 2025
1b36d3a
FE: Fix tests, icon styles
Vixtir Oct 5, 2025
db6aca2
Merge main
germanosin Oct 8, 2025
552c305
Merge branch 'main' into issues/1333-optional-fts-fe
germanosin Oct 8, 2025
40d6a38
Add useFts to topic table
Vixtir Oct 8, 2025
1333af0
Merge branch 'main' into issues/1333-optional-fts-fe
germanosin Oct 8, 2025
fb7faa1
Merge branch 'main' into issues/1333-optional-fts-fe
germanosin Oct 12, 2025
ca25d84
FE: Add fts to other resources, add logic to show and handle fts button
Vixtir Oct 12, 2025
07190b2
FE: Use config vars
Vixtir Oct 15, 2025
4ed5e88
FE: Fix state sync
Vixtir Oct 15, 2025
2a96c1e
FE: Use config vars
Vixtir Oct 15, 2025
6384333
FE: Fix race condition in cluster context
Vixtir Oct 15, 2025
6f5b2ca
FE: Use config vars
Vixtir Oct 15, 2025
9ea7766
FE: Remove redundant connectors request
Vixtir Oct 15, 2025
353bbc2
FE: Fix test
Vixtir Oct 15, 2025
137037d
FE: Fix typos
Vixtir Oct 15, 2025
7470cbd
FE: Fix set params
Vixtir Oct 16, 2025
0285669
FE: Make a nav scrollbar thin
Vixtir Oct 16, 2025
362ff3c
FE: Add useFts deps
Vixtir Oct 18, 2025
40d03b2
Merge branch 'main' into issues/1333-optional-fts-fe
germanosin Oct 22, 2025
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
6 changes: 5 additions & 1 deletion frontend/src/components/ACLPage/List/List.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,17 @@ import ResourcePageHeading from 'components/common/ResourcePageHeading/ResourceP
import BreakableTextCell from 'components/common/NewTable/BreakableTextCell';
import { useQueryPersister } from 'components/common/NewTable/ColumnFilter';
import { ActionPermissionWrapper } from 'components/common/ActionComponent';
import useFts from 'components/common/Fts/useFts';
import Fts from 'components/common/Fts/Fts';

import * as S from './List.styled';

const ACList: React.FC = () => {
const { clusterName } = useAppParams<{ clusterName: ClusterName }>();
const [searchParams, setSearchParams] = useSearchParams();
const [search, setSearch] = useState(searchParams.get('q') || '');
const { data: aclList } = useAcls({ clusterName, search });
const { isFtsEnabled } = useFts('acl');
const { data: aclList } = useAcls({ clusterName, search, fts: isFtsEnabled });
const { deleteResource } = useDeleteAcl(clusterName);
const modal = useConfirm(true);
const theme = useTheme();
Expand Down Expand Up @@ -211,6 +214,7 @@ const ACList: React.FC = () => {
placeholder="Search by Principal Name"
value={search}
onChange={setSearch}
extraActions={<Fts resourceName="acl" />}
/>
</ControlPanelWrapper>
<Table
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
import useFts from 'components/common/Fts/useFts';
import { useConsumerGroups } from 'lib/hooks/api/consumers';
import { useMemo } from 'react';

const useConsumerGroupsOptions = (clusterName: string) => {
const { data } = useConsumerGroups({ clusterName, search: '' });
const { isFtsEnabled } = useFts('consumer_groups');
const { data } = useConsumerGroups({
clusterName,
search: '',
fts: isFtsEnabled,
});
const consumerGroups = useMemo(() => {
return (
data?.consumerGroups?.map((cg) => {
Expand Down
2 changes: 2 additions & 0 deletions frontend/src/components/ClusterPage/ClusterPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ const ClusterPage: React.FC = () => {
hasAclViewConfigured:
features.includes(ClusterFeaturesEnum.KAFKA_ACL_VIEW) ||
features.includes(ClusterFeaturesEnum.KAFKA_ACL_EDIT),
ftsEnabled: false,
ftsDefaultEnabled: false,
};
}, [clusterName, data]);

Expand Down
5 changes: 4 additions & 1 deletion frontend/src/components/Connect/List/List.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { useSearchParams } from 'react-router-dom';
import { useQueryPersister } from 'components/common/NewTable/ColumnFilter';
import { useLocalStoragePersister } from 'components/common/NewTable/ColumnResizer/lib';
import BreakableTextCell from 'components/common/NewTable/BreakableTextCell';
import useFts from 'components/common/Fts/useFts';

import ActionsCell from './ActionsCell';
import TopicsCell from './TopicsCell';
Expand Down Expand Up @@ -80,9 +81,11 @@ const kafkaConnectColumns: ColumnDef<FullConnectorInfo, string>[] = [
const List: React.FC = () => {
const { clusterName } = useAppParams<ClusterNameRoute>();
const [searchParams] = useSearchParams();
const { isFtsEnabled } = useFts('connects');
const { data: connectors } = useConnectors(
clusterName,
searchParams.get('q') || ''
searchParams.get('q') || '',
isFtsEnabled
);

const filterPersister = useQueryPersister(kafkaConnectColumns);
Expand Down
8 changes: 7 additions & 1 deletion frontend/src/components/Connect/List/ListPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,26 @@ import { ClusterNameRoute } from 'lib/paths';
import Search from 'components/common/Search/Search';
import PageLoader from 'components/common/PageLoader/PageLoader';
import { useConnectors } from 'lib/hooks/api/kafkaConnect';
import Fts from 'components/common/Fts/Fts';
import useFts from 'components/common/Fts/useFts';

import * as S from './ListPage.styled';
import List from './List';
import ConnectorsStatistics from './Statistics/Statistics';

const ListPage: React.FC = () => {
useFts('connects');
const { clusterName } = useAppParams<ClusterNameRoute>();
const { data, isLoading } = useConnectors(clusterName);

return (
<>
<ConnectorsStatistics connectors={data ?? []} isLoading={isLoading} />
<S.Search hasInput>
<Search placeholder="Search by Connect Name, Status or Type" />
<Search
placeholder="Search by Connect Name, Status or Type"
extraActions={<Fts resourceName="connects" />}
/>
</S.Search>
<Suspense fallback={<PageLoader />}>
<List />
Expand Down
9 changes: 8 additions & 1 deletion frontend/src/components/ConsumerGroups/List.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,14 @@ import { useConsumerGroups } from 'lib/hooks/api/consumers';
import Tooltip from 'components/common/Tooltip/Tooltip';
import ResourcePageHeading from 'components/common/ResourcePageHeading/ResourcePageHeading';
import { useLocalStoragePersister } from 'components/common/NewTable/ColumnResizer/lib';
import useFts from 'components/common/Fts/useFts';
import Fts from 'components/common/Fts/Fts';

const List = () => {
const { clusterName } = useAppParams<ClusterNameRoute>();
const [searchParams] = useSearchParams();
const navigate = useNavigate();
const { isFtsEnabled } = useFts('consumer_groups');

const consumerGroups = useConsumerGroups({
clusterName,
Expand All @@ -32,6 +35,7 @@ const List = () => {
page: Number(searchParams.get('page') || 1),
perPage: Number(searchParams.get('perPage') || PER_PAGE),
search: searchParams.get('q') || '',
fts: isFtsEnabled,
});

const columns = React.useMemo<ColumnDef<ConsumerGroup>[]>(
Expand Down Expand Up @@ -104,7 +108,10 @@ const List = () => {
<>
<ResourcePageHeading text="Consumers" />
<ControlPanelWrapper hasInput>
<Search placeholder="Search by Consumer Group ID" />
<Search
placeholder="Search by Consumer Group ID"
extraActions={<Fts resourceName="consumer_groups" />}
/>
</ControlPanelWrapper>
<Table
columns={columns}
Expand Down
9 changes: 8 additions & 1 deletion frontend/src/components/Schemas/List/List.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ import { useNavigate, useSearchParams } from 'react-router-dom';
import { PER_PAGE } from 'lib/constants';
import { useGetSchemas } from 'lib/hooks/api/schemas';
import ResourcePageHeading from 'components/common/ResourcePageHeading/ResourcePageHeading';
import useFts from 'components/common/Fts/useFts';
import Fts from 'components/common/Fts/Fts';

import GlobalSchemaSelector from './GlobalSchemaSelector/GlobalSchemaSelector';

Expand All @@ -32,6 +34,7 @@ const List: React.FC = () => {
const { clusterName } = useAppParams<ClusterNameRoute>();
const navigate = useNavigate();
const [searchParams] = useSearchParams();
const { isFtsEnabled } = useFts('schemas');
const {
isInitialLoading,
isError,
Expand All @@ -45,6 +48,7 @@ const List: React.FC = () => {
sortOrder:
(searchParams.get('sortDirection')?.toUpperCase() as SortOrder) ||
undefined,
fts: isFtsEnabled,
});

const columns = React.useMemo<ColumnDef<SchemaSubject>[]>(
Expand Down Expand Up @@ -111,7 +115,10 @@ const List: React.FC = () => {
)}
</ResourcePageHeading>
<ControlPanelWrapper hasInput>
<Search placeholder="Search by Schema Name" />
<Search
placeholder="Search by Schema Name"
extraActions={<Fts resourceName="schemas" />}
/>
</ControlPanelWrapper>
{isInitialLoading || isError ? (
<PageLoader />
Expand Down
9 changes: 8 additions & 1 deletion frontend/src/components/Topics/List/ListPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,15 @@ import PageLoader from 'components/common/PageLoader/PageLoader';
import TopicTable from 'components/Topics/List/TopicTable';
import { Action, ResourceType } from 'generated-sources';
import ResourcePageHeading from 'components/common/ResourcePageHeading/ResourcePageHeading';
import Fts from 'components/common/Fts/Fts';
import useFts from 'components/common/Fts/useFts';

const ListPage: React.FC = () => {
const { isReadOnly } = React.useContext(ClusterContext);
const [searchParams, setSearchParams] = useSearchParams();

useFts('topics');

// Set the search params to the url based on the localStorage value
React.useEffect(() => {
if (!searchParams.has('perPage')) {
Expand Down Expand Up @@ -62,7 +66,10 @@ const ListPage: React.FC = () => {
)}
</ResourcePageHeading>
<ControlPanelWrapper hasInput>
<Search placeholder="Search by Topic Name" />
<Search
placeholder="Search by Topic Name"
extraActions={<Fts resourceName="topics" />}
/>
<label>
<Switch
name="ShowInternalTopics"
Expand Down
4 changes: 4 additions & 0 deletions frontend/src/components/Topics/List/TopicTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import ClusterContext from 'components/contexts/ClusterContext';
import { useTopics } from 'lib/hooks/api/topics';
import { PER_PAGE } from 'lib/constants';
import { useLocalStoragePersister } from 'components/common/NewTable/ColumnResizer/lib';
import useFts from 'components/common/Fts/useFts';

import { TopicTitleCell } from './TopicTitleCell';
import ActionsCell from './ActionsCell';
Expand All @@ -18,8 +19,11 @@ const TopicTable: React.FC = () => {
const { clusterName } = useAppParams<{ clusterName: ClusterName }>();
const [searchParams] = useSearchParams();
const { isReadOnly } = React.useContext(ClusterContext);
const { isFtsEnabled } = useFts('topics');

const { data } = useTopics({
clusterName,
fts: isFtsEnabled,
page: Number(searchParams.get('page') || 1),
perPage: Number(searchParams.get('perPage') || PER_PAGE),
search: searchParams.get('q') || undefined,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ describe('ListPage Component', () => {
hasKafkaConnectConfigured: true,
hasSchemaRegistryConfigured: true,
isTopicDeletionAllowed: true,
ftsEnabled: false,
ftsDefaultEnabled: false,
}}
>
<WithRoute path={clusterTopicsPath()}>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@ describe('TopicTable Components', () => {
hasKafkaConnectConfigured: true,
hasSchemaRegistryConfigured: true,
isTopicDeletionAllowed,
ftsEnabled: false,
ftsDefaultEnabled: false,
}}
>
<WithRoute path={clusterTopicsPath()}>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ const defaultContextValues = {
hasKafkaConnectConfigured: true,
hasSchemaRegistryConfigured: true,
isTopicDeletionAllowed: true,
ftsEnabled: false,
ftsDefaultEnabled: false,
};

jest.mock('lib/hooks/api/topics', () => ({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,8 @@ describe('Details', () => {
hasKafkaConnectConfigured: true,
hasSchemaRegistryConfigured: true,
isTopicDeletionAllowed: true,
ftsEnabled: false,
ftsDefaultEnabled: false,
}}
>
<WithRoute path={getNonExactPath(clusterTopicPath())}>
Expand Down
46 changes: 46 additions & 0 deletions frontend/src/components/common/Fts/Fts.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import React from 'react';
import FtsIcon from 'components/common/Icons/FtsIcon';
import styled from 'styled-components';
import Tooltip from 'components/common/Tooltip/Tooltip';
import ClusterContext from 'components/contexts/ClusterContext';

import useFts, { FtsAvailableResource } from './useFts';

export const IconWrapper = styled.span.attrs<{ active: boolean }>(() => ({
role: 'button',
tabIndex: 1,
}))`
display: inline-block;
&:hover {
cursor: pointer;
}
color: ${(props) =>
props.active
? props.theme.icons.ftsIcon.active
: props.theme.icons.ftsIcon.normal};
`;

const Fts = ({ resourceName }: { resourceName: FtsAvailableResource }) => {
const { ftsEnabled: isFtsFetureEnabled } = React.useContext(ClusterContext);
const { handleSwitch, isFtsEnabled } = useFts(resourceName);

if (!isFtsFetureEnabled) {
return null;
}

return (
<Tooltip
value={
<IconWrapper onClick={handleSwitch} active={isFtsEnabled}>
<FtsIcon />
</IconWrapper>
}
content="Apply full text search"
placement="bottom"
showTooltip
fullWidth
/>
);
};

export default Fts;
73 changes: 73 additions & 0 deletions frontend/src/components/common/Fts/useFts.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import ClusterContext from 'components/contexts/ClusterContext';
import React from 'react';
import { useSearchParams } from 'react-router-dom';

export type FtsAvailableResource =
| 'topics'
| 'acl'
| 'consumer_groups'
| 'connects'
| 'schemas';

const storageName = 'kafbat-ui_fts';

const useFts = (resourceName: FtsAvailableResource) => {
const { ftsEnabled: isFtsFeatureEnabled, ftsDefaultEnabled } =
React.useContext(ClusterContext);
const [searchParams, setSearchParams] = useSearchParams();
const storageKey = `${storageName}:${resourceName}`;

React.useEffect(() => {
if (!isFtsFeatureEnabled) {
searchParams.delete('fts');
localStorage.removeItem(storageKey);
}

if (!searchParams.has('fts')) {
const value = localStorage.getItem(storageKey);
if (value === null) {
searchParams.set('fts', ftsDefaultEnabled ? 'true' : 'false');
} else {
searchParams.set('fts', value);
}
}

setSearchParams(searchParams);
}, [isFtsFeatureEnabled, ftsDefaultEnabled]);

const handleSwitch = () => {
if (!isFtsFeatureEnabled) {
return;
}
const currentValue = searchParams.get('fts') === 'true';
if (currentValue) {
localStorage.setItem(storageKey, 'false');
searchParams.set('fts', 'false');
} else {
localStorage.setItem(storageKey, 'true');
searchParams.set('fts', 'true');
}

searchParams.set('page', '1');
setSearchParams(searchParams);
};

let isFtsEnabled = isFtsFeatureEnabled;
if (isFtsEnabled) {
if (searchParams.has('fts')) {
isFtsEnabled = searchParams.get('fts') === 'true';
} else if (localStorage.getItem(storageKey)) {
isFtsEnabled = localStorage.getItem(storageKey) === 'true';
} else {
isFtsEnabled = ftsDefaultEnabled;
}
}

return {
handleSwitch,
isFtsFetureEnabled: isFtsFeatureEnabled,
isFtsEnabled,
};
};

export default useFts;
20 changes: 20 additions & 0 deletions frontend/src/components/common/Icons/FtsIcon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import React from 'react';

const FtsIcon: React.FC = () => {
return (
<svg
fill="currentColor"
width="800px"
height="800px"
viewBox="0 0 56 56"
xmlns="http://www.w3.org/2000/svg"
>
<path
fill="currentColor"
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"
/>
</svg>
);
};

export default FtsIcon;
Loading
Loading