diff --git a/frontend/src/components/v2/Dropdown/Dropdown.tsx b/frontend/src/components/v2/Dropdown/Dropdown.tsx index cf53714c3..def928c74 100644 --- a/frontend/src/components/v2/Dropdown/Dropdown.tsx +++ b/frontend/src/components/v2/Dropdown/Dropdown.tsx @@ -66,7 +66,7 @@ export const DropdownMenuItem = ({ className )} > - + {icon && {icon}} {children} diff --git a/frontend/src/context/OrganizationContext/OrganizationContext.tsx b/frontend/src/context/OrganizationContext/OrganizationContext.tsx index d05c496f6..69fd7fe38 100644 --- a/frontend/src/context/OrganizationContext/OrganizationContext.tsx +++ b/frontend/src/context/OrganizationContext/OrganizationContext.tsx @@ -3,7 +3,6 @@ import { createContext, ReactNode, useContext, useMemo } from "react"; import { useGetOrganization } from "@app/hooks/api"; import { Organization } from "@app/hooks/api/types"; -import { useWorkspace } from "../WorkspaceContext"; type TOrgContext = { orgs?: Organization[]; @@ -18,10 +17,10 @@ type Props = { }; export const OrgProvider = ({ children }: Props): JSX.Element => { - const { currentWorkspace } = useWorkspace(); const { data: userOrgs, isLoading } = useGetOrganization(); - const currentWsOrgID = currentWorkspace?.organization; + // const currentWsOrgID = currentWorkspace?.organization; + const currentWsOrgID = localStorage.getItem("orgData.id"); // memorize the workspace details for the context const value = useMemo( diff --git a/frontend/src/layouts/AppLayout/AppLayout.tsx b/frontend/src/layouts/AppLayout/AppLayout.tsx index 5bc1bb345..586f171f4 100644 --- a/frontend/src/layouts/AppLayout/AppLayout.tsx +++ b/frontend/src/layouts/AppLayout/AppLayout.tsx @@ -144,6 +144,11 @@ export const AppLayout = ({ children }: LayoutProps) => { } }; + const changeOrg = async (orgId) => { + localStorage.setItem("orgData.id", orgId); + router.push(`/org/${orgId}/overview`) + } + // TODO(akhilmhdh): This entire logic will be rechecked and will try to avoid // Placing the localstorage as much as possible // Wait till tony integrates the azure and its launched @@ -158,7 +163,7 @@ export const AppLayout = ({ children }: LayoutProps) => { if (currentOrg && ( (workspaces?.length === 0 && router.asPath.includes("project")) || router.asPath.includes("/project/undefined") - || (!orgs?.includes(router.query.id) && !router.asPath.includes("project") && !router.asPath.includes("integration")) + || (!orgs?.map(org => org._id)?.includes(router.query.id) && !router.asPath.includes("project") && !router.asPath.includes("integration")) )) { router.push(`/org/${currentOrg?._id}/overview`); } @@ -254,11 +259,21 @@ export const AppLayout = ({ children }: LayoutProps) => {
{currentOrg?.name}
- +
{user?.email}
{orgs?.map(org => -
{org.name}{currentOrg._id === org._id && }
-
)} + + + )}
diff --git a/frontend/src/pages/_app.tsx b/frontend/src/pages/_app.tsx index 164ad5270..963a8d655 100644 --- a/frontend/src/pages/_app.tsx +++ b/frontend/src/pages/_app.tsx @@ -77,8 +77,8 @@ const App = ({ Component, pageProps, ...appProps }: NextAppProp): JSX.Element => - - + + @@ -90,8 +90,8 @@ const App = ({ Component, pageProps, ...appProps }: NextAppProp): JSX.Element => - - + + diff --git a/frontend/src/pages/org/[id]/overview/index.tsx b/frontend/src/pages/org/[id]/overview/index.tsx index cc086937c..6d4f5341d 100644 --- a/frontend/src/pages/org/[id]/overview/index.tsx +++ b/frontend/src/pages/org/[id]/overview/index.tsx @@ -147,9 +147,8 @@ export default function Organization() { const router = useRouter(); - const { workspaces, - // isLoading: isWorkspaceLoading - } = useWorkspace(); + const { workspaces } = useWorkspace(); + const orgWorkspaces = workspaces?.filter(workspace => workspace.organization === localStorage.getItem("orgData.id")) || [] const currentOrg = String(router.query.id); const { createNotification } = useNotificationContext(); const addWsUser = useAddUserToWs(); @@ -243,7 +242,7 @@ export default function Organization() {
-

Projects

+

Projects {orgWorkspaces.map(ws => ws?.name).join("")}

- {workspaces.filter(ws => ws.name.toLowerCase().includes(searchFilter.toLowerCase())).map(workspace =>
+ {orgWorkspaces.filter(ws => ws?.name?.toLowerCase().includes(searchFilter.toLowerCase())).map(workspace =>
{workspace.name}
{(workspace.environments?.length || 0)} environments
@@ -276,7 +275,7 @@ export default function Organization() {
)}
- {workspaces.length === 0 && ( + {orgWorkspaces.length === 0 && (
@@ -300,16 +299,16 @@ export default function Organization() { userAction: "intro_cta_clicked", link: "https://www.youtube.com/watch?v=PK23097-25I" })} - {workspaces.length !== 0 && learningItem({ + {orgWorkspaces.length !== 0 && learningItem({ text: "Add your secrets", subText: "Click to see example secrets, and add your own.", complete: hasUserPushedSecrets, icon: faPlus, time: "1 min", userAction: "first_time_secrets_pushed", - link: `/project/${workspaces[0]?._id}/secrets` + link: `/project/${orgWorkspaces[0]?._id}/secrets` })} - {workspaces.length !== 0 &&
+ {orgWorkspaces.length !== 0 &&
@@ -332,7 +331,7 @@ export default function Organization() { {false &&
}
} - {workspaces.length !== 0 && learningItem({ + {orgWorkspaces.length !== 0 && learningItem({ text: "Integrate Infisical with your infrastructure", subText: "Connect Infisical to various 3rd party services and platforms.", complete: false, diff --git a/frontend/src/views/Org/MembersPage/components/OrgMembersTable/OrgMembersTable.tsx b/frontend/src/views/Org/MembersPage/components/OrgMembersTable/OrgMembersTable.tsx index c9a2cf36c..a995661c9 100644 --- a/frontend/src/views/Org/MembersPage/components/OrgMembersTable/OrgMembersTable.tsx +++ b/frontend/src/views/Org/MembersPage/components/OrgMembersTable/OrgMembersTable.tsx @@ -27,6 +27,7 @@ import { THead, Tr, UpgradePlanModal} from "@app/components/v2"; +import { useWorkspace } from "@app/context"; import { usePopUp, useToggle } from "@app/hooks"; import { useFetchServerStatus } from "@app/hooks/api/serverDetails"; import { OrgUser, Workspace } from "@app/hooks/api/types"; @@ -70,6 +71,7 @@ export const OrgMembersTable = ({ const router = useRouter(); const [searchMemberFilter, setSearchMemberFilter] = useState(""); const {data: serverDetails } = useFetchServerStatus() + const { workspaces } = useWorkspace(); const [isInviteLinkCopied, setInviteLinkCopied] = useToggle(false); const { handlePopUpToggle, popUp, handlePopUpOpen, handlePopUpClose } = usePopUp([ "addMember", @@ -230,7 +232,7 @@ export const OrgMembersTable = ({ : This user isn't part of any projects yet} {router.query.id !== "undefined" && !((status === "invited" || status === "verified") && serverDetails?.emailConfigured) && -
- - handlePopUpToggle("upgradePlan", isOpen)} - text="Add more members by upgrading to a higher Infisical plan." - /> - -
- ); -} \ No newline at end of file diff --git a/frontend/src/views/Settings/OrgSettingsPage/components/OrgMembersSection/OrgMembersTable.tsx b/frontend/src/views/Settings/OrgSettingsPage/components/OrgMembersSection/OrgMembersTable.tsx deleted file mode 100644 index a9f54eee0..000000000 --- a/frontend/src/views/Settings/OrgSettingsPage/components/OrgMembersSection/OrgMembersTable.tsx +++ /dev/null @@ -1,304 +0,0 @@ -import { useMemo, useState } from "react"; -import { useRouter } from "next/router"; -import { faMagnifyingGlass, faPlus, faTrash, faUsers } from "@fortawesome/free-solid-svg-icons"; -import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; - -import { useNotificationContext } from "@app/components/context/Notifications/NotificationProvider"; -import { - decryptAssymmetric, - encryptAssymmetric -} from "@app/components/utilities/cryptography/crypto"; -import { - Button, - DeleteActionModal, - EmptyState, - IconButton, - Input, - Select, - SelectItem, - Table, - TableContainer, - TableSkeleton, - Tag, - TBody, - Td, - Th, - THead, - Tr -} from "@app/components/v2"; -import { useOrganization, useUser, useWorkspace } from "@app/context"; -import { usePopUp } from "@app/hooks"; -import { - useAddUserToOrg, - useDeleteOrgMembership, - useGetOrgUsers, - useGetUserWorkspaceMemberships, - useGetUserWsKey, - useUpdateOrgUserRole, - useUploadWsKey -} from "@app/hooks/api"; -import { useFetchServerStatus } from "@app/hooks/api/serverDetails"; - -export const OrgMembersTable = () => { - const router = useRouter(); - const { user: currentUser } = useUser(); - const { currentWorkspace } = useWorkspace(); - const { currentOrg } = useOrganization(); - const { createNotification } = useNotificationContext(); - const [searchMemberFilter, setSearchMemberFilter] = useState(""); - - const { data: serverDetails } = useFetchServerStatus() - const { data: members, isLoading: isOrgUserLoading } = useGetOrgUsers(currentOrg?._id ?? ""); // members - const { data: workspaceMemberships, isLoading: IsWsMembershipLoading } = useGetUserWorkspaceMemberships(currentOrg?._id ?? ""); - const { data: wsKey } = useGetUserWsKey(currentWorkspace?._id || ""); - - const uploadWsKey = useUploadWsKey(); - const addUserToOrg = useAddUserToOrg(); - const removeUserOrgMembership = useDeleteOrgMembership(); - const updateOrgUserRole = useUpdateOrgUserRole(); - - const { handlePopUpToggle, popUp, handlePopUpOpen, handlePopUpClose } = usePopUp([ - "removeMember", - "setUpEmail" - ] as const); - - const isLoading = isOrgUserLoading || IsWsMembershipLoading; - const userId = currentUser?._id || ""; - const onRemoveMember = async (membershipId: string) => { - if (!currentOrg?._id) return; - - try { - if (!currentOrg?._id) return; - await removeUserOrgMembership.mutateAsync({ orgId: currentOrg?._id, membershipId }); - createNotification({ - text: "Successfully removed user from org", - type: "success" - }); - } catch (error) { - console.error(error); - createNotification({ - text: "Failed to remove user from the organization", - type: "error" - }); - } - }; - - const onRemoveOrgMemberApproved = async () => { - const orgMembershipId = (popUp?.removeMember?.data as { id: string })?.id; - await onRemoveMember(orgMembershipId); - handlePopUpClose("removeMember"); - }; - - - const onInviteMember = async (email: string) => { - if (!currentOrg?._id) return; - - try { - const { data } = await addUserToOrg.mutateAsync({ - organizationId: currentOrg?._id, - inviteeEmail: email - }); - - // only show this notification when email is configured. A [completeInviteLink] will not be sent if smtp is configured - if (!data.completeInviteLink) { - createNotification({ - text: "Successfully invited user to the organization.", - type: "success" - }); - } - } catch (error) { - console.error(error); - createNotification({ - text: "Failed to invite user to org", - type: "error" - }); - } - }; - - const onGrantAccess = async (targetUserId: string, publicKey: string) => { - try { - const PRIVATE_KEY = localStorage.getItem("PRIVATE_KEY") as string; - if (!PRIVATE_KEY || !wsKey) return; - - // assymmetrically decrypt symmetric key with local private key - const key = decryptAssymmetric({ - ciphertext: wsKey.encryptedKey, - nonce: wsKey.nonce, - publicKey: wsKey.sender.publicKey, - privateKey: PRIVATE_KEY - }); - - const { ciphertext, nonce } = encryptAssymmetric({ - plaintext: key, - publicKey, - privateKey: PRIVATE_KEY - }); - - await uploadWsKey.mutateAsync({ - userId: targetUserId, - nonce, - encryptedKey: ciphertext, - workspaceId: currentWorkspace?._id || "" - }); - } catch (err) { - console.error(err); - createNotification({ - text: "Failed to grant access to user", - type: "error" - }); - } - }; - - const onRoleChange = async (membershipId: string, role: string) => { - if (!currentOrg?._id) return; - - try { - await updateOrgUserRole.mutateAsync({ organizationId: currentOrg?._id, membershipId, role }); - createNotification({ - text: "Successfully updated user role", - type: "success" - }); - } catch (error) { - console.error(error); - createNotification({ - text: "Failed to update user role", - type: "error" - }); - } - }; - - const isIamOwner = useMemo( - () => members ? members.find(({ user }) => userId === user?._id)?.role === "owner" : [], - [userId, members] - ); - - const filterdUser = useMemo( - () => - members ? members.filter( - ({ user, inviteEmail }) => - user?.firstName?.toLowerCase().includes(searchMemberFilter) || - user?.lastName?.toLowerCase().includes(searchMemberFilter) || - user?.email?.toLowerCase().includes(searchMemberFilter) || - inviteEmail?.includes(searchMemberFilter) - ) : [], - [members, searchMemberFilter] - ); - - - return ( -
- setSearchMemberFilter(e.target.value)} - leftIcon={} - placeholder="Search members..." - /> - - - - - - - - - - - - {isLoading && } - {!isLoading && - filterdUser.map(({ user, inviteEmail, role, _id: orgMembershipId, status }) => { - const name = user ? `${user.firstName} ${user.lastName}` : "-"; - const email = user?.email || inviteEmail; - const userWs = workspaceMemberships?.[user?._id]; - - return ( - - - - - - - - ); - })} - -
NameEmailRoleProjects -
{name}{email} - {status === "accepted" && ( - - )} - {((status === "invited" || status === "verified") && serverDetails?.emailConfigured) && ( - - )} - {status === "completed" && ( - - )} - - {userWs ? ( - userWs?.map(({ name: wsName, _id }) => ( - - {wsName} - - )) - ) : ( -
- {((status === "invited" || status === "verified") && serverDetails?.emailConfigured) - ? This user hasn't accepted the invite yet - : This user isn't part of any projects yet} - {router.query.id !== "undefined" && !((status === "invited" || status === "verified") && serverDetails?.emailConfigured) && } -
- )} -
- {userId !== user?._id && ( - handlePopUpOpen("removeMember", { id: orgMembershipId })} - > - - - )} -
- {!isLoading && filterdUser?.length === 0 && ( - - )} -
- handlePopUpToggle("removeMember", isOpen)} - onDeleteApproved={onRemoveOrgMemberApproved} - /> -
- ); -}; \ No newline at end of file diff --git a/frontend/src/views/Settings/OrgSettingsPage/components/OrgMembersSection/index.tsx b/frontend/src/views/Settings/OrgSettingsPage/components/OrgMembersSection/index.tsx index 973e12e3e..e69de29bb 100644 --- a/frontend/src/views/Settings/OrgSettingsPage/components/OrgMembersSection/index.tsx +++ b/frontend/src/views/Settings/OrgSettingsPage/components/OrgMembersSection/index.tsx @@ -1 +0,0 @@ -export { OrgMembersSection } from "./OrgMembersSection"; diff --git a/frontend/src/views/Settings/OrgSettingsPage/components/index.tsx b/frontend/src/views/Settings/OrgSettingsPage/components/index.tsx index e852edb06..9d2819536 100644 --- a/frontend/src/views/Settings/OrgSettingsPage/components/index.tsx +++ b/frontend/src/views/Settings/OrgSettingsPage/components/index.tsx @@ -1,4 +1,3 @@ export { OrgIncidentContactsSection } from "./OrgIncidentContactsSection"; -export { OrgMembersSection } from "./OrgMembersSection"; export { OrgNameChangeSection } from "./OrgNameChangeSection"; export { OrgServiceAccountsTable } from "./OrgServiceAccountsTable"; \ No newline at end of file