Machine Identities
@@ -48,6 +54,9 @@ export const MembersPage = withProjectPermission(
+
+
+
diff --git a/frontend/src/views/Project/MembersPage/components/GroupsTab/components/GroupsSection/GroupsTable.tsx b/frontend/src/views/Project/MembersPage/components/GroupsTab/components/GroupsSection/GroupsTable.tsx
index 4bebd7637..f1d9ea1a3 100644
--- a/frontend/src/views/Project/MembersPage/components/GroupsTab/components/GroupsSection/GroupsTable.tsx
+++ b/frontend/src/views/Project/MembersPage/components/GroupsTab/components/GroupsSection/GroupsTable.tsx
@@ -1,4 +1,12 @@
-import { faServer, faTrash } from "@fortawesome/free-solid-svg-icons";
+import { useMemo } from "react";
+import {
+ faArrowDown,
+ faArrowUp,
+ faMagnifyingGlass,
+ faSearch,
+ faTrash,
+ faUsers
+} from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { format } from "date-fns";
@@ -6,6 +14,8 @@ import { ProjectPermissionCan } from "@app/components/permissions";
import {
EmptyState,
IconButton,
+ Input,
+ Pagination,
Table,
TableContainer,
TableSkeleton,
@@ -17,7 +27,9 @@ import {
Tr
} from "@app/components/v2";
import { ProjectPermissionActions, ProjectPermissionSub, useWorkspace } from "@app/context";
+import { usePagination, useResetPageHelper } from "@app/hooks";
import { useListWorkspaceGroups } from "@app/hooks/api";
+import { OrderByDirection } from "@app/hooks/api/generic/types";
import { UsePopUpState } from "@app/hooks/usePopUp";
import { GroupRoles } from "./GroupRoles";
@@ -32,76 +44,159 @@ type Props = {
) => void;
};
+enum GroupsOrderBy {
+ Name = "name"
+}
+
export const GroupTable = ({ handlePopUpOpen }: Props) => {
const { currentWorkspace } = useWorkspace();
- const { data, isLoading } = useListWorkspaceGroups(currentWorkspace?.id || "");
+
+ const {
+ search,
+ setSearch,
+ setPage,
+ page,
+ perPage,
+ setPerPage,
+ offset,
+ orderDirection,
+ orderBy,
+ toggleOrderDirection
+ } = usePagination(GroupsOrderBy.Name, { initPerPage: 20 });
+
+ const { data: groupMemberships = [], isLoading } = useListWorkspaceGroups(
+ currentWorkspace?.id || ""
+ );
+
+ const filteredGroupMemberships = useMemo(() => {
+ const filtered = search
+ ? groupMemberships?.filter(
+ ({ group: { name, slug } }) =>
+ name.toLowerCase().includes(search.toLowerCase()) ||
+ slug.toLowerCase().includes(search.toLowerCase())
+ )
+ : groupMemberships;
+
+ const ordered = filtered?.sort((a, b) =>
+ a.group.name.toLowerCase().localeCompare(b.group.name.toLowerCase())
+ );
+
+ return orderDirection === OrderByDirection.ASC ? ordered : ordered?.reverse();
+ }, [search, groupMemberships, orderBy, orderDirection]);
+
+ useResetPageHelper({
+ totalCount: filteredGroupMemberships.length,
+ offset,
+ setPage
+ });
+
return (
-
-
-
-
- | Name |
- Role |
- Added on |
- |
-
-
-
- {isLoading && }
- {!isLoading &&
- data &&
- data.length > 0 &&
- data.map(({ group: { id, name }, roles, createdAt }) => {
- return (
-
- | {name} |
-
-
- {(isAllowed) => (
-
- )}
-
- |
- {format(new Date(createdAt), "yyyy-MM-dd")} |
-
-
- {(isAllowed) => (
-
-
- {
- handlePopUpOpen("deleteGroup", {
- id,
- name
- });
- }}
- colorSchema="danger"
- variant="plain"
- ariaLabel="update"
- className="ml-4"
- isDisabled={!isAllowed}
- >
-
-
-
-
- )}
-
- |
-
- );
- })}
-
-
- {!isLoading && data?.length === 0 && (
-
- )}
-
+
+
setSearch(e.target.value)}
+ leftIcon={
}
+ placeholder="Search members..."
+ />
+
+
+
+
+ |
+
+ Name
+
+
+
+
+ |
+ Role |
+ Added on |
+ |
+
+
+
+ {isLoading && }
+ {!isLoading &&
+ filteredGroupMemberships &&
+ filteredGroupMemberships.length > 0 &&
+ filteredGroupMemberships
+ .slice(offset, perPage * page)
+ .map(({ group: { id, name }, roles, createdAt }) => {
+ return (
+
+ | {name} |
+
+
+ {(isAllowed) => (
+
+ )}
+
+ |
+ {format(new Date(createdAt), "yyyy-MM-dd")} |
+
+
+ {(isAllowed) => (
+
+
+ {
+ handlePopUpOpen("deleteGroup", {
+ id,
+ name
+ });
+ }}
+ colorSchema="danger"
+ variant="plain"
+ ariaLabel="update"
+ className="ml-4"
+ isDisabled={!isAllowed}
+ >
+
+
+
+
+ )}
+
+ |
+
+ );
+ })}
+
+
+ {Boolean(filteredGroupMemberships.length) && (
+
+ )}
+ {!isLoading && !filteredGroupMemberships?.length && (
+
+ )}
+
+
);
};
diff --git a/frontend/src/views/Project/MembersPage/components/MembersTab/MembersTab.tsx b/frontend/src/views/Project/MembersPage/components/MembersTab/MembersTab.tsx
index 25ffc38da..6b5660c83 100644
--- a/frontend/src/views/Project/MembersPage/components/MembersTab/MembersTab.tsx
+++ b/frontend/src/views/Project/MembersPage/components/MembersTab/MembersTab.tsx
@@ -1,12 +1,8 @@
import { motion } from "framer-motion";
-import { useWorkspace } from "@app/context";
-
-import { GroupsSection } from "../GroupsTab/components";
import { MembersSection } from "./components";
export const MembersTab = () => {
- const { currentWorkspace } = useWorkspace();
return (
{
exit={{ opacity: 0, translateX: 30 }}
>
- {currentWorkspace?.version && currentWorkspace.version > 1 && }
);
};
diff --git a/frontend/src/views/Project/MembersPage/components/MembersTab/components/MembersTable.tsx b/frontend/src/views/Project/MembersPage/components/MembersTab/components/MembersTable.tsx
index d81d4005c..d90468620 100644
--- a/frontend/src/views/Project/MembersPage/components/MembersTab/components/MembersTable.tsx
+++ b/frontend/src/views/Project/MembersPage/components/MembersTab/components/MembersTable.tsx
@@ -86,7 +86,7 @@ export const MembersTable = ({ handlePopUpOpen }: Props) => {
setOrderBy,
setOrderDirection,
toggleOrderDirection
- } = usePagination
(MembersOrderBy.Name);
+ } = usePagination(MembersOrderBy.Name, { initPerPage: 20 });
const { data: members = [], isLoading: isMembersLoading } = useGetWorkspaceUsers(workspaceId);