import { useQuery } from "@tanstack/react-query"; import { UpgradePlanModal } from "@app/components/license/UpgradePlanModal"; import { createNotification } from "@app/components/notifications"; import { OrgPermissionCan } from "@app/components/permissions"; import { Button, Modal, ModalContent, Skeleton, Spinner, Switch } from "@app/components/v2"; import { OrgPermissionActions, OrgPermissionSubjects, useSubscription } from "@app/context"; import { githubOrgSyncConfigQueryKeys, useSyncAllGithubTeams, useUpdateGithubSyncOrgConfig } from "@app/hooks/api"; import { usePopUp } from "@app/hooks/usePopUp"; import { GithubOrgSyncConfigModal } from "./GithubOrgSyncConfigModal"; export const OrgGithubSyncSection = () => { const { subscription } = useSubscription(); const { popUp, handlePopUpOpen, handlePopUpToggle } = usePopUp([ "upgradePlan", "githubOrgSyncConfig", "deleteGithubOrgSyncConfig" ] as const); const githubOrgSyncConfig = useQuery({ ...githubOrgSyncConfigQueryKeys.get(), enabled: subscription.githubOrgSync, retry: false }); const updateGithubSyncOrgConfig = useUpdateGithubSyncOrgConfig(); const syncAllTeamsMutation = useSyncAllGithubTeams(); const isPending = subscription.githubOrgSync && githubOrgSyncConfig.isPending; const data = !isPending && !githubOrgSyncConfig?.isError ? githubOrgSyncConfig?.data : undefined; const handleBulkSync = async () => { try { const result = await syncAllTeamsMutation.mutateAsync(); let message = "Successfully synced teams"; const details = []; if (result.createdTeams.length > 0) { details.push( `${result.createdTeams.length} new team${result.createdTeams.length === 1 ? "" : "s"} created` ); } if (result.updatedTeams.length > 0) { details.push( `${result.updatedTeams.length} team${result.updatedTeams.length === 1 ? "" : "s"} updated` ); } if (result.removedMemberships > 0) { details.push( `${result.removedMemberships} membership${result.removedMemberships === 1 ? "" : "s"} removed` ); } if (details.length > 0) { message += `. ${details.join(", ")}`; } createNotification({ text: message, type: "success" }); if (result.errors && result.errors.length > 0) { createNotification({ text: `Sync completed with ${result.errors.length} warnings. Check the console for details.`, type: "warning" }); console.warn("Sync errors:", result.errors); } } catch (error) { const errorMessage = (error as any)?.response?.data?.message || (error as Error)?.message || "Unknown error"; if ( errorMessage.includes("token") && (errorMessage.includes("required") || errorMessage.includes("invalid") || errorMessage.includes("expired") || errorMessage.includes("set a token first")) ) { createNotification({ text: "Please set a GitHub access token in the configuration modal to continue with the sync", type: "error" }); } else { createNotification({ text: `Failed to sync GitHub teams: ${errorMessage}`, type: "error" }); } } }; return (

Sync user groups from your GitHub Organization

GitHub Organization

{(isAllowed) => ( )}

{isPending ? : null} {data ? data?.githubOrgName : "Not configured"}

{data && (

Enable GitHub Sync

{(isAllowed) => ( updateGithubSyncOrgConfig.mutate({ isActive: value }) } isChecked={githubOrgSyncConfig?.data?.isActive ?? false} isDisabled={!isAllowed} > {updateGithubSyncOrgConfig?.isPending && } )}

Allow group provisioning/deprovisioning with GitHub

)} {data && data.isActive && (

Sync Now

{(isAllowed) => ( )}

Manually sync GitHub teams for all organization members. This will update team memberships for users who have previously logged in with GitHub.

)} { handlePopUpToggle("githubOrgSyncConfig", isOpen); }} > handlePopUpToggle("upgradePlan", isOpen)} text="Your current plan does not include access to GitHub Organization Sync. To unlock this feature, please upgrade to Infisical Enterprise plan." isEnterpriseFeature={popUp.upgradePlan.data?.isEnterpriseFeature} />
); };