diff --git a/api/src/main/java/io/kafbat/ui/controller/AclsController.java b/api/src/main/java/io/kafbat/ui/controller/AclsController.java index bbb30b5c6..b99c8106d 100644 --- a/api/src/main/java/io/kafbat/ui/controller/AclsController.java +++ b/api/src/main/java/io/kafbat/ui/controller/AclsController.java @@ -67,6 +67,7 @@ public Mono>> listAcls(String clusterName, KafkaAclResourceTypeDTO resourceTypeDto, String resourceName, KafkaAclNamePatternTypeDTO namePatternTypeDto, + String search, ServerWebExchange exchange) { AccessContext context = AccessContext.builder() .cluster(clusterName) @@ -87,7 +88,7 @@ public Mono>> listAcls(String clusterName, return validateAccess(context).then( Mono.just( ResponseEntity.ok( - aclsService.listAcls(getCluster(clusterName), filter) + aclsService.listAcls(getCluster(clusterName), filter, search) .map(ClusterMapper::toKafkaAclDto))) ).doOnEach(sig -> audit(context, sig)); } diff --git a/api/src/main/java/io/kafbat/ui/service/acl/AclsService.java b/api/src/main/java/io/kafbat/ui/service/acl/AclsService.java index b3877a336..6a2b48632 100644 --- a/api/src/main/java/io/kafbat/ui/service/acl/AclsService.java +++ b/api/src/main/java/io/kafbat/ui/service/acl/AclsService.java @@ -68,10 +68,11 @@ public Mono deleteAcl(KafkaCluster cluster, AclBinding aclBinding) { .doOnSuccess(v -> log.info("ACL DELETED: [{}]", aclString)); } - public Flux listAcls(KafkaCluster cluster, ResourcePatternFilter filter) { + public Flux listAcls(KafkaCluster cluster, ResourcePatternFilter filter, String principalSearch) { return adminClientService.get(cluster) .flatMap(c -> c.listAcls(filter)) .flatMapIterable(acls -> acls) + .filter(acl -> principalSearch == null || acl.entry().principal().contains(principalSearch)) .sort(Comparator.comparing(AclBinding::toString)); //sorting to keep stable order on different calls } diff --git a/contract/src/main/resources/swagger/kafbat-ui-api.yaml b/contract/src/main/resources/swagger/kafbat-ui-api.yaml index 5eede6cef..9b4b7d26d 100644 --- a/contract/src/main/resources/swagger/kafbat-ui-api.yaml +++ b/contract/src/main/resources/swagger/kafbat-ui-api.yaml @@ -1943,6 +1943,11 @@ paths: required: false schema: $ref: '#/components/schemas/KafkaAclNamePatternType' + - name: search + in: query + required: false + schema: + type: string responses: 200: description: OK diff --git a/frontend/src/components/ACLPage/List/List.tsx b/frontend/src/components/ACLPage/List/List.tsx index 26155172b..9808a6c1c 100644 --- a/frontend/src/components/ACLPage/List/List.tsx +++ b/frontend/src/components/ACLPage/List/List.tsx @@ -1,4 +1,5 @@ -import React from 'react'; +import React, { useEffect, useState } from 'react'; +import { useSearchParams } from 'react-router-dom'; import { ColumnDef, Row } from '@tanstack/react-table'; import PageHeading from 'components/common/PageHeading/PageHeading'; import Table from 'components/common/NewTable'; @@ -20,12 +21,16 @@ import { useTheme } from 'styled-components'; import ACLFormContext from 'components/ACLPage/Form/AclFormContext'; import PlusIcon from 'components/common/Icons/PlusIcon'; import ActionButton from 'components/common/ActionComponent/ActionButton/ActionButton'; +import { ControlPanelWrapper } from 'components/common/ControlPanel/ControlPanel.styled'; +import Search from 'components/common/Search/Search'; import * as S from './List.styled'; const ACList: React.FC = () => { const { clusterName } = useAppParams<{ clusterName: ClusterName }>(); - const { data: aclList } = useAcls(clusterName); + const [searchParams] = useSearchParams(); + const [search, setSearch] = useState(searchParams.get('q') || ''); + const { data: aclList } = useAcls({ clusterName, search }); const { deleteResource } = useDeleteAcl(clusterName); const modal = useConfirm(true); const theme = useTheme(); @@ -36,6 +41,11 @@ const ACList: React.FC = () => { } = useBoolean(); const [rowId, setRowId] = React.useState(''); + // Set the search params to the url based on the localStorage value + useEffect(() => { + setSearch(searchParams.get('q') || ''); + }, [searchParams]); + const handleDeleteClick = (acl: KafkaAcl | null) => { if (acl) { modal('Are you sure want to delete this ACL record?', () => @@ -162,6 +172,9 @@ const ACList: React.FC = () => { Create ACL + + + api.listAcls({ clusterName }), + ['clusters', clusterName, 'acls', { search }], + () => + api.listAcls({ + clusterName, + search, + }), { + keepPreviousData: true, suspense: false, } );