IntegrationSettings.tsx209 lines · main
| 1 | // @ts-nocheck |
| 2 | import { PermissionAction } from '@supabase/shared-types/out/constants' |
| 3 | import { useRouter } from 'next/router' |
| 4 | import { useCallback } from 'react' |
| 5 | import { toast } from 'sonner' |
| 6 | import { GenericSkeletonLoader } from 'ui-patterns' |
| 7 | |
| 8 | import { IntegrationConnectionItem } from '../../Integrations/VercelGithub/IntegrationConnection' |
| 9 | import SidePanelVercelProjectLinker from './SidePanelVercelProjectLinker' |
| 10 | import { EmptyIntegrationConnection } from '@/components/interfaces/Integrations/VercelGithub/IntegrationPanels' |
| 11 | import { IntegrationImageHandler } from '@/components/interfaces/Settings/Integrations/IntegrationsSettings' |
| 12 | import { VercelSection } from '@/components/interfaces/Settings/Integrations/VercelIntegration/VercelSection' |
| 13 | import { |
| 14 | ScaffoldContainer, |
| 15 | ScaffoldContainerLegacy, |
| 16 | ScaffoldDivider, |
| 17 | ScaffoldSection, |
| 18 | ScaffoldSectionContent, |
| 19 | ScaffoldSectionDetail, |
| 20 | ScaffoldTitle, |
| 21 | } from '@/components/layouts/Scaffold' |
| 22 | import { InlineLink } from '@/components/ui/InlineLink' |
| 23 | import NoPermission from '@/components/ui/NoPermission' |
| 24 | import { useGitHubAuthorizationQuery } from '@/data/integrations/github-authorization-query' |
| 25 | import { useGitHubConnectionDeleteMutation } from '@/data/integrations/github-connection-delete-mutation' |
| 26 | import { |
| 27 | useGitHubConnectionsQuery, |
| 28 | type GitHubConnection, |
| 29 | } from '@/data/integrations/github-connections-query' |
| 30 | import type { IntegrationProjectConnection } from '@/data/integrations/integrations.types' |
| 31 | import { useAsyncCheckPermissions } from '@/hooks/misc/useCheckPermissions' |
| 32 | import { useIsFeatureEnabled } from '@/hooks/misc/useIsFeatureEnabled' |
| 33 | import { useSelectedOrganizationQuery } from '@/hooks/misc/useSelectedOrganization' |
| 34 | import { |
| 35 | GITHUB_INTEGRATION_INSTALLATION_URL, |
| 36 | GITHUB_INTEGRATION_REVOKE_AUTHORIZATION_URL, |
| 37 | } from '@/lib/github' |
| 38 | |
| 39 | type GitHubSectionProps = { |
| 40 | canCreateGitHubConnection: boolean |
| 41 | canReadGithubConnection: boolean |
| 42 | canUpdateGitHubConnection: boolean |
| 43 | connections?: GitHubConnection[] |
| 44 | isGitHubAuthorized: boolean |
| 45 | isLoadingPermissions: boolean |
| 46 | onAddGitHubConnection: () => void |
| 47 | onDeleteGitHubConnection: (connection: IntegrationProjectConnection) => void | Promise<void> |
| 48 | } |
| 49 | |
| 50 | const GitHubSection = ({ |
| 51 | canCreateGitHubConnection, |
| 52 | canReadGithubConnection, |
| 53 | canUpdateGitHubConnection, |
| 54 | connections, |
| 55 | isGitHubAuthorized, |
| 56 | isLoadingPermissions, |
| 57 | onAddGitHubConnection, |
| 58 | onDeleteGitHubConnection, |
| 59 | }: GitHubSectionProps) => ( |
| 60 | <ScaffoldContainer> |
| 61 | <ScaffoldSection className="py-12"> |
| 62 | <ScaffoldSectionDetail title="GitHub Connections"> |
| 63 | <p>Connect any of your GitHub repositories to a project.</p> |
| 64 | <IntegrationImageHandler title="github" /> |
| 65 | </ScaffoldSectionDetail> |
| 66 | <ScaffoldSectionContent> |
| 67 | {isLoadingPermissions ? ( |
| 68 | <GenericSkeletonLoader /> |
| 69 | ) : !canReadGithubConnection ? ( |
| 70 | <NoPermission resourceText="view this organization's GitHub connections" /> |
| 71 | ) : ( |
| 72 | <div className="space-y-6"> |
| 73 | <div className="space-y-1"> |
| 74 | <h3 className="text-sm font-medium text-foreground"> |
| 75 | How do GitHub connections work? |
| 76 | </h3> |
| 77 | <p className="text-sm text-foreground-light"> |
| 78 | Connect a GitHub repository to a Briven project. The GitHub app watches file, |
| 79 | branch, and pull request activity in your repository. |
| 80 | </p> |
| 81 | </div> |
| 82 | |
| 83 | <div> |
| 84 | <ul className="flex flex-col gap-y-2"> |
| 85 | {connections?.map((connection) => ( |
| 86 | <IntegrationConnectionItem |
| 87 | key={connection.id} |
| 88 | disabled={!canUpdateGitHubConnection} |
| 89 | connection={{ |
| 90 | id: String(connection.id), |
| 91 | added_by: { |
| 92 | id: String(connection.user?.id), |
| 93 | primary_email: connection.user?.primary_email ?? '', |
| 94 | username: connection.user?.username ?? '', |
| 95 | }, |
| 96 | foreign_project_id: String(connection.repository.id), |
| 97 | briven_project_ref: connection.project.ref, |
| 98 | organization_integration_id: 'unused', |
| 99 | inserted_at: connection.inserted_at, |
| 100 | updated_at: connection.updated_at, |
| 101 | metadata: { |
| 102 | name: connection.repository.name, |
| 103 | } as IntegrationProjectConnection['metadata'], |
| 104 | }} |
| 105 | type="GitHub" |
| 106 | onDeleteConnection={onDeleteGitHubConnection} |
| 107 | /> |
| 108 | ))} |
| 109 | </ul> |
| 110 | |
| 111 | <EmptyIntegrationConnection |
| 112 | onClick={onAddGitHubConnection} |
| 113 | showNode={false} |
| 114 | disabled={!canCreateGitHubConnection} |
| 115 | > |
| 116 | Add new project connection |
| 117 | </EmptyIntegrationConnection> |
| 118 | </div> |
| 119 | |
| 120 | {isGitHubAuthorized && ( |
| 121 | <p className="text-sm text-foreground-light"> |
| 122 | You are authorized with the Briven GitHub App. You can configure your{' '} |
| 123 | <InlineLink href={GITHUB_INTEGRATION_INSTALLATION_URL}> |
| 124 | GitHub App installations and repository access |
| 125 | </InlineLink> |
| 126 | , or{' '} |
| 127 | <InlineLink href={GITHUB_INTEGRATION_REVOKE_AUTHORIZATION_URL}> |
| 128 | revoke your authorization |
| 129 | </InlineLink> |
| 130 | . |
| 131 | </p> |
| 132 | )} |
| 133 | </div> |
| 134 | )} |
| 135 | </ScaffoldSectionContent> |
| 136 | </ScaffoldSection> |
| 137 | </ScaffoldContainer> |
| 138 | ) |
| 139 | |
| 140 | export const IntegrationSettings = () => { |
| 141 | const router = useRouter() |
| 142 | const { data: org } = useSelectedOrganizationQuery() |
| 143 | |
| 144 | const showVercelIntegration = useIsFeatureEnabled('integrations:vercel') |
| 145 | |
| 146 | const { can: canReadGithubConnection, isLoading: isLoadingPermissions } = |
| 147 | useAsyncCheckPermissions(PermissionAction.READ, 'integrations.github_connections') |
| 148 | const { can: canCreateGitHubConnection } = useAsyncCheckPermissions( |
| 149 | PermissionAction.CREATE, |
| 150 | 'integrations.github_connections' |
| 151 | ) |
| 152 | const { can: canUpdateGitHubConnection } = useAsyncCheckPermissions( |
| 153 | PermissionAction.UPDATE, |
| 154 | 'integrations.github_connections' |
| 155 | ) |
| 156 | |
| 157 | const { data: gitHubAuthorization } = useGitHubAuthorizationQuery() |
| 158 | const { data: connections } = useGitHubConnectionsQuery({ organizationId: org?.id }) |
| 159 | |
| 160 | const { mutate: deleteGitHubConnection } = useGitHubConnectionDeleteMutation({ |
| 161 | onSuccess: () => { |
| 162 | toast.success('Successfully deleted GitHub connection') |
| 163 | }, |
| 164 | }) |
| 165 | |
| 166 | const onAddGitHubConnection = useCallback(() => { |
| 167 | router.push('/project/_/settings/integrations') |
| 168 | }, [router]) |
| 169 | |
| 170 | const onDeleteGitHubConnection = useCallback( |
| 171 | async (connection: IntegrationProjectConnection) => { |
| 172 | if (!org?.id) { |
| 173 | toast.error('Organization not found') |
| 174 | return |
| 175 | } |
| 176 | |
| 177 | deleteGitHubConnection({ |
| 178 | connectionId: connection.id, |
| 179 | organizationId: org.id, |
| 180 | }) |
| 181 | }, |
| 182 | [deleteGitHubConnection, org?.id] |
| 183 | ) |
| 184 | |
| 185 | return ( |
| 186 | <> |
| 187 | <ScaffoldContainerLegacy> |
| 188 | <ScaffoldTitle>Integrations</ScaffoldTitle> |
| 189 | </ScaffoldContainerLegacy> |
| 190 | <GitHubSection |
| 191 | canCreateGitHubConnection={canCreateGitHubConnection} |
| 192 | canReadGithubConnection={canReadGithubConnection} |
| 193 | canUpdateGitHubConnection={canUpdateGitHubConnection} |
| 194 | connections={connections} |
| 195 | isGitHubAuthorized={Boolean(gitHubAuthorization)} |
| 196 | isLoadingPermissions={isLoadingPermissions} |
| 197 | onAddGitHubConnection={onAddGitHubConnection} |
| 198 | onDeleteGitHubConnection={onDeleteGitHubConnection} |
| 199 | /> |
| 200 | {showVercelIntegration && ( |
| 201 | <> |
| 202 | <ScaffoldDivider /> |
| 203 | <VercelSection isProjectScoped={false} /> |
| 204 | <SidePanelVercelProjectLinker /> |
| 205 | </> |
| 206 | )} |
| 207 | </> |
| 208 | ) |
| 209 | } |