diff --git a/frontend/src/views/Org/IdentityPage/components/IdentityProjectsSection/IdentityProjectRow.tsx b/frontend/src/views/Org/IdentityPage/components/IdentityProjectsSection/IdentityProjectRow.tsx index 0a9301d56..4cbd1362d 100644 --- a/frontend/src/views/Org/IdentityPage/components/IdentityProjectsSection/IdentityProjectRow.tsx +++ b/frontend/src/views/Org/IdentityPage/components/IdentityProjectsSection/IdentityProjectRow.tsx @@ -62,7 +62,7 @@ export const IdentityProjectRow = ({ }); }} > - {project.name} + {project.name} {`${formatRoleName(roles[0].role, roles[0].customRoleName)}${ roles.length > 1 ? ` (+${roles.length - 1})` : "" }`} diff --git a/frontend/src/views/Org/IdentityPage/components/IdentityProjectsSection/IdentityProjectsTable.tsx b/frontend/src/views/Org/IdentityPage/components/IdentityProjectsSection/IdentityProjectsTable.tsx index a005ad1c8..195f74111 100644 --- a/frontend/src/views/Org/IdentityPage/components/IdentityProjectsSection/IdentityProjectsTable.tsx +++ b/frontend/src/views/Org/IdentityPage/components/IdentityProjectsSection/IdentityProjectsTable.tsx @@ -1,7 +1,18 @@ -import { faFolder } from "@fortawesome/free-solid-svg-icons"; +import { useMemo } from "react"; +import { + faArrowDown, + faArrowUp, + faFolder, + faMagnifyingGlass, + faSearch +} from "@fortawesome/free-solid-svg-icons"; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { EmptyState, + IconButton, + Input, + Pagination, Table, TableContainer, TableSkeleton, @@ -10,7 +21,9 @@ import { THead, Tr } from "@app/components/v2"; +import { usePagination, useResetPageHelper } from "@app/hooks"; import { useGetIdentityProjectMemberships } from "@app/hooks/api"; +import { OrderByDirection } from "@app/hooks/api/generic/types"; import { UsePopUpState } from "@app/hooks/usePopUp"; import { IdentityProjectRow } from "./IdentityProjectRow"; @@ -23,36 +36,115 @@ type Props = { ) => void; }; +enum IdentityProjectsOrderBy { + Name = "name" +} + export const IdentityProjectsTable = ({ identityId, handlePopUpOpen }: Props) => { - const { data: projectMemberships, isLoading } = useGetIdentityProjectMemberships(identityId); + const { data: projectMemberships = [], isLoading } = useGetIdentityProjectMemberships(identityId); + + const { + search, + setSearch, + setPage, + page, + perPage, + setPerPage, + offset, + orderDirection, + toggleOrderDirection + } = usePagination(IdentityProjectsOrderBy.Name, { initPerPage: 10 }); + + const filteredProjectMemberships = useMemo( + () => + projectMemberships + ?.filter((membership) => + membership.project.name.toLowerCase().includes(search.trim().toLowerCase()) + ) + .sort((a, b) => { + const [membershipOne, membershipTwo] = + orderDirection === OrderByDirection.ASC ? [a, b] : [b, a]; + + return membershipOne.project.name + .toLowerCase() + .localeCompare(membershipTwo.project.name.toLowerCase()); + }), + [projectMemberships, orderDirection, search] + ); + + useResetPageHelper({ + totalCount: filteredProjectMemberships.length, + offset, + setPage + }); + return ( - - - - - - - - - - - {isLoading && } - {!isLoading && - projectMemberships?.map((membership) => { - return ( - - ); - })} - -
NameRoleAdded On -
- {!isLoading && !projectMemberships?.length && ( - - )} -
+
+ setSearch(e.target.value)} + leftIcon={} + placeholder="Search projects..." + /> + + + + + + + + + + + + {isLoading && } + {!isLoading && + filteredProjectMemberships.slice(offset, perPage * page).map((membership) => { + return ( + + ); + })} + +
+
+ Name + + + +
+
RoleAdded On +
+ {Boolean(filteredProjectMemberships.length) && ( + + )} + {!isLoading && !filteredProjectMemberships?.length && ( + + )} +
+
); }; diff --git a/frontend/src/views/Org/MembersPage/MembersPage.tsx b/frontend/src/views/Org/MembersPage/MembersPage.tsx index 786e672ac..eb006fef9 100644 --- a/frontend/src/views/Org/MembersPage/MembersPage.tsx +++ b/frontend/src/views/Org/MembersPage/MembersPage.tsx @@ -7,7 +7,7 @@ import { OrgPermissionActions, OrgPermissionSubjects } from "@app/context"; import { withPermission } from "@app/hoc"; import { isTabSection, TabSections } from "@app/views/Org/Types"; -import { OrgIdentityTab, OrgMembersTab, OrgRoleTabSection } from "./components"; +import { OrgGroupsTab, OrgIdentityTab, OrgMembersTab, OrgRoleTabSection } from "./components"; export const MembersPage = withPermission( () => { @@ -25,9 +25,9 @@ export const MembersPage = withPermission( const updateSelectedTab = (tab: string) => { router.push({ pathname: router.pathname, - query: { ...router.query, selectedTab: tab }, + query: { ...router.query, selectedTab: tab } }); - } + }; return (
@@ -36,16 +36,20 @@ export const MembersPage = withPermission( Users + Groups

Machine Identities

- Organization Roles + Organization Roles
+ + + diff --git a/frontend/src/views/Org/MembersPage/components/OrgGroupsTab/components/OrgGroupsSection/OrgGroupsSection.tsx b/frontend/src/views/Org/MembersPage/components/OrgGroupsTab/components/OrgGroupsSection/OrgGroupsSection.tsx index 7738d1353..f72adf61f 100644 --- a/frontend/src/views/Org/MembersPage/components/OrgGroupsTab/components/OrgGroupsSection/OrgGroupsSection.tsx +++ b/frontend/src/views/Org/MembersPage/components/OrgGroupsTab/components/OrgGroupsSection/OrgGroupsSection.tsx @@ -57,7 +57,7 @@ export const OrgGroupsSection = () => { return (
-

User Groups

+

Groups

{(isAllowed) => (