diff --git a/backend/src/server/routes/v2/group-project-router.ts b/backend/src/server/routes/v2/group-project-router.ts index 8ed03ca08..d07e3bd8b 100644 --- a/backend/src/server/routes/v2/group-project-router.ts +++ b/backend/src/server/routes/v2/group-project-router.ts @@ -308,6 +308,9 @@ export const registerGroupProjectRouter = async (server: FastifyZodProvider) => method: "GET", url: "/:projectId/groups/:groupId/users", onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), + config: { + rateLimit: readLimit + }, schema: { hide: false, tags: [ApiDocsTags.ProjectGroups], diff --git a/frontend/src/pages/project/AccessControlPage/components/GroupsTab/components/GroupsSection/GroupRoles.tsx b/frontend/src/pages/project/AccessControlPage/components/GroupsTab/components/GroupsSection/GroupRoles.tsx index c3f255a9b..91b6d3186 100644 --- a/frontend/src/pages/project/AccessControlPage/components/GroupsTab/components/GroupsSection/GroupRoles.tsx +++ b/frontend/src/pages/project/AccessControlPage/components/GroupsTab/components/GroupsSection/GroupRoles.tsx @@ -29,6 +29,7 @@ import { formatProjectRoleName } from "@app/helpers/roles"; import { usePopUp } from "@app/hooks"; import { useGetProjectRoles, useUpdateGroupWorkspaceRole } from "@app/hooks/api"; import { TGroupMembership } from "@app/hooks/api/groups/types"; +import { TProjectRole } from "@app/hooks/api/roles/types"; import { ProjectUserMembershipTemporaryMode } from "@app/hooks/api/workspace/types"; import { groupBy } from "@app/lib/fn/array"; @@ -204,17 +205,22 @@ export type TMemberRolesProp = { const MAX_ROLES_TO_BE_SHOWN_IN_TABLE = 2; -export const GroupRoles = ({ - roles = [], - disableEdit = false, - groupId, - className, - popperContentProps -}: TMemberRolesProp) => { +type FormProps = { + projectRoles: Omit[] | undefined; + roles: TGroupMembership["roles"]; + groupId: string; + onClose: VoidFunction; +}; + +const GroupRolesForm = ({ projectRoles, roles, groupId, onClose }: FormProps) => { const { currentWorkspace } = useWorkspace(); - const { popUp, handlePopUpToggle } = usePopUp(["editRole"] as const); + const [searchRoles, setSearchRoles] = useState(""); + const userRolesGroupBySlug = groupBy(roles, ({ customRoleSlug, role }) => customRoleSlug || role); + + const updateGroupWorkspaceRole = useUpdateGroupWorkspaceRole(); + const { handleSubmit, control, @@ -224,13 +230,6 @@ export const GroupRoles = ({ resolver: zodResolver(formSchema) }); - const { data: projectRoles, isPending: isRolesLoading } = useGetProjectRoles( - currentWorkspace?.id ?? "" - ); - const userRolesGroupBySlug = groupBy(roles, ({ customRoleSlug, role }) => customRoleSlug || role); - - const updateGroupWorkspaceRole = useUpdateGroupWorkspaceRole(); - const handleRoleUpdate = async (data: TForm) => { const selectedRoles = Object.keys(data) .filter((el) => Boolean(data[el].isChecked)) @@ -261,13 +260,126 @@ export const GroupRoles = ({ roles: selectedRoles }); createNotification({ text: "Successfully updated group role", type: "success" }); - handlePopUpToggle("editRole"); + onClose(); setSearchRoles(""); } catch { createNotification({ text: "Failed to update group role", type: "error" }); } }; + return ( +
+
+ {projectRoles + ?.filter( + ({ name, slug }) => + name.toLowerCase().includes(searchRoles.toLowerCase()) || + slug.toLowerCase().includes(searchRoles.toLowerCase()) + ) + ?.map(({ id, name, slug }) => { + const userProjectRoleDetails = userRolesGroupBySlug?.[slug]?.[0]; + + return ( +
+
+ ( + { + field.onChange(isChecked); + setValue(`${slug}.temporaryAccess`, false); + }} + > + {name} + + )} + /> +
+
+ ( + { + setValue(`${slug}.isChecked`, true, { shouldDirty: true }); + field.onChange({ isTemporary: true, ...data }); + }} + onRemoveTemporary={() => { + setValue(`${slug}.isChecked`, false, { shouldDirty: true }); + field.onChange(false); + }} + /> + )} + /> +
+
+ ); + })} +
+
+
+ setSearchRoles(el.target.value)} + leftIcon={} + placeholder="Search roles.." + /> +
+
+ +
+
+
+ ); +}; + +export const GroupRoles = ({ + roles = [], + disableEdit = false, + groupId, + className, + popperContentProps +}: TMemberRolesProp) => { + const { currentWorkspace } = useWorkspace(); + const { popUp, handlePopUpToggle } = usePopUp(["editRole"] as const); + + const { data: projectRoles, isPending: isRolesLoading } = useGetProjectRoles( + currentWorkspace?.id ?? "" + ); + return (
{roles @@ -353,103 +465,12 @@ export const GroupRoles = ({
) : ( -
-
- {projectRoles - ?.filter( - ({ name, slug }) => - name.toLowerCase().includes(searchRoles.toLowerCase()) || - slug.toLowerCase().includes(searchRoles.toLowerCase()) - ) - ?.map(({ id, name, slug }) => { - const userProjectRoleDetails = userRolesGroupBySlug?.[slug]?.[0]; - - return ( -
-
- ( - { - field.onChange(isChecked); - setValue(`${slug}.temporaryAccess`, false); - }} - > - {name} - - )} - /> -
-
- ( - { - setValue(`${slug}.isChecked`, true, { shouldDirty: true }); - field.onChange({ isTemporary: true, ...data }); - }} - onRemoveTemporary={() => { - setValue(`${slug}.isChecked`, false, { shouldDirty: true }); - field.onChange(false); - }} - /> - )} - /> -
-
- ); - })} -
-
-
- setSearchRoles(el.target.value)} - leftIcon={} - placeholder="Search roles.." - /> -
-
- -
-
-
+ handlePopUpToggle("editRole")} + /> )} diff --git a/frontend/src/pages/project/GroupDetailsByIDPage/GroupDetailsByIDPage.tsx b/frontend/src/pages/project/GroupDetailsByIDPage/GroupDetailsByIDPage.tsx index 393419e64..a3dfabcd0 100644 --- a/frontend/src/pages/project/GroupDetailsByIDPage/GroupDetailsByIDPage.tsx +++ b/frontend/src/pages/project/GroupDetailsByIDPage/GroupDetailsByIDPage.tsx @@ -54,7 +54,7 @@ export const GroupDetailsByIDPage = () => { return ( <> - {t("common.head-title", { title: t("settings.members.title") })} + {t("common.head-title", { title: "Project Group" })} { }); createNotification({ - text: "Successfully removed identity from project", + text: "Successfully removed group from project", type: "success" });