Files
590ed362ab feat: Redesign for the integrations pages (#30476)
* Initial commit.

* Minor type fixes.

* Add a integration for Queues. Refactor some of the integration layout.

* Migrate the Cron integration to the new style.

* Add useInstalledIntegrations hook.

* Add an integration entry for vault.

* Add an integration entry for GraphiQL.

* Add supabase webhooks.

* Feat/integrations get layout (#30538)

* scroll based icon

* Update header.tsx

* remove dep from overview

* moar

* more table stuff

* moar

* alt nav put in

* fix MotionNumber issues

* more

* trying both layouts

* Fix bunch of type errors.

---------

Co-authored-by: Ivan Vasilov <vasilov.ivan@gmail.com>

* Migrate Vercel and Github files to their own folders.

* Switch all integrations with the new designs.

* More fixes for links, pages structure and other random stuff.

* Remove unneeded file.

* Another set of fixes. Migrated most of the extension integrations.

* Migrated Vault and webhooks to the new style.

* Various fixes to make the animation work.

* Remove extra code.

* Tiny fixes 😬 i swear its tiny

* Refactor IntegrationOverviewTab

* chore/ update integrations routes (#30585)

* init

* add child support in tabs

* add webhooks

* Update IntegrationPageHandler.tsx

* fix id issues

* use messageId instead

* animation tweaks

* Move the description to the wrappers array.

* The useInstalledIntegrations now provides integrations which could be installed.

* Add static content for the various integrations.

* Move the page handler logic into the integrations definitions.

* Clean up some extra code.

* Add logic to make the overview tab the default tab.

* Don't show the header until the integration id has been checked.

* Add logic to the integration pages to avoid weird loading bugs, deselecting tabs if the integration hasn't been installed etc.

* Fix the webhooks overview tab.

* Fix the buttons for enabling extensions.

* Add padding to all custom tab contents.

* Small fixes

* Prettier lint

* Fix icon color + add empty state for when available integrations are all installed

* Fix ts errors

* Fiox

* Add enable webhooks cta

* Fix key

* Fix all lints

* Fix the queues create sheet.

* Fix the deletion of wrappers.

* Fix the minimum version alert for the wrappers extension.

* Make the queues table fit the whole container.

* Fix an issue which reset the tab when installing an extension.

* Address comments

* Add loading state for installed integrations in side nav

* Fix edit secret not rendering value in input field after subsequent openings

* Fix vault keys auto filling search input with vault

* Fix search input placeholder for cron

* Minor fix in install database extension copy

* Fix a bad redirect when reloading.

* Fix bad url redirects.

* Fix scrolling in create new/edit wrapper sheet.

* Add y padding to the wrappers rows.

* Fix merge errors.

* More merge fixes.

* Fix bad imports during the merge.

---------

Co-authored-by: Jonathan Summers-Muir <MildTomato@users.noreply.github.com>
Co-authored-by: Joshen Lim <joshenlimek@gmail.com>
2024-11-25 13:26:22 +01:00

172 lines
6.7 KiB
TypeScript

import { useMemo } from 'react'
import { toast } from 'sonner'
import ProjectLinker from 'components/interfaces/Integrations/VercelGithub/ProjectLinker'
import { Markdown } from 'components/interfaces/Markdown'
import { useGitHubAuthorizationQuery } from 'data/integrations/github-authorization-query'
import { useGitHubConnectionCreateMutation } from 'data/integrations/github-connection-create-mutation'
import { useGitHubConnectionDeleteMutation } from 'data/integrations/github-connection-delete-mutation'
import { useGitHubConnectionsQuery } from 'data/integrations/github-connections-query'
import { useGitHubRepositoriesQuery } from 'data/integrations/github-repositories-query'
import type { IntegrationConnectionsCreateVariables } from 'data/integrations/integrations.types'
import { useProjectsQuery } from 'data/projects/projects-query'
import { useSelectedOrganization } from 'hooks/misc/useSelectedOrganization'
import { openInstallGitHubIntegrationWindow } from 'lib/github'
import { EMPTY_ARR } from 'lib/void'
import { useSidePanelsStateSnapshot } from 'state/side-panels'
import { Button, SidePanel } from 'ui'
const GITHUB_ICON = (
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 98 96" className="w-6">
<path
fill="#ffffff"
fillRule="evenodd"
d="M48.854 0C21.839 0 0 22 0 49.217c0 21.756 13.993 40.172 33.405 46.69 2.427.49 3.316-1.059 3.316-2.362 0-1.141-.08-5.052-.08-9.127-13.59 2.934-16.42-5.867-16.42-5.867-2.184-5.704-5.42-7.17-5.42-7.17-4.448-3.015.324-3.015.324-3.015 4.934.326 7.523 5.052 7.523 5.052 4.367 7.496 11.404 5.378 14.235 4.074.404-3.178 1.699-5.378 3.074-6.6-10.839-1.141-22.243-5.378-22.243-24.283 0-5.378 1.94-9.778 5.014-13.2-.485-1.222-2.184-6.275.486-13.038 0 0 4.125-1.304 13.426 5.052a46.97 46.97 0 0 1 12.214-1.63c4.125 0 8.33.571 12.213 1.63 9.302-6.356 13.427-5.052 13.427-5.052 2.67 6.763.97 11.816.485 13.038 3.155 3.422 5.015 7.822 5.015 13.2 0 18.905-11.404 23.06-22.324 24.283 1.78 1.548 3.316 4.481 3.316 9.126 0 6.6-.08 11.897-.08 13.526 0 1.304.89 2.853 3.316 2.364 19.412-6.52 33.405-24.935 33.405-46.691C97.707 22 75.788 0 48.854 0z"
clipRule="evenodd"
/>
</svg>
)
export type SidePanelGitHubRepoLinkerProps = {
projectRef?: string
}
const SidePanelGitHubRepoLinker = ({ projectRef }: SidePanelGitHubRepoLinkerProps) => {
const selectedOrganization = useSelectedOrganization()
const sidePanelStateSnapshot = useSidePanelsStateSnapshot()
const { data: gitHubAuthorization, isLoading: isLoadingGitHubAuthorization } =
useGitHubAuthorizationQuery({ enabled: sidePanelStateSnapshot.githubConnectionsOpen })
// [Alaister]: temp override with <any> until the typegen is fixed
const { data: githubReposData, isLoading: isLoadingGitHubRepos } = useGitHubRepositoriesQuery<
any[]
>({
enabled: Boolean(gitHubAuthorization),
})
/**
* Supabase projects available
*/
const { data: supabaseProjectsData, isLoading: isLoadingSupabaseProjects } = useProjectsQuery()
const supabaseProjects = useMemo(
() =>
supabaseProjectsData
?.filter((project) => project.organization_id === selectedOrganization?.id)
.map((project) => ({ name: project.name, ref: project.ref })) ?? EMPTY_ARR,
[selectedOrganization?.id, supabaseProjectsData]
)
const githubRepos = useMemo(
() =>
githubReposData?.map((repo: any) => ({
id: repo.id.toString(),
name: repo.name,
installation_id: repo.installation_id,
})) ?? EMPTY_ARR,
[githubReposData]
)
const { data: connections } = useGitHubConnectionsQuery({
organizationId: selectedOrganization?.id,
})
const { mutate: createConnection, isLoading: isCreatingConnection } =
useGitHubConnectionCreateMutation({
onSuccess() {
toast.success('Successfully linked project to repository!')
sidePanelStateSnapshot.setGithubConnectionsOpen(false)
},
})
const { mutateAsync: deleteConnection } = useGitHubConnectionDeleteMutation()
const createGithubConnection = async (variables: IntegrationConnectionsCreateVariables) => {
if (!selectedOrganization?.id) {
throw new Error('No organization id')
}
if (!variables.new) {
throw new Error('No new connection')
}
const existingConnection = connections?.find(
(connection) => connection.project.ref === projectRef
)
if (existingConnection) {
// remove existing connection so we can recreate it or update it
try {
await deleteConnection({
organizationId: selectedOrganization.id,
connectionId: existingConnection.id,
})
} catch (error) {
// ignore the error to let createConnection handle it
}
}
createConnection({
organizationId: selectedOrganization.id,
connection: variables.new,
})
}
return (
<SidePanel
header={'Add GitHub repository'}
size="large"
visible={sidePanelStateSnapshot.githubConnectionsOpen}
hideFooter
onCancel={() => sidePanelStateSnapshot.setGithubConnectionsOpen(false)}
>
<div className="py-10 flex flex-col gap-6 bg-studio h-full">
<SidePanel.Content className="flex flex-col gap-4">
<Markdown
content={`
### Choose repository to connect to
Check the details below before proceeding
`}
/>
{gitHubAuthorization === null ? (
<div className="flex flex-col items-center justify-center mt-8 relative border rounded-lg p-12 bg shadow px-20s">
<p className="text-sm text-center">
Connect your Supabase projects with your GitHub repositories
</p>
<p className="text-sm text-center text-foreground-light">
Authorize with GitHub to retrieve your GitHub repositories
</p>
<Button
className="w-min mt-3"
onClick={() => {
openInstallGitHubIntegrationWindow('authorize')
}}
>
Authorize GitHub
</Button>
</div>
) : (
<ProjectLinker
defaultSupabaseProjectRef={projectRef}
foreignProjects={githubRepos}
supabaseProjects={supabaseProjects}
onCreateConnections={createGithubConnection}
isLoading={isCreatingConnection}
loadingForeignProjects={isLoadingGitHubRepos}
loadingSupabaseProjects={isLoadingSupabaseProjects}
integrationIcon={GITHUB_ICON}
choosePrompt="Choose GitHub Repo"
showNoEntitiesState={false}
mode="GitHub"
/>
)}
</SidePanel.Content>
</div>
</SidePanel>
)
}
export default SidePanelGitHubRepoLinker