feat: completed all nit changes in review

This commit is contained in:
=
2024-10-25 00:59:40 +05:30
parent 2afc6b133e
commit 3b2b8ca013
18 changed files with 87 additions and 60 deletions
@@ -20,7 +20,7 @@ export const registerIdentityProjectAdditionalPrivilegeRouter = async (server: F
rateLimit: writeLimit rateLimit: writeLimit
}, },
schema: { schema: {
description: "Create an additional privilege for identity.", description: "Add an additional privilege for identity.",
security: [ security: [
{ {
bearerAuth: [] bearerAuth: []
@@ -91,7 +91,7 @@ export const registerIdentityProjectAdditionalPrivilegeRouter = async (server: F
rateLimit: writeLimit rateLimit: writeLimit
}, },
schema: { schema: {
description: "Update a specific privilege of an identity.", description: "Update a specific identity privilege.",
security: [ security: [
{ {
bearerAuth: [] bearerAuth: []
@@ -167,7 +167,7 @@ export const registerIdentityProjectAdditionalPrivilegeRouter = async (server: F
rateLimit: writeLimit rateLimit: writeLimit
}, },
schema: { schema: {
description: "Delete a specific privilege of an identity.", description: "Delete the specified identity privilege.",
security: [ security: [
{ {
bearerAuth: [] bearerAuth: []
@@ -202,7 +202,7 @@ export const registerIdentityProjectAdditionalPrivilegeRouter = async (server: F
rateLimit: readLimit rateLimit: readLimit
}, },
schema: { schema: {
description: "Retrieve details of a specific privilege by privilege id.", description: "Retrieve details of a specific privilege by id.",
security: [ security: [
{ {
bearerAuth: [] bearerAuth: []
@@ -237,7 +237,7 @@ export const registerIdentityProjectAdditionalPrivilegeRouter = async (server: F
rateLimit: readLimit rateLimit: readLimit
}, },
schema: { schema: {
description: "Retrieve details of a specific privilege by privilege slug.", description: "Retrieve details of a specific privilege by slug.",
security: [ security: [
{ {
bearerAuth: [] bearerAuth: []
@@ -277,7 +277,7 @@ export const registerIdentityProjectAdditionalPrivilegeRouter = async (server: F
rateLimit: readLimit rateLimit: readLimit
}, },
schema: { schema: {
description: "List of a specific privilege of an identity in a project.", description: "List privileges for the specified identity by project.",
security: [ security: [
{ {
bearerAuth: [] bearerAuth: []
@@ -76,7 +76,7 @@ export const identityProjectAdditionalPrivilegeV2ServiceFactory = ({
slug, slug,
projectMembershipId: identityProjectMembership.id projectMembershipId: identityProjectMembership.id
}); });
if (existingSlug) throw new BadRequestError({ message: "Additional privilege of provided slug exist" }); if (existingSlug) throw new BadRequestError({ message: "Additional privilege with provided slug already exists" });
if (!dto.isTemporary) { if (!dto.isTemporary) {
const additionalPrivilege = await identityProjectAdditionalPrivilegeDAL.create({ const additionalPrivilege = await identityProjectAdditionalPrivilegeDAL.create({
@@ -117,7 +117,7 @@ export const identityProjectAdditionalPrivilegeV2ServiceFactory = ({
actorAuthMethod actorAuthMethod
}: TUpdateIdentityPrivilegeByIdDTO) => { }: TUpdateIdentityPrivilegeByIdDTO) => {
const identityPrivilege = await identityProjectAdditionalPrivilegeDAL.findById(id); const identityPrivilege = await identityProjectAdditionalPrivilegeDAL.findById(id);
if (!identityPrivilege) throw new NotFoundError({ message: "Identity additional privilege not found" }); if (!identityPrivilege) throw new NotFoundError({ message: `Identity privilege with ${id} not found` });
const identityProjectMembership = await identityProjectDAL.findOne({ id: identityPrivilege.projectMembershipId }); const identityProjectMembership = await identityProjectDAL.findOne({ id: identityPrivilege.projectMembershipId });
if (!identityProjectMembership) if (!identityProjectMembership)
@@ -150,7 +150,7 @@ export const identityProjectAdditionalPrivilegeV2ServiceFactory = ({
projectMembershipId: identityProjectMembership.id projectMembershipId: identityProjectMembership.id
}); });
if (existingSlug && existingSlug.id !== identityPrivilege.id) if (existingSlug && existingSlug.id !== identityPrivilege.id)
throw new BadRequestError({ message: "Additional privilege of provided slug exist" }); throw new BadRequestError({ message: "Additional privilege with provided slug already exists" });
} }
const isTemporary = typeof data?.isTemporary !== "undefined" ? data.isTemporary : identityPrivilege.isTemporary; const isTemporary = typeof data?.isTemporary !== "undefined" ? data.isTemporary : identityPrivilege.isTemporary;
@@ -189,7 +189,7 @@ export const identityProjectAdditionalPrivilegeV2ServiceFactory = ({
const deleteById = async ({ actorId, id, actor, actorOrgId, actorAuthMethod }: TDeleteIdentityPrivilegeByIdDTO) => { const deleteById = async ({ actorId, id, actor, actorOrgId, actorAuthMethod }: TDeleteIdentityPrivilegeByIdDTO) => {
const identityPrivilege = await identityProjectAdditionalPrivilegeDAL.findById(id); const identityPrivilege = await identityProjectAdditionalPrivilegeDAL.findById(id);
if (!identityPrivilege) throw new NotFoundError({ message: "Identity additional privilege not found" }); if (!identityPrivilege) throw new NotFoundError({ message: `Identity privilege with ${id} not found` });
const identityProjectMembership = await identityProjectDAL.findOne({ id: identityPrivilege.projectMembershipId }); const identityProjectMembership = await identityProjectDAL.findOne({ id: identityPrivilege.projectMembershipId });
if (!identityProjectMembership) if (!identityProjectMembership)
@@ -231,7 +231,7 @@ export const identityProjectAdditionalPrivilegeV2ServiceFactory = ({
actorAuthMethod actorAuthMethod
}: TGetIdentityPrivilegeDetailsByIdDTO) => { }: TGetIdentityPrivilegeDetailsByIdDTO) => {
const identityPrivilege = await identityProjectAdditionalPrivilegeDAL.findById(id); const identityPrivilege = await identityProjectAdditionalPrivilegeDAL.findById(id);
if (!identityPrivilege) throw new NotFoundError({ message: "Identity additional privilege not found" }); if (!identityPrivilege) throw new NotFoundError({ message: `Identity privilege with ${id} not found` });
const identityProjectMembership = await identityProjectDAL.findOne({ id: identityPrivilege.projectMembershipId }); const identityProjectMembership = await identityProjectDAL.findOne({ id: identityPrivilege.projectMembershipId });
if (!identityProjectMembership) if (!identityProjectMembership)
@@ -264,7 +264,7 @@ export const identityProjectAdditionalPrivilegeV2ServiceFactory = ({
actorAuthMethod actorAuthMethod
}: TGetIdentityPrivilegeDetailsBySlugDTO) => { }: TGetIdentityPrivilegeDetailsBySlugDTO) => {
const project = await projectDAL.findProjectBySlug(projectSlug, actorOrgId); const project = await projectDAL.findProjectBySlug(projectSlug, actorOrgId);
if (!project) throw new NotFoundError({ message: "Project not found" }); if (!project) throw new NotFoundError({ message: `Project with slug ${slug} not found` });
const projectId = project.id; const projectId = project.id;
const identityProjectMembership = await identityProjectDAL.findOne({ identityId, projectId }); const identityProjectMembership = await identityProjectDAL.findOne({ identityId, projectId });
@@ -2,8 +2,10 @@ import { ForbiddenError, MongoAbility, RawRuleOf } from "@casl/ability";
import { PackRule, unpackRules } from "@casl/ability/extra"; import { PackRule, unpackRules } from "@casl/ability/extra";
import ms from "ms"; import ms from "ms";
import { BadRequestError, NotFoundError } from "@app/lib/errors"; import { isAtLeastAsPrivileged } from "@app/lib/casl";
import { BadRequestError, ForbiddenRequestError, NotFoundError } from "@app/lib/errors";
import { UnpackedPermissionSchema } from "@app/server/routes/santizedSchemas/permission"; import { UnpackedPermissionSchema } from "@app/server/routes/santizedSchemas/permission";
import { ActorType } from "@app/services/auth/auth-type";
import { TProjectMembershipDALFactory } from "@app/services/project-membership/project-membership-dal"; import { TProjectMembershipDALFactory } from "@app/services/project-membership/project-membership-dal";
import { TPermissionServiceFactory } from "../permission/permission-service"; import { TPermissionServiceFactory } from "../permission/permission-service";
@@ -50,7 +52,7 @@ export const projectUserAdditionalPrivilegeServiceFactory = ({
}: TCreateUserPrivilegeDTO) => { }: TCreateUserPrivilegeDTO) => {
const projectMembership = await projectMembershipDAL.findById(projectMembershipId); const projectMembership = await projectMembershipDAL.findById(projectMembershipId);
if (!projectMembership) if (!projectMembership)
throw new NotFoundError({ message: `Project membership with ID '${projectMembershipId}' not found` }); throw new NotFoundError({ message: `Project membership with ID ${projectMembershipId} found` });
const { permission } = await permissionService.getProjectPermission( const { permission } = await permissionService.getProjectPermission(
actor, actor,
@@ -60,13 +62,24 @@ export const projectUserAdditionalPrivilegeServiceFactory = ({
actorOrgId actorOrgId
); );
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Edit, ProjectPermissionSub.Member); ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Edit, ProjectPermissionSub.Member);
const { permission: entityPermission } = await permissionService.getProjectPermission(
ActorType.USER,
projectMembership.userId,
projectMembership.projectId,
actorAuthMethod,
actorOrgId
);
const hasRequiredPriviledges = isAtLeastAsPrivileged(permission, entityPermission);
if (!hasRequiredPriviledges)
throw new ForbiddenRequestError({ message: "Failed to update more privileged identity" });
const existingSlug = await projectUserAdditionalPrivilegeDAL.findOne({ const existingSlug = await projectUserAdditionalPrivilegeDAL.findOne({
slug, slug,
projectId: projectMembership.projectId, projectId: projectMembership.projectId,
userId: projectMembership.userId userId: projectMembership.userId
}); });
if (existingSlug) throw new BadRequestError({ message: "Additional privilege of provided slug exist" }); if (existingSlug)
throw new BadRequestError({ message: `Additional privilege with provided slug ${slug} already exists` });
if (!dto.isTemporary) { if (!dto.isTemporary) {
const additionalPrivilege = await projectUserAdditionalPrivilegeDAL.create({ const additionalPrivilege = await projectUserAdditionalPrivilegeDAL.create({
@@ -109,7 +122,7 @@ export const projectUserAdditionalPrivilegeServiceFactory = ({
}: TUpdateUserPrivilegeDTO) => { }: TUpdateUserPrivilegeDTO) => {
const userPrivilege = await projectUserAdditionalPrivilegeDAL.findById(privilegeId); const userPrivilege = await projectUserAdditionalPrivilegeDAL.findById(privilegeId);
if (!userPrivilege) if (!userPrivilege)
throw new NotFoundError({ message: `User additional privilege with ID '${privilegeId}' not found` }); throw new NotFoundError({ message: `User additional privilege with ID ${privilegeId} not found` });
const projectMembership = await projectMembershipDAL.findOne({ const projectMembership = await projectMembershipDAL.findOne({
userId: userPrivilege.userId, userId: userPrivilege.userId,
@@ -129,6 +142,16 @@ export const projectUserAdditionalPrivilegeServiceFactory = ({
actorOrgId actorOrgId
); );
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Edit, ProjectPermissionSub.Member); ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Edit, ProjectPermissionSub.Member);
const { permission: entityPermission } = await permissionService.getProjectPermission(
ActorType.USER,
projectMembership.userId,
projectMembership.projectId,
actorAuthMethod,
actorOrgId
);
const hasRequiredPriviledges = isAtLeastAsPrivileged(permission, entityPermission);
if (!hasRequiredPriviledges)
throw new ForbiddenRequestError({ message: "Failed to update more privileged identity" });
if (dto?.slug) { if (dto?.slug) {
const existingSlug = await projectUserAdditionalPrivilegeDAL.findOne({ const existingSlug = await projectUserAdditionalPrivilegeDAL.findOne({
@@ -137,7 +160,7 @@ export const projectUserAdditionalPrivilegeServiceFactory = ({
projectId: projectMembership.projectId projectId: projectMembership.projectId
}); });
if (existingSlug && existingSlug.id !== userPrivilege.id) if (existingSlug && existingSlug.id !== userPrivilege.id)
throw new BadRequestError({ message: "Additional privilege of provided slug exist" }); throw new BadRequestError({ message: `Additional privilege with provided slug ${dto.slug} already exists` });
} }
const isTemporary = typeof dto?.isTemporary !== "undefined" ? dto.isTemporary : userPrivilege.isTemporary; const isTemporary = typeof dto?.isTemporary !== "undefined" ? dto.isTemporary : userPrivilege.isTemporary;
@@ -178,7 +201,7 @@ export const projectUserAdditionalPrivilegeServiceFactory = ({
const deleteById = async ({ actorId, actor, actorOrgId, actorAuthMethod, privilegeId }: TDeleteUserPrivilegeDTO) => { const deleteById = async ({ actorId, actor, actorOrgId, actorAuthMethod, privilegeId }: TDeleteUserPrivilegeDTO) => {
const userPrivilege = await projectUserAdditionalPrivilegeDAL.findById(privilegeId); const userPrivilege = await projectUserAdditionalPrivilegeDAL.findById(privilegeId);
if (!userPrivilege) if (!userPrivilege)
throw new NotFoundError({ message: `User additional privilege with ID '${privilegeId}' not found` }); throw new NotFoundError({ message: `User additional privilege with ID ${privilegeId} not found` });
const projectMembership = await projectMembershipDAL.findOne({ const projectMembership = await projectMembershipDAL.findOne({
userId: userPrivilege.userId, userId: userPrivilege.userId,
@@ -214,7 +237,7 @@ export const projectUserAdditionalPrivilegeServiceFactory = ({
}: TGetUserPrivilegeDetailsDTO) => { }: TGetUserPrivilegeDetailsDTO) => {
const userPrivilege = await projectUserAdditionalPrivilegeDAL.findById(privilegeId); const userPrivilege = await projectUserAdditionalPrivilegeDAL.findById(privilegeId);
if (!userPrivilege) if (!userPrivilege)
throw new NotFoundError({ message: `User additional privilege with ID '${privilegeId}' not found` }); throw new NotFoundError({ message: `User additional privilege with ID ${privilegeId} not found` });
const projectMembership = await projectMembershipDAL.findOne({ const projectMembership = await projectMembershipDAL.findOne({
userId: userPrivilege.userId, userId: userPrivilege.userId,
@@ -249,7 +272,7 @@ export const projectUserAdditionalPrivilegeServiceFactory = ({
}: TListUserPrivilegesDTO) => { }: TListUserPrivilegesDTO) => {
const projectMembership = await projectMembershipDAL.findById(projectMembershipId); const projectMembership = await projectMembershipDAL.findById(projectMembershipId);
if (!projectMembership) if (!projectMembership)
throw new NotFoundError({ message: `Project membership with ID '${projectMembershipId}' not found` }); throw new NotFoundError({ message: `Project membership with ID ${projectMembershipId} not found` });
const { permission } = await permissionService.getProjectPermission( const { permission } = await permissionService.getProjectPermission(
actor, actor,
+10 -10
View File
@@ -974,27 +974,27 @@ export const PROJECT_USER_ADDITIONAL_PRIVILEGE = {
export const IDENTITY_ADDITIONAL_PRIVILEGE_V2 = { export const IDENTITY_ADDITIONAL_PRIVILEGE_V2 = {
CREATE: { CREATE: {
identityId: "The ID of the identity to create.", identityId: "The ID of the identity to create the privilege for",
projectId: "The ID of the project of the identity in.", projectId: "The ID of the project of the identity in.",
slug: "The slug of the privilege to create.", slug: "The slug of the privilege to create.",
permission: "The permission for the privilege.", permission: "The permission for the privilege.",
isTemporary: "Whether the privilege is temporary.", isTemporary: "Whether the privilege is temporary or permanent.",
temporaryMode: "Type of temporary access given. Types: relative", temporaryMode: "Type of temporary access given. Types: relative",
temporaryRange: "TTL for the temporay time. Eg: 1m, 1h, 1d", temporaryRange: "The TTL for the temporary access given",
temporaryAccessStartTime: "ISO time for which temporary access should begin." temporaryAccessStartTime: "The start time in ISO format when the temporary access should begin."
}, },
UPDATE: { UPDATE: {
id: "The id of the privilege of the identity.", id: "The ID of the identity privilege.",
identityId: "The ID of the identity to update.", identityId: "The ID of the identity to update.",
slug: "The slug of the privilege to update.", slug: "The slug of the privilege to update.",
privilegePermission: "The permission for the privilege.", privilegePermission: "The permission for the privilege.",
isTemporary: "Whether the privilege is temporary.", isTemporary: "Whether the privilege is temporary.",
temporaryMode: "Type of temporary access given. Types: relative", temporaryMode: "Type of temporary access given. Types: relative",
temporaryRange: "TTL for the temporay time. Eg: 1m, 1h, 1d", temporaryRange: "The TTL for the temporary access given",
temporaryAccessStartTime: "ISO time for which temporary access should begin." temporaryAccessStartTime: "The start time in ISO format when the temporary access should begin."
}, },
DELETE: { DELETE: {
id: "the id of the privilege of the identity.", id: "The ID of the identity privilege.",
identityId: "The ID of the identity to delete.", identityId: "The ID of the identity to delete.",
slug: "The slug of the privilege to delete." slug: "The slug of the privilege to delete."
}, },
@@ -1004,10 +1004,10 @@ export const IDENTITY_ADDITIONAL_PRIVILEGE_V2 = {
slug: "The slug of the privilege." slug: "The slug of the privilege."
}, },
GET_BY_ID: { GET_BY_ID: {
id: "The id of the privilege of the identity." id: "The ID of the identity privilege."
}, },
LIST: { LIST: {
projectId: "The ID of the project of the identity in.", projectId: "The ID of the project that the identity is in.",
identityId: "The ID of the identity to list." identityId: "The ID of the identity to list."
} }
}; };
@@ -118,7 +118,7 @@ export const registerProjectMembershipRouter = async (server: FastifyZodProvider
}) })
} }
}, },
onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY, AuthMode.IDENTITY_ACCESS_TOKEN]), onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
handler: async (req) => { handler: async (req) => {
const membership = await server.services.projectMembership.getProjectMembershipById({ const membership = await server.services.projectMembership.getProjectMembershipById({
actorId: req.permission.id, actorId: req.permission.id,
+1 -1
View File
@@ -38,7 +38,7 @@ const glob: JsInterpreter<FieldCondition<string>> = (node, object, context) => {
const conditionsMatcher = buildMongoQueryMatcher({ $glob }, { glob }); const conditionsMatcher = buildMongoQueryMatcher({ $glob }, { glob });
export const roleQueryKeys = { export const roleQueryKeys = {
getProjectRoles: (projectId: string) => ["roles", { projectSlug: projectId }] as const, getProjectRoles: (projectId: string) => ["roles", { projectId }] as const,
getProjectRoleBySlug: (projectId: string, roleSlug: string) => getProjectRoleBySlug: (projectId: string, roleSlug: string) =>
["roles", { projectId, roleSlug }] as const, ["roles", { projectId, roleSlug }] as const,
getOrgRoles: (orgId: string) => ["org-roles", { orgId }] as const, getOrgRoles: (orgId: string) => ["org-roles", { orgId }] as const,
@@ -1,4 +1,3 @@
/* eslint-disable @typescript-eslint/no-unused-vars */
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import Head from "next/head"; import Head from "next/head";
@@ -1,4 +1,3 @@
/* eslint-disable @typescript-eslint/no-unused-vars */
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import Head from "next/head"; import Head from "next/head";
@@ -56,10 +56,10 @@ export const IdentityDetailsPage = withProjectPermission(
</h3> </h3>
<div> <div>
<ProjectPermissionCan <ProjectPermissionCan
I={ProjectPermissionActions.Edit} I={ProjectPermissionActions.Delete}
a={ProjectPermissionSub.Identity} a={ProjectPermissionSub.Identity}
renderTooltip renderTooltip
allowedLabel="Edit role" allowedLabel="Remove from project"
> >
{(isAllowed) => ( {(isAllowed) => (
<Button <Button
@@ -206,9 +206,7 @@ export const IdentityProjectAdditionalPrivilegeModifySection = ({
<IconButton ariaLabel="go-back" variant="plain" onClick={onGoBack}> <IconButton ariaLabel="go-back" variant="plain" onClick={onGoBack}>
<FontAwesomeIcon icon={faChevronLeft} /> <FontAwesomeIcon icon={faChevronLeft} />
</IconButton> </IconButton>
<h3 className="text-lg font-semibold text-mineshaft-100"> <h3 className="text-lg font-semibold text-mineshaft-100">Edit Additional Privilege</h3>
Modify Additional Privilege
</h3>
</div> </div>
<div className="flex items-center space-x-4"> <div className="flex items-center space-x-4">
{isDirty && ( {isDirty && (
@@ -98,7 +98,7 @@ export const IdentityProjectAdditionalPrivilegeSection = ({ identityMembershipDe
> >
<div className="flex items-center justify-between border-b border-mineshaft-400 pb-4"> <div className="flex items-center justify-between border-b border-mineshaft-400 pb-4">
<h3 className="text-lg font-semibold text-mineshaft-100"> <h3 className="text-lg font-semibold text-mineshaft-100">
Project Additional Privilege Project Additional Privileges
</h3> </h3>
<ProjectPermissionCan <ProjectPermissionCan
@@ -174,7 +174,7 @@ export const IdentityProjectAdditionalPrivilegeSection = ({ identityMembershipDe
}} }}
onClick={() => handlePopUpOpen("modifyPrivilege", privilegeDetails)} onClick={() => handlePopUpOpen("modifyPrivilege", privilegeDetails)}
> >
<Td className="capitalize">{privilegeDetails.slug}</Td> <Td>{privilegeDetails.slug}</Td>
<Td> <Td>
<Tooltip asChild={false} content={toolTipText}> <Tooltip asChild={false} content={toolTipText}>
<Tag <Tag
@@ -72,7 +72,7 @@ export const IdentityRoleDetailsSection = ({
I={ProjectPermissionActions.Edit} I={ProjectPermissionActions.Edit}
a={ProjectPermissionSub.Identity} a={ProjectPermissionSub.Identity}
renderTooltip renderTooltip
allowedLabel="Edit role" allowedLabel="Edit Role(s)"
> >
{(isAllowed) => ( {(isAllowed) => (
<IconButton <IconButton
@@ -54,10 +54,10 @@ export const MemberDetailsPage = withProjectPermission(
<h3 className="text-xl font-semibold text-mineshaft-100">Project User Access</h3> <h3 className="text-xl font-semibold text-mineshaft-100">Project User Access</h3>
<div> <div>
<ProjectPermissionCan <ProjectPermissionCan
I={ProjectPermissionActions.Edit} I={ProjectPermissionActions.Delete}
a={ProjectPermissionSub.Member} a={ProjectPermissionSub.Member}
renderTooltip renderTooltip
allowedLabel="Edit role" allowedLabel="Remove from project"
> >
{(isAllowed) => ( {(isAllowed) => (
<Button <Button
@@ -1,6 +1,6 @@
import { faFolder, faPlus, faTrash } from "@fortawesome/free-solid-svg-icons"; import { faFolder, faPlus, faTrash } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { format,formatDistance } from "date-fns"; import { format, formatDistance } from "date-fns";
import { AnimatePresence, motion } from "framer-motion"; import { AnimatePresence, motion } from "framer-motion";
import { twMerge } from "tailwind-merge"; import { twMerge } from "tailwind-merge";
@@ -19,7 +19,8 @@ import {
Th, Th,
THead, THead,
Tooltip, Tooltip,
Tr} from "@app/components/v2"; Tr
} from "@app/components/v2";
import { import {
ProjectPermissionActions, ProjectPermissionActions,
ProjectPermissionSub, ProjectPermissionSub,
@@ -104,7 +105,7 @@ export const MemberProjectAdditionalPrivilegeSection = ({ membershipDetails }: P
> >
<div className="flex items-center justify-between border-b border-mineshaft-400 pb-4"> <div className="flex items-center justify-between border-b border-mineshaft-400 pb-4">
<h3 className="text-lg font-semibold text-mineshaft-100"> <h3 className="text-lg font-semibold text-mineshaft-100">
Project Additional Privilege Project Additional Privileges
</h3> </h3>
{userId !== membershipDetails?.user?.id && {userId !== membershipDetails?.user?.id &&
membershipDetails?.status !== "invited" && ( membershipDetails?.status !== "invited" && (
@@ -180,7 +181,7 @@ export const MemberProjectAdditionalPrivilegeSection = ({ membershipDetails }: P
}} }}
onClick={() => handlePopUpOpen("modifyPrivilege", privilegeDetails)} onClick={() => handlePopUpOpen("modifyPrivilege", privilegeDetails)}
> >
<Td className="capitalize">{privilegeDetails.slug}</Td> <Td>{privilegeDetails.slug}</Td>
<Td> <Td>
<Tooltip asChild={false} content={toolTipText}> <Tooltip asChild={false} content={toolTipText}>
<Tag <Tag
@@ -163,7 +163,7 @@ export const MembershipProjectAdditionalPrivilegeModifySection = ({
onGoBack(); onGoBack();
} catch (err) { } catch (err) {
console.log(err); console.log(err);
createNotification({ type: "error", text: "Failed to update role" }); createNotification({ type: "error", text: "Failed to update privilege" });
} }
}; };
@@ -20,7 +20,8 @@ import {
Th, Th,
THead, THead,
Tooltip, Tooltip,
Tr} from "@app/components/v2"; Tr
} from "@app/components/v2";
import { import {
ProjectPermissionActions, ProjectPermissionActions,
ProjectPermissionSub, ProjectPermissionSub,
@@ -81,7 +82,7 @@ export const MemberRoleDetailsSection = ({
I={ProjectPermissionActions.Edit} I={ProjectPermissionActions.Edit}
a={ProjectPermissionSub.Member} a={ProjectPermissionSub.Member}
renderTooltip renderTooltip
allowedLabel="Edit role" allowedLabel="Edit role(s)"
> >
{(isAllowed) => ( {(isAllowed) => (
<IconButton <IconButton
@@ -19,16 +19,19 @@ export const IdentityRoleForm = ({ identityProjectMember, onOpenUpgradeModal }:
identityProjectMember={identityProjectMember} identityProjectMember={identityProjectMember}
onOpenUpgradeModal={onOpenUpgradeModal} onOpenUpgradeModal={onOpenUpgradeModal}
/> />
<Alert className="mt-4"> <Alert
title="Additional privileges have been moved and now offer full permission customization."
className="mt-4 border-primary/50 bg-primary/10"
>
<AlertDescription> <AlertDescription>
Additional privileges now offer full permissions and have been moved to a new screen.
<br />
<Link <Link
href={`/project/${currentWorkspace?.id || ""}/identitiesq/${ href={`/project/${currentWorkspace?.id || ""}/identities/${
identityProjectMember?.identity?.id identityProjectMember?.identity?.id
}`} }`}
> >
<span className="cursor-pointer text-primary">Click here to access them.</span> <span className="cursor-pointer text-primary underline underline-offset-2">
Click here to access them now
</span>
</Link> </Link>
</AlertDescription> </AlertDescription>
</Alert> </Alert>
@@ -15,12 +15,15 @@ export const MemberRoleForm = ({ projectMember, onOpenUpgradeModal }: Props) =>
return ( return (
<div> <div>
<MemberRbacSection projectMember={projectMember} onOpenUpgradeModal={onOpenUpgradeModal} /> <MemberRbacSection projectMember={projectMember} onOpenUpgradeModal={onOpenUpgradeModal} />
<Alert className="mt-4"> <Alert
title="Additional privileges have been moved and now offer full permission customization."
className="mt-4 border-primary/50 bg-primary/10"
>
<AlertDescription> <AlertDescription>
Additional privileges now offer full permissions and have been moved to a new screen.
<br />
<Link href={`/project/${currentWorkspace?.id || ""}/members/${projectMember?.id}`}> <Link href={`/project/${currentWorkspace?.id || ""}/members/${projectMember?.id}`}>
<span className="cursor-pointer text-primary">Click here to access them.</span> <span className="cursor-pointer text-primary underline underline-offset-2">
Click here to access them now
</span>
</Link> </Link>
</AlertDescription> </AlertDescription>
</Alert> </Alert>