diff --git a/backend/src/controllers/v1/organizationController.ts b/backend/src/controllers/v1/organizationController.ts index eaf58fad7..66326e560 100644 --- a/backend/src/controllers/v1/organizationController.ts +++ b/backend/src/controllers/v1/organizationController.ts @@ -397,9 +397,21 @@ export const getOrganizationMembersAndTheirWorkspaces = async ( res: Response ) => { const { organizationId } = req.params; - const orgMemberships = await MembershipOrg.find({ organization: organizationId }); - const userIds = orgMemberships.map(orgMembership => orgMembership.user); - const memberships = await Membership.find({ user: { $in: userIds } }); + + const workspacesSet = ( + await Workspace.find( + { + organization: organizationId + }, + '_id' + ) + ).map((w) => w._id.toString()); + + const memberships = ( + await Membership.find({ + workspace: { $in: workspacesSet } + }).populate('workspace') + ); const userToWorkspaceIds: any = {}; memberships.forEach(membership => { @@ -411,15 +423,5 @@ export const getOrganizationMembersAndTheirWorkspaces = async ( } }); - const workspaceIds = Object.values(userToWorkspaceIds).flat() - const workspacesList = await Workspace.find({ - organization: organizationId, - _id: { $in: workspaceIds } - }); - - const populatedUserWorkspaces = _.mapValues(userToWorkspaceIds, workspaceIds => - _.map(workspaceIds, id => _.find(workspacesList, { _id: id })) - ); - - return res.json(populatedUserWorkspaces); + return res.json(userToWorkspaceIds); }; \ No newline at end of file diff --git a/backend/src/controllers/v2/environmentController.ts b/backend/src/controllers/v2/environmentController.ts index 7a0d5e1c5..b82dca9fe 100644 --- a/backend/src/controllers/v2/environmentController.ts +++ b/backend/src/controllers/v2/environmentController.ts @@ -246,13 +246,14 @@ export const getAllAccessibleEnvironmentsOfWorkspace = async ( relatedWorkspace.environments.forEach(environment => { const isReadBlocked = _.some(deniedPermission, { environmentSlug: environment.slug, ability: ABILITY_READ }) const isWriteBlocked = _.some(deniedPermission, { environmentSlug: environment.slug, ability: ABILITY_WRITE }) - if (isReadBlocked) { + if (isReadBlocked && isWriteBlocked) { return } else { accessibleEnvironments.push({ name: environment.name, slug: environment.slug, - isWriteDenied: isWriteBlocked + isWriteDenied: isWriteBlocked, + isReadDenied: isReadBlocked }) } }) diff --git a/frontend/public/data/frequentInterfaces.ts b/frontend/public/data/frequentInterfaces.ts index 9865d9909..fa6c73a57 100644 --- a/frontend/public/data/frequentInterfaces.ts +++ b/frontend/public/data/frequentInterfaces.ts @@ -10,7 +10,7 @@ export interface Tag { export interface SecretDataProps { pos: number; key: string; - value: string; + value: string | undefined; valueOverride: string | undefined; id: string; comment: string; diff --git a/frontend/src/components/basic/table/ProjectUsersTable.tsx b/frontend/src/components/basic/table/ProjectUsersTable.tsx index 9d278bdc4..27346195c 100644 --- a/frontend/src/components/basic/table/ProjectUsersTable.tsx +++ b/frontend/src/components/basic/table/ProjectUsersTable.tsx @@ -1,6 +1,6 @@ import { useEffect, useState } from 'react'; import { useRouter } from 'next/router'; -import { faX } from '@fortawesome/free-solid-svg-icons'; +import { faEye, faEyeSlash, faPenToSquare, faPlus, faX } from '@fortawesome/free-solid-svg-icons'; import { plans } from 'public/data/frequentConstants'; import { useNotificationContext } from '@app/components/context/Notifications/NotificationProvider'; @@ -106,6 +106,11 @@ const ProjectUsersTable = ({ userData, changeData, myUser, filter }: Props) => { ability: "read", environmentSlug: slug }]; + } else if (val === "Add Only") { + denials = [{ + ability: "read", + environmentSlug: slug + }]; } else { denials = []; } @@ -185,21 +190,21 @@ const ProjectUsersTable = ({ userData, changeData, myUser, filter }: Props) => { return (
-
+
- + {workspaceEnvs.map(env => ( - ))} @@ -221,7 +226,7 @@ const ProjectUsersTable = ({ userData, changeData, myUser, filter }: Props) => { user.email?.toLowerCase().includes(filter) ) .map((row, index) => ( - + @@ -231,7 +236,8 @@ const ProjectUsersTable = ({ userData, changeData, myUser, filter }: Props) => { - {workspaceEnvs.map((env) => )}
NAME EMAIL ROLE - {env.name.toUpperCase()}
+
+ {env.slug.toUpperCase()}
{/* PERMISSION */}
{row.firstName} {row.lastName}
+ {workspaceEnvs.map((env) => diff --git a/frontend/src/components/basic/table/UserTable.tsx b/frontend/src/components/basic/table/UserTable.tsx index 02e65c547..c14d77b08 100644 --- a/frontend/src/components/basic/table/UserTable.tsx +++ b/frontend/src/components/basic/table/UserTable.tsx @@ -4,6 +4,7 @@ import { faX } from '@fortawesome/free-solid-svg-icons'; import changeUserRoleInOrganization from '@app/pages/api/organization/changeUserRoleInOrganization'; import deleteUserFromOrganization from '@app/pages/api/organization/deleteUserFromOrganization'; +import getOrganizationProjectMemberships from '@app/pages/api/organization/GetOrgProjectMemberships'; import deleteUserFromWorkspace from '@app/pages/api/workspace/deleteUserFromWorkspace'; import getLatestFileKey from '@app/pages/api/workspace/getLatestFileKey'; import uploadKeys from '@app/pages/api/workspace/uploadKeys'; @@ -36,6 +37,8 @@ const UserTable = ({ userData, changeData, myUser, filter, resendInvite, isOrg } ); const router = useRouter(); const [myRole, setMyRole] = useState('member'); + const [userProjectMemberships, setUserProjectMemberships] = useState([]); + console.log(123, userData) const workspaceId = router.query.id as string; // Delete the row in the table (e.g. a user) @@ -79,6 +82,10 @@ const UserTable = ({ userData, changeData, myUser, filter, resendInvite, isOrg } useEffect(() => { setMyRole(userData.filter((user) => user.email === myUser)[0]?.role); + (async () => { + const result = await getOrganizationProjectMemberships({ orgId: String(localStorage.getItem("orgData.id"))}) + setUserProjectMemberships(result); + })(); }, [userData, myUser]); const grantAccess = async (id: string, publicKey: string) => { @@ -110,7 +117,7 @@ const UserTable = ({ userData, changeData, myUser, filter, resendInvite, isOrg } }; return ( -
+
@@ -118,6 +125,7 @@ const UserTable = ({ userData, changeData, myUser, filter, resendInvite, isOrg } + @@ -189,6 +197,17 @@ const UserTable = ({ userData, changeData, myUser, filter, resendInvite, isOrg } )} + +
NAME EMAIL ROLEPROJECTS
+ + {userProjectMemberships[row.userId] + ? userProjectMemberships[row.userId]?.map((project: any) => ( +
+ {project.name} +
+ )) + : This user isn't part of any projects yet.} +
{myUser !== row.email && // row.role !== "admin" && diff --git a/frontend/src/components/context/Notifications/Notification.tsx b/frontend/src/components/context/Notifications/Notification.tsx index ca1b155bd..921f86dec 100644 --- a/frontend/src/components/context/Notifications/Notification.tsx +++ b/frontend/src/components/context/Notifications/Notification.tsx @@ -1,5 +1,5 @@ import { useEffect, useRef } from 'react'; -import { faX } from '@fortawesome/free-solid-svg-icons'; +import { faXmark } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; type NotificationType = 'success' | 'error' | 'info'; @@ -36,7 +36,7 @@ const Notification = ({ notification, clearNotification }: NotificationProps) => return (
{notification.type === 'error' && ( @@ -48,13 +48,13 @@ const Notification = ({ notification, clearNotification }: NotificationProps) => {notification.type === 'info' && (
)} -

{notification.text}

+

{notification.text}

); diff --git a/frontend/src/components/dashboard/DashboardInputField.tsx b/frontend/src/components/dashboard/DashboardInputField.tsx index a55c3ba61..a5ee0ed3a 100644 --- a/frontend/src/components/dashboard/DashboardInputField.tsx +++ b/frontend/src/components/dashboard/DashboardInputField.tsx @@ -1,9 +1,10 @@ import { memo, SyntheticEvent, useRef } from 'react'; -import { faCircle, faExclamationCircle, faEye, faLayerGroup } from '@fortawesome/free-solid-svg-icons'; +import { faCircle, faCodeBranch, faExclamationCircle, faEye } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import guidGenerator from '../utilities/randomId'; import { HoverObject } from '../v2/HoverCard'; +import { PopoverObject } from '../v2/Popover/Popover'; const REGEX = /([$]{.*?})/g; @@ -112,7 +113,7 @@ const DashboardInputField = ({ }}> @@ -125,24 +126,24 @@ const DashboardInputField = ({ const error = startsWithNumber || isDuplicate; return ( -
-
- onChangeHandler(e.target.value, position)} - type={type} - value={value} - className='z-10 peer ph-no-capture bg-transparent py-2.5 caret-bunker-200 text-sm px-2 w-full min-w-16 outline-none text-bunker-300 focus:text-bunker-100 placeholder:text-bunker-400 placeholder:focus:text-transparent placeholder duration-200' - spellCheck="false" - placeholder='–' - /> + +
+
+ {value?.split("\n")[0] ? + {value?.split("\n")[0]} + : - } + {value?.split("\n")[1] && + {value?.split("\n")[1]} + } +
-
+ ); } if (type === 'value') { @@ -215,7 +216,7 @@ const DashboardInputField = ({ ))} {value?.split('').length === 0 && EMPTY}
-
+
)} diff --git a/frontend/src/components/dashboard/KeyPair.tsx b/frontend/src/components/dashboard/KeyPair.tsx index 711d25a51..de55b7322 100644 --- a/frontend/src/components/dashboard/KeyPair.tsx +++ b/frontend/src/components/dashboard/KeyPair.tsx @@ -132,7 +132,7 @@ const KeyPair = ({ /> -
+
- { if (deleteRow) { deleteRow({ ids: [keyPair.id], secretName: keyPair?.key }) }}} isPlain /> + :
+
null} + role="button" + tabIndex={0} + onClick={() => { if (deleteRow) { + deleteRow({ ids: [keyPair.id], secretName: keyPair?.key }) + }}} + className="invisible group-hover:visible" + > + +
+
}
diff --git a/frontend/src/components/dashboard/SideBar.tsx b/frontend/src/components/dashboard/SideBar.tsx index 1d0996376..6fac52ed7 100644 --- a/frontend/src/components/dashboard/SideBar.tsx +++ b/frontend/src/components/dashboard/SideBar.tsx @@ -18,7 +18,7 @@ import GenerateSecretMenu from './GenerateSecretMenu'; interface SecretProps { key: string; - value: string; + value: string | undefined; valueOverride: string | undefined; pos: number; id: string; @@ -80,9 +80,9 @@ const SideBar = ({ const { t } = useTranslation(); return ( -
+
{isLoading ? ( -
+
) : ( -
+

{t('dashboard:sidebar.secret')}

)} -
+