From 5fdb53b7db1b5c1395112c8430fd48e594efa0a6 Mon Sep 17 00:00:00 2001 From: Arup Chauhan Date: Wed, 20 Nov 2024 00:59:12 -0600 Subject: [PATCH 1/6] Initiated fixing issue #27009 Signed-off-by: Arup Chauhan --- draft.txt | 1 + 1 file changed, 1 insertion(+) create mode 100644 draft.txt diff --git a/draft.txt b/draft.txt new file mode 100644 index 0000000000..736c83d484 --- /dev/null +++ b/draft.txt @@ -0,0 +1 @@ +Working on issue #27009 From a9659a97942d267fd262de26c994f7c277e30249 Mon Sep 17 00:00:00 2001 From: Arup Chauhan Date: Thu, 6 Feb 2025 18:45:35 -0600 Subject: [PATCH 2/6] Reopened PR Signed-off-by: Arup Chauhan --- draft.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/draft.txt b/draft.txt index 736c83d484..e5a33738bc 100644 --- a/draft.txt +++ b/draft.txt @@ -1 +1 @@ -Working on issue #27009 +Working on issue #27009: EnttityMemberListCard From 9c0562f5822fadf34c669d0127539f1b48a487ef Mon Sep 17 00:00:00 2001 From: Arup Chauhan Date: Thu, 2 Oct 2025 02:22:28 -0500 Subject: [PATCH 3/6] feat(plugin-org): add search functionality in MembersListCard Signed-off-by: Arup Chauhan --- .../MembersList/MembersListCard.test.tsx | 56 ++++++++++++++++++- .../Group/MembersList/MembersListCard.tsx | 52 ++++++++++++++--- 2 files changed, 97 insertions(+), 11 deletions(-) diff --git a/plugins/org/src/components/Cards/Group/MembersList/MembersListCard.test.tsx b/plugins/org/src/components/Cards/Group/MembersList/MembersListCard.test.tsx index bdc9456fc1..891c1ba3c7 100644 --- a/plugins/org/src/components/Cards/Group/MembersList/MembersListCard.test.tsx +++ b/plugins/org/src/components/Cards/Group/MembersList/MembersListCard.test.tsx @@ -136,7 +136,7 @@ describe('MemberTab Test', () => { expect(screen.getByText('Super Awesome Developer')).toBeInTheDocument(); - expect(screen.getByText('Members (1)')).toBeInTheDocument(); + expect(screen.getByText('Members (1 of 1)')).toBeInTheDocument(); }); it('Can render different member display title', async () => { @@ -154,7 +154,7 @@ describe('MemberTab Test', () => { }, ); - expect(screen.getByText('Testers (1)')).toBeInTheDocument(); + expect(screen.getByText('Testers (1 of 1)')).toBeInTheDocument(); }); it('Can query a different relationship', async () => { @@ -435,4 +435,56 @@ describe('MemberTab Test', () => { const displayedMemberNames = screen.queryAllByTestId('user-link'); expect(displayedMemberNames).toHaveLength(5); }); + + describe('Search', () => { + it('filters members by name', async () => { + await renderInTestApp( + + + + + , + { + mountedRoutes: { + '/catalog/:namespace/:kind/:name': entityRouteRef, + '/catalog': rootRouteRef, + }, + }, + ); + + // type into the search field + await userEvent.type(screen.getByPlaceholderText(/search/i), 'Tara'); + + // Tara should show + expect(await screen.findByText('Tara MacGovern')).toBeInTheDocument(); + + // Someone else not in results should be missing + expect(screen.queryByText('Nigel Manning')).not.toBeInTheDocument(); + }); + + it('shows no members message when search yields no results', async () => { + await renderInTestApp( + + + + + , + { + mountedRoutes: { + '/catalog/:namespace/:kind/:name': entityRouteRef, + '/catalog': rootRouteRef, + }, + }, + ); + + await userEvent.type( + screen.getByPlaceholderText(/search/i), + 'XYZDoesNotExist', + ); + + expect( + screen.getByText(/This group has no members./i), + ).toBeInTheDocument(); + }); + }); }); diff --git a/plugins/org/src/components/Cards/Group/MembersList/MembersListCard.tsx b/plugins/org/src/components/Cards/Group/MembersList/MembersListCard.tsx index 07119ba85b..550b16b857 100644 --- a/plugins/org/src/components/Cards/Group/MembersList/MembersListCard.tsx +++ b/plugins/org/src/components/Cards/Group/MembersList/MembersListCard.tsx @@ -31,7 +31,7 @@ import Switch from '@material-ui/core/Switch'; import Typography from '@material-ui/core/Typography'; import { createStyles, makeStyles, Theme } from '@material-ui/core/styles'; import Pagination from '@material-ui/lab/Pagination'; -import { useState, ChangeEvent } from 'react'; +import { useState, useEffect, ChangeEvent } from 'react'; import useAsync from 'react-use/esm/useAsync'; import { @@ -50,6 +50,7 @@ import { import { EntityRelationAggregation } from '../../types'; import { useTranslationRef } from '@backstage/frontend-plugin-api'; import { orgTranslationRef } from '../../../../translation'; +import TextField from '@material-ui/core/TextField'; /** @public */ export type MemberComponentClassKey = 'card' | 'avatar'; @@ -190,6 +191,12 @@ export const MembersListCard = (props: { relationAggregation === 'aggregated', ); + const [searchTerm, setSearchTerm] = useState(''); + + useEffect(() => { + setPage(1); + }, [searchTerm]); + const { loading: loadingDescendantMembers, value: descendantMembers } = useAsync(async () => { if (!showAggregateMembers) { @@ -257,13 +264,31 @@ export const MembersListCard = (props: { /> ); + const filteredMembers = members.filter(member => { + const fields = [ + member.metadata.name, + member.metadata.title, + member.spec?.profile?.displayName, + member.spec?.profile?.email, + ]; + return fields.some(val => + val + ?.toLocaleLowerCase('en-US') + .includes(searchTerm.toLocaleLowerCase('en-US')), + ); + }); + + const membersToRender = searchTerm ? filteredMembers : members; + let memberList: JSX.Element; - if (members && members.length > 0) { + if (membersToRender && membersToRender.length > 0) { memberList = ( - {members.slice(pageSize * (page - 1), pageSize * page).map(member => ( - - ))} + {membersToRender + .slice(pageSize * (page - 1), pageSize * page) + .map(member => ( + + ))} ); } else { @@ -277,9 +302,7 @@ export const MembersListCard = (props: { return ( ) : ( - memberList + <> + ) => + setSearchTerm(e.target.value) + } + /> + {memberList} + )} From 1dee6deddc310b89430fb0ebf504b6b834f1e68c Mon Sep 17 00:00:00 2001 From: Arup Chauhan Date: Mon, 17 Nov 2025 16:17:54 -0600 Subject: [PATCH 4/6] rebased and updated changeset for add changeset for plugin-org member search Signed-off-by: Arup Chauhan --- .changeset/tidy-bugs-throw.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/tidy-bugs-throw.md diff --git a/.changeset/tidy-bugs-throw.md b/.changeset/tidy-bugs-throw.md new file mode 100644 index 0000000000..e2785e588c --- /dev/null +++ b/.changeset/tidy-bugs-throw.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-org': patch +--- + +Add search functionality in MembersListCard From 89cffcb854a11573dc0e8357353c417041335980 Mon Sep 17 00:00:00 2001 From: Arup Chauhan Date: Mon, 17 Nov 2025 16:26:55 -0600 Subject: [PATCH 5/6] chore: remove drafts Signed-off-by: Arup Chauhan --- draft.txt | 1 - 1 file changed, 1 deletion(-) delete mode 100644 draft.txt diff --git a/draft.txt b/draft.txt deleted file mode 100644 index e5a33738bc..0000000000 --- a/draft.txt +++ /dev/null @@ -1 +0,0 @@ -Working on issue #27009: EnttityMemberListCard From 74216f31470c03fc1351f47eae163b9760a141d0 Mon Sep 17 00:00:00 2001 From: Arup Chauhan Date: Mon, 12 Jan 2026 03:09:50 -0600 Subject: [PATCH 6/6] fix(plugin-org): add spacing between member search and list Signed-off-by: Arup Chauhan --- .../src/components/Cards/Group/MembersList/MembersListCard.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/org/src/components/Cards/Group/MembersList/MembersListCard.tsx b/plugins/org/src/components/Cards/Group/MembersList/MembersListCard.tsx index 550b16b857..ee2f37ea9c 100644 --- a/plugins/org/src/components/Cards/Group/MembersList/MembersListCard.tsx +++ b/plugins/org/src/components/Cards/Group/MembersList/MembersListCard.tsx @@ -341,7 +341,7 @@ export const MembersListCard = (props: { setSearchTerm(e.target.value) } /> - {memberList} + {memberList} )}