From 6e5a3db24b62422479b18a6969ca0da1be65bfce Mon Sep 17 00:00:00 2001 From: Alaister Young Date: Tue, 11 Jul 2023 20:56:21 +0800 Subject: [PATCH 01/61] initial github integration changes --- .../IntegrationSettings.tsx | 2 +- .../GitHubIntegrationWindowLayout.tsx | 25 ++ .../IntegrationWindowLayout.tsx | 56 ++-- .../VercelIntegrationWindowLayout.tsx | 27 ++ .../github-integration-create-mutation.ts | 56 ++++ .../vercel-integration-create-mutation.ts | 1 - .../github/[slug]/choose-project.tsx | 12 + studio/pages/integrations/github/install.tsx | 290 ++++++++++++++++++ studio/pages/integrations/vercel.tsx | 2 +- .../[slug]/deploy-button/new-project.tsx | 4 +- .../[slug]/marketplace/choose-project.tsx | 4 +- studio/pages/integrations/vercel/install.tsx | 8 +- .../state/github-integration-installation.ts | 15 + 13 files changed, 462 insertions(+), 40 deletions(-) create mode 100644 studio/components/layouts/IntegrationsLayout/GitHubIntegrationWindowLayout.tsx rename studio/components/layouts/{ => IntegrationsLayout}/IntegrationWindowLayout.tsx (54%) create mode 100644 studio/components/layouts/IntegrationsLayout/VercelIntegrationWindowLayout.tsx create mode 100644 studio/data/integrations/github-integration-create-mutation.ts create mode 100644 studio/pages/integrations/github/[slug]/choose-project.tsx create mode 100644 studio/pages/integrations/github/install.tsx create mode 100644 studio/state/github-integration-installation.ts diff --git a/studio/components/interfaces/Organization/IntegrationSettings/IntegrationSettings.tsx b/studio/components/interfaces/Organization/IntegrationSettings/IntegrationSettings.tsx index b80cd93b40a..b19821e45d0 100644 --- a/studio/components/interfaces/Organization/IntegrationSettings/IntegrationSettings.tsx +++ b/studio/components/interfaces/Organization/IntegrationSettings/IntegrationSettings.tsx @@ -13,7 +13,7 @@ const IntegrationSettings = () => { const vercelIntegrations = data ?.filter((integration) => integration.integration.name === 'Vercel') .map((integration) => { - if (integration.metadata) { + if (integration.metadata && integration.integration.name === 'Vercel') { const avatarSrc = !integration.metadata.account.avatar && integration.metadata.account.type === 'Team' ? `https://vercel.com/api/www/avatar?teamId=${integration.metadata.account.team_id}&s=48` diff --git a/studio/components/layouts/IntegrationsLayout/GitHubIntegrationWindowLayout.tsx b/studio/components/layouts/IntegrationsLayout/GitHubIntegrationWindowLayout.tsx new file mode 100644 index 00000000000..f2de6a343e0 --- /dev/null +++ b/studio/components/layouts/IntegrationsLayout/GitHubIntegrationWindowLayout.tsx @@ -0,0 +1,25 @@ +import { PropsWithChildren } from 'react' +import IntegrationWindowLayout from './IntegrationWindowLayout' + +const GITHUB_ICON = ( +
+ + + +
+) + +const GitHubIntegrationWindowLayout = ({ children }: PropsWithChildren<{}>) => { + return ( + + {children} + + ) +} + +export default GitHubIntegrationWindowLayout diff --git a/studio/components/layouts/IntegrationWindowLayout.tsx b/studio/components/layouts/IntegrationsLayout/IntegrationWindowLayout.tsx similarity index 54% rename from studio/components/layouts/IntegrationWindowLayout.tsx rename to studio/components/layouts/IntegrationsLayout/IntegrationWindowLayout.tsx index 123e42f205c..e04d8df5d83 100644 --- a/studio/components/layouts/IntegrationWindowLayout.tsx +++ b/studio/components/layouts/IntegrationsLayout/IntegrationWindowLayout.tsx @@ -1,20 +1,27 @@ -import { FC } from 'react' -import Link from 'next/link' -import { IconChevronRight, IconX, cn } from 'ui' -import { withAuth, useFlag } from 'hooks' -import { observer } from 'mobx-react-lite' -import { BASE_PATH } from 'lib/constants' -import React from 'react' -import { ScaffoldContainer } from './Scaffold' import { useParams } from 'common' +import { useFlag, withAuth } from 'hooks' +import { BASE_PATH } from 'lib/constants' +import { PropsWithChildren, ReactNode, forwardRef } from 'react' +import { IconX, cn } from 'ui' +import { ScaffoldContainer } from '../Scaffold' -const IntegrationWindowLayout: FC = ({ organization, project, children }) => { +export type IntegrationWindowLayoutProps = { + title: string + integrationIcon: ReactNode +} + +const IntegrationWindowLayout = ({ + title, + integrationIcon, + children, +}: PropsWithChildren) => { const ongoingIncident = useFlag('ongoingIncident') const maxHeight = ongoingIncident ? 'calc(100vh - 44px)' : '100vh' return (
-
+
+ {children}
) @@ -22,18 +29,16 @@ const IntegrationWindowLayout: FC = ({ organization, project, children }) = const INTEGRATION_LAYOUT_MAX_WIDTH = '' // 'max-w-[720px]' -export default withAuth(observer(IntegrationWindowLayout)) +export default withAuth(IntegrationWindowLayout) -export const IntegrationWindowLayoutWithoutAuth = observer(IntegrationWindowLayout) +export const IntegrationWindowLayoutWithoutAuth = IntegrationWindowLayout -const Header: FC = ({ organization, project }) => { - let stepNumber = organization ? 1 : project ? 2 : 0 - const { externalId } = useParams() - - const title = externalId - ? 'Supabase + Vercel Deploy Button' - : 'Supabase + Vercel Integration Marketplace Connector' +export type HeaderProps = { + title: string + integrationIcon: ReactNode +} +const Header = ({ title, integrationIcon }: HeaderProps) => { return (
@@ -43,16 +48,7 @@ const Header: FC = ({ organization, project }) => { Supabase
-
- - - -
+ {integrationIcon} {title} @@ -66,7 +62,7 @@ const Header: FC = ({ organization, project }) => { const maxWidthClasses = 'mx-auto w-full max-w-[1600px]' const paddingClasses = 'px-6 lg:px-14 xl:px-28 2xl:px-32' -const IntegrationScaffoldContainer = React.forwardRef< +const IntegrationScaffoldContainer = forwardRef< HTMLDivElement, React.HTMLAttributes >(({ className, ...props }, ref) => { diff --git a/studio/components/layouts/IntegrationsLayout/VercelIntegrationWindowLayout.tsx b/studio/components/layouts/IntegrationsLayout/VercelIntegrationWindowLayout.tsx new file mode 100644 index 00000000000..bcc7ef55adb --- /dev/null +++ b/studio/components/layouts/IntegrationsLayout/VercelIntegrationWindowLayout.tsx @@ -0,0 +1,27 @@ +import { useParams } from 'common' +import { PropsWithChildren } from 'react' +import IntegrationWindowLayout from './IntegrationWindowLayout' + +const VERCEL_ICON = ( +
+ + + +
+) + +const VercelIntegrationWindowLayout = ({ children }: PropsWithChildren<{}>) => { + const { externalId } = useParams() + + const title = externalId + ? 'Supabase + Vercel Deploy Button' + : 'Supabase + Vercel Integration Marketplace Connector' + + return ( + + {children} + + ) +} + +export default VercelIntegrationWindowLayout diff --git a/studio/data/integrations/github-integration-create-mutation.ts b/studio/data/integrations/github-integration-create-mutation.ts new file mode 100644 index 00000000000..73ce49b48b4 --- /dev/null +++ b/studio/data/integrations/github-integration-create-mutation.ts @@ -0,0 +1,56 @@ +import { useMutation, UseMutationOptions, useQueryClient } from '@tanstack/react-query' +import { post } from 'lib/common/fetch' +import { API_URL } from 'lib/constants' +import { integrationKeys } from './keys' + +export type GitHubIntegrationCreateVariables = { + code: string + installationId: string + orgSlug: string + metadata: { [key: string]: string } +} + +export async function createGitHubIntegration({ + code, + installationId, + orgSlug, + metadata, +}: GitHubIntegrationCreateVariables) { + const response = await post(`${API_URL}/integrations/github`, { + code, + installation_id: installationId, + organization_slug: orgSlug, + metadata, + }) + if (response.error) { + throw response.error + } + + return response +} + +type GitHubIntegrationCreateData = Awaited> + +export const useGitHubIntegrationCreateMutation = ({ + onSuccess, + ...options +}: Omit< + UseMutationOptions, + 'mutationFn' +> = {}) => { + const queryClient = useQueryClient() + return useMutation( + (vars) => createGitHubIntegration(vars), + { + async onSuccess(data, variables, context) { + await Promise.all([ + queryClient.invalidateQueries(integrationKeys.integrationsList()), + queryClient.invalidateQueries(integrationKeys.integrationsListWithOrg(variables.orgSlug)), + // queryClient.invalidateQueries(integrationKeys.githubProjectList(data.id)), + ]) + await onSuccess?.(data, variables, context) + }, + ...options, + } + ) +} diff --git a/studio/data/integrations/vercel-integration-create-mutation.ts b/studio/data/integrations/vercel-integration-create-mutation.ts index ae99a6e5785..53f1666e05d 100644 --- a/studio/data/integrations/vercel-integration-create-mutation.ts +++ b/studio/data/integrations/vercel-integration-create-mutation.ts @@ -47,7 +47,6 @@ export const useVercelIntegrationCreateMutation = ({ 'mutationFn' > = {}) => { const queryClient = useQueryClient() - console.log('mutating') return useMutation( (vars) => createVercelIntegration(vars), { diff --git a/studio/pages/integrations/github/[slug]/choose-project.tsx b/studio/pages/integrations/github/[slug]/choose-project.tsx new file mode 100644 index 00000000000..056571b9458 --- /dev/null +++ b/studio/pages/integrations/github/[slug]/choose-project.tsx @@ -0,0 +1,12 @@ +import GitHubIntegrationWindowLayout from 'components/layouts/IntegrationsLayout/GitHubIntegrationWindowLayout' +import { NextPageWithLayout } from 'types' + +const ChooseProjectGitHubPage: NextPageWithLayout = () => { + return
+} + +ChooseProjectGitHubPage.getLayout = (page) => ( + {page} +) + +export default ChooseProjectGitHubPage diff --git a/studio/pages/integrations/github/install.tsx b/studio/pages/integrations/github/install.tsx new file mode 100644 index 00000000000..c0da8558089 --- /dev/null +++ b/studio/pages/integrations/github/install.tsx @@ -0,0 +1,290 @@ +import { useParams } from 'common' +import { Markdown } from 'components/interfaces/Markdown' +import GitHubIntegrationWindowLayout from 'components/layouts/IntegrationsLayout/GitHubIntegrationWindowLayout' +import IntegrationWindowLayout from 'components/layouts/IntegrationsLayout/IntegrationWindowLayout' +import { ScaffoldContainer, ScaffoldDivider } from 'components/layouts/Scaffold' +import { useGitHubIntegrationCreateMutation } from 'data/integrations/github-integration-create-mutation' +import { useIntegrationsQuery } from 'data/integrations/integrations-query' +import { IntegrationName } from 'data/integrations/integrations.types' +import { useOrganizationsQuery } from 'data/organizations/organizations-query' +import { useStore } from 'hooks' +import { useRouter } from 'next/router' +import { useState } from 'react' +import { useGitHubIntegrationInstallationState } from 'state/github-integration-installation' +import { NextPageWithLayout, Organization } from 'types' +import { Alert, Badge, Button, IconBook, IconHexagon, IconLifeBuoy, Listbox, LoadingLine } from 'ui' + +/** + * Organization type with `installationInstalled` added + */ +interface OrganizationsResponseWithInstalledData extends Organization { + installationInstalled?: boolean +} + +/** + * Variations of the GitHub integration flow. + * They require different UI and logic. + * + * Deploy Button - the flow that starts from the Deploy Button - https://github.com/docs/integrations#deploy-button + * Marketplace - the flow that starts from the Marketplace - https://github.com/integrations + * + */ +export type GitHubIntegrationFlow = 'deploy-button' | 'marketing' + +const GitHubIntegration: NextPageWithLayout = () => { + const router = useRouter() + const { ui } = useStore() + const { code, installation_id: installationId } = useParams() + const [selectedOrg, setSelectedOrg] = useState(null) + const [organizationIntegrationId, setOrganizationIntegrationId] = useState(null) + + const snapshot = useGitHubIntegrationInstallationState() + + /** + * Fetch the list of organization based integration installations for GitHub. + * + * Array of integrations installed on all + */ + const { data: integrationData, isLoading: integrationDataLoading } = useIntegrationsQuery() + + const { data: organizationsData, isLoading: isLoadingOrganizationsQuery } = useOrganizationsQuery( + { + onSuccess(organizations) { + const firstOrg = organizations?.[0] + if (firstOrg && selectedOrg === null) { + setSelectedOrg(firstOrg) + snapshot.setSelectedOrganizationSlug(firstOrg.slug) + router.query.organizationSlug = firstOrg.slug + } + }, + } + ) + + /** + * Flat array of org slugs that have integration installed + * + */ + const flatInstalledConnectionsIds: string[] | [] = + integrationData && integrationData.length > 0 + ? integrationData?.map((x) => x.organization.slug) + : [] + + /** + * Organizations with extra `installationInstalled` attribute + * + * Used to show label/badge and allow/disallow installing + * + */ + const organizationsWithInstalledData: OrganizationsResponseWithInstalledData[] = organizationsData + ? organizationsData.map((org) => { + return { + ...org, + installationInstalled: flatInstalledConnectionsIds.includes(org.slug) ? true : false, + } + }) + : [] + + /** + * Handle the correct route change based on wether the github integration + * is following the 'marketplace' flow or 'deploy button' flow. + * + */ + function handleRouteChange() { + const orgSlug = selectedOrg?.slug + + router.push({ + pathname: `/integrations/github/${orgSlug}/choose-project`, + query: router.query, + }) + } + + const { mutate, isLoading: isLoadingGitHubIntegrationCreateMutation } = + useGitHubIntegrationCreateMutation({ + onSuccess({ id }) { + const orgSlug = selectedOrg?.slug + + setOrganizationIntegrationId(id) + + handleRouteChange() + }, + onError(error: any) { + ui.setNotification({ + category: 'error', + message: `Creating GitHub integration failed: ${error.message}`, + }) + }, + }) + + function onInstall() { + const orgSlug = selectedOrg?.slug + + const isIntegrationInstalled = organizationsWithInstalledData.some( + (x) => x.slug === orgSlug && x.installationInstalled + ) + + if (!orgSlug) { + return ui.setNotification({ category: 'error', message: 'Please select an organization' }) + } + + if (!code) { + return ui.setNotification({ category: 'error', message: 'GitHub code missing' }) + } + + if (!installationId) { + return ui.setNotification({ category: 'error', message: 'GitHub Installation ID is missing' }) + } + + /** + * Only install if instgration hasn't already been installed + */ + if (!isIntegrationInstalled) { + mutate({ + code, + installationId, + orgSlug, + metadata: {}, + }) + } else { + handleRouteChange() + } + } + + const dataLoading = isLoadingGitHubIntegrationCreateMutation || isLoadingOrganizationsQuery + + return ( + <> +
+ + {organizationIntegrationId === null && ( + <> + +

Choose organization

+ <> + + { + router.query.organizationSlug = e.slug + setSelectedOrg(e) + }} + dataLoading={dataLoading} + /> +
+ +
+ +
+ + + + + + + )} + + +
+ +
+ Docs +
+
+ Support +
+
+ + ) +} + +GitHubIntegration.getLayout = (page) => ( + {page} +) + +export interface OrganizationPickerProps { + label?: string + onSelectedOrgChange?: (org: Organization) => void + integrationName: IntegrationName + dataLoading: boolean + organizationsWithInstalledData: OrganizationsResponseWithInstalledData[] +} + +const OrganizationPicker = ({ + label = 'Choose an organization', + onSelectedOrgChange, + integrationName, + dataLoading, + organizationsWithInstalledData, +}: OrganizationPickerProps) => { + const { ui } = useStore() + const [selectedOrg, setSelectedOrg] = useState(null) + + const { data, isLoading } = useOrganizationsQuery({ + onSuccess(organizations) { + const firstOrg = organizations?.[0] + if (firstOrg && selectedOrg === null) { + setSelectedOrg(firstOrg) + onSelectedOrgChange?.(firstOrg) + } + }, + }) + + function _onSelectedOrgChange(slug: string) { + const org = data?.find((org) => org.slug === slug) + + if (org) { + setSelectedOrg(org) + onSelectedOrgChange?.(org) + } + } + + if (dataLoading) { + return ( + + + Loading... + + + ) + } + + return ( + + {organizationsWithInstalledData?.map((org) => { + const label = ( +
+ {org.name} + {org.installationInstalled && Integration Installed} +
+ ) + return ( + } + > + {label} + + ) + })} +
+ ) +} + +export default GitHubIntegration diff --git a/studio/pages/integrations/vercel.tsx b/studio/pages/integrations/vercel.tsx index 9b2a5ac0c5a..29c927001cf 100644 --- a/studio/pages/integrations/vercel.tsx +++ b/studio/pages/integrations/vercel.tsx @@ -1,6 +1,6 @@ import { useEffect } from 'react' -import IntegrationWindowLayout from 'components/layouts/IntegrationWindowLayout' +import IntegrationWindowLayout from 'components/layouts/IntegrationsLayout/IntegrationWindowLayout' import { useRouter } from 'next/router' import { NextPageWithLayout } from 'types' diff --git a/studio/pages/integrations/vercel/[slug]/deploy-button/new-project.tsx b/studio/pages/integrations/vercel/[slug]/deploy-button/new-project.tsx index 7736f118c58..4465635cb5c 100644 --- a/studio/pages/integrations/vercel/[slug]/deploy-button/new-project.tsx +++ b/studio/pages/integrations/vercel/[slug]/deploy-button/new-project.tsx @@ -4,7 +4,7 @@ import { ChangeEvent, useRef, useState } from 'react' import { useParams } from 'common' import { Markdown } from 'components/interfaces/Markdown' -import IntegrationWindowLayout from 'components/layouts/IntegrationWindowLayout' +import { VercelIntegrationLayout } from 'components/layouts' import { ScaffoldContainer, ScaffoldDivider } from 'components/layouts/Scaffold' import PasswordStrengthBar from 'components/ui/PasswordStrengthBar' import { useProjectApiQuery } from 'data/config/project-api-query' @@ -61,7 +61,7 @@ const VercelIntegration: NextPageWithLayout = () => { ) } -VercelIntegration.getLayout = (page) => {page} +VercelIntegration.getLayout = (page) => {page} const CreateProject = ({ loading, diff --git a/studio/pages/integrations/vercel/[slug]/marketplace/choose-project.tsx b/studio/pages/integrations/vercel/[slug]/marketplace/choose-project.tsx index 75a9ae1bece..defe66f8310 100644 --- a/studio/pages/integrations/vercel/[slug]/marketplace/choose-project.tsx +++ b/studio/pages/integrations/vercel/[slug]/marketplace/choose-project.tsx @@ -3,7 +3,7 @@ import { useMemo, useState } from 'react' import { useParams } from 'common' import ProjectLinker from 'components/interfaces/Integrations/ProjectLinker' import { Markdown } from 'components/interfaces/Markdown' -import IntegrationWindowLayout from 'components/layouts/IntegrationWindowLayout' +import { VercelIntegrationLayout } from 'components/layouts' import { ScaffoldContainer, ScaffoldDivider } from 'components/layouts/Scaffold' import { useOrgIntegrationsQuery } from 'data/integrations/integrations-query-org-only' import { useVercelProjectsQuery } from 'data/integrations/integrations-vercel-projects-query' @@ -103,6 +103,6 @@ This Supabase integration manages your envioemnt variables automatically to prov ) } -VercelIntegration.getLayout = (page) => {page} +VercelIntegration.getLayout = (page) => {page} export default VercelIntegration diff --git a/studio/pages/integrations/vercel/install.tsx b/studio/pages/integrations/vercel/install.tsx index 67e8ef2f022..dd629aed8b5 100644 --- a/studio/pages/integrations/vercel/install.tsx +++ b/studio/pages/integrations/vercel/install.tsx @@ -1,6 +1,6 @@ import { useParams } from 'common' import { Markdown } from 'components/interfaces/Markdown' -import IntegrationWindowLayout from 'components/layouts/IntegrationWindowLayout' +import VercelIntegrationWindowLayout from 'components/layouts/IntegrationsLayout/VercelIntegrationWindowLayout' import { ScaffoldContainer, ScaffoldDivider } from 'components/layouts/Scaffold' import { useIntegrationsQuery } from 'data/integrations/integrations-query' import { IntegrationName } from 'data/integrations/integrations.types' @@ -150,7 +150,7 @@ const VercelIntegration: NextPageWithLayout = () => { } /** - * Only install if instgration hasn't already been installed + * Only install if integration hasn't already been installed */ if (!isIntegrationInstalled) { mutate({ @@ -228,7 +228,9 @@ const VercelIntegration: NextPageWithLayout = () => { ) } -VercelIntegration.getLayout = (page) => {page} +VercelIntegration.getLayout = (page) => ( + {page} +) export interface OrganizationPickerProps { label?: string diff --git a/studio/state/github-integration-installation.ts b/studio/state/github-integration-installation.ts new file mode 100644 index 00000000000..8d134d2b168 --- /dev/null +++ b/studio/state/github-integration-installation.ts @@ -0,0 +1,15 @@ +import { proxy, snapshot, useSnapshot } from 'valtio' + +export const githubIntegrationInstallationState = proxy({ + selectedOrganizationSlug: '' as string, + setSelectedOrganizationSlug: (selectedOrganizationSlug: string) => { + githubIntegrationInstallationState.selectedOrganizationSlug = selectedOrganizationSlug + }, +}) + +export const getGitHubIntegrationInstallationState = () => + snapshot(githubIntegrationInstallationState) + +export const useGitHubIntegrationInstallationState = ( + options?: Parameters[1] +) => useSnapshot(githubIntegrationInstallationState, options) From db34ee6cf9008565f0ad68a546b019e2547461ae Mon Sep 17 00:00:00 2001 From: Alaister Young Date: Thu, 13 Jul 2023 01:55:07 +0800 Subject: [PATCH 02/61] working github integration --- .../interfaces/Integrations/ProjectLinker.tsx | 109 ++++--------- .../IntegrationSettings.tsx | 2 - .../SidePanelVercelProjectLinker.tsx | 81 +++++++++- .../github-integration-create-mutation.ts | 3 - ...ions-github-connections-create-mutation.ts | 58 +++++++ .../integrations-github-repos-query.ts | 152 ++++-------------- .../data/integrations/integrations-query.ts | 8 +- ...ons-vercel-connections-create-mutation.ts} | 25 ++- studio/data/integrations/keys.ts | 4 + studio/data/integrations/types.ts | 9 ++ studio/next.config.js | 7 +- .../github/[integrationId]/choose-project.tsx | 116 +++++++++++++ .../github/[slug]/choose-project.tsx | 12 -- studio/pages/integrations/github/install.tsx | 62 +++---- studio/pages/integrations/vercel.tsx | 19 --- .../[slug]/deploy-button/new-project.tsx | 4 +- .../[slug]/marketplace/choose-project.tsx | 95 +++++++++-- studio/pages/integrations/vercel/install.tsx | 7 +- 18 files changed, 451 insertions(+), 322 deletions(-) create mode 100644 studio/data/integrations/integrations-github-connections-create-mutation.ts rename studio/data/integrations/{integration-connections-create-mutation.ts => integrations-vercel-connections-create-mutation.ts} (71%) create mode 100644 studio/data/integrations/types.ts create mode 100644 studio/pages/integrations/github/[integrationId]/choose-project.tsx delete mode 100644 studio/pages/integrations/github/[slug]/choose-project.tsx delete mode 100644 studio/pages/integrations/vercel.tsx diff --git a/studio/components/interfaces/Integrations/ProjectLinker.tsx b/studio/components/interfaces/Integrations/ProjectLinker.tsx index 0be4ac9d5d4..88295e172d9 100644 --- a/studio/components/interfaces/Integrations/ProjectLinker.tsx +++ b/studio/components/interfaces/Integrations/ProjectLinker.tsx @@ -1,28 +1,32 @@ -import { useState } from 'react' +import { ReactNode, useState } from 'react' -import { ENV_VAR_RAW_KEYS } from 'components/interfaces/Integrations/Integrations-Vercel.constants' -import { Markdown } from 'components/interfaces/Markdown' -import { vercelIcon } from 'components/to-be-cleaned/ListIcons' -import { useIntegrationConnectionsCreateMutation } from 'data/integrations/integration-connections-create-mutation' -import { VercelProjectsResponse } from 'data/integrations/integrations-vercel-projects-query' import { IntegrationProjectConnection } from 'data/integrations/integrations.types' +import { IntegrationConnectionsCreateVariables } from 'data/integrations/types' import { useSelectedOrganization } from 'hooks' import { BASE_PATH } from 'lib/constants' import { Button, Listbox, cn } from 'ui' -interface Project { +export interface Project { id: string name: string ref: string } +export interface ForeignProject { + id: string + name: string +} + export interface ProjectLinkerProps { organizationIntegrationId: string | undefined - foreignProjects: VercelProjectsResponse[] + foreignProjects: ForeignProject[] supabaseProjects: Project[] - onCreateConnections?: () => void + onCreateConnections: (variables: IntegrationConnectionsCreateVariables) => void installedConnections: IntegrationProjectConnection[] | undefined - setLoading?: (x: boolean) => void + isLoading?: boolean + integrationIcon: ReactNode + getForeignProjectIcon?: (project: ForeignProject) => ReactNode + choosePrompt?: string } const UNDEFINED_SELECT_VALUE = 'undefined' @@ -33,45 +37,31 @@ const ProjectLinker = ({ supabaseProjects, onCreateConnections: _onCreateConnections, installedConnections = [], - setLoading, + isLoading, + integrationIcon, + getForeignProjectIcon, + choosePrompt = 'Choose a project', }: ProjectLinkerProps) => { const selectedOrganization = useSelectedOrganization() const [supabaseProjectRef, setSupabaseProjectRef] = useState(UNDEFINED_SELECT_VALUE) - const [vercelProjectId, setVercelProjectId] = useState(UNDEFINED_SELECT_VALUE) - - const { mutate: createConnections, isLoading } = useIntegrationConnectionsCreateMutation({ - onSuccess() { - _onCreateConnections?.() - }, - - onSettled() { - if (setLoading) setLoading(false) - }, - }) + const [foreignProjectId, setForeignProjectId] = useState(UNDEFINED_SELECT_VALUE) function onCreateConnections() { - const projectDetails = foreignProjects.filter((x) => x.id === vercelProjectId)[0] + const projectDetails = foreignProjects.filter((x) => x.id === foreignProjectId)[0] if (!organizationIntegrationId) { console.error('No integration ID set') return } - if (setLoading) setLoading(true) - - createConnections({ + _onCreateConnections({ organizationIntegrationId, connection: { - foreign_project_id: vercelProjectId, + foreign_project_id: foreignProjectId, supabase_project_ref: supabaseProjectRef, metadata: { ...projectDetails, - supabaseConfig: { - projectEnvVars: { - write: true, - }, - }, }, }, orgSlug: selectedOrganization?.slug, @@ -95,12 +85,10 @@ const ProjectLinker = ({ // create a flat array of foreign project ids. ie, ["prj_MlkO6AiLG5ofS9ojKrkS3PhhlY3f", ..] const flatInstalledConnectionsIds = new Set(installedConnections.map((x) => x.foreign_project_id)) - // check that vercel project is not already installed - const filteredForeignProjects: VercelProjectsResponse[] = foreignProjects.filter( - (foreignProject) => { - return !flatInstalledConnectionsIds.has(foreignProject.id) - } - ) + // check that foreign project is not already installed + const filteredForeignProjects = foreignProjects.filter((foreignProject) => { + return !flatInstalledConnectionsIds.has(foreignProject.id) + }) return (
@@ -149,23 +137,15 @@ const ProjectLinker = ({
- {/* integration icon */} - - - + {integrationIcon}
setVercelProjectId(e)} + value={foreignProjectId ?? UNDEFINED_SELECT_VALUE} + onChange={(e) => setForeignProjectId(e)} > - - Choose Vercel project + + {choosePrompt} {filteredForeignProjects.map((project) => { return ( @@ -174,20 +154,7 @@ const ProjectLinker = ({ value={project.id} label={project.name} addOnBefore={() => { - return ( - <> - {!project?.framework ? ( - vercelIcon - ) : ( - {`icon`} - )} - - ) + return getForeignProjectIcon?.(project) ?? null }} > {project.name} @@ -209,18 +176,6 @@ const ProjectLinker = ({ Connect project
- { - return ` - \n - - \`${x}\` -` -})} -`} - /> ) } diff --git a/studio/components/interfaces/Organization/IntegrationSettings/IntegrationSettings.tsx b/studio/components/interfaces/Organization/IntegrationSettings/IntegrationSettings.tsx index b19821e45d0..d3091a75519 100644 --- a/studio/components/interfaces/Organization/IntegrationSettings/IntegrationSettings.tsx +++ b/studio/components/interfaces/Organization/IntegrationSettings/IntegrationSettings.tsx @@ -77,8 +77,6 @@ You can change the scope of the access for Supabase by configuring [here](${getV Connect any of your GitHub repositories to a project. `} description={` -GitHub connections are coming soon. - ### How will GitHub connections work? You will be able to connect a GitHub repository to a Supabase project. diff --git a/studio/components/interfaces/Organization/IntegrationSettings/SidePanelVercelProjectLinker.tsx b/studio/components/interfaces/Organization/IntegrationSettings/SidePanelVercelProjectLinker.tsx index 6beed7de861..e3ac21e5850 100644 --- a/studio/components/interfaces/Organization/IntegrationSettings/SidePanelVercelProjectLinker.tsx +++ b/studio/components/interfaces/Organization/IntegrationSettings/SidePanelVercelProjectLinker.tsx @@ -1,15 +1,26 @@ -import { useMemo } from 'react' +import { keyBy } from 'lodash' +import { useCallback, useMemo } from 'react' -import ProjectLinker from 'components/interfaces/Integrations/ProjectLinker' +import { ENV_VAR_RAW_KEYS } from 'components/interfaces/Integrations/Integrations-Vercel.constants' +import ProjectLinker, { ForeignProject } from 'components/interfaces/Integrations/ProjectLinker' import { Markdown } from 'components/interfaces/Markdown' +import { vercelIcon } from 'components/to-be-cleaned/ListIcons' import { useOrgIntegrationsQuery } from 'data/integrations/integrations-query-org-only' +import { useIntegrationVercelConnectionsCreateMutation } from 'data/integrations/integrations-vercel-connections-create-mutation' import { useVercelProjectsQuery } from 'data/integrations/integrations-vercel-projects-query' import { useProjectsQuery } from 'data/projects/projects-query' import { useSelectedOrganization } from 'hooks' +import { BASE_PATH } from 'lib/constants' import { EMPTY_ARR } from 'lib/void' import { useGithubConnectionConfigPanelSnapshot } from 'state/github-connection-config-panel' import { SidePanel } from 'ui' +const VERCEL_ICON = ( + + + +) + const SidePanelVercelProjectLinker = () => { const selectedOrganization = useSelectedOrganization() @@ -58,6 +69,52 @@ const SidePanelVercelProjectLinker = () => { ) const vercelProjects = useMemo(() => vercelProjectsData ?? EMPTY_ARR, [vercelProjectsData]) + const vercelProjectsById = useMemo(() => keyBy(vercelProjects, 'id'), [vercelProjects]) + + const getForeignProjectIcon = useCallback( + (_project: ForeignProject) => { + const project = vercelProjectsById[_project.id] + + return !project?.framework ? ( + vercelIcon + ) : ( + {`icon`} + ) + }, + [vercelProjectsById] + ) + + const { mutate: createConnections, isLoading: isCreatingConnection } = + useIntegrationVercelConnectionsCreateMutation({ + onSuccess() { + snapshot.setOpen(false) + }, + }) + + const onCreateConnections = useCallback( + (vars) => { + createConnections({ + ...vars, + connection: { + ...vars.connection, + metadata: { + ...vars.connection.metadata, + supabaseConfig: { + projectEnvVars: { + write: true, + }, + }, + }, + }, + }) + }, + [createConnections] + ) return ( { - snapshot.setOpen(false) - }} + onCreateConnections={onCreateConnections} installedConnections={selectedIntegration?.connections} + isLoading={isCreatingConnection} + integrationIcon={VERCEL_ICON} + getForeignProjectIcon={getForeignProjectIcon} + choosePrompt="Choose Vercel Project" + /> + { + return ` + \n + - \`${x}\` +` +})} +`} /> diff --git a/studio/data/integrations/github-integration-create-mutation.ts b/studio/data/integrations/github-integration-create-mutation.ts index 73ce49b48b4..8ae13f84b94 100644 --- a/studio/data/integrations/github-integration-create-mutation.ts +++ b/studio/data/integrations/github-integration-create-mutation.ts @@ -4,20 +4,17 @@ import { API_URL } from 'lib/constants' import { integrationKeys } from './keys' export type GitHubIntegrationCreateVariables = { - code: string installationId: string orgSlug: string metadata: { [key: string]: string } } export async function createGitHubIntegration({ - code, installationId, orgSlug, metadata, }: GitHubIntegrationCreateVariables) { const response = await post(`${API_URL}/integrations/github`, { - code, installation_id: installationId, organization_slug: orgSlug, metadata, diff --git a/studio/data/integrations/integrations-github-connections-create-mutation.ts b/studio/data/integrations/integrations-github-connections-create-mutation.ts new file mode 100644 index 00000000000..6a924b9e509 --- /dev/null +++ b/studio/data/integrations/integrations-github-connections-create-mutation.ts @@ -0,0 +1,58 @@ +import { useMutation, UseMutationOptions, useQueryClient } from '@tanstack/react-query' +import { post } from 'lib/common/fetch' +import { API_URL } from 'lib/constants' +import { integrationKeys } from './keys' +import { IntegrationConnectionsCreateVariables } from './types' + +export async function createIntegrationGitHubConnections({ + organizationIntegrationId, + connection, +}: IntegrationConnectionsCreateVariables) { + const response = await post(`${API_URL}/integrations/github/connections`, { + organization_integration_id: organizationIntegrationId, + connection, + }) + if (response.error) { + throw response.error + } + + return response +} + +export type IntegrationGitHubConnectionsCreateData = Awaited< + ReturnType +> + +export const useIntegrationGitHubConnectionsCreateMutation = ({ + onSuccess, + ...options +}: Omit< + UseMutationOptions< + IntegrationGitHubConnectionsCreateData, + unknown, + IntegrationConnectionsCreateVariables + >, + 'mutationFn' +> = {}) => { + const queryClient = useQueryClient() + return useMutation< + IntegrationGitHubConnectionsCreateData, + unknown, + IntegrationConnectionsCreateVariables + >((vars) => createIntegrationGitHubConnections(vars), { + async onSuccess(data, variables, context) { + await Promise.all([ + queryClient.invalidateQueries(integrationKeys.integrationsList()), + queryClient.invalidateQueries(integrationKeys.integrationsListWithOrg(variables.orgSlug)), + queryClient.invalidateQueries( + integrationKeys.githubRepoList(variables.organizationIntegrationId) + ), + queryClient.invalidateQueries( + integrationKeys.githubConnectionsList(variables.organizationIntegrationId) + ), + ]) + await onSuccess?.(data, variables, context) + }, + ...options, + }) +} diff --git a/studio/data/integrations/integrations-github-repos-query.ts b/studio/data/integrations/integrations-github-repos-query.ts index 4b1141df100..5bbc2be894c 100644 --- a/studio/data/integrations/integrations-github-repos-query.ts +++ b/studio/data/integrations/integrations-github-repos-query.ts @@ -1,137 +1,47 @@ -import { useQuery, useQueryClient, UseQueryOptions } from '@tanstack/react-query' +import { useQuery, UseQueryOptions } from '@tanstack/react-query' import { get } from 'lib/common/fetch' import { API_URL } from 'lib/constants' import { integrationKeys } from './keys' -// repos fetch -export type IntegrationsVariables = { - orgSlug?: string +export type GitHubReposVariables = { + integrationId: string | undefined } -export type IntegrationProjectConnection = { - id: string - createdAt: string - from: { - name: string - } - to: { - name: string - } +export type GitHubReposResponse = { + id: number + full_name: string } -export type Integration = { - id: string - type: 'VERCEL' | 'NETLIFY' | 'GITHUB' - createdBy: string - createdAt: string - connections: IntegrationProjectConnection[] - metadata?: { - vercelTeam?: string - gitHubConnectionOwner?: string - } -} - -export type IntegrationsResponse = Integration[] - -export async function getIntegrations({ orgSlug }: IntegrationsVariables, signal?: AbortSignal) { - if (!orgSlug) { - throw new Error('orgSlug is required') +export async function getGitHubRepos( + { integrationId }: GitHubReposVariables, + signal?: AbortSignal +) { + if (!integrationId) { + throw new Error('integrationId is required') } - const response: IntegrationsResponse = [ - { - id: '1', - type: 'VERCEL', - createdBy: 'alaister@supabase.io', - createdAt: '2023-06-05T06:56:25.565Z', - metadata: { - vercelTeam: 'alaister-team', - }, - connections: [ - { - id: '1.0', - createdAt: '2023-06-05T01:56:25.565Z', - to: { - name: 'www prod', - }, - from: { - name: 'alaister project prod', - }, - }, - { - id: '1.1', - createdAt: '2023-06-14T06:56:25.565Z', - to: { - name: 'www staging', - }, - from: { - name: 'alaister project staging', - }, - }, - { - id: '1.1', - createdAt: '2023-06-02T21:56:25.565Z', - to: { - name: 'bees knees', - }, - from: { - name: 'jonny bee project', - }, - }, - ], - }, - { - id: '2', - type: 'VERCEL', - createdBy: 'alaister@supabase.io', - createdAt: '2023-06-05T06:56:25.565Z', - metadata: { - vercelTeam: 'alaister-team', - }, - connections: [], - }, - { - id: '3', - type: 'GITHUB', - createdBy: 'Alaister', - createdAt: '2023-06-05T06:56:25.565Z', - metadata: { - gitHubConnectionOwner: 'alaister', - }, - connections: [ - { - id: '1.2', - createdAt: '2023-06-05T06:56:25.565Z', - to: { - name: 'supabase/supabase', - }, - from: { - name: 'alaister project', - }, - }, - ], - }, - ] + const response = await get(`${API_URL}/integrations/github/repos/${integrationId}`, { + signal, + }) + if (response.error) { + throw response.error + } - // const response = await get(`${API_URL}/projects/${orgSlug}/integrations`, { - // signal, - // }) - // if (response.error) { - // throw response.error - // } - - return response as IntegrationsResponse + return response as GitHubReposResponse[] } -export type IntegrationsData = Awaited> -export type IntegrationsError = unknown +export type GitHubReposData = Awaited> +export type GitHubReposError = unknown -export const useIntegrationsGitHubReposQuery = ( - { orgSlug }: IntegrationsVariables, - { enabled = true, ...options }: UseQueryOptions = {} +export const useGitHubReposQuery = ( + { integrationId }: GitHubReposVariables, + { enabled = true, ...options }: UseQueryOptions = {} ) => - useQuery( - integrationKeys.integrationsList(), // TODO: make a unique key for github repos - ({ signal }) => getIntegrations({ orgSlug }, signal), - { enabled: enabled && typeof orgSlug !== 'undefined', ...options } + useQuery( + integrationKeys.githubRepoList(integrationId), + ({ signal }) => getGitHubRepos({ integrationId }, signal), + { + enabled: enabled && typeof integrationId !== 'undefined', + ...options, + } ) diff --git a/studio/data/integrations/integrations-query.ts b/studio/data/integrations/integrations-query.ts index a522135fa2a..4549f2d6bf0 100644 --- a/studio/data/integrations/integrations-query.ts +++ b/studio/data/integrations/integrations-query.ts @@ -1,12 +1,12 @@ -import { useQuery, useQueryClient, UseQueryOptions } from '@tanstack/react-query' +import { useQuery, UseQueryOptions } from '@tanstack/react-query' import { get } from 'lib/common/fetch' import { API_URL } from 'lib/constants' +import { Integration } from './integrations.types' import { integrationKeys } from './keys' -import { IntegrationsVariables, Integration } from './integrations.types' export type IntegrationsResponse = Integration[] -export async function getIntegrations({}: {}, signal?: AbortSignal) { +export async function getIntegrations(signal?: AbortSignal) { const response = await get(`${API_URL}/integrations`, { signal, }) @@ -27,6 +27,6 @@ export const useIntegrationsQuery = ({ }: UseQueryOptions = {}) => useQuery( integrationKeys.integrationsList(), - ({ signal }) => getIntegrations({}, signal), + ({ signal }) => getIntegrations(signal), { enabled: enabled, ...options } ) diff --git a/studio/data/integrations/integration-connections-create-mutation.ts b/studio/data/integrations/integrations-vercel-connections-create-mutation.ts similarity index 71% rename from studio/data/integrations/integration-connections-create-mutation.ts rename to studio/data/integrations/integrations-vercel-connections-create-mutation.ts index 9431e94aafb..edf8799d9e5 100644 --- a/studio/data/integrations/integration-connections-create-mutation.ts +++ b/studio/data/integrations/integrations-vercel-connections-create-mutation.ts @@ -2,18 +2,9 @@ import { useMutation, UseMutationOptions, useQueryClient } from '@tanstack/react import { post } from 'lib/common/fetch' import { API_URL } from 'lib/constants' import { integrationKeys } from './keys' +import { IntegrationConnectionsCreateVariables } from './types' -export type IntegrationConnectionsCreateVariables = { - organizationIntegrationId: string - connection: { - foreign_project_id: string - supabase_project_ref: string - metadata: any - } - orgSlug: string | undefined -} - -export async function createIntegrationConnections({ +export async function createIntegrationVercelConnections({ organizationIntegrationId, connection, }: IntegrationConnectionsCreateVariables) { @@ -28,14 +19,16 @@ export async function createIntegrationConnections({ return response } -type IntegrationConnectionsCreateData = Awaited> +export type IntegrationVercelConnectionsCreateData = Awaited< + ReturnType +> -export const useIntegrationConnectionsCreateMutation = ({ +export const useIntegrationVercelConnectionsCreateMutation = ({ onSuccess, ...options }: Omit< UseMutationOptions< - IntegrationConnectionsCreateData, + IntegrationVercelConnectionsCreateData, unknown, IntegrationConnectionsCreateVariables >, @@ -43,10 +36,10 @@ export const useIntegrationConnectionsCreateMutation = ({ > = {}) => { const queryClient = useQueryClient() return useMutation< - IntegrationConnectionsCreateData, + IntegrationVercelConnectionsCreateData, unknown, IntegrationConnectionsCreateVariables - >((vars) => createIntegrationConnections(vars), { + >((vars) => createIntegrationVercelConnections(vars), { async onSuccess(data, variables, context) { await Promise.all([ queryClient.invalidateQueries(integrationKeys.integrationsList()), diff --git a/studio/data/integrations/keys.ts b/studio/data/integrations/keys.ts index c099d9d7783..cf889d06b13 100644 --- a/studio/data/integrations/keys.ts +++ b/studio/data/integrations/keys.ts @@ -4,6 +4,10 @@ export const integrationKeys = { integrationsList: () => ['organizations', 'integrations'] as const, vercelProjectList: (organization_integration_id: string | undefined) => ['organizations', organization_integration_id, 'vercel-projects'] as const, + githubRepoList: (organization_integration_id: string | undefined) => + ['organizations', organization_integration_id, 'github-repos'] as const, vercelConnectionsList: (organization_integration_id: string | undefined) => ['organizations', organization_integration_id, 'vercel-connections'] as const, + githubConnectionsList: (organization_integration_id: string | undefined) => + ['organizations', organization_integration_id, 'github-connections'] as const, } diff --git a/studio/data/integrations/types.ts b/studio/data/integrations/types.ts new file mode 100644 index 00000000000..50ff9e34d05 --- /dev/null +++ b/studio/data/integrations/types.ts @@ -0,0 +1,9 @@ +export type IntegrationConnectionsCreateVariables = { + organizationIntegrationId: string + connection: { + foreign_project_id: string + supabase_project_ref: string + metadata: any + } + orgSlug: string | undefined +} diff --git a/studio/next.config.js b/studio/next.config.js index d95d252877e..5a10643bf13 100644 --- a/studio/next.config.js +++ b/studio/next.config.js @@ -201,7 +201,12 @@ const nextConfig = { ] }, images: { - domains: ['github.com', 'api-frameworks.vercel.sh', 'vercel.com'], + domains: [ + 'github.com', + 'avatars.githubusercontent.com', + 'api-frameworks.vercel.sh', + 'vercel.com', + ], }, // Ref: https://nextjs.org/docs/advanced-features/output-file-tracing#caveats experimental: { diff --git a/studio/pages/integrations/github/[integrationId]/choose-project.tsx b/studio/pages/integrations/github/[integrationId]/choose-project.tsx new file mode 100644 index 00000000000..dc1d7545f93 --- /dev/null +++ b/studio/pages/integrations/github/[integrationId]/choose-project.tsx @@ -0,0 +1,116 @@ +import { useParams } from 'common' +import ProjectLinker from 'components/interfaces/Integrations/ProjectLinker' +import { Markdown } from 'components/interfaces/Markdown' +import GitHubIntegrationWindowLayout from 'components/layouts/IntegrationsLayout/GitHubIntegrationWindowLayout' +import { ScaffoldContainer, ScaffoldDivider } from 'components/layouts/Scaffold' +import { useIntegrationGitHubConnectionsCreateMutation } from 'data/integrations/integrations-github-connections-create-mutation' +import { useGitHubReposQuery } from 'data/integrations/integrations-github-repos-query' +import { useIntegrationsQuery } from 'data/integrations/integrations-query' +import { useOrganizationsQuery } from 'data/organizations/organizations-query' +import { useProjectsQuery } from 'data/projects/projects-query' +import { EMPTY_ARR } from 'lib/void' +import { useRouter } from 'next/router' +import { useMemo } from 'react' +import { NextPageWithLayout } from 'types' +import { IconBook, IconLifeBuoy, LoadingLine } from 'ui' + +const GITHUB_ICON = ( + + + +) + +const ChooseProjectGitHubPage: NextPageWithLayout = () => { + const router = useRouter() + const { integrationId } = useParams() + + const { data: integrations } = useIntegrationsQuery() + const { data: organizations } = useOrganizationsQuery() + const { data: allProjects } = useProjectsQuery() + const { data: allRepos } = useGitHubReposQuery({ integrationId }) + + const integration = integrations?.find((integration) => integration.id === integrationId) + const orgSlug = integration?.organization.slug + const organization = organizations?.find((organization) => organization.slug === orgSlug) + const projects = useMemo( + () => + allProjects + ?.filter((project) => project.organization_id === organization?.id) + .map((project) => ({ id: project.id.toString(), name: project.name, ref: project.ref })) ?? + EMPTY_ARR, + [allProjects, organization?.id] + ) + + const repos = useMemo( + () => + allRepos?.map((repo) => ({ + id: repo.id.toString(), + name: repo.full_name, + })) ?? EMPTY_ARR, + [allRepos] + ) + + const { mutate: createConnections, isLoading: isCreatingConnection } = + useIntegrationGitHubConnectionsCreateMutation({ + onSuccess() { + router.push(`/org/${orgSlug}/integrations`) + }, + }) + + return ( + <> +
+ + <> + +
+

+ Link a Supabase project to a GitHub repository +

+ +
+ { + createConnections(vars) + }} + installedConnections={integration?.connections} + isLoading={isCreatingConnection} + integrationIcon={GITHUB_ICON} + choosePrompt="Choose GitHub Repo" + /> +
+ + + +
+ +
+ Docs +
+
+ Support +
+
+ + ) +} + +ChooseProjectGitHubPage.getLayout = (page) => ( + {page} +) + +export default ChooseProjectGitHubPage diff --git a/studio/pages/integrations/github/[slug]/choose-project.tsx b/studio/pages/integrations/github/[slug]/choose-project.tsx deleted file mode 100644 index 056571b9458..00000000000 --- a/studio/pages/integrations/github/[slug]/choose-project.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import GitHubIntegrationWindowLayout from 'components/layouts/IntegrationsLayout/GitHubIntegrationWindowLayout' -import { NextPageWithLayout } from 'types' - -const ChooseProjectGitHubPage: NextPageWithLayout = () => { - return
-} - -ChooseProjectGitHubPage.getLayout = (page) => ( - {page} -) - -export default ChooseProjectGitHubPage diff --git a/studio/pages/integrations/github/install.tsx b/studio/pages/integrations/github/install.tsx index c0da8558089..4a70943340c 100644 --- a/studio/pages/integrations/github/install.tsx +++ b/studio/pages/integrations/github/install.tsx @@ -1,15 +1,15 @@ +import { useRouter } from 'next/router' +import { useState } from 'react' + import { useParams } from 'common' import { Markdown } from 'components/interfaces/Markdown' import GitHubIntegrationWindowLayout from 'components/layouts/IntegrationsLayout/GitHubIntegrationWindowLayout' -import IntegrationWindowLayout from 'components/layouts/IntegrationsLayout/IntegrationWindowLayout' import { ScaffoldContainer, ScaffoldDivider } from 'components/layouts/Scaffold' import { useGitHubIntegrationCreateMutation } from 'data/integrations/github-integration-create-mutation' import { useIntegrationsQuery } from 'data/integrations/integrations-query' import { IntegrationName } from 'data/integrations/integrations.types' import { useOrganizationsQuery } from 'data/organizations/organizations-query' import { useStore } from 'hooks' -import { useRouter } from 'next/router' -import { useState } from 'react' import { useGitHubIntegrationInstallationState } from 'state/github-integration-installation' import { NextPageWithLayout, Organization } from 'types' import { Alert, Badge, Button, IconBook, IconHexagon, IconLifeBuoy, Listbox, LoadingLine } from 'ui' @@ -21,20 +21,10 @@ interface OrganizationsResponseWithInstalledData extends Organization { installationInstalled?: boolean } -/** - * Variations of the GitHub integration flow. - * They require different UI and logic. - * - * Deploy Button - the flow that starts from the Deploy Button - https://github.com/docs/integrations#deploy-button - * Marketplace - the flow that starts from the Marketplace - https://github.com/integrations - * - */ -export type GitHubIntegrationFlow = 'deploy-button' | 'marketing' - const GitHubIntegration: NextPageWithLayout = () => { const router = useRouter() const { ui } = useStore() - const { code, installation_id: installationId } = useParams() + const { installation_id: installationId } = useParams() const [selectedOrg, setSelectedOrg] = useState(null) const [organizationIntegrationId, setOrganizationIntegrationId] = useState(null) @@ -45,7 +35,7 @@ const GitHubIntegration: NextPageWithLayout = () => { * * Array of integrations installed on all */ - const { data: integrationData, isLoading: integrationDataLoading } = useIntegrationsQuery() + const { data: integrationData } = useIntegrationsQuery() const { data: organizationsData, isLoading: isLoadingOrganizationsQuery } = useOrganizationsQuery( { @@ -66,7 +56,9 @@ const GitHubIntegration: NextPageWithLayout = () => { */ const flatInstalledConnectionsIds: string[] | [] = integrationData && integrationData.length > 0 - ? integrationData?.map((x) => x.organization.slug) + ? integrationData + .filter((x) => x.integration.name === 'Vercel') + .map((x) => x.organization.slug) : [] /** @@ -84,28 +76,15 @@ const GitHubIntegration: NextPageWithLayout = () => { }) : [] - /** - * Handle the correct route change based on wether the github integration - * is following the 'marketplace' flow or 'deploy button' flow. - * - */ - function handleRouteChange() { - const orgSlug = selectedOrg?.slug - - router.push({ - pathname: `/integrations/github/${orgSlug}/choose-project`, - query: router.query, - }) - } - const { mutate, isLoading: isLoadingGitHubIntegrationCreateMutation } = useGitHubIntegrationCreateMutation({ onSuccess({ id }) { - const orgSlug = selectedOrg?.slug - setOrganizationIntegrationId(id) - handleRouteChange() + router.push({ + pathname: `/integrations/github/${id}/choose-project`, + query: router.query, + }) }, onError(error: any) { ui.setNotification({ @@ -118,18 +97,13 @@ const GitHubIntegration: NextPageWithLayout = () => { function onInstall() { const orgSlug = selectedOrg?.slug - const isIntegrationInstalled = organizationsWithInstalledData.some( - (x) => x.slug === orgSlug && x.installationInstalled - ) + const installedIntegration = integrationData?.find((x) => x.organization.slug === orgSlug) + const isIntegrationInstalled = Boolean(installedIntegration) if (!orgSlug) { return ui.setNotification({ category: 'error', message: 'Please select an organization' }) } - if (!code) { - return ui.setNotification({ category: 'error', message: 'GitHub code missing' }) - } - if (!installationId) { return ui.setNotification({ category: 'error', message: 'GitHub Installation ID is missing' }) } @@ -139,13 +113,15 @@ const GitHubIntegration: NextPageWithLayout = () => { */ if (!isIntegrationInstalled) { mutate({ - code, installationId, orgSlug, metadata: {}, }) } else { - handleRouteChange() + router.push({ + pathname: `/integrations/github/${installedIntegration?.id}/choose-project`, + query: router.query, + }) } } @@ -226,11 +202,9 @@ export interface OrganizationPickerProps { const OrganizationPicker = ({ label = 'Choose an organization', onSelectedOrgChange, - integrationName, dataLoading, organizationsWithInstalledData, }: OrganizationPickerProps) => { - const { ui } = useStore() const [selectedOrg, setSelectedOrg] = useState(null) const { data, isLoading } = useOrganizationsQuery({ diff --git a/studio/pages/integrations/vercel.tsx b/studio/pages/integrations/vercel.tsx deleted file mode 100644 index 29c927001cf..00000000000 --- a/studio/pages/integrations/vercel.tsx +++ /dev/null @@ -1,19 +0,0 @@ -import { useEffect } from 'react' - -import IntegrationWindowLayout from 'components/layouts/IntegrationsLayout/IntegrationWindowLayout' -import { useRouter } from 'next/router' -import { NextPageWithLayout } from 'types' - -const VercelIntegration: NextPageWithLayout = () => { - const router = useRouter() - - useEffect(() => { - router.push({ pathname: '/integrations/vercel/install', query: router.query }) - }, [router]) - - return <> -} - -VercelIntegration.getLayout = (page) => {page} - -export default VercelIntegration diff --git a/studio/pages/integrations/vercel/[slug]/deploy-button/new-project.tsx b/studio/pages/integrations/vercel/[slug]/deploy-button/new-project.tsx index 4465635cb5c..abf5107a1be 100644 --- a/studio/pages/integrations/vercel/[slug]/deploy-button/new-project.tsx +++ b/studio/pages/integrations/vercel/[slug]/deploy-button/new-project.tsx @@ -8,7 +8,7 @@ import { VercelIntegrationLayout } from 'components/layouts' import { ScaffoldContainer, ScaffoldDivider } from 'components/layouts/Scaffold' import PasswordStrengthBar from 'components/ui/PasswordStrengthBar' import { useProjectApiQuery } from 'data/config/project-api-query' -import { useIntegrationConnectionsCreateMutation } from 'data/integrations/integration-connections-create-mutation' +import { useIntegrationVercelConnectionsCreateMutation } from 'data/integrations/integrations-vercel-connections-create-mutation' import { useIntegrationsQuery } from 'data/integrations/integrations-query' import { useVercelProjectsQuery } from 'data/integrations/integrations-vercel-projects-query' import { Integration } from 'data/integrations/integrations.types' @@ -93,7 +93,7 @@ const CreateProject = ({ } = useParams() const { mutateAsync: createConnections, isLoading: isLoadingCreateConnections } = - useIntegrationConnectionsCreateMutation({}) + useIntegrationVercelConnectionsCreateMutation() const { data: organizationData, isLoading: isLoadingOrganizationsQuery } = useOrganizationsQuery() diff --git a/studio/pages/integrations/vercel/[slug]/marketplace/choose-project.tsx b/studio/pages/integrations/vercel/[slug]/marketplace/choose-project.tsx index defe66f8310..8e2032902a6 100644 --- a/studio/pages/integrations/vercel/[slug]/marketplace/choose-project.tsx +++ b/studio/pages/integrations/vercel/[slug]/marketplace/choose-project.tsx @@ -1,23 +1,33 @@ -import { useMemo, useState } from 'react' +import { keyBy } from 'lodash' +import { useCallback, useMemo } from 'react' import { useParams } from 'common' -import ProjectLinker from 'components/interfaces/Integrations/ProjectLinker' +import ProjectLinker, { ForeignProject } from 'components/interfaces/Integrations/ProjectLinker' import { Markdown } from 'components/interfaces/Markdown' import { VercelIntegrationLayout } from 'components/layouts' import { ScaffoldContainer, ScaffoldDivider } from 'components/layouts/Scaffold' +import { vercelIcon } from 'components/to-be-cleaned/ListIcons' import { useOrgIntegrationsQuery } from 'data/integrations/integrations-query-org-only' +import { useIntegrationVercelConnectionsCreateMutation } from 'data/integrations/integrations-vercel-connections-create-mutation' import { useVercelProjectsQuery } from 'data/integrations/integrations-vercel-projects-query' import { useOrganizationsQuery } from 'data/organizations/organizations-query' import { useProjectsQuery } from 'data/projects/projects-query' +import { BASE_PATH } from 'lib/constants' import { EMPTY_ARR } from 'lib/void' + import { NextPageWithLayout, Organization } from 'types' import { IconBook, IconLifeBuoy, LoadingLine } from 'ui' +import { ENV_VAR_RAW_KEYS } from 'components/interfaces/Integrations/Integrations-Vercel.constants' + +const VERCEL_ICON = ( + + + +) const VercelIntegration: NextPageWithLayout = () => { const { slug, configurationId, next, organizationSlug } = useParams() - const [loading, setLoading] = useState(false) - /** * Fetch the list of organization based integration installations for Vercel. * @@ -45,7 +55,7 @@ const VercelIntegration: NextPageWithLayout = () => { ?.filter((project) => project.organization_id === organization?.id) .map((project) => ({ id: project.id.toString(), name: project.name, ref: project.ref })) ?? EMPTY_ARR, - [organizationSlug, supabaseProjectsData] + [organization?.id, supabaseProjectsData] ) const { data: vercelProjectsData } = useVercelProjectsQuery( @@ -56,11 +66,59 @@ const VercelIntegration: NextPageWithLayout = () => { ) const vercelProjects = useMemo(() => vercelProjectsData ?? EMPTY_ARR, [vercelProjectsData]) + const vercelProjectsById = useMemo(() => keyBy(vercelProjects, 'id'), [vercelProjects]) + + const getForeignProjectIcon = useCallback( + (_project: ForeignProject) => { + const project = vercelProjectsById[_project.id] + + return !project?.framework ? ( + vercelIcon + ) : ( + {`icon`} + ) + }, + [vercelProjectsById] + ) + + const { mutate: createConnections, isLoading: isCreatingConnection } = + useIntegrationVercelConnectionsCreateMutation({ + onSuccess() { + if (next) { + window.location.href = next + } + }, + }) + + const onCreateConnections = useCallback( + (vars) => { + createConnections({ + ...vars, + connection: { + ...vars.connection, + metadata: { + ...vars.connection.metadata, + supabaseConfig: { + projectEnvVars: { + write: true, + }, + }, + }, + }, + }) + }, + [createConnections] + ) return ( <>
- + <>
@@ -70,7 +128,7 @@ const VercelIntegration: NextPageWithLayout = () => {
@@ -78,13 +136,24 @@ This Supabase integration manages your envioemnt variables automatically to prov organizationIntegrationId={integration?.id} foreignProjects={vercelProjects} supabaseProjects={supabaseProjects} - onCreateConnections={() => { - if (next) { - window.location.href = next - } - }} + onCreateConnections={onCreateConnections} installedConnections={integration?.connections} - setLoading={setLoading} + isLoading={isCreatingConnection} + integrationIcon={VERCEL_ICON} + getForeignProjectIcon={getForeignProjectIcon} + choosePrompt="Choose Vercel Project" + /> + { + return ` + \n + - \`${x}\` +` +})} +`} />
diff --git a/studio/pages/integrations/vercel/install.tsx b/studio/pages/integrations/vercel/install.tsx index dd629aed8b5..67016004b90 100644 --- a/studio/pages/integrations/vercel/install.tsx +++ b/studio/pages/integrations/vercel/install.tsx @@ -46,7 +46,7 @@ const VercelIntegration: NextPageWithLayout = () => { * * Array of integrations installed on all */ - const { data: integrationData, isLoading: integrationDataLoading } = useIntegrationsQuery() + const { data: integrationData } = useIntegrationsQuery() const { data: organizationsData, isLoading: isLoadingOrganizationsQuery } = useOrganizationsQuery( { @@ -63,11 +63,12 @@ const VercelIntegration: NextPageWithLayout = () => { /** * Flat array of org slugs that have integration installed - * */ const flatInstalledConnectionsIds: string[] | [] = integrationData && integrationData.length > 0 - ? integrationData?.map((x) => x.organization.slug) + ? integrationData + .filter((x) => x.integration.name === 'Vercel') + .map((x) => x.organization.slug) : [] /** From 0e7b1f4f61f088d0cdc782a33c6a9eb322f01934 Mon Sep 17 00:00:00 2001 From: Alaister Young Date: Thu, 13 Jul 2023 15:01:27 +0800 Subject: [PATCH 03/61] adds SidePanelGitHubRepoLinker --- .../IntegrationSettings.tsx | 2 + .../SidePanelGitHubRepoLinker.tsx | 130 ++++++++++++++++++ studio/data/api.d.ts | 123 ++++++++++++++++- .../github-integration-create-mutation.ts | 24 ++-- studio/pages/integrations/github/install.tsx | 2 +- 5 files changed, 265 insertions(+), 16 deletions(-) create mode 100644 studio/components/interfaces/Organization/IntegrationSettings/SidePanelGitHubRepoLinker.tsx diff --git a/studio/components/interfaces/Organization/IntegrationSettings/IntegrationSettings.tsx b/studio/components/interfaces/Organization/IntegrationSettings/IntegrationSettings.tsx index d3091a75519..73ecdfb1e36 100644 --- a/studio/components/interfaces/Organization/IntegrationSettings/IntegrationSettings.tsx +++ b/studio/components/interfaces/Organization/IntegrationSettings/IntegrationSettings.tsx @@ -4,6 +4,7 @@ import { useVercelProjectsQuery } from 'data/integrations/integrations-vercel-pr import { useSelectedOrganization } from 'hooks' import { getVercelConfigurationUrl } from 'lib/integration-utils' import Integration from './Integration' +import SidePanelGitHubRepoLinker from './SidePanelGitHubRepoLinker' import SidePanelVercelProjectLinker from './SidePanelVercelProjectLinker' const IntegrationSettings = () => { @@ -87,6 +88,7 @@ These connections will be part of a GitHub workflow that is currently in develop integrations={githubIntegrations} /> + ) } diff --git a/studio/components/interfaces/Organization/IntegrationSettings/SidePanelGitHubRepoLinker.tsx b/studio/components/interfaces/Organization/IntegrationSettings/SidePanelGitHubRepoLinker.tsx new file mode 100644 index 00000000000..4ff69b1585e --- /dev/null +++ b/studio/components/interfaces/Organization/IntegrationSettings/SidePanelGitHubRepoLinker.tsx @@ -0,0 +1,130 @@ +import { useCallback, useMemo } from 'react' + +import ProjectLinker from 'components/interfaces/Integrations/ProjectLinker' +import { Markdown } from 'components/interfaces/Markdown' +import { useIntegrationGitHubConnectionsCreateMutation } from 'data/integrations/integrations-github-connections-create-mutation' +import { useGitHubReposQuery } from 'data/integrations/integrations-github-repos-query' +import { useOrgIntegrationsQuery } from 'data/integrations/integrations-query-org-only' +import { useProjectsQuery } from 'data/projects/projects-query' +import { useSelectedOrganization } from 'hooks' +import { EMPTY_ARR } from 'lib/void' +import { useGithubConnectionConfigPanelSnapshot } from 'state/github-connection-config-panel' +import { SidePanel } from 'ui' + +const GITHUB_ICON = ( + + + +) + +const SidePanelGitHubRepoLinker = () => { + const selectedOrganization = useSelectedOrganization() + + const { data: integrationData } = useOrgIntegrationsQuery({ + orgSlug: selectedOrganization?.slug, + }) + const githubIntegrations = integrationData?.filter( + (integration) => integration.integration.name === 'GitHub' + ) // github + + const snapshot = useGithubConnectionConfigPanelSnapshot() + + /** + * Find the right integration + * + * we use the snapshot.organizationIntegrationId which should be set whenever this sidepanel is opened + */ + const selectedIntegration = githubIntegrations?.find( + (x) => x.id === snapshot.organizationIntegrationId + ) + + const organizationIntegrationId = snapshot.organizationIntegrationId + const open = snapshot.open + + /** + * Supabase projects available + */ + const { data: supabaseProjectsData } = useProjectsQuery({ + enabled: organizationIntegrationId !== undefined, + }) + + const supabaseProjects = useMemo( + () => + supabaseProjectsData + ?.filter((project) => project.organization_id === selectedOrganization?.id) + .map((project) => ({ id: project.id.toString(), name: project.name, ref: project.ref })) ?? + EMPTY_ARR, + [selectedOrganization?.id, supabaseProjectsData] + ) + + const { data: githubProjectsData } = useGitHubReposQuery( + { + integrationId: organizationIntegrationId, + }, + { enabled: organizationIntegrationId !== undefined } + ) + + const githubRepos = useMemo( + () => + githubProjectsData?.map((repo) => ({ + id: repo.id.toString(), + name: repo.full_name, + })) ?? EMPTY_ARR, + [githubProjectsData] + ) + + const { mutate: createConnections, isLoading: isCreatingConnection } = + useIntegrationGitHubConnectionsCreateMutation({ + onSuccess() { + snapshot.setOpen(false) + }, + }) + + const onCreateConnections = useCallback( + (vars) => { + createConnections(vars) + }, + [createConnections] + ) + + return ( + snapshot.setOpen(false)} + > +
+ + + + + + +
+
+ ) +} + +export default SidePanelGitHubRepoLinker diff --git a/studio/data/api.d.ts b/studio/data/api.d.ts index 57c1537e7bf..88909a8dd2a 100644 --- a/studio/data/api.d.ts +++ b/studio/data/api.d.ts @@ -704,6 +704,29 @@ export interface paths { /** Deletes vercel project connection */ delete: operations["VercelConnectionsController_deleteVercelConnection"]; }; + "/platform/integrations/github": { + /** + * Create github integration + * @description Exchanges a github code for an access token and saves the access token to the new integration record + */ + post: operations["GitHubIntegrationController_createGitHubIntegration"]; + }; + "/platform/integrations/github/repos/{organization_integration_id}": { + /** Gets github repos for the given organization */ + get: operations["GitHubRepoController_getRepos"]; + }; + "/platform/integrations/github/connections/{organization_integration_id}": { + /** Gets installed github project connections for the given organization integration */ + get: operations["GitHubConnectionsController_getGitHubConnections"]; + }; + "/platform/integrations/github/connections": { + /** Connects a GitHub project to a supabase project */ + post: operations["GitHubConnectionsController_createGitHubConnection"]; + }; + "/platform/integrations/github/connections/{connection_id}": { + /** Deletes github project connection */ + delete: operations["GitHubConnectionsController_deleteGitHubConnection"]; + }; "/system/auth/{ref}/templates/{template}": { /** Gets GoTrue template */ get: operations["AuthTemplateController_getTemplate"]; @@ -2449,9 +2472,6 @@ export interface components { packagePrice: number; freeUnits?: number; }; - BillingPricingOptionsNone: { - freeUnits?: number; - }; BillingUsageBasedPrice: { /** @enum {string} */ metric: "EGRESS" | "DATABASE_EGRESS" | "DATABASE_SIZE" | "STORAGE_EGRESS" | "STORAGE_SIZE" | "MONTHLY_ACTIVE_USERS" | "MONTHLY_ACTIVE_SSO_USERS" | "FUNCTION_INVOCATIONS" | "FUNCTION_COUNT" | "STORAGE_IMAGES_TRANSFORMED" | "REALTIME_MESSAGE_COUNT" | "REALTIME_PEAK_CONNECTIONS" | "COMPUTE_HOURS_XS" | "COMPUTE_HOURS_SM" | "COMPUTE_HOURS_MD" | "COMPUTE_HOURS_L" | "COMPUTE_HOURS_XL" | "COMPUTE_HOURS_2XL" | "COMPUTE_HOURS_4XL" | "COMPUTE_HOURS_8XL" | "COMPUTE_HOURS_12XL" | "COMPUTE_HOURS_16XL"; @@ -3723,6 +3743,27 @@ export interface components { organization_integration_id: string; connection: components["schemas"]["IntegrationConnection"]; }; + CreateGitHubIntegrationBody: { + installation_id: number; + organization_slug: string; + metadata: Record; + }; + CreateGitHubIntegrationResponse: { + id: string; + }; + GetGitHubConnections: { + id: string; + inserted_at: string; + updated_at: string; + organization_integration_id: string; + supabase_project_ref: string; + foreign_project_id: string; + metadata: Record; + }; + CreateGitHubConnectionsBody: { + organization_integration_id: string; + connection: components["schemas"]["IntegrationConnection"]; + }; FunctionResponse: { id: string; slug: string; @@ -8132,6 +8173,82 @@ export interface operations { 500: never; }; }; + /** + * Create github integration + * @description Exchanges a github code for an access token and saves the access token to the new integration record + */ + GitHubIntegrationController_createGitHubIntegration: { + requestBody: { + content: { + "application/json": components["schemas"]["CreateGitHubIntegrationBody"]; + }; + }; + responses: { + 201: { + content: { + "application/json": components["schemas"]["CreateGitHubIntegrationResponse"]; + }; + }; + /** @description Failed to create github integration */ + 500: never; + }; + }; + /** Gets github repos for the given organization */ + GitHubRepoController_getRepos: { + parameters: { + path: { + organization_integration_id: string; + }; + }; + responses: { + 200: never; + /** @description Failed to get github repos for the given organization */ + 500: never; + }; + }; + /** Gets installed github project connections for the given organization integration */ + GitHubConnectionsController_getGitHubConnections: { + parameters: { + path: { + organization_integration_id: string; + }; + }; + responses: { + 200: { + content: { + "application/json": (components["schemas"]["GetGitHubConnections"])[]; + }; + }; + /** @description Failed to get installed github connections for the given organization integration */ + 500: never; + }; + }; + /** Connects a GitHub project to a supabase project */ + GitHubConnectionsController_createGitHubConnection: { + requestBody: { + content: { + "application/json": components["schemas"]["CreateGitHubConnectionsBody"]; + }; + }; + responses: { + 201: never; + /** @description Failed to create project connections */ + 500: never; + }; + }; + /** Deletes github project connection */ + GitHubConnectionsController_deleteGitHubConnection: { + parameters: { + path: { + connection_id: string; + }; + }; + responses: { + 200: never; + /** @description Failed to delete github integration project connection */ + 500: never; + }; + }; /** Gets GoTrue template */ AuthTemplateController_getTemplate: { parameters: { diff --git a/studio/data/integrations/github-integration-create-mutation.ts b/studio/data/integrations/github-integration-create-mutation.ts index 8ae13f84b94..668e2880e4b 100644 --- a/studio/data/integrations/github-integration-create-mutation.ts +++ b/studio/data/integrations/github-integration-create-mutation.ts @@ -1,10 +1,10 @@ import { useMutation, UseMutationOptions, useQueryClient } from '@tanstack/react-query' -import { post } from 'lib/common/fetch' -import { API_URL } from 'lib/constants' + +import { post } from 'data/fetchers' import { integrationKeys } from './keys' export type GitHubIntegrationCreateVariables = { - installationId: string + installationId: number orgSlug: string metadata: { [key: string]: string } } @@ -14,16 +14,16 @@ export async function createGitHubIntegration({ orgSlug, metadata, }: GitHubIntegrationCreateVariables) { - const response = await post(`${API_URL}/integrations/github`, { - installation_id: installationId, - organization_slug: orgSlug, - metadata, + const { data, error } = await post('/platform/integrations/github', { + body: { + installation_id: installationId, + organization_slug: orgSlug, + metadata: metadata as any, + }, }) - if (response.error) { - throw response.error - } + if (error) throw error - return response + return data } type GitHubIntegrationCreateData = Awaited> @@ -43,7 +43,7 @@ export const useGitHubIntegrationCreateMutation = ({ await Promise.all([ queryClient.invalidateQueries(integrationKeys.integrationsList()), queryClient.invalidateQueries(integrationKeys.integrationsListWithOrg(variables.orgSlug)), - // queryClient.invalidateQueries(integrationKeys.githubProjectList(data.id)), + queryClient.invalidateQueries(integrationKeys.githubRepoList(data.id)), ]) await onSuccess?.(data, variables, context) }, diff --git a/studio/pages/integrations/github/install.tsx b/studio/pages/integrations/github/install.tsx index 4a70943340c..1d0637d223f 100644 --- a/studio/pages/integrations/github/install.tsx +++ b/studio/pages/integrations/github/install.tsx @@ -113,7 +113,7 @@ const GitHubIntegration: NextPageWithLayout = () => { */ if (!isIntegrationInstalled) { mutate({ - installationId, + installationId: Number(installationId), orgSlug, metadata: {}, }) From 0b7295ced46324ce36a885c090b9bd23869a3579 Mon Sep 17 00:00:00 2001 From: Alaister Young Date: Thu, 13 Jul 2023 16:56:06 +0800 Subject: [PATCH 04/61] improve integration creation and deletion --- .../Integrations/IntegrationPanels.tsx | 13 +- .../IntegrationSettings/Integration.tsx | 162 ++++++++++-------- .../IntegrationSettings.tsx | 79 ++++++++- .../SidePanelGitHubRepoLinker.tsx | 39 ++--- .../SidePanelVercelProjectLinker.tsx | 28 +-- ...tions-github-connection-delete-mutation.ts | 46 +++++ ...el-installed-connection-delete-mutation.ts | 1 - studio/lib/integration-utils.ts | 8 + .../github/[integrationId]/choose-project.tsx | 4 +- studio/pages/integrations/github/install.tsx | 4 +- studio/pages/integrations/vercel/install.tsx | 8 +- .../state/github-connection-config-panel.ts | 19 -- .../state/vercel-integration-installation.ts | 15 -- 13 files changed, 260 insertions(+), 166 deletions(-) create mode 100644 studio/data/integrations/integrations-github-connection-delete-mutation.ts delete mode 100644 studio/state/github-connection-config-panel.ts delete mode 100644 studio/state/vercel-integration-installation.ts diff --git a/studio/components/interfaces/Integrations/IntegrationPanels.tsx b/studio/components/interfaces/Integrations/IntegrationPanels.tsx index e4e6d36cb9f..6863006001c 100644 --- a/studio/components/interfaces/Integrations/IntegrationPanels.tsx +++ b/studio/components/interfaces/Integrations/IntegrationPanels.tsx @@ -6,7 +6,6 @@ import { Markdown } from 'components/interfaces/Markdown' import { Integration, IntegrationProjectConnection } from 'data/integrations/integrations.types' import { useProjectsQuery } from 'data/projects/projects-query' import { BASE_PATH } from 'lib/constants' -import { getVercelConfigurationUrl } from 'lib/integration-utils' import { Badge, Button, IconArrowRight, IconExternalLink, IconGitHub, IconSquare, cn } from 'ui' const ICON_STROKE_WIDTH = 2 @@ -15,6 +14,7 @@ const ICON_SIZE = 14 export interface IntegrationInstallationProps extends React.RefAttributes { title: string integration: Integration + getManageUrl: (integration: Integration) => string } type HandleIconType = Integration['integration']['name'] | 'Supabase' @@ -66,7 +66,7 @@ const Avatar = ({ src }: { src: string | undefined }) => { } const IntegrationInstallation = React.forwardRef( - ({ title, integration, ...props }, ref) => { + ({ title, integration, getManageUrl, ...props }, ref) => { const IntegrationIconBlock = () => { return (
@@ -112,12 +112,7 @@ const IntegrationInstallation = React.forwardRef @@ -153,7 +148,7 @@ const IntegrationConnection = React.forwardRef {!connection?.metadata?.framework ? (
- +
) : ( string + onAddConnection: (integrationId: string) => void + onDeleteConnection: (connection: IntegrationProjectConnection) => void | Promise } const Integration = ({ title, - orgName, description, note, detail, integrations = EMPTY_ARR, + getManageUrl, + onAddConnection, + onDeleteConnection, }: IntegrationProps) => { - const snapshot = useGithubConnectionConfigPanelSnapshot() - - const selectedOrganization = useSelectedOrganization() - - const { mutate: deleteMutate, isLoading: isDeleteLoading } = - useIntegrationsVercelInstalledConnectionDeleteMutation() - const ConnectionHeading = ({ integration }: { integration: TIntegration }) => { return ( { - const variables = { - organization_integration_id: organizationIntegrationId, - id: projectIntegrationId, - orgSlug: selectedOrganization?.slug, - } - - deleteMutate(variables) - } - return ( <> @@ -89,60 +75,32 @@ Repository connections for ${title?.toLowerCase()} {integrations.length > 0 && integrations.map((integration, i) => { return ( -
- +
+ + {integration.connections.length > 0 ? ( <>
    - {integration.connections.map( - (connection: IntegrationProjectConnection, i) => ( - - } - onSelect={() => - handleDelete(integration.id, connection.id) - } - > - Delete - - - } - > - - - } - /> - ) - )} + {integration.connections.map((connection) => ( + + ))}
) : ( )} - { - snapshot.setOrganizationIntegrationId(integration.id) - snapshot.setOpen(true) - }} - > + onAddConnection(integration.id)}> Add new project connection
@@ -158,3 +116,71 @@ Repository connections for ${title?.toLowerCase()} } export default Integration + +type IntegrationConnectionItemProps = { + connection: IntegrationProjectConnection + type: IntegrationName + onDeleteConnection: (connection: IntegrationProjectConnection) => void | Promise +} + +const IntegrationConnectionItem = ({ + connection, + type, + onDeleteConnection, +}: IntegrationConnectionItemProps) => { + const [isOpen, setIsOpen] = useState(false) + + const onConfirm = useCallback(async () => { + try { + await onDeleteConnection(connection) + } finally { + setIsOpen(false) + } + }, [connection, onDeleteConnection]) + + const onCancel = useCallback(() => { + setIsOpen(false) + }, []) + + return ( + <> + + } onSelect={() => setIsOpen(true)}> + Delete + + + } + > + + + } + /> + + + +

+ {`This action cannot be undone. Are you sure you want to delete this connection?`} +

+
+
+ + ) +} diff --git a/studio/components/interfaces/Organization/IntegrationSettings/IntegrationSettings.tsx b/studio/components/interfaces/Organization/IntegrationSettings/IntegrationSettings.tsx index 73ecdfb1e36..1f122d5462e 100644 --- a/studio/components/interfaces/Organization/IntegrationSettings/IntegrationSettings.tsx +++ b/studio/components/interfaces/Organization/IntegrationSettings/IntegrationSettings.tsx @@ -1,15 +1,20 @@ +import { useCallback, useState } from 'react' + +import { useParams } from 'common' import { ScaffoldDivider } from 'components/layouts/Scaffold' +import { useIntegrationsGitHubInstalledConnectionDeleteMutation } from 'data/integrations/integrations-github-connection-delete-mutation' import { useOrgIntegrationsQuery } from 'data/integrations/integrations-query-org-only' +import { useIntegrationsVercelInstalledConnectionDeleteMutation } from 'data/integrations/integrations-vercel-installed-connection-delete-mutation' import { useVercelProjectsQuery } from 'data/integrations/integrations-vercel-projects-query' -import { useSelectedOrganization } from 'hooks' -import { getVercelConfigurationUrl } from 'lib/integration-utils' +import { IntegrationProjectConnection } from 'data/integrations/integrations.types' +import { getGitHubConfigurationUrl, getVercelConfigurationUrl } from 'lib/integration-utils' import Integration from './Integration' import SidePanelGitHubRepoLinker from './SidePanelGitHubRepoLinker' import SidePanelVercelProjectLinker from './SidePanelVercelProjectLinker' const IntegrationSettings = () => { - const org = useSelectedOrganization() - const { data } = useOrgIntegrationsQuery({ orgSlug: org?.slug }) + const { slug } = useParams() + const { data } = useOrgIntegrationsQuery({ orgSlug: slug }) const vercelIntegrations = data ?.filter((integration) => integration.integration.name === 'Vercel') @@ -40,11 +45,56 @@ const IntegrationSettings = () => { ) const vercelProjectCount = vercelProjectsData?.length ?? 0 + const [addPanelOpen, setAddPanelOpen] = useState(undefined) + const [addPanelIntegrationId, setAddPanelIntegrationId] = useState(undefined) + + const onAddVercelConnection = useCallback((integrationId: string) => { + setAddPanelIntegrationId(integrationId) + setAddPanelOpen('VERCEL') + }, []) + + const onAddGitHubConnection = useCallback((integrationId: string) => { + setAddPanelIntegrationId(integrationId) + setAddPanelOpen('GITHUB') + }, []) + + const onCloseAddPanel = useCallback(() => { + setAddPanelOpen(undefined) + setAddPanelIntegrationId(undefined) + }, []) + + const { mutateAsync: deleteVercelConnection } = + useIntegrationsVercelInstalledConnectionDeleteMutation() + + const onDeleteVercelConnection = useCallback( + async (connection: IntegrationProjectConnection) => { + await deleteVercelConnection({ + id: connection.id, + organization_integration_id: connection.organization_integration_id, + orgSlug: slug, + }) + }, + [deleteVercelConnection, slug] + ) + + const { mutateAsync: deleteGitHubConnection } = + useIntegrationsGitHubInstalledConnectionDeleteMutation() + + const onDeleteGitHubConnection = useCallback( + async (connection: IntegrationProjectConnection) => { + await deleteGitHubConnection({ + connectionId: connection.id, + integrationId: connection.organization_integration_id, + orgSlug: slug, + }) + }, + [deleteGitHubConnection, slug] + ) + return ( <> + + - - ) } diff --git a/studio/components/interfaces/Organization/IntegrationSettings/SidePanelGitHubRepoLinker.tsx b/studio/components/interfaces/Organization/IntegrationSettings/SidePanelGitHubRepoLinker.tsx index 4ff69b1585e..48b4fc77db7 100644 --- a/studio/components/interfaces/Organization/IntegrationSettings/SidePanelGitHubRepoLinker.tsx +++ b/studio/components/interfaces/Organization/IntegrationSettings/SidePanelGitHubRepoLinker.tsx @@ -1,4 +1,4 @@ -import { useCallback, useMemo } from 'react' +import { useMemo } from 'react' import ProjectLinker from 'components/interfaces/Integrations/ProjectLinker' import { Markdown } from 'components/interfaces/Markdown' @@ -8,7 +8,6 @@ import { useOrgIntegrationsQuery } from 'data/integrations/integrations-query-or import { useProjectsQuery } from 'data/projects/projects-query' import { useSelectedOrganization } from 'hooks' import { EMPTY_ARR } from 'lib/void' -import { useGithubConnectionConfigPanelSnapshot } from 'state/github-connection-config-panel' import { SidePanel } from 'ui' const GITHUB_ICON = ( @@ -22,7 +21,17 @@ const GITHUB_ICON = ( ) -const SidePanelGitHubRepoLinker = () => { +export type SidePanelGitHubRepoLinkerProps = { + isOpen?: boolean + onClose?: () => void + organizationIntegrationId?: string +} + +const SidePanelGitHubRepoLinker = ({ + isOpen = false, + onClose, + organizationIntegrationId, +}: SidePanelGitHubRepoLinkerProps) => { const selectedOrganization = useSelectedOrganization() const { data: integrationData } = useOrgIntegrationsQuery({ @@ -32,19 +41,12 @@ const SidePanelGitHubRepoLinker = () => { (integration) => integration.integration.name === 'GitHub' ) // github - const snapshot = useGithubConnectionConfigPanelSnapshot() - /** * Find the right integration * * we use the snapshot.organizationIntegrationId which should be set whenever this sidepanel is opened */ - const selectedIntegration = githubIntegrations?.find( - (x) => x.id === snapshot.organizationIntegrationId - ) - - const organizationIntegrationId = snapshot.organizationIntegrationId - const open = snapshot.open + const selectedIntegration = githubIntegrations?.find((x) => x.id === organizationIntegrationId) /** * Supabase projects available @@ -81,24 +83,17 @@ const SidePanelGitHubRepoLinker = () => { const { mutate: createConnections, isLoading: isCreatingConnection } = useIntegrationGitHubConnectionsCreateMutation({ onSuccess() { - snapshot.setOpen(false) + onClose?.() }, }) - const onCreateConnections = useCallback( - (vars) => { - createConnections(vars) - }, - [createConnections] - ) - return ( snapshot.setOpen(false)} + onCancel={() => onClose?.()} >
@@ -115,7 +110,7 @@ Check the details below before proceeding organizationIntegrationId={selectedIntegration?.id} foreignProjects={githubRepos} supabaseProjects={supabaseProjects} - onCreateConnections={onCreateConnections} + onCreateConnections={createConnections} installedConnections={selectedIntegration?.connections} isLoading={isCreatingConnection} integrationIcon={GITHUB_ICON} diff --git a/studio/components/interfaces/Organization/IntegrationSettings/SidePanelVercelProjectLinker.tsx b/studio/components/interfaces/Organization/IntegrationSettings/SidePanelVercelProjectLinker.tsx index e3ac21e5850..f2b092bf758 100644 --- a/studio/components/interfaces/Organization/IntegrationSettings/SidePanelVercelProjectLinker.tsx +++ b/studio/components/interfaces/Organization/IntegrationSettings/SidePanelVercelProjectLinker.tsx @@ -12,7 +12,6 @@ import { useProjectsQuery } from 'data/projects/projects-query' import { useSelectedOrganization } from 'hooks' import { BASE_PATH } from 'lib/constants' import { EMPTY_ARR } from 'lib/void' -import { useGithubConnectionConfigPanelSnapshot } from 'state/github-connection-config-panel' import { SidePanel } from 'ui' const VERCEL_ICON = ( @@ -21,7 +20,17 @@ const VERCEL_ICON = ( ) -const SidePanelVercelProjectLinker = () => { +export type SidePanelVercelProjectLinkerProps = { + isOpen?: boolean + onClose?: () => void + organizationIntegrationId?: string +} + +const SidePanelVercelProjectLinker = ({ + isOpen = false, + onClose, + organizationIntegrationId, +}: SidePanelVercelProjectLinkerProps) => { const selectedOrganization = useSelectedOrganization() const { data: integrationData } = useOrgIntegrationsQuery({ @@ -31,19 +40,12 @@ const SidePanelVercelProjectLinker = () => { (integration) => integration.integration.name === 'Vercel' ) // vercel - const snapshot = useGithubConnectionConfigPanelSnapshot() - /** * Find the right integration * * we use the snapshot.organizationIntegrationId which should be set whenever this sidepanel is opened */ - const selectedIntegration = vercelIntegrations?.find( - (x) => x.id === snapshot.organizationIntegrationId - ) - - const organizationIntegrationId = snapshot.organizationIntegrationId - const open = snapshot.open + const selectedIntegration = vercelIntegrations?.find((x) => x.id === organizationIntegrationId) /** * Supabase projects available @@ -92,7 +94,7 @@ const SidePanelVercelProjectLinker = () => { const { mutate: createConnections, isLoading: isCreatingConnection } = useIntegrationVercelConnectionsCreateMutation({ onSuccess() { - snapshot.setOpen(false) + onClose?.() }, }) @@ -120,9 +122,9 @@ const SidePanelVercelProjectLinker = () => { snapshot.setOpen(false)} + onCancel={() => onClose?.()} >
diff --git a/studio/data/integrations/integrations-github-connection-delete-mutation.ts b/studio/data/integrations/integrations-github-connection-delete-mutation.ts new file mode 100644 index 00000000000..f61d2495a13 --- /dev/null +++ b/studio/data/integrations/integrations-github-connection-delete-mutation.ts @@ -0,0 +1,46 @@ +import { useMutation, UseMutationOptions, useQueryClient } from '@tanstack/react-query' + +import { del } from 'data/fetchers' +import { integrationKeys } from './keys' + +type DeleteVariables = { + connectionId: string + + integrationId: string + orgSlug: string | undefined +} + +export async function deleteConnection({ connectionId }: DeleteVariables, signal?: AbortSignal) { + const { data, error } = await del('/platform/integrations/github/connections/{connection_id}', { + params: { path: { connection_id: connectionId } }, + }) + if (error) throw error + + return data +} + +type DeleteContentData = Awaited> + +export const useIntegrationsGitHubInstalledConnectionDeleteMutation = ({ + onSuccess, + ...options +}: Omit, 'mutationFn'> = {}) => { + const queryClient = useQueryClient() + return useMutation( + (args) => deleteConnection(args), + { + async onSuccess(data, variables, context) { + await Promise.all([ + queryClient.invalidateQueries(integrationKeys.integrationsList()), + queryClient.invalidateQueries(integrationKeys.integrationsListWithOrg(variables.orgSlug)), + queryClient.invalidateQueries(integrationKeys.githubRepoList(variables.integrationId)), + queryClient.invalidateQueries( + integrationKeys.githubConnectionsList(variables.integrationId) + ), + ]) + await onSuccess?.(data, variables, context) + }, + ...options, + } + ) +} diff --git a/studio/data/integrations/integrations-vercel-installed-connection-delete-mutation.ts b/studio/data/integrations/integrations-vercel-installed-connection-delete-mutation.ts index 58ab5c10fee..41c65d99018 100644 --- a/studio/data/integrations/integrations-vercel-installed-connection-delete-mutation.ts +++ b/studio/data/integrations/integrations-vercel-installed-connection-delete-mutation.ts @@ -39,7 +39,6 @@ export const useIntegrationsVercelInstalledConnectionDeleteMutation = ({ (args) => deleteConnection(args), { async onSuccess(data, variables, context) { - console.log('variables in mutate delete onSuccess', variables) await Promise.all([ queryClient.invalidateQueries(integrationKeys.integrationsList()), queryClient.invalidateQueries(integrationKeys.integrationsListWithOrg(variables.orgSlug)), diff --git a/studio/lib/integration-utils.ts b/studio/lib/integration-utils.ts index b16b53efdfc..278cc5b93da 100644 --- a/studio/lib/integration-utils.ts +++ b/studio/lib/integration-utils.ts @@ -122,3 +122,11 @@ export function getVercelConfigurationUrl(integration: Integration) { : '' }integrations/${integration.metadata?.configuration_id}` } + +export function getGitHubConfigurationUrl(integration: Integration) { + return `https://github.com/${ + integration.metadata?.account.type === 'Organization' + ? `organizations/${integration.metadata?.account.name}/` + : '' + }settings/installations/${integration.metadata.installation_id}` +} diff --git a/studio/pages/integrations/github/[integrationId]/choose-project.tsx b/studio/pages/integrations/github/[integrationId]/choose-project.tsx index dc1d7545f93..c49ed89439c 100644 --- a/studio/pages/integrations/github/[integrationId]/choose-project.tsx +++ b/studio/pages/integrations/github/[integrationId]/choose-project.tsx @@ -84,9 +84,7 @@ This Supabase integration will allow you to link a Supabase project to a GitHub organizationIntegrationId={integration?.id} foreignProjects={repos ?? EMPTY_ARR} supabaseProjects={projects} - onCreateConnections={(vars) => { - createConnections(vars) - }} + onCreateConnections={createConnections} installedConnections={integration?.connections} isLoading={isCreatingConnection} integrationIcon={GITHUB_ICON} diff --git a/studio/pages/integrations/github/install.tsx b/studio/pages/integrations/github/install.tsx index 1d0637d223f..08987421df3 100644 --- a/studio/pages/integrations/github/install.tsx +++ b/studio/pages/integrations/github/install.tsx @@ -97,7 +97,9 @@ const GitHubIntegration: NextPageWithLayout = () => { function onInstall() { const orgSlug = selectedOrg?.slug - const installedIntegration = integrationData?.find((x) => x.organization.slug === orgSlug) + const installedIntegration = integrationData?.find( + (x) => x.organization.slug === orgSlug && x.metadata?.installation_id === installationId + ) const isIntegrationInstalled = Boolean(installedIntegration) if (!orgSlug) { diff --git a/studio/pages/integrations/vercel/install.tsx b/studio/pages/integrations/vercel/install.tsx index 67016004b90..0ef60b6f003 100644 --- a/studio/pages/integrations/vercel/install.tsx +++ b/studio/pages/integrations/vercel/install.tsx @@ -9,7 +9,6 @@ import { useOrganizationsQuery } from 'data/organizations/organizations-query' import { useStore } from 'hooks' import { useRouter } from 'next/router' import { useState } from 'react' -import { useVercelIntegrationInstallationState } from 'state/vercel-integration-installation' import { NextPageWithLayout, Organization } from 'types' import { Alert, Badge, Button, IconBook, IconHexagon, IconLifeBuoy, Listbox, LoadingLine } from 'ui' @@ -33,14 +32,10 @@ export type VercelIntegrationFlow = 'deploy-button' | 'marketing' const VercelIntegration: NextPageWithLayout = () => { const router = useRouter() const { ui } = useStore() - const { code, configurationId, next, teamId, source, externalId } = useParams() + const { code, configurationId, teamId, source, externalId } = useParams() const [selectedOrg, setSelectedOrg] = useState(null) const [organizationIntegrationId, setOrganizationIntegrationId] = useState(null) - const snapshot = useVercelIntegrationInstallationState() - - const flow: VercelIntegrationFlow = externalId ? 'marketing' : 'deploy-button' - /** * Fetch the list of organization based integration installations for Vercel. * @@ -54,7 +49,6 @@ const VercelIntegration: NextPageWithLayout = () => { const firstOrg = organizations?.[0] if (firstOrg && selectedOrg === null) { setSelectedOrg(firstOrg) - snapshot.setSelectedOrganizationSlug(firstOrg.slug) router.query.organizationSlug = firstOrg.slug } }, diff --git a/studio/state/github-connection-config-panel.ts b/studio/state/github-connection-config-panel.ts deleted file mode 100644 index 78feb1a3615..00000000000 --- a/studio/state/github-connection-config-panel.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { proxy, snapshot, useSnapshot } from 'valtio' - -export const githubConnectionConfigPanelState = proxy({ - open: false as boolean, - setOpen: (open: boolean) => { - githubConnectionConfigPanelState.open = open - }, - organizationIntegrationId: undefined as string | undefined, - setOrganizationIntegrationId: (organizationIntegrationId: string) => { - githubConnectionConfigPanelState.organizationIntegrationId = organizationIntegrationId - }, -}) - -export const getGithubConnectionConfigPanelSnapshot = () => - snapshot(githubConnectionConfigPanelState) - -export const useGithubConnectionConfigPanelSnapshot = ( - options?: Parameters[1] -) => useSnapshot(githubConnectionConfigPanelState, options) diff --git a/studio/state/vercel-integration-installation.ts b/studio/state/vercel-integration-installation.ts deleted file mode 100644 index 737879f6fe1..00000000000 --- a/studio/state/vercel-integration-installation.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { proxy, snapshot, useSnapshot } from 'valtio' - -export const vercelIntegrationInstallationState = proxy({ - selectedOrganizationSlug: '' as string, - setSelectedOrganizationSlug: (selectedOrganizationSlug: string) => { - vercelIntegrationInstallationState.selectedOrganizationSlug = selectedOrganizationSlug - }, -}) - -export const getVercelIntegrationInstallationState = () => - snapshot(vercelIntegrationInstallationState) - -export const useVercelIntegrationInstallationState = ( - options?: Parameters[1] -) => useSnapshot(vercelIntegrationInstallationState, options) From 1cc2adc03c15f9501d48d550fa9e506ce25c61a4 Mon Sep 17 00:00:00 2001 From: Alaister Young Date: Sat, 15 Jul 2023 01:23:31 +0800 Subject: [PATCH 05/61] remove missing import --- .../IntegrationSettings/SidePanelGitHubRepoSelection.tsx | 3 --- 1 file changed, 3 deletions(-) diff --git a/studio/components/interfaces/Organization/IntegrationSettings/SidePanelGitHubRepoSelection.tsx b/studio/components/interfaces/Organization/IntegrationSettings/SidePanelGitHubRepoSelection.tsx index 4b978dd0ae2..53a4bb42ed8 100644 --- a/studio/components/interfaces/Organization/IntegrationSettings/SidePanelGitHubRepoSelection.tsx +++ b/studio/components/interfaces/Organization/IntegrationSettings/SidePanelGitHubRepoSelection.tsx @@ -3,7 +3,6 @@ import { Markdown } from 'components/interfaces/Markdown' // import { useIntegrationsQuery } from 'data/integrations/integrations-query-org-only' import { useStore } from 'hooks' import { observer } from 'mobx-react-lite' -import { useGithubConnectionConfigPanelSnapshot } from 'state/github-connection-config-panel' import { IconGitHub, IconSearch, Input, Select, SidePanel } from 'ui' // TO DO @@ -13,8 +12,6 @@ const GitHubRepoSelection = () => { const { slug } = useParams() // const { data } = useIntegrationsQuery({ orgSlug: slug }) - const githubConnectionConfigPanelSnapshot = useGithubConnectionConfigPanelSnapshot() - return ( Date: Mon, 17 Jul 2023 11:29:14 +0800 Subject: [PATCH 06/61] fix integration types --- .../Integrations/IntegrationPanels.tsx | 22 +++++---- .../IntegrationSettings/Integration.tsx | 8 +--- .../IntegrationSettings.tsx | 6 +-- .../data/integrations/integrations.types.ts | 48 ++++++++++++++----- studio/lib/integration-utils.ts | 23 +++++++-- studio/pages/integrations/github/install.tsx | 6 ++- .../[slug]/marketplace/choose-project.tsx | 7 ++- 7 files changed, 84 insertions(+), 36 deletions(-) diff --git a/studio/components/interfaces/Integrations/IntegrationPanels.tsx b/studio/components/interfaces/Integrations/IntegrationPanels.tsx index 6863006001c..268e6c79dd3 100644 --- a/studio/components/interfaces/Integrations/IntegrationPanels.tsx +++ b/studio/components/interfaces/Integrations/IntegrationPanels.tsx @@ -7,6 +7,7 @@ import { Integration, IntegrationProjectConnection } from 'data/integrations/int import { useProjectsQuery } from 'data/projects/projects-query' import { BASE_PATH } from 'lib/constants' import { Badge, Button, IconArrowRight, IconExternalLink, IconGitHub, IconSquare, cn } from 'ui' +import { getIntegrationConfigurationUrl } from 'lib/integration-utils' const ICON_STROKE_WIDTH = 2 const ICON_SIZE = 14 @@ -14,7 +15,6 @@ const ICON_SIZE = 14 export interface IntegrationInstallationProps extends React.RefAttributes { title: string integration: Integration - getManageUrl: (integration: Integration) => string } type HandleIconType = Integration['integration']['name'] | 'Supabase' @@ -24,9 +24,9 @@ const HandleIcon = ({ type, className }: { type: HandleIconType; className?: str case 'GitHub': return break - case 'Netlify': - return - break + // case 'Netlify': + // return + // break case 'Vercel': return ( { } const IntegrationInstallation = React.forwardRef( - ({ title, integration, getManageUrl, ...props }, ref) => { + ({ title, integration, ...props }, ref) => { const IntegrationIconBlock = () => { return (
@@ -92,8 +92,10 @@ const IntegrationInstallation = React.forwardRef
- {/* {title} integration connection •{' '} */} - {integration.metadata?.account.name || integration.metadata?.gitHubConnectionOwner} + {integration.metadata?.account.name || + (integration.metadata !== undefined && + 'gitHubConnectionOwner' in integration.metadata && + integration.metadata?.gitHubConnectionOwner)} @@ -112,7 +114,11 @@ const IntegrationInstallation = React.forwardRef diff --git a/studio/components/interfaces/Organization/IntegrationSettings/Integration.tsx b/studio/components/interfaces/Organization/IntegrationSettings/Integration.tsx index 624d050743b..c86012940a2 100644 --- a/studio/components/interfaces/Organization/IntegrationSettings/Integration.tsx +++ b/studio/components/interfaces/Organization/IntegrationSettings/Integration.tsx @@ -29,7 +29,6 @@ export interface IntegrationProps { note?: string detail?: string integrations?: TIntegration[] - getManageUrl: (integration: TIntegration) => string onAddConnection: (integrationId: string) => void onDeleteConnection: (connection: IntegrationProjectConnection) => void | Promise } @@ -40,7 +39,6 @@ const Integration = ({ note, detail, integrations = EMPTY_ARR, - getManageUrl, onAddConnection, onDeleteConnection, }: IntegrationProps) => { @@ -76,11 +74,7 @@ Repository connections for ${title?.toLowerCase()} integrations.map((integration, i) => { return (
- + {integration.connections.length > 0 ? ( <> diff --git a/studio/components/interfaces/Organization/IntegrationSettings/IntegrationSettings.tsx b/studio/components/interfaces/Organization/IntegrationSettings/IntegrationSettings.tsx index 1f122d5462e..a0be0c4b15c 100644 --- a/studio/components/interfaces/Organization/IntegrationSettings/IntegrationSettings.tsx +++ b/studio/components/interfaces/Organization/IntegrationSettings/IntegrationSettings.tsx @@ -7,7 +7,7 @@ import { useOrgIntegrationsQuery } from 'data/integrations/integrations-query-or import { useIntegrationsVercelInstalledConnectionDeleteMutation } from 'data/integrations/integrations-vercel-installed-connection-delete-mutation' import { useVercelProjectsQuery } from 'data/integrations/integrations-vercel-projects-query' import { IntegrationProjectConnection } from 'data/integrations/integrations.types' -import { getGitHubConfigurationUrl, getVercelConfigurationUrl } from 'lib/integration-utils' +import { getIntegrationConfigurationUrl } from 'lib/integration-utils' import Integration from './Integration' import SidePanelGitHubRepoLinker from './SidePanelGitHubRepoLinker' import SidePanelVercelProjectLinker from './SidePanelVercelProjectLinker' @@ -110,14 +110,13 @@ You can also link multiple Vercel Projects to the same Supabase project. vercelProjectCount > 0 && vercelIntegration !== undefined ? ` Your Vercel connection has access to ${vercelProjectCount} Vercel Projects. -You can change the scope of the access for Supabase by configuring [here](${getVercelConfigurationUrl( +You can change the scope of the access for Supabase by configuring [here](${getIntegrationConfigurationUrl( vercelIntegration )}). ` : undefined } integrations={vercelIntegrations} - getManageUrl={getVercelConfigurationUrl} onAddConnection={onAddVercelConnection} onDeleteConnection={onDeleteVercelConnection} /> @@ -138,7 +137,6 @@ The GitHub app will watch for changes in your repository such as file changes, b These connections will be part of a GitHub workflow that is currently in development. `} integrations={githubIntegrations} - getManageUrl={getGitHubConfigurationUrl} onAddConnection={onAddGitHubConnection} onDeleteConnection={onDeleteGitHubConnection} /> diff --git a/studio/data/integrations/integrations.types.ts b/studio/data/integrations/integrations.types.ts index 13dbf066ea1..eb2bf344d11 100644 --- a/studio/data/integrations/integrations.types.ts +++ b/studio/data/integrations/integrations.types.ts @@ -156,7 +156,7 @@ export type userDetails = { type addedBy = userDetails type updatedBy = userDetails -export type IntegrationName = 'Vercel' | 'Netlify' | 'GitHub' +export type IntegrationName = 'Vercel' | 'GitHub' // | 'Netlify' export type VercelAccountType = 'Team' | 'Personal' export type VercelSource = 'marketplace' | 'deploy button' @@ -177,11 +177,27 @@ export type VercelTeamAccount = BaseVercelAccount & { team_slug: string } -export type Integration = { +export type VercelMetadata = { + vercelTeam?: string + gitHubConnectionOwner?: string + account: VercelAccount | VercelTeamAccount + configuration_id: string +} + +export type GitHubAccount = { + name: string + type: 'User' | 'Organization' + avatar: string + installed_by_user_id: number +} + +export type GitHubMetadata = { + installation_id: number + account: GitHubAccount +} + +export type IntegrationBase = { id: string - integration: { - name: IntegrationName - } added_by: addedBy inserted_at: string updated_at: string @@ -189,10 +205,20 @@ export type Integration = { organization: { slug: string } - metadata?: { - vercelTeam?: string - gitHubConnectionOwner?: string - account: VercelAccount | VercelTeamAccount - configuration_id: string - } } + +export type Integration = + | (IntegrationBase & { + id: string + integration: { + name: 'Vercel' + } + metadata?: VercelMetadata + }) + | (IntegrationBase & { + id: string + integration: { + name: 'GitHub' + } + metadata?: GitHubMetadata + }) diff --git a/studio/lib/integration-utils.ts b/studio/lib/integration-utils.ts index 278cc5b93da..79095f65829 100644 --- a/studio/lib/integration-utils.ts +++ b/studio/lib/integration-utils.ts @@ -1,5 +1,5 @@ -import { SupaResponseV2 } from 'types' import { Integration } from 'data/integrations/integrations.types' +import { SupaResponseV2 } from 'types' async function fetchGitHub(url: string, responseJson = true): Promise> { const response = await fetch(url) @@ -115,7 +115,22 @@ export async function getInitialMigrationSQLFromGitHubRepo( return `${migrations};${migrationsTableSql};${seed}` } -export function getVercelConfigurationUrl(integration: Integration) { +type VercelIntegration = Extract +type GitHubIntegration = Extract + +export function getIntegrationConfigurationUrl(integration: Integration) { + if (integration.integration.name === 'Vercel') { + return getVercelConfigurationUrl(integration as VercelIntegration) + } + + if (integration.integration.name === 'GitHub') { + return getGitHubConfigurationUrl(integration as GitHubIntegration) + } + + return '' +} + +export function getVercelConfigurationUrl(integration: VercelIntegration) { return `https://vercel.com/dashboard/${ integration.metadata?.account.type === 'Team' ? `${integration.metadata?.account.team_slug}/` @@ -123,10 +138,10 @@ export function getVercelConfigurationUrl(integration: Integration) { }integrations/${integration.metadata?.configuration_id}` } -export function getGitHubConfigurationUrl(integration: Integration) { +export function getGitHubConfigurationUrl(integration: GitHubIntegration) { return `https://github.com/${ integration.metadata?.account.type === 'Organization' ? `organizations/${integration.metadata?.account.name}/` : '' - }settings/installations/${integration.metadata.installation_id}` + }settings/installations/${integration.metadata?.installation_id}` } diff --git a/studio/pages/integrations/github/install.tsx b/studio/pages/integrations/github/install.tsx index 08987421df3..46eb8c30f59 100644 --- a/studio/pages/integrations/github/install.tsx +++ b/studio/pages/integrations/github/install.tsx @@ -98,7 +98,11 @@ const GitHubIntegration: NextPageWithLayout = () => { const orgSlug = selectedOrg?.slug const installedIntegration = integrationData?.find( - (x) => x.organization.slug === orgSlug && x.metadata?.installation_id === installationId + (x) => + x.organization.slug === orgSlug && + x.metadata !== undefined && + 'installation_id' in x.metadata && + String(x.metadata?.installation_id) === String(installationId) ) const isIntegrationInstalled = Boolean(installedIntegration) diff --git a/studio/pages/integrations/vercel/[slug]/marketplace/choose-project.tsx b/studio/pages/integrations/vercel/[slug]/marketplace/choose-project.tsx index 8e2032902a6..0cb0cacc947 100644 --- a/studio/pages/integrations/vercel/[slug]/marketplace/choose-project.tsx +++ b/studio/pages/integrations/vercel/[slug]/marketplace/choose-project.tsx @@ -43,7 +43,12 @@ const VercelIntegration: NextPageWithLayout = () => { const organization = data?.find((organization: Organization) => organization.slug === slug) - const integration = integrationData?.find((x) => x.metadata?.configuration_id === configurationId) + const integration = integrationData?.find( + (x) => + x.metadata !== undefined && + 'configuration_id' in x.metadata && + x.metadata?.configuration_id === configurationId + ) const { data: supabaseProjectsData } = useProjectsQuery({ enabled: integration?.id !== undefined, From 43088e2d264cd68881503f481b9f60638aa7cee7 Mon Sep 17 00:00:00 2001 From: Jonathan Summers-Muir Date: Mon, 17 Jul 2023 11:31:21 +0800 Subject: [PATCH 07/61] chore: fix the column issue on github integration page --- .../IntegrationWindowLayout.tsx | 2 +- studio/components/layouts/Scaffold.tsx | 16 +++++ studio/pages/integrations/github/install.tsx | 61 +++++++++++-------- 3 files changed, 51 insertions(+), 28 deletions(-) diff --git a/studio/components/layouts/IntegrationsLayout/IntegrationWindowLayout.tsx b/studio/components/layouts/IntegrationsLayout/IntegrationWindowLayout.tsx index e04d8df5d83..4aa3e3a6a81 100644 --- a/studio/components/layouts/IntegrationsLayout/IntegrationWindowLayout.tsx +++ b/studio/components/layouts/IntegrationsLayout/IntegrationWindowLayout.tsx @@ -41,7 +41,7 @@ export type HeaderProps = { const Header = ({ title, integrationIcon }: HeaderProps) => { return (
- +
diff --git a/studio/components/layouts/Scaffold.tsx b/studio/components/layouts/Scaffold.tsx index 92c695d0e85..0e03bf8f030 100644 --- a/studio/components/layouts/Scaffold.tsx +++ b/studio/components/layouts/Scaffold.tsx @@ -4,6 +4,8 @@ import { cn } from 'ui' const maxWidthClasses = 'mx-auto w-full max-w-[1600px]' const paddingClasses = 'px-6 lg:px-14 xl:px-28 2xl:px-32' +const maxWidthClassesColumn = 'min-w-[420px]' + // lg: pt - 8 const ScaffoldHeader = React.forwardRef>( @@ -45,6 +47,18 @@ const ScaffoldSection = React.forwardRef>( + ({ className, ...props }, ref) => { + return ( +
+ ) + } +) + const ScaffoldSectionDetail = React.forwardRef< HTMLDivElement, React.HTMLAttributes @@ -107,6 +121,7 @@ ScaffoldTitle.displayName = 'ScaffoldTitle' ScaffoldContainer.displayName = 'ScaffoldContainer' ScaffoldDivider.displayName = 'ScaffoldDivider' ScaffoldSection.displayName = 'ScaffoldSection' +ScaffoldColoum.displayName = 'ScaffoldColoum' ScaffoldSectionDetail.displayName = 'ScaffoldSectionDetail' ScaffoldSectionContent.displayName = 'ScaffoldSectionContent' ScaffoldFilterAndContent.displayName = 'ScaffoldFilterAndContent' @@ -120,6 +135,7 @@ export { ScaffoldContainer, ScaffoldDivider, ScaffoldSection, + ScaffoldColoum, ScaffoldSectionDetail, ScaffoldSectionContent, ScaffoldFilterAndContent, diff --git a/studio/pages/integrations/github/install.tsx b/studio/pages/integrations/github/install.tsx index 46eb8c30f59..30748430bb5 100644 --- a/studio/pages/integrations/github/install.tsx +++ b/studio/pages/integrations/github/install.tsx @@ -4,7 +4,12 @@ import { useState } from 'react' import { useParams } from 'common' import { Markdown } from 'components/interfaces/Markdown' import GitHubIntegrationWindowLayout from 'components/layouts/IntegrationsLayout/GitHubIntegrationWindowLayout' -import { ScaffoldContainer, ScaffoldDivider } from 'components/layouts/Scaffold' +import { + ScaffoldColoum, + ScaffoldContainer, + ScaffoldDivider, + ScaffoldSectionCol, +} from 'components/layouts/Scaffold' import { useGitHubIntegrationCreateMutation } from 'data/integrations/github-integration-create-mutation' import { useIntegrationsQuery } from 'data/integrations/integrations-query' import { IntegrationName } from 'data/integrations/integrations.types' @@ -139,31 +144,33 @@ const GitHubIntegration: NextPageWithLayout = () => { {organizationIntegrationId === null && ( <> - -

Choose organization

- <> - - { - router.query.organizationSlug = e.slug - setSelectedOrg(e) - }} - dataLoading={dataLoading} - /> -
- -
- + + +

Choose organization

+ <> + + { + router.query.organizationSlug = e.slug + setSelectedOrg(e) + }} + dataLoading={dataLoading} + /> +
+ +
+ +
{
- +
Docs
From b52ac37c28629f088dcd9239fbc17ffeba6a3ee1 Mon Sep 17 00:00:00 2001 From: Alaister Young Date: Mon, 17 Jul 2023 11:49:11 +0800 Subject: [PATCH 08/61] fix ScaffoldColumn name spelling --- studio/components/layouts/Scaffold.tsx | 6 +- studio/pages/integrations/github/install.tsx | 13 ++--- studio/pages/integrations/vercel/install.tsx | 58 ++++++++++---------- studio/styles/main.scss | 2 +- 4 files changed, 37 insertions(+), 42 deletions(-) diff --git a/studio/components/layouts/Scaffold.tsx b/studio/components/layouts/Scaffold.tsx index 0e03bf8f030..aec55712385 100644 --- a/studio/components/layouts/Scaffold.tsx +++ b/studio/components/layouts/Scaffold.tsx @@ -47,7 +47,7 @@ const ScaffoldSection = React.forwardRef>( +const ScaffoldColumn = React.forwardRef>( ({ className, ...props }, ref) => { return (
{ return ( <> -
+
{organizationIntegrationId === null && ( <> - +

Choose organization

<> @@ -170,7 +165,7 @@ const GitHubIntegration: NextPageWithLayout = () => {
- +
{ const { mutate, isLoading: isLoadingVercelIntegrationCreateMutation } = useVercelIntegrationCreateMutation({ onSuccess({ id }) { - const orgSlug = selectedOrg?.slug - setOrganizationIntegrationId(id) handleRouteChange() @@ -165,35 +163,37 @@ const VercelIntegration: NextPageWithLayout = () => { return ( <> -
+
{organizationIntegrationId === null && ( <> - -

Choose organization

- <> - - { - router.query.organizationSlug = e.slug - setSelectedOrg(e) - }} - dataLoading={dataLoading} - /> -
- -
- + + +

Choose organization

+ <> + + { + router.query.organizationSlug = e.slug + setSelectedOrg(e) + }} + dataLoading={dataLoading} + /> +
+ +
+ +
Date: Mon, 17 Jul 2023 15:55:49 +0800 Subject: [PATCH 09/61] revert min-height change --- studio/styles/main.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/studio/styles/main.scss b/studio/styles/main.scss index a57fb498dc3..344bc70f909 100644 --- a/studio/styles/main.scss +++ b/studio/styles/main.scss @@ -23,7 +23,7 @@ body, .main { @apply bg-scale-200; @apply text-scale-1200; - min-height: 100%; + height: 100%; padding: 0; margin: 0; -moz-osx-font-smoothing: grayscale; From 739f3d4a49921c811c154f55736d0955fa119362 Mon Sep 17 00:00:00 2001 From: Bo Lu Date: Tue, 25 Jul 2023 17:34:54 +1000 Subject: [PATCH 10/61] feat(docs): pull docs from external wrappers repo --- .../guides/database/extensions/wrappers.mdx | 13 +- .../database/extensions/wrappers/[slug].tsx | 178 ++++++++++++++++++ 2 files changed, 185 insertions(+), 6 deletions(-) create mode 100644 apps/docs/pages/guides/database/extensions/wrappers/[slug].tsx diff --git a/apps/docs/pages/guides/database/extensions/wrappers.mdx b/apps/docs/pages/guides/database/extensions/wrappers.mdx index 5d99f88ea08..e19b099c1e3 100644 --- a/apps/docs/pages/guides/database/extensions/wrappers.mdx +++ b/apps/docs/pages/guides/database/extensions/wrappers.mdx @@ -60,12 +60,13 @@ A web interface for connecting to external data is coming to Supabase Studio in ## Integrations -- [Firebase](https://supabase.github.io/wrappers/firebase/) -- [Stripe](https://supabase.github.io/wrappers/stripe/) -- [BigQuery](https://supabase.github.io/wrappers/bigquery/) -- [AWS S3](https://supabase.github.io/wrappers/s3/) -- Airtable - Coming Soon -- Clickhouse - Coming Soon +- [Airtable](/docs/guides/database/extensions/wrappers/airtable) +- [AWS S3](/docs/guides/database/extensions/wrappers/s3) +- [BigQuery](/docs/guides/database/extensions/wrappers/bigquery) +- [ClickHouse](/docs/guides/database/extensions/wrappers/clickhouse) +- [Firebase](/docs/guides/database/extensions/wrappers/firebase) +- [Logflare](/docs/guides/database/extensions/wrappers/logflare) +- [Stripe](/docs/guides/database/extensions/wrappers/stripe) ## Resources diff --git a/apps/docs/pages/guides/database/extensions/wrappers/[slug].tsx b/apps/docs/pages/guides/database/extensions/wrappers/[slug].tsx new file mode 100644 index 00000000000..25249cecba4 --- /dev/null +++ b/apps/docs/pages/guides/database/extensions/wrappers/[slug].tsx @@ -0,0 +1,178 @@ +import { CodeHikeConfig, remarkCodeHike } from '@code-hike/mdx' +import { GetStaticPaths, GetStaticProps } from 'next' +import { MDXRemote, MDXRemoteSerializeResult } from 'next-mdx-remote' +import { serialize } from 'next-mdx-remote/serialize' +import { relative } from 'path' +import rehypeSlug from 'rehype-slug' +import remarkGfm from 'remark-gfm' +import codeHikeTheme from 'config/code-hike.theme.json' assert { type: 'json' } +import components from '~/components' +import Layout from '~/layouts/DefaultGuideLayout' +import { UrlTransformFunction, linkTransform } from '~/lib/mdx/plugins/rehypeLinkTransform' +import remarkMkDocsAdmonition from '~/lib/mdx/plugins/remarkAdmonition' +import { removeTitle } from '~/lib/mdx/plugins/remarkRemoveTitle' + +// We fetch these docs at build time from an external repo +const org = 'supabase' +const repo = 'wrappers' +const branch = 'main' +const docsDir = 'docs' +const externalSite = 'https://supabase.github.io/wrappers' + +// Each external docs page is mapped to a local page +const pageMap = [ + { + slug: 'airtable', + meta: { + title: 'Airtable', + }, + remoteFile: 'airtable.md', + }, + { + slug: 's3', + meta: { + title: 'AWS S3', + }, + remoteFile: 's3.md', + }, + { + slug: 'bigquery', + meta: { + title: 'BigQuery', + }, + remoteFile: 'bigquery.md', + }, + { + slug: 'clickhouse', + meta: { + title: 'ClickHouse', + }, + remoteFile: 'clickhouse.md', + }, + { + slug: 'firebase', + meta: { + title: 'Firebase', + }, + remoteFile: 'firebase.md', + }, + { + slug: 'logflare', + meta: { + title: 'Logflare', + }, + remoteFile: 'logflare.md', + }, + { + slug: 'stripe', + meta: { + title: 'Stripe', + }, + remoteFile: 'stripe.md', + }, +] + +interface WrappersDocsProps { + source: MDXRemoteSerializeResult + meta: { + title: string + description?: string + } +} + +export default function WrappersDocs({ source, meta }: WrappersDocsProps) { + return ( + + + + ) +} + +/** + * Fetch markdown from external repo and transform links + */ +export const getStaticProps: GetStaticProps = async ({ params }) => { + const page = pageMap.find(({ slug }) => slug === params.slug) + + if (!page) { + throw new Error(`No page mapping found for slug '${params.slug}'`) + } + + const { remoteFile, meta } = page + + const response = await fetch( + `https://raw.githubusercontent.com/${org}/${repo}/${branch}/${docsDir}/${remoteFile}` + ) + + const source = await response.text() + + const urlTransform: UrlTransformFunction = (url) => { + try { + const externalSiteUrl = new URL(externalSite) + + const placeholderHostname = 'placeholder' + const { hostname, pathname, hash } = new URL(url, `http://${placeholderHostname}`) + + // Don't modify a url with a FQDN or a url that's only a hash + if (hostname !== placeholderHostname || pathname === '/') { + return url + } + + const relativePage = ( + pathname.endsWith('.md') + ? pathname.replace(/\.md$/, '') + : relative(externalSiteUrl.pathname, pathname) + ).replace(/^\//, '') + + const page = pageMap.find(({ remoteFile }) => `${relativePage}.md` === remoteFile) + + // If we have a mapping for this page, use the mapped path + if (page) { + return page.slug + hash + } + + // If we don't have this page in our docs, link to original docs + return `${externalSite}/${relativePage}${hash}` + } catch (err) { + console.error('Error transforming markdown URL', err) + return url + } + } + + const codeHikeOptions: CodeHikeConfig = { + theme: codeHikeTheme, + lineNumbers: true, + showCopyButton: true, + skipLanguages: [], + autoImport: false, + } + + const mdxSource = await serialize(source, { + scope: { + chCodeConfig: codeHikeOptions, + }, + mdxOptions: { + remarkPlugins: [ + remarkGfm, + remarkMkDocsAdmonition, + [removeTitle, meta.title], + [remarkCodeHike, codeHikeOptions], + ], + rehypePlugins: [[linkTransform, urlTransform], rehypeSlug], + }, + }) + + return { props: { source: mdxSource, meta } } +} + +export const getStaticPaths: GetStaticPaths = async () => { + return { + paths: pageMap.map(({ slug }) => ({ + params: { + slug, + }, + })), + fallback: false, + } +} + From 5be9633d21eac411c70954e836564965547d2201 Mon Sep 17 00:00:00 2001 From: Bo Lu Date: Tue, 25 Jul 2023 19:41:26 +1000 Subject: [PATCH 11/61] fix: prettier code --- apps/docs/pages/guides/database/extensions/wrappers/[slug].tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/docs/pages/guides/database/extensions/wrappers/[slug].tsx b/apps/docs/pages/guides/database/extensions/wrappers/[slug].tsx index 25249cecba4..9438e14ffce 100644 --- a/apps/docs/pages/guides/database/extensions/wrappers/[slug].tsx +++ b/apps/docs/pages/guides/database/extensions/wrappers/[slug].tsx @@ -175,4 +175,3 @@ export const getStaticPaths: GetStaticPaths = async () => { fallback: false, } } - From f651c359241cba7b86dcd1b6126d4ef3e8373724 Mon Sep 17 00:00:00 2001 From: Bo Lu Date: Thu, 27 Jul 2023 10:57:31 +1000 Subject: [PATCH 12/61] feat(docs): add emoji support --- apps/docs/package.json | 1 + .../database/extensions/wrappers/[slug].tsx | 2 ++ package-lock.json | 31 +++++++++++++++++++ 3 files changed, 34 insertions(+) diff --git a/apps/docs/package.json b/apps/docs/package.json index 5d79d59dddd..e3710ea9ba6 100644 --- a/apps/docs/package.json +++ b/apps/docs/package.json @@ -97,6 +97,7 @@ "remark-admonitions": "^1.2.1", "remark-gfm": "^3.0.1", "remark-slug": "^7.0.1", + "remark-emoji": "^3.1.2", "shiki": "^0.11.1", "sse.js": "^0.6.1", "ui": "*", diff --git a/apps/docs/pages/guides/database/extensions/wrappers/[slug].tsx b/apps/docs/pages/guides/database/extensions/wrappers/[slug].tsx index 9438e14ffce..81beffacd4b 100644 --- a/apps/docs/pages/guides/database/extensions/wrappers/[slug].tsx +++ b/apps/docs/pages/guides/database/extensions/wrappers/[slug].tsx @@ -5,6 +5,7 @@ import { serialize } from 'next-mdx-remote/serialize' import { relative } from 'path' import rehypeSlug from 'rehype-slug' import remarkGfm from 'remark-gfm' +import emoji from 'remark-emoji' import codeHikeTheme from 'config/code-hike.theme.json' assert { type: 'json' } import components from '~/components' import Layout from '~/layouts/DefaultGuideLayout' @@ -155,6 +156,7 @@ export const getStaticProps: GetStaticProps = async ({ params remarkPlugins: [ remarkGfm, remarkMkDocsAdmonition, + emoji, [removeTitle, meta.title], [remarkCodeHike, codeHikeOptions], ], diff --git a/package-lock.json b/package-lock.json index 084b2d064df..b2312485765 100644 --- a/package-lock.json +++ b/package-lock.json @@ -87,6 +87,7 @@ "rehype-slug": "^5.1.0", "remark": "^14.0.2", "remark-admonitions": "^1.2.1", + "remark-emoji": "^3.1.2", "remark-gfm": "^3.0.1", "remark-slug": "^7.0.1", "shiki": "^0.11.1", @@ -19846,6 +19847,15 @@ "node": ">= 4" } }, + "node_modules/emoticon": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/emoticon/-/emoticon-4.0.1.tgz", + "integrity": "sha512-dqx7eA9YaqyvYtUhJwT4rC1HIp82j5ybS1/vQ42ur+jBe17dJMwZE4+gvL1XadSFfxaPFFGt3Xsw+Y8akThDlw==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/encodeurl": { "version": "1.0.2", "dev": true, @@ -29421,6 +29431,14 @@ "node": ">=10.5.0" } }, + "node_modules/node-emoji": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/node-emoji/-/node-emoji-1.11.0.tgz", + "integrity": "sha512-wo2DpQkQp7Sjm2A0cq+sN7EHKO6Sl0ctXeBdFZrL9T9+UywORbufTcTZxom8YqpLQt/FqNMUkOpkZrJVYSKD3A==", + "dependencies": { + "lodash": "^4.17.21" + } + }, "node_modules/node-fetch": { "version": "2.6.11", "license": "MIT", @@ -34211,6 +34229,19 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/remark-emoji": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/remark-emoji/-/remark-emoji-3.1.2.tgz", + "integrity": "sha512-QwhAzNk27Ol64uV4z/3n55MKrNz9bhr8wg+mO5aGqIYDS+jUarS1d8Y0ZIeEBVhfGkXj6gGYM+727sOgAPvV/A==", + "dependencies": { + "emoticon": "^4.0.1", + "mdast-util-find-and-replace": "^2.2.2", + "node-emoji": "^1.11.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + } + }, "node_modules/remark-external-links": { "version": "8.0.0", "dev": true, From dc87ae4d83c9e1dec731206ea43ca854343042dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niko=20Hoffr=C3=A9n?= Date: Fri, 28 Jul 2023 22:42:33 +0300 Subject: [PATCH 13/61] docs: Fix grammar issues --- i18n/README.fi.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/i18n/README.fi.md b/i18n/README.fi.md index 70bd873e5e1..5ffe5c18acc 100644 --- a/i18n/README.fi.md +++ b/i18n/README.fi.md @@ -31,10 +31,10 @@ Jos haluat nähdä, miten osallistuminen tapahtuu, käy osoitteessa [Getting Sta ## Yhteisö ja tuki -- [Yhteisön foorumi](https://github.com/supabase/supabase/discussions). Paras: Apua rakentamiseen, keskustelua tietokannan parhaista käytännöistä. -- [GitHub Issues](https://github.com/supabase/supabase/issues). Parasta: Supabasea käytettäessä kohdatut viat ja virheet. -- [Sähköpostituki](https://supabase.com/docs/support#business-support). Paras: tietokantaan tai infrastruktuuriin liittyvät ongelmat. -- [Discord](https://discord.supabase.com). Paras: sovellusten jakamiseen ja yhteisön kanssa hengailuun. +- [Yhteisön foorumi](https://github.com/supabase/supabase/discussions). Sopii parhaiten: Apua rakentamiseen, keskustelua tietokannan parhaista käytännöistä. +- [GitHub Issues](https://github.com/supabase/supabase/issues). Sopii parhaiten: Supabasea käytettäessä kohdatut viat ja virheet. +- [Sähköpostituki](https://supabase.com/docs/support#business-support). Sopii parhaiten: Tietokantaan tai infrastruktuuriin liittyvät ongelmat. +- [Discord](https://discord.supabase.com). Sopii parhaiten: Sovellusten jakamiseen ja yhteisön kanssa hengailuun. ## Status From 7dbd035fa77b14f09a4bdfa839c863eddb7f0429 Mon Sep 17 00:00:00 2001 From: Luong Minh Date: Sat, 29 Jul 2023 12:32:41 +0700 Subject: [PATCH 14/61] fix a minor typo --- apps/docs/pages/guides/self-hosting/docker.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/docs/pages/guides/self-hosting/docker.mdx b/apps/docs/pages/guides/self-hosting/docker.mdx index d3d326c5c11..3122ba067d3 100644 --- a/apps/docs/pages/guides/self-hosting/docker.mdx +++ b/apps/docs/pages/guides/self-hosting/docker.mdx @@ -48,7 +48,7 @@ We can use your JWT Secret to generate new `anon` and `service` API keys using t ### Update API Keys -Replace the values the `.env` file: +Replace the values in the `.env` file: - `ANON_KEY` - replace with an `anon` key - `SERVICE_ROLE_KEY` - replace with a `service` key From d93b7aeee2ede6d270cb0af36aa65bd51bef52af Mon Sep 17 00:00:00 2001 From: Hieu Vu Date: Sat, 29 Jul 2023 13:21:55 +0700 Subject: [PATCH 15/61] docs: fix typo in kotlin doc --- spec/supabase_kt_v0.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/supabase_kt_v0.yml b/spec/supabase_kt_v0.yml index e3e0b032dd4..248e2aed65e 100644 --- a/spec/supabase_kt_v0.yml +++ b/spec/supabase_kt_v0.yml @@ -58,7 +58,7 @@ functions: On IOS/MacOS: `client.handleDeeplinks(url)` ### PKCE Authentication flow - suapbase-kt supports the [PKCE authentication flow](https://supabase.com/blog/supabase-auth-sso-pkce). + supabase-kt supports the [PKCE authentication flow](https://supabase.com/blog/supabase-auth-sso-pkce). To use it, you just have to change the `flowType` in the GoTrue configuration: ```kotlin install(GoTrue) { From b77c020033b1b8e26e8cfc66ac9ccda5207ad3d0 Mon Sep 17 00:00:00 2001 From: Jonathan Summers-Muir Date: Sun, 30 Jul 2023 16:58:24 +0800 Subject: [PATCH 16/61] remove `brand` from original color setup --- packages/config/ui.config.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/config/ui.config.js b/packages/config/ui.config.js index be34a9cf667..b9f24c04676 100644 --- a/packages/config/ui.config.js +++ b/packages/config/ui.config.js @@ -26,7 +26,7 @@ const excludedRadixColors = [ // generates fixed scales // based on the root/light mode version -const fixedOptions = ['scale', 'scaleA', 'brand'] +const fixedOptions = ['scale', 'scaleA'] function radixColorKeys() { let keys = Object.keys(radixUiColors) @@ -51,7 +51,7 @@ function radixColorKeys() { } function generateColorClasses() { - const brandColors = ['brand', 'scale', 'scaleA'] + const brandColors = ['scale', 'scaleA'] const colors = [...radixColorKeys(), ...brandColors] let mappedColors = {} From ab46d23d588c08f6a1a72c91da4afd5197905c2e Mon Sep 17 00:00:00 2001 From: Jonathan Summers-Muir Date: Sun, 30 Jul 2023 16:58:54 +0800 Subject: [PATCH 17/61] chore: update `brand-900` to `brand` --- .../CustomHTMLElements.utils.ts | 6 +- .../docs/components/GuidesTableOfContents.tsx | 2 +- apps/docs/components/HomePageCover.tsx | 2 +- apps/docs/components/LinkCard.tsx | 2 +- apps/docs/components/Navigation/Footer.tsx | 6 +- .../NavigationMenu/NavigationMenuCliList.tsx | 4 +- .../NavigationMenuGuideListItems.tsx | 14 +- .../NavigationMenuRefListItems.tsx | 2 +- .../NavigationMenu/TopNavBarRef.tsx | 2 +- apps/docs/components/Navigation/SideBar.tsx | 10 +- apps/docs/components/Pagination.tsx | 2 +- apps/docs/components/TableOfContents.tsx | 2 +- .../reference/CLICommandSection.tsx | 2 +- .../reference/RefFunctionSection.tsx | 2 +- apps/docs/layouts/SiteLayout.tsx | 2 +- apps/docs/layouts/guides/index.tsx | 2 +- .../docs/layouts/tutorials/TutorialLayout.tsx | 4 +- apps/docs/pages/index.mdx | 10 +- apps/docs/pages/reference/cli/config.tsx | 2 +- .../AuthWidget/AuthWidgetSection.tsx | 4 +- apps/www/components/CodeBlock/CodeBlock.tsx | 2 +- apps/www/components/Hero/Hero.tsx | 2 +- .../LaunchWeek/6/HackathonSection.tsx | 2 +- .../7/LaunchSection/ArticleButtonListItem.tsx | 2 +- .../7/LaunchSection/ProductButtonListItem.tsx | 2 +- .../LaunchWeek/7/LaunchSection/index.tsx | 6 +- .../8/Ticket/TicketCustomizationForm.tsx | 12 +- apps/www/components/MagnifiedProducts.tsx | 2 +- apps/www/components/Nav/Company.tsx | 2 +- apps/www/components/Nav/index.tsx | 14 +- .../components/Partners/PartnerLinkBox.tsx | 2 +- .../Pricing/ComputePricingModal.tsx | 2 +- apps/www/components/ProductIcon.tsx | 2 +- apps/www/components/Quote.tsx | 2 +- apps/www/components/SOC2RequestForm.tsx | 2 +- apps/www/components/ScrollProgress.tsx | 2 +- .../components/Sections/CommunitySlider.tsx | 2 +- .../Sections/CustomerQuotesSection.tsx | 2 +- .../Sections/ProductHeaderCentered.tsx | 2 +- .../components/Sections/TimedTabsSection.tsx | 2 +- apps/www/data/products/vector/pageData.tsx | 4 +- apps/www/layouts/comparison.tsx | 2 +- apps/www/pages/beta.tsx | 63 +++++---- apps/www/pages/blog/[slug].tsx | 2 +- apps/www/pages/careers/index.tsx | 12 +- apps/www/pages/customers/[slug].tsx | 4 +- .../pages/edge-functions/edge-functions.tsx | 2 +- apps/www/pages/launch-week/6/index.tsx | 22 ++-- apps/www/pages/legal/dpa.tsx | 2 +- apps/www/pages/partners/experts/[slug].tsx | 6 +- .../pages/partners/integrations/[slug].tsx | 6 +- .../www/pages/partners/integrations/index.tsx | 4 +- apps/www/pages/pricing/index.tsx | 16 +-- apps/www/pages/support.tsx | 16 +-- apps/www/styles/index.css | 4 +- .../src/components/Button/Button.module.css | 4 +- .../src/components/Command/Command.icons.tsx | 4 +- .../ui/src/components/Command/CommandMenu.tsx | 2 +- .../Command/GenerateSQL/SQLOutputActions.tsx | 4 +- .../ui/src/components/Form/Form.stories.tsx | 122 ++++-------------- .../src/components/Form/examples/AuthForm.tsx | 12 +- .../src/components/GlassPanel/GlassPanel.tsx | 2 +- .../ui/src/components/IconPanel/IconPanel.tsx | 10 +- .../ui/src/lib/theme/customThemeExample.ts | 2 +- packages/ui/src/lib/theme/defaultTheme.ts | 20 +-- studio/.storybook/preview.css | 4 +- .../grid/components/header/Header.tsx | 6 +- .../grid/components/header/RefreshButton.tsx | 2 +- .../Auth/AuthProvidersForm/ProviderForm.tsx | 4 +- .../Auth/Policies/PolicySelection.tsx | 2 +- .../interfaces/BillingV2/SpendCapModal.tsx | 2 +- .../Subscription/Tier/EnterpriseCard.tsx | 6 +- .../Subscription/Tier/SubscriptionTier.tsx | 2 +- .../Subscription/Tier/TierUpdateSidePanel.tsx | 6 +- .../BillingV2/Usage/Usage.constants.tsx | 2 +- .../Database/Backups/BackupsError.tsx | 2 +- .../Database/Backups/PITR/PITRNotice.tsx | 2 +- .../interfaces/Database/Roles/RoleRow.tsx | 4 +- .../Database/Schemas/SchemaGraph.tsx | 6 +- .../interfaces/Functions/CommandRender.tsx | 2 +- .../EdgeFunctionDetails.tsx | 4 +- .../Functions/EdgeFunctionsListItem.tsx | 2 +- .../Home/NewProjectPanel/APIKeys.tsx | 2 +- .../Home/NewProjectPanel/NewProjectPanel.tsx | 2 +- .../Organization/AuditLogs/AuditLogs.tsx | 2 +- .../Subscription/EnterpriseCard.tsx | 6 +- .../Subscription/PlanUpdateSidePanel.tsx | 6 +- .../Subscription/Subscription.tsx | 4 +- .../GeneralSettings/GeneralSettings.tsx | 2 +- .../OAuthApps/AuthorizedAppRow.tsx | 4 +- .../Organization/OAuthApps/OAuthAppRow.tsx | 6 +- .../Settings/Addons/CustomDomainSidePanel.tsx | 2 +- .../CustomDomainConfig/CustomDomainDelete.tsx | 2 +- .../CustomDomainConfig/CustomDomainVerify.tsx | 4 +- .../ProjectUpgradeAlert.tsx | 4 +- .../TransferProjectButton.tsx | 4 +- .../Settings/Vault/Secrets/SecretRow.tsx | 4 +- .../interfaces/Storage/CreateBucketModal.tsx | 2 +- .../interfaces/Storage/EditBucketModal.tsx | 2 +- .../components/interfaces/Support/Success.tsx | 4 +- .../ColumnEditor/ColumnEditor.tsx | 2 +- .../ColumnEditor/ColumnForeignKey.tsx | 6 +- .../ForeignKeySelector/ForeignKeySelector.tsx | 2 +- .../ForeignRowSelector/SelectorGrid.tsx | 2 +- .../SpreadSheetFileUpload.tsx | 2 +- studio/components/layouts/FunctionsLayout.tsx | 2 +- .../layouts/ProjectLayout/BuildingState.tsx | 2 +- .../FeedbackDropdown/FeedbackWidget.tsx | 4 +- .../ProjectLayout/ProjectPausedState.tsx | 2 +- .../layouts/ProjectLayout/RestoringState.tsx | 2 +- .../UpgradingState/UpgradingState.tsx | 2 +- .../ui/DisabledWarningDueToIncident.tsx | 2 +- .../components/ui/Logs/LogsExplorerHeader.tsx | 6 +- studio/components/ui/PasswordStrengthBar.tsx | 2 +- studio/hooks/misc/useStore.tsx | 2 +- studio/pages/join/index.tsx | 2 +- studio/pages/new/[slug].tsx | 2 +- .../[ref]/database/backups/scheduled.tsx | 2 +- .../project/[ref]/logs/explorer/templates.tsx | 2 +- .../pages/project/[ref]/reports/database.tsx | 8 +- .../[ref]/reports/query-performance.tsx | 2 +- .../pages/project/[ref]/settings/addons.tsx | 2 +- .../[ref]/settings/billing/invoices.tsx | 2 +- .../[ref]/settings/billing/subscription.tsx | 2 +- .../project/[ref]/settings/infrastructure.tsx | 2 +- studio/pages/support/new.tsx | 2 +- studio/pages/vercel/integrate.tsx | 2 +- studio/styles/code.scss | 6 +- studio/styles/date-picker.scss | 6 +- studio/styles/grid.scss | 10 +- studio/styles/react-data-grid-logs.scss | 4 +- studio/styles/ui.scss | 6 +- 132 files changed, 305 insertions(+), 412 deletions(-) diff --git a/apps/docs/components/CustomHTMLElements/CustomHTMLElements.utils.ts b/apps/docs/components/CustomHTMLElements/CustomHTMLElements.utils.ts index 844724a5466..337f48b2bbf 100644 --- a/apps/docs/components/CustomHTMLElements/CustomHTMLElements.utils.ts +++ b/apps/docs/components/CustomHTMLElements/CustomHTMLElements.utils.ts @@ -89,13 +89,13 @@ export const highlightSelectedNavItem = (id: string) => { const navMenuItems = document.querySelectorAll('.function-link-item a') // find any currently active items and remove them - const currentActiveItems = document.querySelectorAll('.function-link-list .text-brand-900') - currentActiveItems.forEach((item) => item.classList.remove('text-brand-900')) + const currentActiveItems = document.querySelectorAll('.function-link-list .text-brand') + currentActiveItems.forEach((item) => item.classList.remove('text-brand')) // Add active class to the current item navMenuItems.forEach((item) => { if (item.href.split('/').at(-1) === id) { - item.classList.add('text-brand-900') + item.classList.add('text-brand') } }) } diff --git a/apps/docs/components/GuidesTableOfContents.tsx b/apps/docs/components/GuidesTableOfContents.tsx index 9d25121f661..553f3165452 100644 --- a/apps/docs/components/GuidesTableOfContents.tsx +++ b/apps/docs/components/GuidesTableOfContents.tsx @@ -46,7 +46,7 @@ const GuidesTableOfContents: FC = ({ list }) => {
  • diff --git a/apps/docs/components/HomePageCover.tsx b/apps/docs/components/HomePageCover.tsx index e760c411dc3..c45156c09cd 100644 --- a/apps/docs/components/HomePageCover.tsx +++ b/apps/docs/components/HomePageCover.tsx @@ -69,7 +69,7 @@ const HomePageCover = (props) => {
    - +

    Getting Started

    diff --git a/apps/docs/components/LinkCard.tsx b/apps/docs/components/LinkCard.tsx index e74ac68384a..6e22200bbda 100644 --- a/apps/docs/components/LinkCard.tsx +++ b/apps/docs/components/LinkCard.tsx @@ -14,7 +14,7 @@ export default function LinkCard({ }) { return ( -
    + {description ? ( <>

    {title}

    diff --git a/apps/docs/components/Navigation/Footer.tsx b/apps/docs/components/Navigation/Footer.tsx index 32f1b4f73db..6550b0f24ce 100644 --- a/apps/docs/components/Navigation/Footer.tsx +++ b/apps/docs/components/Navigation/Footer.tsx @@ -29,11 +29,7 @@ const Footer = () => ( {Icon && }

    {text}

    -
    + {ctaLabel} diff --git a/apps/docs/components/Navigation/NavigationMenu/NavigationMenuCliList.tsx b/apps/docs/components/Navigation/NavigationMenu/NavigationMenuCliList.tsx index deb8caf1f17..5821f1de362 100644 --- a/apps/docs/components/Navigation/NavigationMenu/NavigationMenuCliList.tsx +++ b/apps/docs/components/Navigation/NavigationMenu/NavigationMenuCliList.tsx @@ -23,7 +23,7 @@ const NavigationMenuCliList = ({ currentLevel, setLevel, id }) => { return (
  • - + {icon && } {title} @@ -100,7 +100,7 @@ const NavigationMenuCliList = ({ currentLevel, setLevel, id }) => {
    diff --git a/apps/docs/components/Navigation/NavigationMenu/NavigationMenuGuideListItems.tsx b/apps/docs/components/Navigation/NavigationMenu/NavigationMenuGuideListItems.tsx index f264a4112b7..995bc5f6c1c 100644 --- a/apps/docs/components/Navigation/NavigationMenu/NavigationMenuGuideListItems.tsx +++ b/apps/docs/components/Navigation/NavigationMenu/NavigationMenuGuideListItems.tsx @@ -19,7 +19,7 @@ const HeaderLink = React.memo(function HeaderLink(props: { className={[ ' ', !props.title && 'capitalize', - props.url === router.pathname ? 'text-brand-900' : 'hover:text-brand-900 text-scale-1200', + props.url === router.pathname ? 'text-brand' : 'hover:text-brand text-scale-1200', ].join(' ')} > {props.title ?? props.id} @@ -68,7 +68,7 @@ const ContentAccordionLink = React.memo(function ContentAccordionLink(props: any 'flex items-center gap-2', 'cursor-pointer transition text-sm', activeItem - ? 'text-brand-900 font-medium' + ? 'text-brand font-medium' : 'hover:text-scale-1200 dark:hover:text-scale-1100 text-scale-1000', ].join(' ')} parent={props.subItem.parent} @@ -97,8 +97,8 @@ const ContentAccordionLink = React.memo(function ContentAccordionLink(props: any className={[ 'cursor-pointer transition text-sm', subSubItem.url === router.pathname - ? 'text-brand-900' - : 'hover:text-brand-900 text-scale-1000', + ? 'text-brand' + : 'hover:text-brand text-scale-1000', ].join(' ')} > {subSubItem.name} @@ -124,7 +124,7 @@ const ContentLink = React.memo(function ContentLink(props: any) { className={[ 'cursor-pointer transition text-sm', props.url === router.pathname - ? 'text-brand-900' + ? 'text-brand' : 'hover:text-scale-1200 dark:hover:text-scale-1100 text-scale-1000', ].join(' ')} > @@ -152,7 +152,7 @@ const Content = (props) => {
    @@ -166,7 +166,7 @@ const Content = (props) => { -
    +
    diff --git a/apps/docs/components/Navigation/NavigationMenu/NavigationMenuRefListItems.tsx b/apps/docs/components/Navigation/NavigationMenu/NavigationMenuRefListItems.tsx index a280bf07da6..07e9d7f3363 100644 --- a/apps/docs/components/Navigation/NavigationMenu/NavigationMenuRefListItems.tsx +++ b/apps/docs/components/Navigation/NavigationMenu/NavigationMenuRefListItems.tsx @@ -64,7 +64,7 @@ const FunctionLink = React.memo(function FunctionLink({ className={cn( 'cursor-pointer transition text-sm hover:text-scale-1200 gap-3 relative', isParent ? 'flex justify-between' : 'leading-3', - active ? 'text-brand-900' : 'text-scale-1000' + active ? 'text-brand' : 'text-scale-1000' )} > {icon && {icon}} diff --git a/apps/docs/components/Navigation/NavigationMenu/TopNavBarRef.tsx b/apps/docs/components/Navigation/NavigationMenu/TopNavBarRef.tsx index bd080d8e7c9..f8358d3d75d 100644 --- a/apps/docs/components/Navigation/NavigationMenu/TopNavBarRef.tsx +++ b/apps/docs/components/Navigation/NavigationMenu/TopNavBarRef.tsx @@ -68,7 +68,7 @@ const TopNavBarRef: FC = () => { height={24} alt="Supabase Logo" /> - DOCS + DOCS
    {/* {router.asPath.includes('/reference/') && } */} diff --git a/apps/docs/components/Navigation/SideBar.tsx b/apps/docs/components/Navigation/SideBar.tsx index d679b7c7414..e76fa4954bf 100644 --- a/apps/docs/components/Navigation/SideBar.tsx +++ b/apps/docs/components/Navigation/SideBar.tsx @@ -83,7 +83,7 @@ const SideBar = ({ menuItems = [] }: { menuItems: any }) => { 'py-1.5 px-5 rounded text-sm transition', `${ item.url === asPath - ? 'bg-scale-200 text-brand-900' + ? 'bg-scale-200 text-brand' : 'text-scale-1100 hover:text-scale-1200' }`, ].join(' ')} @@ -109,7 +109,7 @@ const SideBar = ({ menuItems = [] }: { menuItems: any }) => { size={14} strokeWidth={2} /> - + {group.label} @@ -124,7 +124,7 @@ const SideBar = ({ menuItems = [] }: { menuItems: any }) => { 'py-1.5 px-5 rounded text-sm transition', `${ section.url === asPath - ? 'bg-scale-200 text-brand-900' + ? 'bg-scale-200 text-brand' : 'text-scale-1100 hover:text-scale-1200' }`, ].join(' ')} @@ -150,7 +150,7 @@ const SideBar = ({ menuItems = [] }: { menuItems: any }) => { size={14} strokeWidth={2} /> - + {section.name} @@ -164,7 +164,7 @@ const SideBar = ({ menuItems = [] }: { menuItems: any }) => { 'py-1.5 ml-4 px-5 rounded text-sm transition', `${ item.url === asPath - ? 'bg-scale-200 text-brand-900' + ? 'bg-scale-200 text-brand' : 'text-scale-1100 hover:text-scale-1200' }`, ].join(' ')} diff --git a/apps/docs/components/Pagination.tsx b/apps/docs/components/Pagination.tsx index 97221d63963..ed6b6e510e5 100644 --- a/apps/docs/components/Pagination.tsx +++ b/apps/docs/components/Pagination.tsx @@ -27,7 +27,7 @@ const Pagination = ({ currentPage, totalCount }: { currentPage: number; totalCou {page} diff --git a/apps/docs/components/TableOfContents.tsx b/apps/docs/components/TableOfContents.tsx index 8be2a831646..297ade47499 100644 --- a/apps/docs/components/TableOfContents.tsx +++ b/apps/docs/components/TableOfContents.tsx @@ -69,7 +69,7 @@ const TableOfContents: FC = ({ toc, video }) => {
  • diff --git a/apps/docs/components/reference/CLICommandSection.tsx b/apps/docs/components/reference/CLICommandSection.tsx index 400b3fa7287..792297211de 100644 --- a/apps/docs/components/reference/CLICommandSection.tsx +++ b/apps/docs/components/reference/CLICommandSection.tsx @@ -96,7 +96,7 @@ const CliCommandSection = (props) => {
    $ {subcommand.replace(/-/g, ' ')} diff --git a/apps/docs/components/reference/RefFunctionSection.tsx b/apps/docs/components/reference/RefFunctionSection.tsx index 2be99d3e0d7..88c06beda04 100644 --- a/apps/docs/components/reference/RefFunctionSection.tsx +++ b/apps/docs/components/reference/RefFunctionSection.tsx @@ -174,7 +174,7 @@ const RefFunctionSection: React.FC = (props) => {
    -
    +
    diff --git a/apps/docs/layouts/SiteLayout.tsx b/apps/docs/layouts/SiteLayout.tsx index 59bead2a64d..94cd0ae0631 100644 --- a/apps/docs/layouts/SiteLayout.tsx +++ b/apps/docs/layouts/SiteLayout.tsx @@ -228,7 +228,7 @@ const HeaderLogo = memo(function HeaderLogo() { height={24} alt="Supabase Logo" /> - DOCS + DOCS ) diff --git a/apps/docs/layouts/guides/index.tsx b/apps/docs/layouts/guides/index.tsx index 1363448853c..130e76e2510 100644 --- a/apps/docs/layouts/guides/index.tsx +++ b/apps/docs/layouts/guides/index.tsx @@ -115,7 +115,7 @@ const Layout: FC = (props) => { ].join(' ')} > {props.meta.breadcrumb && ( -

    {props.meta.breadcrumb}

    +

    {props.meta.breadcrumb}

    )}
    = (props: Props) => { ].join(' ')} >
    -

    Tutorials

    +

    Tutorials

    {props.meta.title}

    -
    +
    diff --git a/apps/docs/pages/index.mdx b/apps/docs/pages/index.mdx index 8024c9629a4..f76ceb55913 100644 --- a/apps/docs/pages/index.mdx +++ b/apps/docs/pages/index.mdx @@ -25,7 +25,7 @@ export const meta = { ## Products
    -
    +
    {products.map((product) => { return ( @@ -44,7 +44,7 @@ export const meta = {
    -
    +
    {/* */} @@ -89,7 +89,7 @@ export const meta = {
    @@ -148,7 +148,7 @@ export const meta = {
    -
    +
    @@ -160,7 +160,7 @@ export const meta = {
    diff --git a/apps/docs/pages/reference/cli/config.tsx b/apps/docs/pages/reference/cli/config.tsx index 096aa30b6aa..1d7e448b234 100644 --- a/apps/docs/pages/reference/cli/config.tsx +++ b/apps/docs/pages/reference/cli/config.tsx @@ -29,7 +29,7 @@ export default function Config() {

    CLI configuration

    -
    +
    {specFile.info.description}
    {TAGS.map((tag) => diff --git a/apps/www/components/AuthWidget/AuthWidgetSection.tsx b/apps/www/components/AuthWidget/AuthWidgetSection.tsx index f9ee1bbf25a..fe3099cf041 100644 --- a/apps/www/components/AuthWidget/AuthWidgetSection.tsx +++ b/apps/www/components/AuthWidget/AuthWidgetSection.tsx @@ -146,9 +146,9 @@ function AuthWidgetSection() { }) } className={[ - 'bg-brand-300 border-brand-900 h-10 w-10 rounded-full border-2 transition hover:scale-105', + 'bg-brand-300 border-brand h-10 w-10 rounded-full border-2 transition hover:scale-105', brandColor.brand === 'var(--colors-brand9)' - ? ' !bg-brand-900 ring-scale-400 border-scale-800 ring-2 drop-shadow-lg dark:ring-white' + ? ' !bg-brand ring-scale-400 border-scale-800 ring-2 drop-shadow-lg dark:ring-white' : '', ].join(' ')} > diff --git a/apps/www/components/CodeBlock/CodeBlock.tsx b/apps/www/components/CodeBlock/CodeBlock.tsx index 99f0cb02169..1269b1f11ff 100644 --- a/apps/www/components/CodeBlock/CodeBlock.tsx +++ b/apps/www/components/CodeBlock/CodeBlock.tsx @@ -119,7 +119,7 @@ function CodeBlock(props: CodeBlockProps) { type="text" icon={ copied ? ( - + ) : ( diff --git a/apps/www/components/Hero/Hero.tsx b/apps/www/components/Hero/Hero.tsx index 6aba7c1539c..9ce53bff3a8 100644 --- a/apps/www/components/Hero/Hero.tsx +++ b/apps/www/components/Hero/Hero.tsx @@ -41,7 +41,7 @@ const Hero = () => { {showAnnouncement && ( -
    +
    Get your ticket
    Launch Week 8 - August 7-11 diff --git a/apps/www/components/LaunchWeek/6/HackathonSection.tsx b/apps/www/components/LaunchWeek/6/HackathonSection.tsx index ad73a8a52a5..c2be728bb50 100644 --- a/apps/www/components/LaunchWeek/6/HackathonSection.tsx +++ b/apps/www/components/LaunchWeek/6/HackathonSection.tsx @@ -44,7 +44,7 @@ export default function LaunchHero() {

    Submission

    Submit your project through{' '} - + madewithsupabase.com . diff --git a/apps/www/components/LaunchWeek/7/LaunchSection/ArticleButtonListItem.tsx b/apps/www/components/LaunchWeek/7/LaunchSection/ArticleButtonListItem.tsx index e374bd023fc..8aee78e4070 100644 --- a/apps/www/components/LaunchWeek/7/LaunchSection/ArticleButtonListItem.tsx +++ b/apps/www/components/LaunchWeek/7/LaunchSection/ArticleButtonListItem.tsx @@ -9,7 +9,7 @@ const ArticleButtonListItem = (props: Article) => {

    - + {props.title}

    {props.description}

    diff --git a/apps/www/components/LaunchWeek/7/LaunchSection/ProductButtonListItem.tsx b/apps/www/components/LaunchWeek/7/LaunchSection/ProductButtonListItem.tsx index 07ed656ae0c..f14095db860 100644 --- a/apps/www/components/LaunchWeek/7/LaunchSection/ProductButtonListItem.tsx +++ b/apps/www/components/LaunchWeek/7/LaunchSection/ProductButtonListItem.tsx @@ -18,7 +18,7 @@ export const ProductButtonListItem = (props: Article) => {
    - {props.title} + {props.title}

    {props.description}

    diff --git a/apps/www/components/LaunchWeek/7/LaunchSection/index.tsx b/apps/www/components/LaunchWeek/7/LaunchSection/index.tsx index 3faf36f20d0..db093a84ca8 100644 --- a/apps/www/components/LaunchWeek/7/LaunchSection/index.tsx +++ b/apps/www/components/LaunchWeek/7/LaunchSection/index.tsx @@ -25,7 +25,7 @@ export const LaunchSection = (props: WeekDayProps) => {
    {/* END timeline dot */} @@ -63,7 +63,7 @@ export const LaunchSection = (props: WeekDayProps) => { nextDayNotShipped ? 'launch-week-timeline-border--approaching' : props.shipped - ? 'border-brand-900' + ? 'border-brand' : 'border-purple-700', className, ].join(' ')} @@ -152,7 +152,7 @@ export const LaunchSection = (props: WeekDayProps) => { md:pl-8 lg:pl-8 `, - props.shipped ? 'border-brand-900' : 'border-purple-700', + props.shipped ? 'border-brand' : 'border-purple-700', props.shippingHasStarted && 'lg:col-span-6', !lastIndex && 'pb-8 lg:pb-16', ].join(' ')} diff --git a/apps/www/components/LaunchWeek/8/Ticket/TicketCustomizationForm.tsx b/apps/www/components/LaunchWeek/8/Ticket/TicketCustomizationForm.tsx index dd9aa9e243c..6d6f848b536 100644 --- a/apps/www/components/LaunchWeek/8/Ticket/TicketCustomizationForm.tsx +++ b/apps/www/components/LaunchWeek/8/Ticket/TicketCustomizationForm.tsx @@ -54,9 +54,7 @@ const TicketCustomizationForm = ({ supabase, user }: Props) => { Connected account )} - {IS_SAVED && ( - Saved - )} + {IS_SAVED && Saved} {HAS_ERROR && ( Something went wrong @@ -72,7 +70,7 @@ const TicketCustomizationForm = ({ supabase, user }: Props) => { disabled placeholder="name" value={user.name} - icon={} + icon={} /> { className={[ 'w-3', IS_SAVING && 'text-scale-300', - !!formData.role ? 'text-brand-900' : 'text-scale-300', + !!formData.role ? 'text-brand' : 'text-scale-300', ].join(' ')} /> } @@ -113,7 +111,7 @@ const TicketCustomizationForm = ({ supabase, user }: Props) => { className={[ 'w-3', IS_SAVING && 'text-scale-300', - !!formData.company ? 'text-brand-900' : 'text-scale-300', + !!formData.company ? 'text-brand' : 'text-scale-300', ].join(' ')} /> } @@ -135,7 +133,7 @@ const TicketCustomizationForm = ({ supabase, user }: Props) => { className={[ 'w-3 flex spin', IS_SAVING && 'text-scale-300', - !!formData.location ? 'text-brand-900' : 'text-scale-300', + !!formData.location ? 'text-brand' : 'text-scale-300', ].join(' ')} /> } diff --git a/apps/www/components/MagnifiedProducts.tsx b/apps/www/components/MagnifiedProducts.tsx index 17880f85e71..ac9bea22e66 100644 --- a/apps/www/components/MagnifiedProducts.tsx +++ b/apps/www/components/MagnifiedProducts.tsx @@ -93,7 +93,7 @@ function Product({ lazyBoundary="100px" /> -
    +
    {product.name}
    diff --git a/apps/www/components/Nav/Company.tsx b/apps/www/components/Nav/Company.tsx index 7b263e0bc9b..d7c21238697 100644 --- a/apps/www/components/Nav/Company.tsx +++ b/apps/www/components/Nav/Company.tsx @@ -82,7 +82,7 @@ const Company = () => {
    View all posts diff --git a/apps/www/components/Nav/index.tsx b/apps/www/components/Nav/index.tsx index 2439d76df00..e8ad79db017 100644 --- a/apps/www/components/Nav/index.tsx +++ b/apps/www/components/Nav/index.tsx @@ -85,7 +85,7 @@ const Nav = () => {

    {description}

    {url && ( -

    +

    )} @@ -120,7 +120,7 @@ const Nav = () => { >
    )} -
    +
    ) diff --git a/apps/www/components/SOC2RequestForm.tsx b/apps/www/components/SOC2RequestForm.tsx index fb45809b19f..841e7e0e5b9 100644 --- a/apps/www/components/SOC2RequestForm.tsx +++ b/apps/www/components/SOC2RequestForm.tsx @@ -68,7 +68,7 @@ const SOC2RequestForm = () => { return (
    {formSubmitted ? ( -

    +

    Thank you for your submission! A member from the Supabase team will reach out to you shortly!

    diff --git a/apps/www/components/ScrollProgress.tsx b/apps/www/components/ScrollProgress.tsx index ddbea562561..cd366d1c21f 100644 --- a/apps/www/components/ScrollProgress.tsx +++ b/apps/www/components/ScrollProgress.tsx @@ -30,7 +30,7 @@ const ScrollProgress = () => { return (
    {

    {card.abstract}

    {card.url && ( -
    Read Customer Story
    +
    Read Customer Story
    )}
    ) diff --git a/apps/www/components/Sections/CustomerQuotesSection.tsx b/apps/www/components/Sections/CustomerQuotesSection.tsx index bfcd363fc8a..4715d7f390a 100644 --- a/apps/www/components/Sections/CustomerQuotesSection.tsx +++ b/apps/www/components/Sections/CustomerQuotesSection.tsx @@ -74,7 +74,7 @@ const CustomerQuotesSection = (props: Props) => { {customer.author}, {customer.role}

    {customer.url && ( -
    +
    Read Customer Story
    diff --git a/apps/www/components/Sections/ProductHeaderCentered.tsx b/apps/www/components/Sections/ProductHeaderCentered.tsx index 4aedc75221b..194d000f1b5 100644 --- a/apps/www/components/Sections/ProductHeaderCentered.tsx +++ b/apps/www/components/Sections/ProductHeaderCentered.tsx @@ -47,7 +47,7 @@ const ProductHeaderCentered = (props: Types) => ( {props.icon && } {props.title && ( {props.title} diff --git a/apps/www/components/Sections/TimedTabsSection.tsx b/apps/www/components/Sections/TimedTabsSection.tsx index 532a70fb177..1de3cc0ddd7 100644 --- a/apps/www/components/Sections/TimedTabsSection.tsx +++ b/apps/www/components/Sections/TimedTabsSection.tsx @@ -29,7 +29,7 @@ const Tab = ({ isActive, label, paragraph, onClick, progress, intervalDuration } {isActive && ( 99.7 ? 'opacity-0' : 'opacity-100', ].join(' ')} style={{ x: `${progress! - 100}%` }} diff --git a/apps/www/data/products/vector/pageData.tsx b/apps/www/data/products/vector/pageData.tsx index 2da32838233..2ae6b53155f 100644 --- a/apps/www/data/products/vector/pageData.tsx +++ b/apps/www/data/products/vector/pageData.tsx @@ -162,7 +162,7 @@ export default { <> Simple yet
    - powerful APIs + powerful APIs ), paragraph: 'Easy-to-use client libraries for managing and querying vector stores in Postgres.', @@ -242,7 +242,7 @@ docs.query( <> Powerful Features
    - Scale to millions + Scale to millions ), paragraph: diff --git a/apps/www/layouts/comparison.tsx b/apps/www/layouts/comparison.tsx index 020d31e2559..c832c800eda 100644 --- a/apps/www/layouts/comparison.tsx +++ b/apps/www/layouts/comparison.tsx @@ -90,7 +90,7 @@ const LayoutComparison = ({ components, props }: Props) => { {/* Title and description */}
    -

    Alternative

    +

    Alternative

    {props.blog.title}

    {props.blog.date}

    diff --git a/apps/www/pages/beta.tsx b/apps/www/pages/beta.tsx index 8ac450a2b35..bec142fdab7 100644 --- a/apps/www/pages/beta.tsx +++ b/apps/www/pages/beta.tsx @@ -118,7 +118,7 @@ const Hero = (props: Props) => {

    Supabase is an open source Firebase alternative.

    - Today, we're moving to Beta + Today, we're moving to Beta

    Xendit @@ -162,7 +162,7 @@ const Introduction = () => { Monitoro @@ -170,7 +170,7 @@ const Introduction = () => { TAYFA {' '} @@ -223,8 +223,7 @@ const TableOfContents = (props: any) => {

    - Supabase Beta is starting - now. + Supabase Beta is starting now.

    @@ -314,7 +313,7 @@ const Performance = () => { { Elixir {' '} @@ -361,7 +360,7 @@ const Performance = () => { Realtime engine @@ -369,7 +368,7 @@ const Performance = () => { PostgREST {' '} @@ -381,7 +380,7 @@ const Performance = () => { benchmarks {' '} @@ -451,11 +450,7 @@ const Security = () => {
  • Adopted the{' '} - + Snyk {' '} dependency monitor as part of our SSDLC on several key component of our system, to @@ -467,7 +462,7 @@ const Security = () => { now uses {' '} @@ -513,7 +508,7 @@ const Reliability = () => { https://status.supabase.com {' '} @@ -557,7 +552,7 @@ const NewFeaturesAndIntegrations = () => { JavaScript {' '} @@ -565,7 +560,7 @@ const NewFeaturesAndIntegrations = () => { HTTP @@ -587,7 +582,7 @@ const NewFeaturesAndIntegrations = () => { subscribe to changes in your database {' '} @@ -606,7 +601,7 @@ const NewFeaturesAndIntegrations = () => { querying from multiple tables {' '} @@ -614,7 +609,7 @@ const NewFeaturesAndIntegrations = () => { invoke complex functions @@ -703,7 +698,7 @@ const BetaPricing = () => ( rory@supabase.io @@ -716,7 +711,7 @@ const BetaPricing = () => (

    The Supabase Base plan is now called the Supabase Pro plan as per the{' '} - + pricing page . @@ -747,7 +742,7 @@ const OpenSource = () => ( sponsorship {' '} @@ -759,7 +754,7 @@ const OpenSource = () => ( partnering with Strive School {' '} @@ -772,7 +767,7 @@ const OpenSource = () => ( rory@supabase.io {' '} @@ -783,7 +778,7 @@ const OpenSource = () => ( our GitHub. {' '} @@ -819,7 +814,7 @@ const FundingPartners = () => ( Twitter {' '} @@ -856,7 +851,7 @@ const ScalingOurTeam = () => ( work@supabase.io @@ -917,7 +912,7 @@ const WhatsNext = () => ( support@supabase.io {' '} @@ -925,7 +920,7 @@ const WhatsNext = () => ( discussion {' '} diff --git a/apps/www/pages/blog/[slug].tsx b/apps/www/pages/blog/[slug].tsx index 1b1fcbd5b8b..356c3d5c107 100644 --- a/apps/www/pages/blog/[slug].tsx +++ b/apps/www/pages/blog/[slug].tsx @@ -202,7 +202,7 @@ function BlogPostPage(props: any) { {/* Title and description */}

    -

    Blog post

    +

    Blog post

    {props.blog.title}

    {props.blog.date}

    diff --git a/apps/www/pages/careers/index.tsx b/apps/www/pages/careers/index.tsx index a303e9f2e9a..d6acf681121 100644 --- a/apps/www/pages/careers/index.tsx +++ b/apps/www/pages/careers/index.tsx @@ -101,7 +101,7 @@ const CareerPage: NextPage = ({ jobs, contributors }: any) => {
    -

    +

    Supabase Careers

    @@ -121,9 +121,9 @@ const CareerPage: NextPage = ({ jobs, contributors }: any) => { return (
    -
    +

    {company.number}

    @@ -153,7 +153,7 @@ const CareerPage: NextPage = ({ jobs, contributors }: any) => { Discord to stay connected to our team, and our community.

    -
    +

    We deeply believe in the efficacy of collaborative open source

    @@ -445,7 +445,7 @@ const CareerPage: NextPage = ({ jobs, contributors }: any) => { className="flex lg:block items-start space-x-6 lg:space-x-0 lg:w-full" >
    -

    +

    {i + 1}

    @@ -461,7 +461,7 @@ const CareerPage: NextPage = ({ jobs, contributors }: any) => {
    ) })} -

    +

    diff --git a/apps/www/pages/customers/[slug].tsx b/apps/www/pages/customers/[slug].tsx index 7be097ca5b9..ea186151c78 100644 --- a/apps/www/pages/customers/[slug].tsx +++ b/apps/www/pages/customers/[slug].tsx @@ -122,9 +122,7 @@ function CaseStudyPage(props: any) {
    - - Customer Stories - + Customer Stories

    {props.blog.title} diff --git a/apps/www/pages/edge-functions/edge-functions.tsx b/apps/www/pages/edge-functions/edge-functions.tsx index 20900033d31..981685a0268 100644 --- a/apps/www/pages/edge-functions/edge-functions.tsx +++ b/apps/www/pages/edge-functions/edge-functions.tsx @@ -145,7 +145,7 @@ function Database() { className="bg-scale-100 dark:bg-scale-300 group flex flex-col gap-4 rounded border px-8 py-6" key={i} > -
    +
    {item.icon ? item.icon : }
    diff --git a/apps/www/pages/launch-week/6/index.tsx b/apps/www/pages/launch-week/6/index.tsx index 7f8f8426cc1..dbef8ec6eeb 100644 --- a/apps/www/pages/launch-week/6/index.tsx +++ b/apps/www/pages/launch-week/6/index.tsx @@ -1018,7 +1018,7 @@ export default function launchweek() { href="https://supabase.com/blog/launch-week-6-hackathon" target="_blank" rel="nooper noreferrer" - className="text-brand-900" + className="text-brand" > blog post @@ -1052,7 +1052,7 @@ export default function launchweek() { Join our Discord @@ -1064,7 +1064,7 @@ export default function launchweek() {

    Submit your project through{' '} @@ -1091,7 +1091,7 @@ export default function launchweek() {

    Supabase Cache Helpers

    Previous Best Overall Project Winner

    @@ -1105,7 +1105,7 @@ export default function launchweek() {

    Super UI

    Previous Best Overall Project Runner Up

    @@ -1120,7 +1120,7 @@ export default function launchweek() {

    Quid Faciam Hodie?

    Winner Best Flutter Project

    @@ -1130,7 +1130,7 @@ export default function launchweek() {

    That Hot Dog Game

    Previous Winner: Most Fun/Interesting

    @@ -1145,7 +1145,7 @@ export default function launchweek() {

    RepoWatch

    Previous Winner Best Realtime Project

    @@ -1180,7 +1180,7 @@ export default function launchweek() {
    @@ -1204,7 +1204,7 @@ export default function launchweek() { We worked with more than 30 content creators from around the world to drop a mountain of content simultaneously! -
    +
    See all the content
    @@ -1220,7 +1220,7 @@ export default function launchweek() { {activeCreator !== null && (

    {creators[activeCreator].description}

    )} -

    +

    {creators[activeCreator].link_title} diff --git a/apps/www/pages/legal/dpa.tsx b/apps/www/pages/legal/dpa.tsx index 7814c69a208..3e8bd8429fd 100644 --- a/apps/www/pages/legal/dpa.tsx +++ b/apps/www/pages/legal/dpa.tsx @@ -52,7 +52,7 @@ const DPA = () => {

    You can download our latest DPA document by submitting your email here.

    {formSubmitted ? ( -

    +

    Thank you for your submission! A new tab should have opened with the DPA document

    diff --git a/apps/www/pages/partners/experts/[slug].tsx b/apps/www/pages/partners/experts/[slug].tsx index ffb5f8fe409..8603d2a86ac 100644 --- a/apps/www/pages/partners/experts/[slug].tsx +++ b/apps/www/pages/partners/experts/[slug].tsx @@ -160,7 +160,7 @@ function Partner({
    Category - + {partner.category} @@ -172,7 +172,7 @@ function Partner({ href={partner.website} target="_blank" rel="noreferrer" - className="text-brand-900 hover:text-brand-800 transition-colors" + className="text-brand hover:text-brand-800 transition-colors" > {new URL(partner.website).host} @@ -185,7 +185,7 @@ function Partner({ href={partner.docs} target="_blank" rel="noreferrer" - className="text-brand-900 hover:text-brand-800 transition-colors" + className="text-brand hover:text-brand-800 transition-colors" > Learn diff --git a/apps/www/pages/partners/integrations/[slug].tsx b/apps/www/pages/partners/integrations/[slug].tsx index 95a87f58eba..cf1bb175550 100644 --- a/apps/www/pages/partners/integrations/[slug].tsx +++ b/apps/www/pages/partners/integrations/[slug].tsx @@ -201,7 +201,7 @@ function Partner({
    Category - + {partner.category} @@ -213,7 +213,7 @@ function Partner({ href={partner.website} target="_blank" rel="noreferrer" - className="text-brand-900 hover:text-brand-800 transition-colors" + className="text-brand hover:text-brand-800 transition-colors" > {new URL(partner.website).host} @@ -226,7 +226,7 @@ function Partner({ href={partner.docs} target="_blank" rel="noreferrer" - className="text-brand-900 hover:text-brand-800 transition-colors" + className="text-brand hover:text-brand-800 transition-colors" > Learn diff --git a/apps/www/pages/partners/integrations/index.tsx b/apps/www/pages/partners/integrations/index.tsx index 2e878b0a792..7665cace8fa 100644 --- a/apps/www/pages/partners/integrations/index.tsx +++ b/apps/www/pages/partners/integrations/index.tsx @@ -200,10 +200,10 @@ function IntegrationPartnersPage(props: Props) { INTEGRATIONS - EXPERTS + EXPERTS - + BECOME A PARTNER diff --git a/apps/www/pages/pricing/index.tsx b/apps/www/pages/pricing/index.tsx index 3940e1b06e6..618833e74a8 100644 --- a/apps/www/pages/pricing/index.tsx +++ b/apps/www/pages/pricing/index.tsx @@ -150,7 +150,7 @@ export default function IndexPage() {
    -

    Pricing

    +

    Pricing

    Predictable pricing, no surprises

    Start building for free, collaborate with a team, then scale to millions of users @@ -174,7 +174,7 @@ export default function IndexPage() { key={`row-${plan.name}`} className={[ plan.name === 'Pro' - ? 'bg-brand-1100 dark:bg-brand-900 border px-0.5 -mt-8 rounded-[6px]' + ? 'bg-brand-1100 dark:bg-brand border px-0.5 -mt-8 rounded-[6px]' : '', ].join(' ')} > @@ -273,7 +273,7 @@ export default function IndexPage() { {plan.features.map((feature) => (

  • -
  • ))} @@ -953,7 +949,7 @@ export default function IndexPage() { open a support ticket {' '} @@ -964,7 +960,7 @@ export default function IndexPage() { you can contact the team here diff --git a/apps/www/pages/support.tsx b/apps/www/pages/support.tsx index 0ee2f30c399..5dd7c36e5e1 100644 --- a/apps/www/pages/support.tsx +++ b/apps/www/pages/support.tsx @@ -38,9 +38,7 @@ const Index = ({}: Props) => {
    -

    - Support -

    +

    Support

    Get Support

    The Supabase Support Team is ready to help. @@ -64,8 +62,8 @@ const Index = ({}: Props) => { our GitHub issues. This can be feature requests too!

    - Use this for: Bugs and - other issues + Use this for: Bugs and other + issues

    @@ -112,8 +110,8 @@ const Index = ({}: Props) => { join us on Discord. Browse and ask questions.

    - Use this for:{' '} - General questions + Use this for: General + questions

    @@ -183,8 +181,8 @@ const Index = ({}: Props) => { or have an issue, please contact us here.

    - Use this for:{' '} - Issues or questions specific to you + Use this for: Issues + or questions specific to you

    diff --git a/apps/www/styles/index.css b/apps/www/styles/index.css index e0843c3b687..2e10d81a737 100644 --- a/apps/www/styles/index.css +++ b/apps/www/styles/index.css @@ -95,11 +95,11 @@ h6:not(.overwrite) { } .heading-gradient-brand { - @apply text-[#3ECF8E00] bg-clip-text bg-gradient-to-b from-brand-1000 to-brand-900 dark:to-brand-800; + @apply text-[#3ECF8E00] bg-clip-text bg-gradient-to-b from-brand-1000 to-brand dark:to-brand-800; } .toc-animate { - @apply !translate-x-1 !text-brand-900; + @apply !translate-x-1 !text-brand; } .prose-toc a { diff --git a/packages/ui/src/components/Button/Button.module.css b/packages/ui/src/components/Button/Button.module.css index 8c4d9b48a9a..d9cac9315ac 100644 --- a/packages/ui/src/components/Button/Button.module.css +++ b/packages/ui/src/components/Button/Button.module.css @@ -51,7 +51,7 @@ */ /* .sbui-btn-primary { @apply text-white bg-brand-800 hover:bg-brand-600; - @apply dark:hover:bg-brand-900; + @apply dark:hover:bg-brand; } */ .dark .sbui-btn-primary { text-shadow: 0px 0px 4px rgba(38 111 78 / 50%); @@ -87,7 +87,7 @@ @apply dark:text-white dark:border-dark-400 dark:hover:text-white dark:hover:border-white; } */ /* .sbui-btn-link { - @apply bg-transparent text-brand-800 border-none hover:bg-brand-900 hover:bg-opacity-25; + @apply bg-transparent text-brand-800 border-none hover:bg-brand hover:bg-opacity-25; box-shadow: none; } */ /* .sbui-btn-text { diff --git a/packages/ui/src/components/Command/Command.icons.tsx b/packages/ui/src/components/Command/Command.icons.tsx index 9d0914765b0..bc3fdcee576 100644 --- a/packages/ui/src/components/Command/Command.icons.tsx +++ b/packages/ui/src/components/Command/Command.icons.tsx @@ -4,7 +4,7 @@ interface AiIconProps { className?: string } -export const AiIcon = ({ className = 'text-brand-900' }: AiIconProps) => ( +export const AiIcon = ({ className = 'text-brand' }: AiIconProps) => ( ( export const AiIconChat = () => (
    + Ask Supabase AI {search ? ( <> diff --git a/packages/ui/src/components/Command/GenerateSQL/SQLOutputActions.tsx b/packages/ui/src/components/Command/GenerateSQL/SQLOutputActions.tsx index fe59affa469..270c78f66de 100644 --- a/packages/ui/src/components/Command/GenerateSQL/SQLOutputActions.tsx +++ b/packages/ui/src/components/Command/GenerateSQL/SQLOutputActions.tsx @@ -81,7 +81,7 @@ const SQLOutputActions = ({ answer, messages }: SQLOutputActionsProps) => { type="default" icon={ showCopied ? ( - + ) : ( ) @@ -98,7 +98,7 @@ const SQLOutputActions = ({ answer, messages }: SQLOutputActionsProps) => { disabled={isSaving} icon={ isSaved ? ( - + ) : ( ) diff --git a/packages/ui/src/components/Form/Form.stories.tsx b/packages/ui/src/components/Form/Form.stories.tsx index 277ae09180e..45f022d2f7c 100644 --- a/packages/ui/src/components/Form/Form.stories.tsx +++ b/packages/ui/src/components/Form/Form.stories.tsx @@ -1,14 +1,5 @@ import { Form } from '.' -import { - Input, - Button, - InputNumber, - Toggle, - Checkbox, - Radio, - Select, - Listbox, -} from '../../index' +import { Input, Button, InputNumber, Toggle, Checkbox, Radio, Select, Listbox } from '../../index' import * as Yup from 'yup' import { User } from '../Icon/IconImportHandler' @@ -103,14 +94,8 @@ export const InputLevelValidation = () => { export const InputLevelValidationYip = () => { // validation schema const SignupSchema = Yup.object().shape({ - firstname: Yup.string() - .min(2, 'Too Short!') - .max(50, 'Too Long!') - .required('Required'), - lastname: Yup.string() - .min(2, 'Too Short!') - .max(50, 'Too Long!') - .required('Required'), + firstname: Yup.string().min(2, 'Too Short!').max(50, 'Too Long!').required('Required'), + lastname: Yup.string().min(2, 'Too Short!').max(50, 'Too Long!').required('Required'), email: Yup.string().email('Invalid email').required('Required'), }) @@ -131,24 +116,9 @@ export const InputLevelValidationYip = () => { > {({ isSubmitting }: any) => (
    - - - + + + @@ -239,9 +209,7 @@ export const LargerExample = () => { if (!values.email) { errors.email = 'Required' - } else if ( - !/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i.test(values.email) - ) { + } else if (!/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i.test(values.email)) { errors.email = 'Invalid email address' } @@ -286,21 +254,9 @@ export const LargerExample = () => { <>

    {isSubmitting ? 'submitting' : 'not submitting'}

    - - - + + @@ -551,7 +473,7 @@ export const CardForm = () => { descriptionText={ This can be found in{' '} - + the developer settings diff --git a/packages/ui/src/components/Form/examples/AuthForm.tsx b/packages/ui/src/components/Form/examples/AuthForm.tsx index 5053216d6bb..b64e5d18614 100644 --- a/packages/ui/src/components/Form/examples/AuthForm.tsx +++ b/packages/ui/src/components/Form/examples/AuthForm.tsx @@ -40,7 +40,7 @@ const DocsButton = () => { transition " > -
    +
    {/* {

    Learn how to use Supabase Auth with Auth Policies to pick and choose what users see what.

    -

    +

    See Documenation @@ -338,8 +338,8 @@ const AuthForm = () => {

    {active ? ( -
    - +
    + Enabled @@ -1114,7 +1114,7 @@ export function WholeForm() { transition " > -
    +
    {/* -

    +

    See Documenation diff --git a/packages/ui/src/components/GlassPanel/GlassPanel.tsx b/packages/ui/src/components/GlassPanel/GlassPanel.tsx index 4f84bb995da..1d9425b936d 100644 --- a/packages/ui/src/components/GlassPanel/GlassPanel.tsx +++ b/packages/ui/src/components/GlassPanel/GlassPanel.tsx @@ -114,7 +114,7 @@ const GlassPanel = ({

    {children && {children}} - {showLink && Learn more} + {showLink && Learn more}
    ) diff --git a/packages/ui/src/components/IconPanel/IconPanel.tsx b/packages/ui/src/components/IconPanel/IconPanel.tsx index 00fc05a700f..90eb83e55e4 100644 --- a/packages/ui/src/components/IconPanel/IconPanel.tsx +++ b/packages/ui/src/components/IconPanel/IconPanel.tsx @@ -70,7 +70,13 @@ const IconPanel = ({ {title ) : ( @@ -92,7 +98,7 @@ const IconPanel = ({ )}
    {children && {children}} - {showLink && Learn more} + {showLink && Learn more}
    diff --git a/packages/ui/src/lib/theme/customThemeExample.ts b/packages/ui/src/lib/theme/customThemeExample.ts index 284a945e2d8..91eb4ad1bcd 100644 --- a/packages/ui/src/lib/theme/customThemeExample.ts +++ b/packages/ui/src/lib/theme/customThemeExample.ts @@ -35,7 +35,7 @@ const default__padding_and_text = { export default { button: { type: { - primary: `${defaults.brandBackground} text-white hover:bg-brand-600 dark:hover:bg-brand-900`, + primary: `${defaults.brandBackground} text-white hover:bg-brand-600 dark:hover:bg-brand`, }, }, } diff --git a/packages/ui/src/lib/theme/defaultTheme.ts b/packages/ui/src/lib/theme/defaultTheme.ts index dc20809681e..25782badb7e 100644 --- a/packages/ui/src/lib/theme/defaultTheme.ts +++ b/packages/ui/src/lib/theme/defaultTheme.ts @@ -270,7 +270,7 @@ export default { }, success: { base: `bg-brand-300 dark:bg-brand-100 border-brand-700`, - icon: `text-brand-900`, + icon: `text-brand`, header: `text-brand-1200`, description: `text-brand-1100`, }, @@ -568,7 +568,7 @@ export default { bg-transparent ${defaults.focus} focus:ring-scale-400 - text-brand-900 + text-brand border-scale-700 shadow-sm rounded @@ -629,7 +629,7 @@ export default { focus:ring-brand-400 border-scale-700 - text-brand-900 + text-brand shadow-sm cursor-pointer peer @@ -934,8 +934,8 @@ export default { hover:bg-scale-700 `, active: ` - !bg-brand-900 - !hover:bg-brand-900 + !bg-brand + !hover:bg-brand `, handle_container: { tiny: 'h-4 w-7', @@ -1268,8 +1268,8 @@ export default { z-10 border-l - border-brand-900 - group-hover:border-brand-900 + border-brand + group-hover:border-brand `, rounded: `rounded-md`, }, @@ -1455,8 +1455,8 @@ export default { option_active: `text-scale-1200 bg-scale-600`, option_disabled: `cursor-not-allowed opacity-50`, option_inner: `flex items-center space-x-3`, - option_check: `absolute inset-y-0 right-0 flex items-center pr-3 text-brand-900`, - option_check_active: `text-brand-900`, + option_check: `absolute inset-y-0 right-0 flex items-center pr-3 text-brand`, + option_check_active: `text-brand`, option_check_icon: `h-5 w-5`, }, @@ -1500,7 +1500,7 @@ export default { }, spinner: ` absolute - text-brand-900 animate-spin + text-brand animate-spin inset-0 m-auto `, diff --git a/studio/.storybook/preview.css b/studio/.storybook/preview.css index c12137dbd9d..2ba4312331c 100644 --- a/studio/.storybook/preview.css +++ b/studio/.storybook/preview.css @@ -105,9 +105,9 @@ } .react-datepicker__day--range-start { - @apply bg-brand-900 text-white hover:text-scale-700 hover:bg-white; + @apply bg-brand text-white hover:text-scale-700 hover:bg-white; } .react-datepicker__day--range-end { - @apply bg-brand-900 text-white hover:text-scale-700 hover:bg-white; + @apply bg-brand text-white hover:text-scale-700 hover:bg-white; } diff --git a/studio/components/grid/components/header/Header.tsx b/studio/components/grid/components/header/Header.tsx index 1a27e3a5fff..80f32781146 100644 --- a/studio/components/grid/components/header/Header.tsx +++ b/studio/components/grid/components/header/Header.tsx @@ -142,7 +142,7 @@ const DefaultHeader = ({
    @@ -168,7 +168,7 @@ const DefaultHeader = ({
    @@ -193,7 +193,7 @@ const DefaultHeader = ({ { !status ? ( ) : status === 'saved' ? ( - + ) : ( <> ) diff --git a/studio/components/interfaces/Auth/AuthProvidersForm/ProviderForm.tsx b/studio/components/interfaces/Auth/AuthProvidersForm/ProviderForm.tsx index 0851c3e397f..2107aac22b7 100644 --- a/studio/components/interfaces/Auth/AuthProvidersForm/ProviderForm.tsx +++ b/studio/components/interfaces/Auth/AuthProvidersForm/ProviderForm.tsx @@ -104,8 +104,8 @@ const ProviderForm = ({ provider }: ProviderFormProps) => {
    {isActive ? ( -
    - +
    + Enabled diff --git a/studio/components/interfaces/Auth/Policies/PolicySelection.tsx b/studio/components/interfaces/Auth/Policies/PolicySelection.tsx index af4727eeb8f..adb9d3aa77e 100644 --- a/studio/components/interfaces/Auth/Policies/PolicySelection.tsx +++ b/studio/components/interfaces/Auth/Policies/PolicySelection.tsx @@ -62,7 +62,7 @@ const PolicySelection: FC = ({ here diff --git a/studio/components/interfaces/BillingV2/SpendCapModal.tsx b/studio/components/interfaces/BillingV2/SpendCapModal.tsx index 81e06529ddd..e3bb6b7f7ee 100644 --- a/studio/components/interfaces/BillingV2/SpendCapModal.tsx +++ b/studio/components/interfaces/BillingV2/SpendCapModal.tsx @@ -165,7 +165,7 @@ const SpendCapModal: FC = ({ visible, onHide }) => {

    See{' '} - + pricing page {' '} diff --git a/studio/components/interfaces/BillingV2/Subscription/Tier/EnterpriseCard.tsx b/studio/components/interfaces/BillingV2/Subscription/Tier/EnterpriseCard.tsx index af9608f0dd0..cbf139f924b 100644 --- a/studio/components/interfaces/BillingV2/Subscription/Tier/EnterpriseCard.tsx +++ b/studio/components/interfaces/BillingV2/Subscription/Tier/EnterpriseCard.tsx @@ -18,13 +18,13 @@ const EnterpriseCard = ({ plan, isCurrentPlan }: EnterpriseCardProps) => { >

    -

    {plan.name}

    +

    {plan.name}

    {isCurrentPlan ? (
    Current plan
    ) : plan.nameBadge ? ( -
    +
    {plan.nameBadge}
    ) : null} @@ -43,7 +43,7 @@ const EnterpriseCard = ({ plan, isCurrentPlan }: EnterpriseCardProps) => {
      {plan.features.map((feature) => (
    • -
    • ))} diff --git a/studio/components/interfaces/BillingV2/Subscription/Tier/SubscriptionTier.tsx b/studio/components/interfaces/BillingV2/Subscription/Tier/SubscriptionTier.tsx index 443c4b9b08a..0bfde8d1793 100644 --- a/studio/components/interfaces/BillingV2/Subscription/Tier/SubscriptionTier.tsx +++ b/studio/components/interfaces/BillingV2/Subscription/Tier/SubscriptionTier.tsx @@ -75,7 +75,7 @@ const SubscriptionTier = ({}: SubscriptionTierProps) => {

      This project is currently on the plan:

      -

      {tierName}

      +

      {tierName}

      diff --git a/studio/components/interfaces/BillingV2/Subscription/Tier/TierUpdateSidePanel.tsx b/studio/components/interfaces/BillingV2/Subscription/Tier/TierUpdateSidePanel.tsx index 2472ed8332c..2fdd7e919c9 100644 --- a/studio/components/interfaces/BillingV2/Subscription/Tier/TierUpdateSidePanel.tsx +++ b/studio/components/interfaces/BillingV2/Subscription/Tier/TierUpdateSidePanel.tsx @@ -155,13 +155,13 @@ const TierUpdateSidePanel = () => { >
      -

      {plan.name}

      +

      {plan.name}

      {isCurrentPlan ? (
      Current plan
      ) : plan.nameBadge ? ( -
      +
      {plan.nameBadge}
      ) : ( @@ -258,7 +258,7 @@ const TierUpdateSidePanel = () => {
    • diff --git a/studio/components/interfaces/Database/Roles/RoleRow.tsx b/studio/components/interfaces/Database/Roles/RoleRow.tsx index cd2de5f63be..f069754cb84 100644 --- a/studio/components/interfaces/Database/Roles/RoleRow.tsx +++ b/studio/components/interfaces/Database/Roles/RoleRow.tsx @@ -114,8 +114,8 @@ const RoleRow: FC = ({ role, disabled = false, onSelectDelete }) => { {role.active_connections > 0 && (
      - - + +
      )} diff --git a/studio/components/interfaces/Database/Schemas/SchemaGraph.tsx b/studio/components/interfaces/Database/Schemas/SchemaGraph.tsx index 4a9dfc3ac67..cd5467b1fde 100644 --- a/studio/components/interfaces/Database/Schemas/SchemaGraph.tsx +++ b/studio/components/interfaces/Database/Schemas/SchemaGraph.tsx @@ -205,7 +205,7 @@ function TableNode({ data, targetPosition, sourcePosition }: NodeProps {data.isForeign ? (
      -
      +
      {data.name} {targetPosition && ( ) : (
      -
      +
      {data.name}
      @@ -230,7 +230,7 @@ function TableNode({ data, targetPosition, sourcePosition }: NodeProps diff --git a/studio/components/interfaces/Functions/CommandRender.tsx b/studio/components/interfaces/Functions/CommandRender.tsx index 6a3b83b2a86..c56be3351b5 100644 --- a/studio/components/interfaces/Functions/CommandRender.tsx +++ b/studio/components/interfaces/Functions/CommandRender.tsx @@ -38,7 +38,7 @@ const Command = ({ item }: any) => { }} > {isCopied ? ( -
      +
      ) : ( diff --git a/studio/components/interfaces/Functions/EdgeFunctionDetails/EdgeFunctionDetails.tsx b/studio/components/interfaces/Functions/EdgeFunctionDetails/EdgeFunctionDetails.tsx index a601e794816..3d984779e4e 100644 --- a/studio/components/interfaces/Functions/EdgeFunctionDetails/EdgeFunctionDetails.tsx +++ b/studio/components/interfaces/Functions/EdgeFunctionDetails/EdgeFunctionDetails.tsx @@ -181,9 +181,7 @@ const EdgeFunctionDetails = () => {

      Import maps are{' '} - + {hasImportMap ? 'used' : 'not used'} {' '} for this function diff --git a/studio/components/interfaces/Functions/EdgeFunctionsListItem.tsx b/studio/components/interfaces/Functions/EdgeFunctionsListItem.tsx index 4237781074c..e968c6e115e 100644 --- a/studio/components/interfaces/Functions/EdgeFunctionsListItem.tsx +++ b/studio/components/interfaces/Functions/EdgeFunctionsListItem.tsx @@ -55,7 +55,7 @@ const EdgeFunctionsListItem: FC = ({ function: item }) => { }} > {isCopied ? ( -

      +
      ) : ( diff --git a/studio/components/interfaces/Home/NewProjectPanel/APIKeys.tsx b/studio/components/interfaces/Home/NewProjectPanel/APIKeys.tsx index 815ac8cec05..b493941459f 100644 --- a/studio/components/interfaces/Home/NewProjectPanel/APIKeys.tsx +++ b/studio/components/interfaces/Home/NewProjectPanel/APIKeys.tsx @@ -139,7 +139,7 @@ const APIKeys = () => { for your tables and configured policies. You may also use the service key which can be found{' '} - here + here {' '} to bypass RLS.

      diff --git a/studio/components/interfaces/Home/NewProjectPanel/NewProjectPanel.tsx b/studio/components/interfaces/Home/NewProjectPanel/NewProjectPanel.tsx index 090b720fb29..d8a76c8ef54 100644 --- a/studio/components/interfaces/Home/NewProjectPanel/NewProjectPanel.tsx +++ b/studio/components/interfaces/Home/NewProjectPanel/NewProjectPanel.tsx @@ -242,7 +242,7 @@ const NewProjectPanel: FC = ({}) => {

      Interact with your database through the{' '} - Supabase client libraries + Supabase client libraries {' '} with your API keys.

      diff --git a/studio/components/interfaces/Organization/AuditLogs/AuditLogs.tsx b/studio/components/interfaces/Organization/AuditLogs/AuditLogs.tsx index c463ce98397..7a864aef626 100644 --- a/studio/components/interfaces/Organization/AuditLogs/AuditLogs.tsx +++ b/studio/components/interfaces/Organization/AuditLogs/AuditLogs.tsx @@ -132,7 +132,7 @@ const AuditLogs = () => { return ( Your organization has a log retention period of{' '} - + {retentionPeriod} day {retentionPeriod > 1 ? 's' : ''} diff --git a/studio/components/interfaces/Organization/BillingSettingsV2/Subscription/EnterpriseCard.tsx b/studio/components/interfaces/Organization/BillingSettingsV2/Subscription/EnterpriseCard.tsx index af9608f0dd0..cbf139f924b 100644 --- a/studio/components/interfaces/Organization/BillingSettingsV2/Subscription/EnterpriseCard.tsx +++ b/studio/components/interfaces/Organization/BillingSettingsV2/Subscription/EnterpriseCard.tsx @@ -18,13 +18,13 @@ const EnterpriseCard = ({ plan, isCurrentPlan }: EnterpriseCardProps) => { >
      -

      {plan.name}

      +

      {plan.name}

      {isCurrentPlan ? (
      Current plan
      ) : plan.nameBadge ? ( -
      +
      {plan.nameBadge}
      ) : null} @@ -43,7 +43,7 @@ const EnterpriseCard = ({ plan, isCurrentPlan }: EnterpriseCardProps) => {
        {plan.features.map((feature) => (
      • -
      • ))} diff --git a/studio/components/interfaces/Organization/BillingSettingsV2/Subscription/PlanUpdateSidePanel.tsx b/studio/components/interfaces/Organization/BillingSettingsV2/Subscription/PlanUpdateSidePanel.tsx index fd50323a60e..dabc1f474f3 100644 --- a/studio/components/interfaces/Organization/BillingSettingsV2/Subscription/PlanUpdateSidePanel.tsx +++ b/studio/components/interfaces/Organization/BillingSettingsV2/Subscription/PlanUpdateSidePanel.tsx @@ -157,13 +157,13 @@ const PlanUpdateSidePanel = () => { >
        -

        {plan.name}

        +

        {plan.name}

        {isCurrentPlan ? (
        Current plan
        ) : plan.nameBadge ? ( -
        +
        {plan.nameBadge}
        ) : ( @@ -250,7 +250,7 @@ const PlanUpdateSidePanel = () => {

    {plan.nameBadge && ( - + {plan.nameBadge} )} @@ -249,7 +249,7 @@ export default function IndexPage() { {plan.warning && (

    - + {plan.warning}

    @@ -436,7 +436,7 @@ export default function IndexPage() { className="grid lg:grid-cols-2 gap-8 items-center mt-12 lg:mt-8 max-w-6xl mx-auto" >
    - + Available for Pro plan

    Cost control with spend caps

    @@ -792,7 +792,7 @@ export default function IndexPage() { {plan.warning && (

    - + {plan.warning}

    diff --git a/packages/ui/src/components/Button/Button.tsx b/packages/ui/src/components/Button/Button.tsx index fbb217b0a97..202bad9b7bf 100644 --- a/packages/ui/src/components/Button/Button.tsx +++ b/packages/ui/src/components/Button/Button.tsx @@ -51,7 +51,7 @@ const buttonVariants = cva( focus-visible:outline-brand-600 shadow-sm`, alternative: ` - text-brand-1100 + text-brand-600 bg-brand-200 hover:bg-brand-400 border-brand-600 hover:border-brand-300 dark:border-brand-400 hover:dark:border-brand-300 @@ -73,7 +73,7 @@ const buttonVariants = cva( focus-visible:outline-scale-700 shadow-sm`, link: ` - text-brand-1100 + text-brand-600 border border-transparent hover:bg-brand-400 diff --git a/packages/ui/src/components/Command/CommandMenu.tsx b/packages/ui/src/components/Command/CommandMenu.tsx index 04d856720f7..918fdaf001d 100644 --- a/packages/ui/src/components/Command/CommandMenu.tsx +++ b/packages/ui/src/components/Command/CommandMenu.tsx @@ -122,7 +122,7 @@ const CommandMenu = ({ projectRef }: CommandMenuProps) => { forceMount > - + Ask Supabase AI {search ? ( <> diff --git a/packages/ui/src/components/shadcn/ui/badge.tsx b/packages/ui/src/components/shadcn/ui/badge.tsx index cccbca72050..2b4eaf92bf3 100644 --- a/packages/ui/src/components/shadcn/ui/badge.tsx +++ b/packages/ui/src/components/shadcn/ui/badge.tsx @@ -56,7 +56,7 @@ const badgeVariants = cva( // }, // dot: '-ml-0.5 mr-1.5 h-2 w-2 rounded-full', // color: { -// brand: 'bg-brand-200 text-brand-1100 border border-brand-400', +// brand: 'bg-brand-200 text-brand-600 border border-brand-400', // scale: 'bg-scale-200 text-scale-1100 border border-scale-700', // tomato: `bg-tomato-200 text-tomato-1100 border border-tomato-700`, // red: `bg-red-200 text-red-1100 border border-red-700`, diff --git a/packages/ui/src/lib/theme/defaultTheme.ts b/packages/ui/src/lib/theme/defaultTheme.ts index 2779aa37be4..11626d99435 100644 --- a/packages/ui/src/lib/theme/defaultTheme.ts +++ b/packages/ui/src/lib/theme/defaultTheme.ts @@ -216,7 +216,7 @@ export default { }, dot: '-ml-0.5 mr-1.5 h-2 w-2 rounded-full', color: { - brand: 'bg-brand-200 text-brand-1100 border border-brand-400', + brand: 'bg-brand-200 text-brand-600 border border-brand-400', scale: 'bg-scale-200 text-scale-1100 border border-scale-700', tomato: `bg-tomato-200 text-tomato-1100 border border-tomato-700`, red: `bg-red-200 text-red-1100 border border-red-700`, @@ -271,8 +271,8 @@ export default { success: { base: `bg-brand-300 dark:bg-brand-100 border-brand-400`, icon: `text-brand`, - header: `text-brand-1200`, - description: `text-brand-1100`, + header: `text-brand-600`, + description: `text-brand-600`, }, neutral: { base: `bg-scale-300 dark:bg-scale-300 border-scale-500`, diff --git a/studio/components/interfaces/Auth/Policies/PolicySelection.tsx b/studio/components/interfaces/Auth/Policies/PolicySelection.tsx index adb9d3aa77e..5598c600550 100644 --- a/studio/components/interfaces/Auth/Policies/PolicySelection.tsx +++ b/studio/components/interfaces/Auth/Policies/PolicySelection.tsx @@ -62,7 +62,7 @@ const PolicySelection: FC = ({
    here diff --git a/studio/components/interfaces/BillingV2/Subscription/Tier/TierUpdateSidePanel.tsx b/studio/components/interfaces/BillingV2/Subscription/Tier/TierUpdateSidePanel.tsx index 2fdd7e919c9..b2c2c5c914a 100644 --- a/studio/components/interfaces/BillingV2/Subscription/Tier/TierUpdateSidePanel.tsx +++ b/studio/components/interfaces/BillingV2/Subscription/Tier/TierUpdateSidePanel.tsx @@ -180,7 +180,7 @@ const TierUpdateSidePanel = () => {

    {tierMeta?.costUnit}

    -
    +
    {tierMeta?.warning}
    diff --git a/studio/components/interfaces/Database/Migrations/MigrationsEmptyState.tsx b/studio/components/interfaces/Database/Migrations/MigrationsEmptyState.tsx index b4f2153339c..ab1d31a5941 100644 --- a/studio/components/interfaces/Database/Migrations/MigrationsEmptyState.tsx +++ b/studio/components/interfaces/Database/Migrations/MigrationsEmptyState.tsx @@ -16,7 +16,7 @@ const MigrationsEmptyState = () => { jsx: () => { return ( <> - supabase link --project-ref {ref} + supabase link --project-ref {ref} ) }, @@ -27,7 +27,7 @@ const MigrationsEmptyState = () => { jsx: () => { return ( <> - supabase migration new new-migration + supabase migration new new-migration ) }, @@ -38,7 +38,7 @@ const MigrationsEmptyState = () => { jsx: () => { return ( <> - supabase db push + supabase db push ) }, diff --git a/studio/components/interfaces/Functions/EdgeFunctionDetails/EdgeFunctionDetails.utils.tsx b/studio/components/interfaces/Functions/EdgeFunctionDetails/EdgeFunctionDetails.utils.tsx index bc2ae902432..e8ec2079990 100644 --- a/studio/components/interfaces/Functions/EdgeFunctionDetails/EdgeFunctionDetails.utils.tsx +++ b/studio/components/interfaces/Functions/EdgeFunctionDetails/EdgeFunctionDetails.utils.tsx @@ -10,7 +10,7 @@ export const generateCLICommands = ( jsx: () => { return ( <> - supabase functions deploy{' '} + supabase functions deploy{' '} {selectedFunction?.slug} ) @@ -23,7 +23,7 @@ export const generateCLICommands = ( jsx: () => { return ( <> - supabase functions delete{' '} + supabase functions delete{' '} {selectedFunction?.slug} ) @@ -39,7 +39,7 @@ export const generateCLICommands = ( jsx: () => { return ( <> - supabase secrets list + supabase secrets list ) }, @@ -51,7 +51,7 @@ export const generateCLICommands = ( jsx: () => { return ( <> - supabase secrets set NAME1=VALUE1 NAME2=VALUE2 + supabase secrets set NAME1=VALUE1 NAME2=VALUE2 ) }, @@ -63,7 +63,7 @@ export const generateCLICommands = ( jsx: () => { return ( <> - supabase secrets unset NAME1 NAME2 + supabase secrets unset NAME1 NAME2 ) }, @@ -80,7 +80,7 @@ export const generateCLICommands = ( jsx: () => { return ( <> - curl -L -X POST '{functionUrl}' -H + curl -L -X POST '{functionUrl}' -H 'Authorization: Bearer [YOUR ANON KEY]' {`--data '{"name":"Functions"}'`} ) diff --git a/studio/components/interfaces/Functions/TerminalInstructions.tsx b/studio/components/interfaces/Functions/TerminalInstructions.tsx index 3862be68f51..71cd7cb22e1 100644 --- a/studio/components/interfaces/Functions/TerminalInstructions.tsx +++ b/studio/components/interfaces/Functions/TerminalInstructions.tsx @@ -39,7 +39,7 @@ const TerminalInstructions: FC = ({ closable = false, removeBorder = fals jsx: () => { return ( <> - supabase functions new hello-world + supabase functions new hello-world ) }, @@ -51,7 +51,7 @@ const TerminalInstructions: FC = ({ closable = false, removeBorder = fals jsx: () => { return ( <> - supabase functions deploy hello-world + supabase functions deploy hello-world --project-ref {projectRef} ) @@ -66,7 +66,7 @@ const TerminalInstructions: FC = ({ closable = false, removeBorder = fals jsx: () => { return ( <> - curl -L -X POST 'https://{functionsEndpoint} + curl -L -X POST 'https://{functionsEndpoint} /hello-world' -H 'Authorization: Bearer [YOUR ANON KEY]'{' '} {`--data '{"name":"Functions"}'`} diff --git a/studio/components/interfaces/Organization/BillingSettingsV2/Subscription/PlanUpdateSidePanel.tsx b/studio/components/interfaces/Organization/BillingSettingsV2/Subscription/PlanUpdateSidePanel.tsx index dabc1f474f3..d91951a27a5 100644 --- a/studio/components/interfaces/Organization/BillingSettingsV2/Subscription/PlanUpdateSidePanel.tsx +++ b/studio/components/interfaces/Organization/BillingSettingsV2/Subscription/PlanUpdateSidePanel.tsx @@ -182,7 +182,7 @@ const PlanUpdateSidePanel = () => {

    {tierMeta?.costUnitOrg}

    -
    +
    {tierMeta?.warning}
    diff --git a/studio/components/interfaces/Settings/Logs/LogsFormatters.tsx b/studio/components/interfaces/Settings/Logs/LogsFormatters.tsx index 6ea93cd06f8..9a31cbe0b2d 100644 --- a/studio/components/interfaces/Settings/Logs/LogsFormatters.tsx +++ b/studio/components/interfaces/Settings/Logs/LogsFormatters.tsx @@ -276,7 +276,7 @@ export function jsonSyntaxHighlight(input: Object) { if (/:$/.test(match)) { cls = 'key text-scale-1200' } else { - cls = 'string text-brand-1100' + cls = 'string text-brand-600' } } else if (/true|false/.test(match)) { cls = 'boolean text-blue-900' diff --git a/studio/components/layouts/ProjectLayout/BuildingState.tsx b/studio/components/layouts/ProjectLayout/BuildingState.tsx index b4010ba078d..53188486c5d 100644 --- a/studio/components/layouts/ProjectLayout/BuildingState.tsx +++ b/studio/components/layouts/ProjectLayout/BuildingState.tsx @@ -82,7 +82,7 @@ const BuildingState = ({ project }: BuildingStateProps) => { Browse the Supabase{' '}
    diff --git a/studio/components/layouts/ProjectLayout/LayoutHeader/FeedbackDropdown/FeedbackWidget.tsx b/studio/components/layouts/ProjectLayout/LayoutHeader/FeedbackDropdown/FeedbackWidget.tsx index b5ef7aee1e5..cb18ee373cc 100644 --- a/studio/components/layouts/ProjectLayout/LayoutHeader/FeedbackDropdown/FeedbackWidget.tsx +++ b/studio/components/layouts/ProjectLayout/LayoutHeader/FeedbackDropdown/FeedbackWidget.tsx @@ -222,14 +222,14 @@ const FeedbackWidget: FC = ({ Have a technical issue? Contact{' '} - + Supabase support {' '} or{' '} - + browse our docs diff --git a/studio/pages/project/[ref]/database/backups/scheduled.tsx b/studio/pages/project/[ref]/database/backups/scheduled.tsx index 0bcba0f4ab9..2a6fe5fbd3b 100644 --- a/studio/pages/project/[ref]/database/backups/scheduled.tsx +++ b/studio/pages/project/[ref]/database/backups/scheduled.tsx @@ -64,7 +64,7 @@ const DatabaseScheduledBackups: NextPageWithLayout = () => { needed, as PITR supports a superset of functionality, in terms of the granular recovery that can be performed.{' '} Learn more diff --git a/studio/pages/project/[ref]/logs/explorer/templates.tsx b/studio/pages/project/[ref]/logs/explorer/templates.tsx index c199577067b..7eb8d932f42 100644 --- a/studio/pages/project/[ref]/logs/explorer/templates.tsx +++ b/studio/pages/project/[ref]/logs/explorer/templates.tsx @@ -42,7 +42,7 @@ const Template = ({ projectRef, template }: { projectRef?: string; template: Log text-scale-100 transition-colors group-hover:bg-brand - group-hover:text-brand-1200 + group-hover:text-brand-600 " >
    From 568e76dcdf2314911c47c1f6e76a56e491a3a864 Mon Sep 17 00:00:00 2001 From: Jonathan Summers-Muir Date: Sun, 30 Jul 2023 17:50:33 +0800 Subject: [PATCH 25/61] update var(--*) values --- apps/docs/styles/main.scss | 2 +- .../AuthWidget/AuthWidgetSection.tsx | 14 ++++++------- apps/www/components/Charts/PGCharts.tsx | 2 +- .../InteractiveShimmerCard/index.tsx | 4 ++-- .../LaunchWeek/7/Ticket/form.module.css | 6 +++--- .../LaunchWeek/8/Ticket/form.module.css | 8 +++---- apps/www/styles/index.css | 21 ++++++++++++------- packages/config/code-hike.scss | 12 +++++------ packages/config/default-colors.js | 4 ++-- packages/config/tailwind.config.js | 4 ++-- .../src/components/GlassPanel/GlassPanel.tsx | 4 +++- .../ui/src/components/Icon/IconBackground.tsx | 2 +- packages/ui/src/lib/theme/defaultTheme.ts | 4 ++-- .../components/ui/Charts/Charts.constants.ts | 8 +++---- studio/styles/react-data-grid-logs.scss | 4 ++-- 15 files changed, 54 insertions(+), 45 deletions(-) diff --git a/apps/docs/styles/main.scss b/apps/docs/styles/main.scss index ec6e38a814e..ece45d88688 100644 --- a/apps/docs/styles/main.scss +++ b/apps/docs/styles/main.scss @@ -169,7 +169,7 @@ pre[class*='language-'] { // ToC styles .toc__menu-item--active { - color: var(--colors-brand9) !important; + color: hsl(var(--brand-default)) !important; } .video-container { diff --git a/apps/www/components/AuthWidget/AuthWidgetSection.tsx b/apps/www/components/AuthWidget/AuthWidgetSection.tsx index fe3099cf041..6d840b80c68 100644 --- a/apps/www/components/AuthWidget/AuthWidgetSection.tsx +++ b/apps/www/components/AuthWidget/AuthWidgetSection.tsx @@ -19,9 +19,9 @@ function AuthWidgetSection() { const { basePath } = useRouter() const [radius, setRadius] = useState('4px') const [brandColor, setBrandColor] = useState({ - brand: 'var(--colors-brand9)', - brandAccent: 'var(--colors-brand11)', - brandAccent2: 'var(--colors-brand3)', + brand: 'hsl(var(--brand-default))', + brandAccent: 'hsl(var(--brand-500))', + brandAccent2: 'hsl(var(--brand-200))', }) const [layout, setLayout] = useState('horizontal') @@ -140,14 +140,14 @@ function AuthWidgetSection() { + + + + + + No results found. + + {organizationsData?.map((org) => { + return ( + { + const org = organizationsData?.find( + (org) => org.slug.toLowerCase() === slug.toLowerCase() + ) + if (org) { + onSelectedOrgChange(org) + } + + setOpen(false) + }} + > + + {org.name}{' '} + {configurationId && installed[org.slug] && ( + + Integration Installed + + )} + + ) + })} + + + + + + + ) +} + +export default OrganizationPicker diff --git a/studio/components/interfaces/Integrations/ProjectLinker.tsx b/studio/components/interfaces/Integrations/ProjectLinker.tsx index 8aefbcc265e..ac592a45df6 100644 --- a/studio/components/interfaces/Integrations/ProjectLinker.tsx +++ b/studio/components/interfaces/Integrations/ProjectLinker.tsx @@ -205,14 +205,7 @@ const ProjectLinker = ({
    - - - + {integrationIcon}
    [ + org.slug, + Boolean( + integrationData.find( + (integration) => + integration.organization.slug === org.slug && + integration.integration.name === 'Vercel' + ) + ), + ]) + .filter(([, v]) => Boolean(v)) + ) + } + + if (integrationName === 'GitHub') { + return Object.fromEntries( + organizationsData + .map((org) => [ + org.slug, + Boolean( + integrationData.find( + (integration) => + integration.organization.slug === org.slug && + integration.integration.name === 'GitHub' && + integration.metadata !== undefined && + 'installation_id' in integration.metadata && + String(integration.metadata.installation_id) === String(installationId) + ) + ), + ]) + .filter(([, v]) => Boolean(v)) + ) + } + + return {} +} diff --git a/studio/components/ui/OrganizationPicker.tsx b/studio/components/ui/OrganizationPicker.tsx deleted file mode 100644 index c6308ef4a6b..00000000000 --- a/studio/components/ui/OrganizationPicker.tsx +++ /dev/null @@ -1,115 +0,0 @@ -import { useIntegrationsQuery } from 'data/integrations/integrations-query' -import { IntegrationName } from 'data/integrations/integrations.types' -import { useOrganizationsQuery } from 'data/organizations/organizations-query' -import { useState } from 'react' -import { Organization } from 'types' -import { Badge, IconHexagon, Listbox } from 'ui' - -export interface OrganizationPickerProps { - label?: string - onSelectedOrgChange?: (org: Organization) => void - integrationName: IntegrationName -} - -const OrganizationPicker = ({ - label = 'Choose an organization', - onSelectedOrgChange, - integrationName, -}: OrganizationPickerProps) => { - const [selectedOrg, setSelectedOrg] = useState(null) - - /** - * array of integrations installed on all - */ - const { data: integrationData, isLoading: integrationDataLoading } = useIntegrationsQuery() - - /** - * filter integrations to match integrationName - */ - const vercelIntegrationsInstalled = integrationData?.filter( - (integration) => integration.integration.name === 'Vercel' - ) - - const { data, isLoading } = useOrganizationsQuery({ - onSuccess(organizations) { - const firstOrg = organizations?.[0] - if (firstOrg && selectedOrg === null) { - setSelectedOrg(firstOrg) - onSelectedOrgChange?.(firstOrg) - } - }, - }) - - function _onSelectedOrgChange(slug: string) { - const org = data?.find((org) => org.slug === slug) - - if (org) { - setSelectedOrg(org) - onSelectedOrgChange?.(org) - } - } - - if (isLoading || integrationDataLoading) { - return ( - - - Loading... - - - ) - } - - /** - * Organization type with `installationInstalled` added - */ - interface OrganizationsResponseWithInstalledData extends Organization { - installationInstalled?: boolean - } - - /** - * A flat array of org slugs that have integration installed - */ - const flatInstalledConnectionsIds = - integrationData && integrationData.length > 0 - ? integrationData?.map((x) => x.organization.slug) - : [] - - /** - * Organizations with extra `installationInstalled` attribute - * Used to show label/badge and allow/disallow installing - */ - const organizationsWithInstalledData: OrganizationsResponseWithInstalledData[] = data - ? data.map((org) => { - return { - ...org, - installationInstalled: !flatInstalledConnectionsIds.includes(org.slug) ? true : false, - } - }) - : [] - - return ( - - {organizationsWithInstalledData?.map((org) => { - const label = ( -
    - {org.name} - {org.installationInstalled && Integration Installed} -
    - ) - return ( - } - > - {label} - - ) - })} -
    - ) -} - -export default OrganizationPicker diff --git a/studio/pages/integrations/github/install.tsx b/studio/pages/integrations/github/install.tsx index d781df31966..a3453862232 100644 --- a/studio/pages/integrations/github/install.tsx +++ b/studio/pages/integrations/github/install.tsx @@ -1,18 +1,28 @@ import { useRouter } from 'next/router' -import { useState } from 'react' +import { useMemo, useState } from 'react' import { useParams } from 'common' +import OrganizationPicker from 'components/interfaces/Integrations/OrganizationPicker' import { Markdown } from 'components/interfaces/Markdown' import GitHubIntegrationWindowLayout from 'components/layouts/IntegrationsLayout/GitHubIntegrationWindowLayout' +import { getHasInstalledObject } from 'components/layouts/IntegrationsLayout/Integrations.utils' import { ScaffoldColumn, ScaffoldContainer, ScaffoldDivider } from 'components/layouts/Scaffold' import { useGitHubIntegrationCreateMutation } from 'data/integrations/github-integration-create-mutation' import { useIntegrationsQuery } from 'data/integrations/integrations-query' -import { IntegrationName } from 'data/integrations/integrations.types' import { useOrganizationsQuery } from 'data/organizations/organizations-query' import { useStore } from 'hooks' -import { useGitHubIntegrationInstallationState } from 'state/github-integration-installation' import { NextPageWithLayout, Organization } from 'types' -import { Alert, Badge, Button, IconBook, IconHexagon, IconLifeBuoy, Listbox, LoadingLine } from 'ui' +import { + Alert, + AlertDescription_Shadcn_, + AlertTitle_Shadcn_, + Alert_Shadcn_, + Button, + IconAlertTriangle, + IconBook, + IconLifeBuoy, + LoadingLine, +} from 'ui' /** * Organization type with `installationInstalled` added @@ -28,8 +38,6 @@ const GitHubIntegration: NextPageWithLayout = () => { const [selectedOrg, setSelectedOrg] = useState(null) const [organizationIntegrationId, setOrganizationIntegrationId] = useState(null) - const snapshot = useGitHubIntegrationInstallationState() - /** * Fetch the list of organization based integration installations for GitHub. * @@ -37,44 +45,15 @@ const GitHubIntegration: NextPageWithLayout = () => { */ const { data: integrationData } = useIntegrationsQuery() - const { data: organizationsData, isLoading: isLoadingOrganizationsQuery } = useOrganizationsQuery( - { - onSuccess(organizations) { - const firstOrg = organizations?.[0] - if (firstOrg && selectedOrg === null) { - setSelectedOrg(firstOrg) - snapshot.setSelectedOrganizationSlug(firstOrg.slug) - router.query.organizationSlug = firstOrg.slug - } - }, - } - ) - - /** - * Flat array of org slugs that have integration installed - * - */ - const flatInstalledConnectionsIds: string[] | [] = - integrationData && integrationData.length > 0 - ? integrationData - .filter((x) => x.integration.name === 'Vercel') - .map((x) => x.organization.slug) - : [] - - /** - * Organizations with extra `installationInstalled` attribute - * - * Used to show label/badge and allow/disallow installing - * - */ - const organizationsWithInstalledData: OrganizationsResponseWithInstalledData[] = organizationsData - ? organizationsData.map((org) => { - return { - ...org, - installationInstalled: flatInstalledConnectionsIds.includes(org.slug) ? true : false, - } - }) - : [] + const { data: organizationsData } = useOrganizationsQuery({ + onSuccess(organizations) { + const firstOrg = organizations?.[0] + if (firstOrg && selectedOrg === null) { + setSelectedOrg(firstOrg) + router.query.organizationSlug = firstOrg.slug + } + }, + }) const { mutate, isLoading: isLoadingGitHubIntegrationCreateMutation } = useGitHubIntegrationCreateMutation({ @@ -94,6 +73,19 @@ const GitHubIntegration: NextPageWithLayout = () => { }, }) + const installed = useMemo( + () => + integrationData && organizationsData + ? getHasInstalledObject({ + integrationName: 'GitHub', + integrationData, + organizationsData, + installationId, + }) + : {}, + [installationId, integrationData, organizationsData] + ) + function onInstall() { const orgSlug = selectedOrg?.slug @@ -131,7 +123,7 @@ const GitHubIntegration: NextPageWithLayout = () => { } } - const dataLoading = isLoadingGitHubIntegrationCreateMutation || isLoadingOrganizationsQuery + const disableInstallationForm = Boolean(selectedOrg && installed[selectedOrg.slug]) return ( <> @@ -146,18 +138,29 @@ const GitHubIntegration: NextPageWithLayout = () => { { - router.query.organizationSlug = e.slug - setSelectedOrg(e) + selectedOrg={selectedOrg} + onSelectedOrgChange={(org) => { + router.query.organizationSlug = org.slug + setSelectedOrg(org) }} - dataLoading={dataLoading} + configurationId={installationId} /> + {disableInstallationForm && ( + + + + GitHub Integration is already installed. + + + You will need to choose another organization to install the integration. + + + )}
    - - - - - - No results found. - - {organizationsWithInstalledData?.map((org) => { - return ( - { - if (slug) onSelectedOrgChange(slug) - setOpen(false) - }} - > - - {org.name}{' '} - {org?.installationInstalled && ( - - Integration Installed - - )} - - ) - })} - - - - - - - ) -} - export default VercelIntegration diff --git a/studio/state/github-integration-installation.ts b/studio/state/github-integration-installation.ts deleted file mode 100644 index 8d134d2b168..00000000000 --- a/studio/state/github-integration-installation.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { proxy, snapshot, useSnapshot } from 'valtio' - -export const githubIntegrationInstallationState = proxy({ - selectedOrganizationSlug: '' as string, - setSelectedOrganizationSlug: (selectedOrganizationSlug: string) => { - githubIntegrationInstallationState.selectedOrganizationSlug = selectedOrganizationSlug - }, -}) - -export const getGitHubIntegrationInstallationState = () => - snapshot(githubIntegrationInstallationState) - -export const useGitHubIntegrationInstallationState = ( - options?: Parameters[1] -) => useSnapshot(githubIntegrationInstallationState, options) From a724b8910905cd453610b35a40ba78612a16074d Mon Sep 17 00:00:00 2001 From: Alaister Young Date: Mon, 31 Jul 2023 20:07:05 +1000 Subject: [PATCH 35/61] skip github linking --- .../integrations/github/[integrationId]/choose-project.tsx | 3 +++ studio/pages/integrations/github/install.tsx | 7 ------- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/studio/pages/integrations/github/[integrationId]/choose-project.tsx b/studio/pages/integrations/github/[integrationId]/choose-project.tsx index c49ed89439c..0d274a676a5 100644 --- a/studio/pages/integrations/github/[integrationId]/choose-project.tsx +++ b/studio/pages/integrations/github/[integrationId]/choose-project.tsx @@ -89,6 +89,9 @@ This Supabase integration will allow you to link a Supabase project to a GitHub isLoading={isCreatingConnection} integrationIcon={GITHUB_ICON} choosePrompt="Choose GitHub Repo" + onSkip={() => { + router.push(`/org/${orgSlug}/integrations`) + }} /> diff --git a/studio/pages/integrations/github/install.tsx b/studio/pages/integrations/github/install.tsx index a3453862232..665530e9ac3 100644 --- a/studio/pages/integrations/github/install.tsx +++ b/studio/pages/integrations/github/install.tsx @@ -24,13 +24,6 @@ import { LoadingLine, } from 'ui' -/** - * Organization type with `installationInstalled` added - */ -interface OrganizationsResponseWithInstalledData extends Organization { - installationInstalled?: boolean -} - const GitHubIntegration: NextPageWithLayout = () => { const router = useRouter() const { ui } = useStore() From 3459430bfafa00a8e27ccac0aeba84f4953bd69b Mon Sep 17 00:00:00 2001 From: Ivan Vasilov Date: Mon, 31 Jul 2023 12:28:09 +0200 Subject: [PATCH 36/61] Use the supplied connection string from the backend. --- .../interfaces/Settings/Database/ConnectionPooling.tsx | 8 +++----- studio/data/database/pooling-configuration-query.ts | 3 ++- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/studio/components/interfaces/Settings/Database/ConnectionPooling.tsx b/studio/components/interfaces/Settings/Database/ConnectionPooling.tsx index 8eb6c0b4812..cfb85ffcccb 100644 --- a/studio/components/interfaces/Settings/Database/ConnectionPooling.tsx +++ b/studio/components/interfaces/Settings/Database/ConnectionPooling.tsx @@ -35,6 +35,7 @@ const ConnectionPooling = () => { 'pool_mode', 'pgbouncer_enabled', 'max_client_conn', + 'connectionString', ] const bouncerInfo = isSuccess ? pluckObjectFields(formModel, BOUNCER_FIELDS) : {} @@ -107,6 +108,7 @@ interface ConfigProps { pool_mode: string pgbouncer_enabled: boolean max_client_conn: number + connectionString: string } connectionInfo: { db_host: string @@ -256,11 +258,7 @@ export const PgbouncerConfig: FC = ({ projectRef, bouncerInfo, conn copy disabled label="Connection string" - value={ - `postgres://${connectionInfo.db_user}:[YOUR-PASSWORD]@` + - `${connectionInfo.db_host}:${connectionInfo.db_port}` + - `/${connectionInfo.db_name}` - } + value={bouncerInfo.connectionString} />
    diff --git a/studio/data/database/pooling-configuration-query.ts b/studio/data/database/pooling-configuration-query.ts index 38f457e6401..348cb639a98 100644 --- a/studio/data/database/pooling-configuration-query.ts +++ b/studio/data/database/pooling-configuration-query.ts @@ -2,8 +2,8 @@ import { useQuery, useQueryClient, UseQueryOptions } from '@tanstack/react-query import { get } from 'lib/common/fetch' import { API_URL } from 'lib/constants' import { useCallback } from 'react' -import { databaseKeys } from './keys' import { ResponseError } from 'types' +import { databaseKeys } from './keys' export type PoolingConfigurationVariables = { projectRef: string @@ -23,6 +23,7 @@ export type PoolingConfiguration = { pgbouncer_enabled: boolean pgbouncer_status: string pool_mode: string + connectionString: string } export async function getPoolingConfiguration( From d27134c93b4fc7660a2940d4a5e8091bc3cbc267 Mon Sep 17 00:00:00 2001 From: Jonathan Summers-Muir Date: Mon, 31 Jul 2023 19:10:48 +0800 Subject: [PATCH 37/61] fix bg colors --- studio/pages/integrations/github/install.tsx | 2 +- studio/pages/integrations/vercel/install.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/studio/pages/integrations/github/install.tsx b/studio/pages/integrations/github/install.tsx index d781df31966..5ade1648793 100644 --- a/studio/pages/integrations/github/install.tsx +++ b/studio/pages/integrations/github/install.tsx @@ -135,7 +135,7 @@ const GitHubIntegration: NextPageWithLayout = () => { return ( <> -
    +
    {organizationIntegrationId === null && ( <> diff --git a/studio/pages/integrations/vercel/install.tsx b/studio/pages/integrations/vercel/install.tsx index a93bee324e4..28ac4cf975d 100644 --- a/studio/pages/integrations/vercel/install.tsx +++ b/studio/pages/integrations/vercel/install.tsx @@ -206,7 +206,7 @@ const VercelIntegration: NextPageWithLayout = () => { return ( <> -
    +
    {organizationIntegrationId === null && ( <> From 6b912ff1b4d508204e31d5e4488ce9bf37ff5988 Mon Sep 17 00:00:00 2001 From: Jon Meyers Date: Mon, 31 Jul 2023 21:31:52 +1000 Subject: [PATCH 38/61] add examples for edge and static routes --- .../pages/guides/auth/auth-helpers/nextjs.mdx | 248 ++++++++++++++++++ 1 file changed, 248 insertions(+) diff --git a/apps/docs/pages/guides/auth/auth-helpers/nextjs.mdx b/apps/docs/pages/guides/auth/auth-helpers/nextjs.mdx index cbb1ae76649..8c57226a701 100644 --- a/apps/docs/pages/guides/auth/auth-helpers/nextjs.mdx +++ b/apps/docs/pages/guides/auth/auth-helpers/nextjs.mdx @@ -846,6 +846,254 @@ TypeScript types can be [generated with the Supabase CLI](/docs/reference/javasc See [refreshing session example](/docs/guides/auth/auth-helpers/nextjs#managing-session-with-middleware) above. +### Edge Runtime + +The Next.js Edge Runtime allows you to host Server Components and Route Handlers from Edge nodes, serving the routes as close as possible to your user's location. + +A route can be configured to use the Edge Runtime by exporting a `runtime` variable set to `edge`. Additionally, the `cookies()` function must be called from the Edge route, before creating a Supabase Client. + +#### Server Components + + + + +```jsx app/page.jsx +import { cookies } from 'next/headers' +import { createServerComponentClient } from '@supabase/auth-helpers-nextjs' + +export const runtime = 'edge' +export const dynamic = 'force-dynamic' + +export default async function Home() { + const cookieStore = cookies() + + const supabase = createServerComponentClient({ + cookies: () => cookieStore, + }) + + const { data } = await supabase.from('todos').select() + return
    {JSON.stringify(data, null, 2)}
    +} +``` + +
    + + + +```tsx app/page.tsx +import { cookies } from 'next/headers' +import { createServerComponentClient } from '@supabase/auth-helpers-nextjs' + +import type { Database } from '@/lib/database.types' + +export const runtime = 'edge' +export const dynamic = 'force-dynamic' + +export default async function ServerComponent() { + const cookieStore = cookies() + + const supabase = createServerComponentClient({ + cookies: () => cookieStore, + }) + + const { data } = await supabase.from('todos').select() + return
    {JSON.stringify(data, null, 2)}
    +} +``` + + + +TypeScript types can be [generated with the Supabase CLI](/docs/reference/javascript/typescript-support) and passed to `createServerComponentClient` to add type support to the Supabase client. + + + +
    +
    + +#### Route Handlers + + + + +```jsx app/api/todos/route.jsx +import { createRouteHandlerClient } from '@supabase/auth-helpers-nextjs' +import { NextResponse } from 'next/server' +import { cookies } from 'next/headers' + +export const runtime = 'edge' +export const dynamic = 'force-dynamic' + +export async function POST(request) { + const { title } = await request.json() + const cookieStore = cookies() + + const supabase = createRouteHandlerClient({ + cookies: () => cookieStore, + }) + + const { data } = await supabase.from('todos').insert({ title }).select() + return NextResponse.json(data) +} +``` + + + + + +```tsx app/api/todos/route.tsx +import { createRouteHandlerClient } from '@supabase/auth-helpers-nextjs' +import { NextResponse } from 'next/server' +import { cookies } from 'next/headers' + +import type { Database } from '@/lib/database.types' + +export const runtime = 'edge' +export const dynamic = 'force-dynamic' + +export async function POST(request: Request) { + const { title } = await request.json() + const cookieStore = cookies() + + const supabase = createRouteHandlerClient({ + cookies: () => cookieStore, + }) + + const { data } = await supabase.from('todos').insert({ title }).select() + return NextResponse.json(data) +} +``` + + + +TypeScript types can be [generated with the Supabase CLI](/docs/reference/javascript/typescript-support) and passed to `createRouteHandlerClient` to add type support to the Supabase client. + + + + + + +### Static Routes + +Server Components and Route Handlers are static by default - data is fetched once at build time and the value is cached. Since the request to Supabase now happens at build time, there is no user, session or cookie to pass along with the request to Supabase. Therefore, the `createClient` function from `supabase-js` can be used to fetch data for static routes. + +#### Server Components + + + + +```jsx app/page.jsx +import { createClient } from '@supabase/supabase-js' + +export default async function Home() { + const supabase = createClient( + process.env.NEXT_PUBLIC_SUPABASE_URL, + process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY + ) + + const { data } = await supabase.from('todos').select() + return
    {JSON.stringify(data, null, 2)}
    +} +``` + +
    + + + +```tsx app/page.tsx +import { createClient } from '@supabase/supabase-js' + +export default async function Home() { + const supabase = createClient( + process.env.NEXT_PUBLIC_SUPABASE_URL!, + process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY! + ) + + const { data } = await supabase.from('todos').select() + return
    {JSON.stringify(data, null, 2)}
    +} +``` + + + +TypeScript types can be [generated with the Supabase CLI](/docs/reference/javascript/typescript-support) and passed to `createServerComponentClient` to add type support to the Supabase client. + + + +
    +
    + +#### Route Handlers + + + + +```jsx app/api/todos/route.jsx +import { createClient } from '@supabase/supabase-js' +import { NextResponse } from 'next/server' + +export async function POST(request) { + const { title } = await request.json() + + const supabase = createClient( + process.env.NEXT_PUBLIC_SUPABASE_URL, + process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY + ) + + const { data } = await supabase.from('todos').insert({ title }).select() + return NextResponse.json(data) +} +``` + + + + + +```tsx app/api/todos/route.tsx +import { createClient } from '@supabase/supabase-js' +import { NextResponse } from 'next/server' + +export async function POST(request: Request) { + const { title } = await request.json() + + const supabase = createClient( + process.env.NEXT_PUBLIC_SUPABASE_URL!, + process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY! + ) + + const { data } = await supabase.from('todos').insert({ title }).select() + return NextResponse.json(data) +} +``` + + + +TypeScript types can be [generated with the Supabase CLI](/docs/reference/javascript/typescript-support) and passed to `createRouteHandlerClient` to add type support to the Supabase client. + + + + + + ## More examples - [Build a Twitter Clone with the Next.js App Router and Supabase - free egghead course](https://egghead.io/courses/build-a-twitter-clone-with-the-next-js-app-router-and-supabase-19bebadb) From 922aad461878f00a1605e6a4190b8f1d376582a0 Mon Sep 17 00:00:00 2001 From: Greg Richardson Date: Wed, 7 Jun 2023 00:23:36 -0600 Subject: [PATCH 39/61] feat(federation): remark pymdown tab support --- apps/docs/lib/mdx/plugins/remarkTabs.ts | 138 ++++++++++++++++++ .../pages/guides/cli/github-action/[slug].tsx | 9 ++ 2 files changed, 147 insertions(+) create mode 100644 apps/docs/lib/mdx/plugins/remarkTabs.ts diff --git a/apps/docs/lib/mdx/plugins/remarkTabs.ts b/apps/docs/lib/mdx/plugins/remarkTabs.ts new file mode 100644 index 00000000000..3562c2a6eca --- /dev/null +++ b/apps/docs/lib/mdx/plugins/remarkTabs.ts @@ -0,0 +1,138 @@ +import { Content, Paragraph, Parent } from 'mdast' +import { MdxJsxFlowElement } from 'mdast-util-mdx' +import { Node } from 'unist' +import { visit } from 'unist-util-visit' + +/** + * Transforms PyMdown Tabs to Supabase Tabs. + * + * https://facelessuser.github.io/pymdown-extensions/extensions/tabbed/ + */ +const remarkPyMdownTabs = function () { + return function transformer(root: Parent) { + visit(root, 'paragraph', (node: Paragraph, nodeIndex: number, parent: Parent) => { + for (let i = 0; i < node.children.length; i++) { + const child = node.children[i] + if (child.type !== 'text') { + continue + } + + // Look for 3 '=', followed by an optionally quoted title, + // followed by optional newlines of text + const match = child.value.match(/^\n*=== ("?)(.+)\1\n?((?:.|\n)*)/) + + if (!match) { + continue + } + + // Extract the tab title along with the remaining text + const [, , title, value] = match + + // Rewrite the node's value to remove the tab syntax + child.value = value + + // Extract sibling nodes that should be linked to this tab + const siblingsToNest = extractLinkedSiblings(parent, node, nodeIndex) + + const children: any[] = [...node.children.slice(i), ...siblingsToNest] + + const tabPanelElement: MdxJsxFlowElement = { + type: 'mdxJsxFlowElement', + name: 'TabPanel', + attributes: [ + { + type: 'mdxJsxAttribute', + name: 'id', + value: title, + }, + { + type: 'mdxJsxAttribute', + name: 'label', + value: title, + }, + ], + children, + } + + let nodesAdded = 0 + const previousNode = parent.children[nodeIndex - 1] + + if (previousNode?.type === 'mdxJsxFlowElement' && previousNode.name === 'Tabs') { + // Add TabPanel to existing Tabs component + previousNode.children.push(tabPanelElement) + + // Remove this node + parent.children.splice(nodeIndex, 1) + nodesAdded-- + } else { + // Create new Tabs components and add TabPanel + const tabsElement: MdxJsxFlowElement = { + type: 'mdxJsxFlowElement', + name: 'Tabs', + attributes: [ + { + type: 'mdxJsxAttribute', + name: 'scrollable', + }, + { + type: 'mdxJsxAttribute', + name: 'size', + value: 'small', + }, + { + type: 'mdxJsxAttribute', + name: 'type', + value: 'underlined', + }, + ], + children: [tabPanelElement], + } + + // Overwrite this paragraph node with Tabs component + parent.children.splice(nodeIndex, 1, tabsElement) + } + + // If this wasn't the first child of the paragraph, create + // a new paragraph before this with the previous text children + if (i > 0) { + const previousChildren = node.children.slice(0, i) + const paragraph: Paragraph = { + type: 'paragraph', + children: previousChildren, + } + parent.children.splice(nodeIndex, 0, paragraph) + + nodesAdded++ + } + + // Return the correct index for the next visit, since + // we may have added or removed an element in the array + return nodeIndex + nodesAdded + } + }) + } +} + +/** + * Identifies sibling nodes that should be linked to this admonition + * based on their indent level (ie. 4 spaces). + * + * Iterates through proceeding siblings until one is found that is + * not indented relative to the original node. + * + * Splices the discovered siblings out of the original parent and returns them. + */ +function extractLinkedSiblings(parent: Parent, node: Node, index: number, indentAmount = 4) { + const { column } = node.position.start + + let nextSibling: Content + let i = index + + do { + nextSibling = parent.children[++i] + } while (nextSibling?.position && nextSibling.position.start.column === column + indentAmount) + + return parent.children.splice(index + 1, i - index - 1) +} + +export default remarkPyMdownTabs diff --git a/apps/docs/pages/guides/cli/github-action/[slug].tsx b/apps/docs/pages/guides/cli/github-action/[slug].tsx index 181f3acb409..fe30a5f3f2a 100644 --- a/apps/docs/pages/guides/cli/github-action/[slug].tsx +++ b/apps/docs/pages/guides/cli/github-action/[slug].tsx @@ -11,6 +11,7 @@ import Layout from '~/layouts/DefaultGuideLayout' import { UrlTransformFunction, linkTransform } from '~/lib/mdx/plugins/rehypeLinkTransform' import remarkMkDocsAdmonition from '~/lib/mdx/plugins/remarkAdmonition' import { removeTitle } from '~/lib/mdx/plugins/remarkRemoveTitle' +import remarkPyMdownTabs from '~/lib/mdx/plugins/remarkTabs' // We fetch these docs at build time from an external repo const org = 'supabase' @@ -31,6 +32,13 @@ const pageMap = [ }, remoteFile: 'generating-types.md', }, + { + slug: 'api', + meta: { + title: 'GraphQL API', + }, + remoteFile: 'api.md', + }, ] interface ActionDocsProps { @@ -116,6 +124,7 @@ export const getStaticProps: GetStaticProps = async ({ params } remarkPlugins: [ remarkGfm, remarkMkDocsAdmonition, + remarkPyMdownTabs, [removeTitle, meta.title], [remarkCodeHike, codeHikeOptions], ], From 743f5009f6e9e07bcc1ffded15034b59a4d54df9 Mon Sep 17 00:00:00 2001 From: Jon Meyers Date: Mon, 31 Jul 2023 21:37:32 +1000 Subject: [PATCH 40/61] add force-dynamic to routes that import Next.js cookies function --- .../pages/guides/auth/auth-helpers/nextjs.mdx | 32 ++++++++++++++++--- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/apps/docs/pages/guides/auth/auth-helpers/nextjs.mdx b/apps/docs/pages/guides/auth/auth-helpers/nextjs.mdx index 8c57226a701..cca63f190bd 100644 --- a/apps/docs/pages/guides/auth/auth-helpers/nextjs.mdx +++ b/apps/docs/pages/guides/auth/auth-helpers/nextjs.mdx @@ -162,6 +162,8 @@ import { createRouteHandlerClient } from '@supabase/auth-helpers-nextjs' import { cookies } from 'next/headers' import { NextResponse } from 'next/server' +export const dynamic = 'force-dynamic' + export async function GET(request) { const requestUrl = new URL(request.url) const code = requestUrl.searchParams.get('code') @@ -190,6 +192,8 @@ import { NextResponse } from 'next/server' import type { NextRequest } from 'next/server' import type { Database } from '@/lib/database.types' +export const dynamic = 'force-dynamic' + export async function GET(request: NextRequest) { const requestUrl = new URL(request.url) const code = requestUrl.searchParams.get('code') @@ -390,6 +394,8 @@ import { createServerActionClient } from '@supabase/auth-helpers-nextjs' import { revalidatePath } from 'next/cache' import { cookies } from 'next/headers' +export const dynamic = 'force-dynamic' + export default async function Login() { const handleSignUp = async (formData) => { 'use server' @@ -452,6 +458,8 @@ import { cookies } from 'next/headers' import type { Database } from '@/lib/database.types' +export const dynamic = 'force-dynamic' + export default async function Login() { const handleSignUp = async (formData: FormData) => { 'use server' @@ -653,6 +661,8 @@ In order to use Supabase in Server Components, you need to have implemented the import { cookies } from 'next/headers' import { createServerComponentClient } from '@supabase/auth-helpers-nextjs' +export const dynamic = 'force-dynamic' + export default async function Home() { const supabase = createServerComponentClient({ cookies }) const { data } = await supabase.from('todos').select() @@ -670,6 +680,8 @@ import { createServerComponentClient } from '@supabase/auth-helpers-nextjs' import type { Database } from '@/lib/database.types' +export const dynamic = 'force-dynamic' + export default async function ServerComponent() { const supabase = createServerComponentClient({ cookies }) const { data } = await supabase.from('todos').select() @@ -724,6 +736,8 @@ import { cookies } from 'next/headers' import { createServerActionClient } from '@supabase/auth-helpers-nextjs' import { revalidatePath } from 'next/cache' +export const dynamic = 'force-dynamic' + export default async function NewTodo() { const addTodo = async (formData) => { 'use server' @@ -753,6 +767,8 @@ import { revalidatePath } from 'next/cache' import type { Database } from '@/lib/database.types' +export const dynamic = 'force-dynamic' + export default async function NewTodo() { const addTodo = async (formData: FormData) => { 'use server' @@ -806,6 +822,8 @@ import { createRouteHandlerClient } from '@supabase/auth-helpers-nextjs' import { NextResponse } from 'next/server' import { cookies } from 'next/headers' +export const dynamic = 'force-dynamic' + export async function POST(request) { const { title } = await request.json() const supabase = createRouteHandlerClient({ cookies }) @@ -825,6 +843,8 @@ import { cookies } from 'next/headers' import type { Database } from '@/lib/database.types' +export const dynamic = 'force-dynamic' + export async function POST(request: Request) { const { title } = await request.json() const supabase = createRouteHandlerClient({ cookies }) @@ -894,7 +914,7 @@ import type { Database } from '@/lib/database.types' export const runtime = 'edge' export const dynamic = 'force-dynamic' -export default async function ServerComponent() { +export default async function ServerComponent() { const cookieStore = cookies() const supabase = createServerComponentClient({ @@ -964,7 +984,7 @@ export async function POST(request: Request) { const { title } = await request.json() const cookieStore = cookies() - const supabase = createRouteHandlerClient({ + const supabase = createRouteHandlerClient({ cookies: () => cookieStore, }) @@ -1017,8 +1037,10 @@ export default async function Home() { ```tsx app/page.tsx import { createClient } from '@supabase/supabase-js' +import type { Database } from '@/lib/database.types' + export default async function Home() { - const supabase = createClient( + const supabase = createClient( process.env.NEXT_PUBLIC_SUPABASE_URL!, process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY! ) @@ -1072,10 +1094,12 @@ export async function POST(request) { import { createClient } from '@supabase/supabase-js' import { NextResponse } from 'next/server' +import type { Database } from '@/lib/database.types' + export async function POST(request: Request) { const { title } = await request.json() - const supabase = createClient( + const supabase = createClient( process.env.NEXT_PUBLIC_SUPABASE_URL!, process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY! ) From 27479dbd862bce279f7e5aba54d686eab072bcfc Mon Sep 17 00:00:00 2001 From: Jon Meyers Date: Mon, 31 Jul 2023 21:45:41 +1000 Subject: [PATCH 41/61] rename Home routes to be Page --- apps/docs/pages/guides/auth/auth-helpers/nextjs.mdx | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/apps/docs/pages/guides/auth/auth-helpers/nextjs.mdx b/apps/docs/pages/guides/auth/auth-helpers/nextjs.mdx index cca63f190bd..dba2976c0a1 100644 --- a/apps/docs/pages/guides/auth/auth-helpers/nextjs.mdx +++ b/apps/docs/pages/guides/auth/auth-helpers/nextjs.mdx @@ -559,7 +559,7 @@ This allows for the Supabase client to be easily instantiated in the correct con import { createClientComponentClient } from '@supabase/auth-helpers-nextjs' import { useEffect, useState } from 'react' -export default function Home() { +export default function Page() { const [todos, setTodos] = useState() const supabase = createClientComponentClient() @@ -590,7 +590,7 @@ import type { Database } from '@/lib/database.types' type Todo = Database['public']['Tables']['todos']['Row'] -export default function Home() { +export default function Page() { const [todos, setTodos] = useState(null) const supabase = createClientComponentClient() @@ -663,7 +663,7 @@ import { createServerComponentClient } from '@supabase/auth-helpers-nextjs' export const dynamic = 'force-dynamic' -export default async function Home() { +export default async function Page() { const supabase = createServerComponentClient({ cookies }) const { data } = await supabase.from('todos').select() return
    {JSON.stringify(data, null, 2)}
    @@ -889,7 +889,7 @@ import { createServerComponentClient } from '@supabase/auth-helpers-nextjs' export const runtime = 'edge' export const dynamic = 'force-dynamic' -export default async function Home() { +export default async function Page() { const cookieStore = cookies() const supabase = createServerComponentClient({ @@ -1019,7 +1019,7 @@ Server Components and Route Handlers are static by default - data is fetched onc ```jsx app/page.jsx import { createClient } from '@supabase/supabase-js' -export default async function Home() { +export default async function Page() { const supabase = createClient( process.env.NEXT_PUBLIC_SUPABASE_URL, process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY @@ -1039,7 +1039,7 @@ import { createClient } from '@supabase/supabase-js' import type { Database } from '@/lib/database.types' -export default async function Home() { +export default async function Page() { const supabase = createClient( process.env.NEXT_PUBLIC_SUPABASE_URL!, process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY! From 1e2c14808808b718015367e225efd8e41c561673 Mon Sep 17 00:00:00 2001 From: Bo Lu Date: Mon, 31 Jul 2023 22:15:55 +1000 Subject: [PATCH 42/61] fix: add tabs remark plugin --- .../NavigationMenu/NavigationMenu.constants.ts | 9 +++++++++ .../pages/guides/database/extensions/wrappers/[slug].tsx | 2 ++ 2 files changed, 11 insertions(+) diff --git a/apps/docs/components/Navigation/NavigationMenu/NavigationMenu.constants.ts b/apps/docs/components/Navigation/NavigationMenu/NavigationMenu.constants.ts index 4e0bdaa626a..e427afe443f 100644 --- a/apps/docs/components/Navigation/NavigationMenu/NavigationMenu.constants.ts +++ b/apps/docs/components/Navigation/NavigationMenu/NavigationMenu.constants.ts @@ -660,6 +660,15 @@ export const database: NavMenuConstant = { { name: 'wrappers: 3rd Party Integrations', url: '/guides/database/extensions/wrappers', + items: [ + { name: 'Airtable', url: '/guides/database/extensions/wrappers/airtable' }, + { name: 'AWS S3', url: '/guides/database/extensions/wrappers/s3' }, + { name: 'BigQuery', url: '/guides/database/extensions/wrappers/bigquery' }, + { name: 'ClickHouse', url: '/guides/database/extensions/wrappers/clickhouse' }, + { name: 'Firebase', url: '/guides/database/extensions/wrappers/firebase' }, + { name: 'Logflare', url: '/guides/database/extensions/wrappers/logflare' }, + { name: 'Stripe', url: '/guides/database/extensions/wrappers/stripe' }, + ], }, ], }, diff --git a/apps/docs/pages/guides/database/extensions/wrappers/[slug].tsx b/apps/docs/pages/guides/database/extensions/wrappers/[slug].tsx index 81beffacd4b..2363a4ce7d0 100644 --- a/apps/docs/pages/guides/database/extensions/wrappers/[slug].tsx +++ b/apps/docs/pages/guides/database/extensions/wrappers/[slug].tsx @@ -12,6 +12,7 @@ import Layout from '~/layouts/DefaultGuideLayout' import { UrlTransformFunction, linkTransform } from '~/lib/mdx/plugins/rehypeLinkTransform' import remarkMkDocsAdmonition from '~/lib/mdx/plugins/remarkAdmonition' import { removeTitle } from '~/lib/mdx/plugins/remarkRemoveTitle' +import remarkPyMdownTabs from '~/lib/mdx/plugins/remarkTabs' // We fetch these docs at build time from an external repo const org = 'supabase' @@ -157,6 +158,7 @@ export const getStaticProps: GetStaticProps = async ({ params remarkGfm, remarkMkDocsAdmonition, emoji, + remarkPyMdownTabs, [removeTitle, meta.title], [remarkCodeHike, codeHikeOptions], ], From e3ee24a937aeaa7c8d7459193b269c33c9588659 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kevin=20Gr=C3=BCneberg?= Date: Thu, 20 Jul 2023 18:12:54 +0200 Subject: [PATCH 43/61] chore: improve redirects for org-level-billing --- .../BillingV2/Subscription/Subscription.tsx | 37 ++------------ .../Database/Backups/BackupsList.tsx | 1 + .../CustomDomainConfig/CustomDomainConfig.tsx | 1 + studio/components/ui/UpgradeToPro.tsx | 7 +-- .../project/[ref]/database/backups/pitr.tsx | 1 + .../[ref]/settings/billing/invoices.tsx | 28 ++++------- .../[ref]/settings/billing/subscription.tsx | 49 ++++++++++++------- 7 files changed, 52 insertions(+), 72 deletions(-) diff --git a/studio/components/interfaces/BillingV2/Subscription/Subscription.tsx b/studio/components/interfaces/BillingV2/Subscription/Subscription.tsx index b228c80fcee..d0c42f0c4ab 100644 --- a/studio/components/interfaces/BillingV2/Subscription/Subscription.tsx +++ b/studio/components/interfaces/BillingV2/Subscription/Subscription.tsx @@ -5,7 +5,6 @@ import CostControl from './CostControl/CostControl' import SubscriptionTier from './Tier/SubscriptionTier' import { SUBSCRIPTION_PANEL_KEYS, useSubscriptionPageStateSnapshot } from 'state/subscription-page' import { useSelectedOrganization } from 'hooks' -import { useEffect } from 'react' export interface SubscriptionProps {} @@ -24,41 +23,13 @@ const Subscription = ({}: SubscriptionProps) => { const panel = router.query.panel const isOrgBilling = !!organization?.subscription_id - useEffect(() => { - if (isOrgBilling) { - const { ref, panel } = router.query - let redirectUri = `/org/${organization.slug}/billing` - switch (panel) { - case 'subscriptionPlan': - redirectUri = `/org/${organization.slug}/billing?panel=subscriptionPlan` - break - case 'costControl': - redirectUri = `/org/${organization.slug}/billing?panel=costControl` - break - case 'computeInstance': - redirectUri = `/project/${ref}/settings/addons?panel=computeInstance` - break - case 'pitr': - redirectUri = `/project/${ref}/settings/addons?panel=pitr` - break - case 'customDomain': - redirectUri = `/project/${ref}/settings/addons?panel=customDomain` - break - } - - router.push(redirectUri) - } - }, [router, organization?.slug, isOrgBilling]) - - useEffect(() => { - if (panel && typeof panel === 'string' && allowedValues.includes(panel)) { - snap.setPanelKey(panel as SUBSCRIPTION_PANEL_KEYS) - } - }, [panel]) - // No need to bother rendering, we'll redirect anyway if (isOrgBilling) return null + if (panel && typeof panel === 'string' && allowedValues.includes(panel)) { + snap.setPanelKey(panel as SUBSCRIPTION_PANEL_KEYS) + } + return ( <>
    diff --git a/studio/components/interfaces/Database/Backups/BackupsList.tsx b/studio/components/interfaces/Database/Backups/BackupsList.tsx index fd379d00293..4bf28b80dee 100644 --- a/studio/components/interfaces/Database/Backups/BackupsList.tsx +++ b/studio/components/interfaces/Database/Backups/BackupsList.tsx @@ -36,6 +36,7 @@ const BackupsList = () => { primaryText="Free Plan does not include project backups." projectRef={projectRef} secondaryText="Upgrade to the Pro plan for up to 7 days of scheduled backups." + addon="pitr" /> ) } diff --git a/studio/components/interfaces/Settings/General/CustomDomainConfig/CustomDomainConfig.tsx b/studio/components/interfaces/Settings/General/CustomDomainConfig/CustomDomainConfig.tsx index abb91c8a96e..d2e68280594 100644 --- a/studio/components/interfaces/Settings/General/CustomDomainConfig/CustomDomainConfig.tsx +++ b/studio/components/interfaces/Settings/General/CustomDomainConfig/CustomDomainConfig.tsx @@ -69,6 +69,7 @@ const CustomDomainConfig = () => { ? 'To configure a custom domain for your project, please upgrade to the Pro plan with the custom domains add-on selected' : 'To configure a custom domain for your project, please enable the add-on' } + addon="customDomain" /> ) : ( diff --git a/studio/components/ui/UpgradeToPro.tsx b/studio/components/ui/UpgradeToPro.tsx index 9c36fb4b2cf..3436f9cc8a2 100644 --- a/studio/components/ui/UpgradeToPro.tsx +++ b/studio/components/ui/UpgradeToPro.tsx @@ -12,9 +12,10 @@ interface Props { primaryText: string projectRef: string secondaryText: string + addon?: 'pitr' | 'customDomain' | 'computeInstance' } -const UpgradeToPro: FC = ({ icon, primaryText, projectRef, secondaryText }) => { +const UpgradeToPro: FC = ({ icon, primaryText, projectRef, secondaryText, addon }) => { const { data: subscription } = useProjectSubscriptionV2Query({ projectRef }) const plan = subscription?.plan?.id @@ -45,8 +46,8 @@ const UpgradeToPro: FC = ({ icon, primaryText, projectRef, secondaryText - - + + + ) } @@ -451,72 +636,21 @@ export default async function Login() { -```tsx app/login.ts -import { createServerActionClient } from '@supabase/auth-helpers-nextjs' -import { revalidatePath } from 'next/cache' -import { cookies } from 'next/headers' - -import type { Database } from '@/lib/database.types' - -export const dynamic = 'force-dynamic' - -export default async function Login() { - const handleSignUp = async (formData: FormData) => { - 'use server' - const email = String(formData.get('email')) - const password = String(formData.get('password')) - - const supabase = createServerActionClient({ cookies }) - await supabase.auth.signUp({ - email, - password, - options: { - emailRedirectTo: 'http://localhost:3000/auth/callback', - }, - }) - - revalidatePath('/') - } - - const handleSignIn = async (formData: FormData) => { - 'use server' - const email = String(formData.get('email')) - const password = String(formData.get('password')) - - const supabase = createServerActionClient({ cookies }) - await supabase.auth.signInWithPassword({ - email, - password, - }) - - revalidatePath('/') - } - - const handleSignOut = async () => { - 'use server' - const supabase = createServerActionClient({ cookies }) - await supabase.auth.signOut() - revalidatePath('/') - } - +```tsx app/login.tsx +export default function Login() { return ( -
    + + + - - - + +
    ) } ``` - - -TypeScript types can be [generated with the Supabase CLI](/docs/reference/javascript/typescript-support) and passed to `createServerActionClient` to add type support to the Supabase client. - - -
    @@ -817,7 +951,7 @@ TypeScript types can be [generated with the Supabase CLI](/docs/reference/javasc > -```jsx app/api/todos/route.jsx +```jsx app/api/todos/route.js import { createRouteHandlerClient } from '@supabase/auth-helpers-nextjs' import { NextResponse } from 'next/server' import { cookies } from 'next/headers' @@ -836,7 +970,7 @@ export async function POST(request) { -```tsx app/api/todos/route.tsx +```tsx app/api/todos/route.ts import { createRouteHandlerClient } from '@supabase/auth-helpers-nextjs' import { NextResponse } from 'next/server' import { cookies } from 'next/headers' @@ -914,10 +1048,10 @@ import type { Database } from '@/lib/database.types' export const runtime = 'edge' export const dynamic = 'force-dynamic' -export default async function ServerComponent() { +export default async function Page() { const cookieStore = cookies() - const supabase = createServerComponentClient({ + const supabase = createServerComponentClient({ cookies: () => cookieStore, }) @@ -945,7 +1079,7 @@ TypeScript types can be [generated with the Supabase CLI](/docs/reference/javasc > -```jsx app/api/todos/route.jsx +```jsx app/api/todos/route.js import { createRouteHandlerClient } from '@supabase/auth-helpers-nextjs' import { NextResponse } from 'next/server' import { cookies } from 'next/headers' @@ -970,7 +1104,7 @@ export async function POST(request) { -```tsx app/api/todos/route.tsx +```tsx app/api/todos/route.ts import { createRouteHandlerClient } from '@supabase/auth-helpers-nextjs' import { NextResponse } from 'next/server' import { cookies } from 'next/headers' @@ -1052,7 +1186,7 @@ export default async function Page() { -TypeScript types can be [generated with the Supabase CLI](/docs/reference/javascript/typescript-support) and passed to `createServerComponentClient` to add type support to the Supabase client. +TypeScript types can be [generated with the Supabase CLI](/docs/reference/javascript/typescript-support) and passed to `createClient` to add type support to the Supabase client. @@ -1069,7 +1203,7 @@ TypeScript types can be [generated with the Supabase CLI](/docs/reference/javasc > -```jsx app/api/todos/route.jsx +```jsx app/api/todos/route.js import { createClient } from '@supabase/supabase-js' import { NextResponse } from 'next/server' @@ -1090,7 +1224,7 @@ export async function POST(request) { -```tsx app/api/todos/route.tsx +```tsx app/api/todos/route.ts import { createClient } from '@supabase/supabase-js' import { NextResponse } from 'next/server' @@ -1111,7 +1245,7 @@ export async function POST(request: Request) { -TypeScript types can be [generated with the Supabase CLI](/docs/reference/javascript/typescript-support) and passed to `createRouteHandlerClient` to add type support to the Supabase client. +TypeScript types can be [generated with the Supabase CLI](/docs/reference/javascript/typescript-support) and passed to `createClient` to add type support to the Supabase client. From f0f07fbeb83407ae116c302eb24eb28a764778ee Mon Sep 17 00:00:00 2001 From: Alaister Young Date: Tue, 1 Aug 2023 13:17:13 +1000 Subject: [PATCH 47/61] Update studio/components/interfaces/Organization/IntegrationSettings/Integration.tsx Co-authored-by: Joshen Lim --- .../interfaces/Organization/IntegrationSettings/Integration.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/studio/components/interfaces/Organization/IntegrationSettings/Integration.tsx b/studio/components/interfaces/Organization/IntegrationSettings/Integration.tsx index c86012940a2..ffd8d671337 100644 --- a/studio/components/interfaces/Organization/IntegrationSettings/Integration.tsx +++ b/studio/components/interfaces/Organization/IntegrationSettings/Integration.tsx @@ -170,7 +170,7 @@ const IntegrationConnectionItem = ({ onSelectConfirm={onConfirm} > -

    +

    {`This action cannot be undone. Are you sure you want to delete this connection?`}

    From 6d5d0cb723e12fea1c3fd8df6d8bc466d401648c Mon Sep 17 00:00:00 2001 From: Alaister Young Date: Tue, 1 Aug 2023 15:48:09 +1000 Subject: [PATCH 48/61] move icons into files --- .../GitHubIntegrationWindowLayout.tsx | 15 +++++++-------- .../VercelIntegrationWindowLayout.tsx | 8 ++++---- .../github/[integrationId]/choose-project.tsx | 19 +++++++++---------- .../[slug]/marketplace/choose-project.tsx | 4 +--- studio/public/img/icons/vercel-icon.svg | 4 ++++ 5 files changed, 25 insertions(+), 25 deletions(-) create mode 100644 studio/public/img/icons/vercel-icon.svg diff --git a/studio/components/layouts/IntegrationsLayout/GitHubIntegrationWindowLayout.tsx b/studio/components/layouts/IntegrationsLayout/GitHubIntegrationWindowLayout.tsx index f2de6a343e0..f08a6ca6c0e 100644 --- a/studio/components/layouts/IntegrationsLayout/GitHubIntegrationWindowLayout.tsx +++ b/studio/components/layouts/IntegrationsLayout/GitHubIntegrationWindowLayout.tsx @@ -1,16 +1,15 @@ import { PropsWithChildren } from 'react' + +import { BASE_PATH } from 'lib/constants' import IntegrationWindowLayout from './IntegrationWindowLayout' const GITHUB_ICON = (
    - - - + GitHub Icon
    ) diff --git a/studio/components/layouts/IntegrationsLayout/VercelIntegrationWindowLayout.tsx b/studio/components/layouts/IntegrationsLayout/VercelIntegrationWindowLayout.tsx index bcc7ef55adb..a70e1ef9bae 100644 --- a/studio/components/layouts/IntegrationsLayout/VercelIntegrationWindowLayout.tsx +++ b/studio/components/layouts/IntegrationsLayout/VercelIntegrationWindowLayout.tsx @@ -1,12 +1,12 @@ -import { useParams } from 'common' import { PropsWithChildren } from 'react' + +import { useParams } from 'common' +import { BASE_PATH } from 'lib/constants' import IntegrationWindowLayout from './IntegrationWindowLayout' const VERCEL_ICON = (
    - - - + Vercel Icon
    ) diff --git a/studio/pages/integrations/github/[integrationId]/choose-project.tsx b/studio/pages/integrations/github/[integrationId]/choose-project.tsx index 0d274a676a5..cf3fbdb6be3 100644 --- a/studio/pages/integrations/github/[integrationId]/choose-project.tsx +++ b/studio/pages/integrations/github/[integrationId]/choose-project.tsx @@ -1,3 +1,6 @@ +import { useRouter } from 'next/router' +import { useMemo } from 'react' + import { useParams } from 'common' import ProjectLinker from 'components/interfaces/Integrations/ProjectLinker' import { Markdown } from 'components/interfaces/Markdown' @@ -8,21 +11,17 @@ import { useGitHubReposQuery } from 'data/integrations/integrations-github-repos import { useIntegrationsQuery } from 'data/integrations/integrations-query' import { useOrganizationsQuery } from 'data/organizations/organizations-query' import { useProjectsQuery } from 'data/projects/projects-query' +import { BASE_PATH } from 'lib/constants' import { EMPTY_ARR } from 'lib/void' -import { useRouter } from 'next/router' -import { useMemo } from 'react' import { NextPageWithLayout } from 'types' import { IconBook, IconLifeBuoy, LoadingLine } from 'ui' const GITHUB_ICON = ( - - - + GitHub Icon ) const ChooseProjectGitHubPage: NextPageWithLayout = () => { diff --git a/studio/pages/integrations/vercel/[slug]/marketplace/choose-project.tsx b/studio/pages/integrations/vercel/[slug]/marketplace/choose-project.tsx index 02228325215..9e302c67622 100644 --- a/studio/pages/integrations/vercel/[slug]/marketplace/choose-project.tsx +++ b/studio/pages/integrations/vercel/[slug]/marketplace/choose-project.tsx @@ -21,9 +21,7 @@ import { NextPageWithLayout, Organization } from 'types' import { IconBook, IconLifeBuoy, LoadingLine } from 'ui' const VERCEL_ICON = ( - - - + Vercel Icon ) const VercelIntegration: NextPageWithLayout = () => { diff --git a/studio/public/img/icons/vercel-icon.svg b/studio/public/img/icons/vercel-icon.svg new file mode 100644 index 00000000000..ff2881f0c67 --- /dev/null +++ b/studio/public/img/icons/vercel-icon.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file From e111c67f9f471d2a62de97cdc4f29de158981394 Mon Sep 17 00:00:00 2001 From: Alaister Young Date: Tue, 1 Aug 2023 16:27:26 +1000 Subject: [PATCH 49/61] update github integration queries --- .../IntegrationsLayout/Integrations.utils.ts | 4 +- studio/data/api.d.ts | 243 +++++++++++++++--- .../github-integration-create-mutation.ts | 14 +- ...tions-github-connection-delete-mutation.ts | 17 +- ...ions-github-connections-create-mutation.ts | 32 ++- .../integrations-github-repos-query.ts | 32 ++- .../integrations-query-org-only.ts | 5 +- .../data/integrations/integrations-query.ts | 19 +- .../github/[integrationId]/choose-project.tsx | 10 +- studio/pages/integrations/github/install.tsx | 2 +- .../[slug]/deploy-button/new-project.tsx | 5 +- studio/pages/integrations/vercel/install.tsx | 8 +- 12 files changed, 301 insertions(+), 90 deletions(-) diff --git a/studio/components/layouts/IntegrationsLayout/Integrations.utils.ts b/studio/components/layouts/IntegrationsLayout/Integrations.utils.ts index 3bedace7fac..0d19f996f5c 100644 --- a/studio/components/layouts/IntegrationsLayout/Integrations.utils.ts +++ b/studio/components/layouts/IntegrationsLayout/Integrations.utils.ts @@ -1,4 +1,4 @@ -import { IntegrationsResponse } from 'data/integrations/integrations-query' +import { IntegrationsData } from 'data/integrations/integrations-query' import { IntegrationName } from 'data/integrations/integrations.types' import { Organization } from 'types' @@ -9,7 +9,7 @@ export function getHasInstalledObject({ installationId, }: { integrationName: IntegrationName - integrationData: IntegrationsResponse + integrationData: IntegrationsData organizationsData: Organization[] installationId?: string | number }): { [orgSlug: string]: boolean } { diff --git a/studio/data/api.d.ts b/studio/data/api.d.ts index ebb7e809177..b324c448314 100644 --- a/studio/data/api.d.ts +++ b/studio/data/api.d.ts @@ -396,6 +396,8 @@ export interface paths { "/platform/projects/{ref}/content": { /** Gets project's content */ get: operations["ContentController_getContent"]; + /** Updates project's content */ + put: operations["ContentController_updateWholeContent"]; /** Creates project's content */ post: operations["ContentController_createContent"]; /** Deletes project's content */ @@ -1084,6 +1086,8 @@ export interface paths { "/v0/projects/{ref}/content": { /** Gets project's content */ get: operations["ContentController_getContent"]; + /** Updates project's content */ + put: operations["ContentController_updateWholeContent"]; /** Creates project's content */ post: operations["ContentController_createContent"]; /** Deletes project's content */ @@ -1275,7 +1279,7 @@ export interface paths { /** Deletes objects */ delete: operations["StorageObjectsController_deleteObjects"]; }; - "/v1/branch/{branch_id}": { + "/v1/branches/{branch_id}": { /** * Get database branch config * @description Fetches configurations of the specified database branch @@ -1367,7 +1371,7 @@ export interface paths { /** Updates project's postgrest config */ patch: operations["PostgrestConfigController_updatePostgRESTConfig"]; }; - "/v1/projects/{ref}/query": { + "/v1/projects/{ref}/database/query": { /** Run sql query */ post: operations["QueryController_runQuery"]; }; @@ -1513,7 +1517,6 @@ export interface paths { post: operations["OAuthAppsController_createOAuthApp"]; }; "/v1/organizations/{slug}/oauth/apps/{id}": { - get: operations["OAuthAppsController_getOAuthApp"]; /** Update an oauth app */ put: operations["OAuthAppsController_updateOAuthApp"]; /** Remove a published oauth app */ @@ -1637,7 +1640,8 @@ export interface components { SMTP_HOST: string; SMTP_PORT: string; SMTP_USER: string; - SMTP_PASS: string; + SMTP_PASS?: string | null; + SMTP_PASS_ENCRYPTED?: string | null; SMTP_MAX_FREQUENCY: number; MAILER_AUTOCONFIRM: boolean; MAILER_URLPATHS_INVITE: string; @@ -1712,7 +1716,6 @@ export interface components { EXTERNAL_SLACK_SECRET: string; SMS_MESSAGEBIRD_ACCESS_KEY: string; SMS_MESSAGEBIRD_ORIGINATOR: string; - SMTP_PASS_ENCRYPTED: string; REFRESH_TOKEN_ROTATION_ENABLED: boolean; EXTERNAL_LINKEDIN_ENABLED: boolean; EXTERNAL_LINKEDIN_CLIENT_ID: string; @@ -1777,7 +1780,8 @@ export interface components { SMTP_HOST: string; SMTP_PORT: string; SMTP_USER: string; - SMTP_PASS: string; + SMTP_PASS?: string | null; + SMTP_PASS_ENCRYPTED?: string | null; SMTP_MAX_FREQUENCY: number; MAILER_AUTOCONFIRM: boolean; MAILER_URLPATHS_INVITE: string; @@ -1852,7 +1856,6 @@ export interface components { EXTERNAL_SLACK_SECRET: string; SMS_MESSAGEBIRD_ACCESS_KEY: string; SMS_MESSAGEBIRD_ORIGINATOR: string; - SMTP_PASS_ENCRYPTED: string; REFRESH_TOKEN_ROTATION_ENABLED: boolean; EXTERNAL_LINKEDIN_ENABLED: boolean; EXTERNAL_LINKEDIN_CLIENT_ID: string; @@ -1917,7 +1920,8 @@ export interface components { SMTP_HOST: string; SMTP_PORT: string; SMTP_USER: string; - SMTP_PASS: string; + SMTP_PASS?: string | null; + SMTP_PASS_ENCRYPTED?: string | null; SMTP_MAX_FREQUENCY: number; MAILER_AUTOCONFIRM: boolean; MAILER_URLPATHS_INVITE: string; @@ -1992,7 +1996,6 @@ export interface components { EXTERNAL_SLACK_SECRET: string; SMS_MESSAGEBIRD_ACCESS_KEY: string; SMS_MESSAGEBIRD_ORIGINATOR: string; - SMTP_PASS_ENCRYPTED: string; REFRESH_TOKEN_ROTATION_ENABLED: boolean; EXTERNAL_LINKEDIN_ENABLED: boolean; EXTERNAL_LINKEDIN_CLIENT_ID: string; @@ -3023,6 +3026,7 @@ export interface components { status: string; subscription_id: string; is_readonly_mode_enabled?: boolean; + preview_branch_refs: (string)[]; }; AmiSearchOptions: { search_tags?: Record; @@ -3062,10 +3066,34 @@ export interface components { status: string; subscription_id: string; is_readonly_mode_enabled?: boolean; + preview_branch_refs: (string)[]; endpoint: string; anon_key: string; service_key: string; }; + GetUserContentObject: { + owner: { + id?: number; + username?: string; + }; + updated_by: { + id?: number; + username?: string; + }; + id: string; + inserted_at: string; + updated_at: string; + type: Record; + visibility: Record; + name: string; + description?: string; + project_id: number; + owner_id: number; + last_updated_by: number; + }; + GetUserContentResponse: { + data: (components["schemas"]["GetUserContentObject"])[]; + }; CreateContentParams: { id: string; name: string; @@ -3077,6 +3105,30 @@ export interface components { content?: Record; owner_id?: number; }; + UserContentObject: { + id: string; + inserted_at: string; + updated_at: string; + type: Record; + visibility: Record; + name: string; + description?: string; + project_id: number; + owner_id: number; + last_updated_by: number; + }; + UpsertContentParams: { + id: string; + name: string; + description: string; + /** @enum {string} */ + type: "sql" | "report" | "log_sql"; + /** @enum {string} */ + visibility: "user" | "project" | "org" | "public"; + content?: Record; + owner_id?: number; + project_id: number; + }; UpdateContentParams: { id?: string; name?: string; @@ -3104,6 +3156,7 @@ export interface components { id: string; name: string; project_ref: string; + parent_project_ref: string; is_default: boolean; git_branch: string; created_at: string; @@ -3130,6 +3183,7 @@ export interface components { maxDatabasePreprovisionGb?: number; lastDatabaseResizeAt?: string; preview_branches: (components["schemas"]["BranchResponse"])[]; + parent_project_ref?: string; }; ProjectRefResponse: { id: number; @@ -3154,7 +3208,7 @@ export interface components { back_ups: (components["schemas"]["BackupId"])[]; }; RestartServiceRequest: { - services: ("adminapi" | "api-gateway" | "functions" | "gotrue" | "kong" | "pgbouncer" | "pgsodium" | "postgresql" | "postgrest" | "realtime" | "storage" | "walg")[]; + services: ("adminapi" | "api-gateway" | "functions" | "gotrue" | "kong" | "pgbouncer" | "pgsodium" | "postgresql" | "postgrest" | "realtime" | "storage" | "walg" | "autoshutdown")[]; source_notification_id?: string; region: string; }; @@ -3219,6 +3273,11 @@ export interface components { name: string; limit: number; }; + PreviewTransferInvoiceItem: { + description: string; + quantity: number; + amount: number; + }; PreviewProjectTransferResponse: { valid: boolean; warnings: (components["schemas"]["PreviewTransferInfo"])[]; @@ -3234,6 +3293,8 @@ export interface components { charge_on_target_organization: number; source_subscription_plan: Record; target_subscription_plan: Record | null; + source_invoice_items: (components["schemas"]["PreviewTransferInvoiceItem"])[]; + target_invoice_items: (components["schemas"]["PreviewTransferInvoiceItem"])[]; }; AnalyticsResponse: { error?: OneOf<[{ @@ -3266,6 +3327,7 @@ export interface components { /** @enum {string} */ pool_mode: "transaction" | "session" | "statement"; max_client_conn?: number | null; + connectionString: string; }; UpdatePgbouncerConfigBody: { default_pool_size?: number; @@ -4143,19 +4205,56 @@ export interface components { created_at?: string; updated_at?: string; }; + OAuthAppResponse: { + id: string; + name: string; + website: string; + icon?: string; + authorized_at?: string; + created_at?: string; + client_id?: string; + client_secret_alias?: string; + redirect_uris?: (string)[]; + }; CreateOAuthAppBody: { name: string; website: string; icon?: string; redirect_uris: (string)[]; }; - UpdateOAuthAppBody: { + CreateOAuthAppResponse: { + id: string; + client_id: string; + client_secret: string; + }; + PutOAuthAppResponse: { + id: string; + client_id: string; + client_secret_alias: string; + created_at: string; name: string; website: string; - redirect_uris: (string)[]; icon?: string; + redirect_uris: (string)[]; }; - TokenDTO: { + RevokeAuthorizedOAuthAppResponse: { + id: string; + name: string; + website: string; + icon?: string; + authorized_at: string; + }; + DeleteOAuthAppResponse: { + id: string; + name: string; + website: string; + icon?: string; + created_at: string; + client_id: string; + client_secret_alias: string; + redirect_uris: (string)[]; + }; + OAuthTokenBody: { /** @enum {string} */ grant_type: "authorization_code" | "refresh_token"; client_id: string; @@ -4165,9 +4264,31 @@ export interface components { redirect_uri?: string; refresh_token?: string; }; + OAuthTokenResponse: { + /** @enum {string} */ + token_type: "Bearer"; + access_token: string; + refresh_token: string; + expires_in: number; + }; + GetAuthorizationResponse: { + name: string; + website: string; + icon?: string; + domain: string; + expires_at: string; + approved_at?: string; + approved_organization_slug?: string; + }; AuthorizationsApproveBody: { organization_id: string; }; + ApproveAuthorizationResponse: { + url: string; + }; + DeclineAuthorizationResponse: { + id: string; + }; }; responses: never; parameters: never; @@ -6794,11 +6915,38 @@ export interface operations { }; }; responses: { - 200: never; + 200: { + content: { + "application/json": components["schemas"]["GetUserContentResponse"]; + }; + }; /** @description Failed to retrieve project's content */ 500: never; }; }; + /** Updates project's content */ + ContentController_updateWholeContent: { + parameters: { + path: { + /** @description Project ref */ + ref: string; + }; + }; + requestBody: { + content: { + "application/json": components["schemas"]["UpsertContentParams"]; + }; + }; + responses: { + 200: { + content: { + "application/json": components["schemas"]["UserContentObject"]; + }; + }; + /** @description Failed to update project's content */ + 500: never; + }; + }; /** Creates project's content */ ContentController_createContent: { parameters: { @@ -6815,7 +6963,7 @@ export interface operations { responses: { 201: { content: { - "application/json": (Record)[]; + "application/json": (components["schemas"]["UserContentObject"])[]; }; }; /** @description Failed to create project's content */ @@ -6832,7 +6980,7 @@ export interface operations { responses: { 200: { content: { - "application/json": Record; + "application/json": components["schemas"]["UserContentObject"]; }; }; /** @description Failed to delete project's content */ @@ -6854,7 +7002,7 @@ export interface operations { responses: { 200: { content: { - "application/json": (Record)[]; + "application/json": (components["schemas"]["UserContentObject"])[]; }; }; /** @description Failed to update project's content */ @@ -9839,7 +9987,7 @@ export interface operations { responses: { 200: { content: { - "application/json": Record; + "application/json": (components["schemas"]["OAuthAppResponse"])[]; }; }; }; @@ -9857,12 +10005,11 @@ export interface operations { }; }; responses: { - 201: never; - }; - }; - OAuthAppsController_getOAuthApp: { - responses: { - 200: never; + 201: { + content: { + "application/json": components["schemas"]["CreateOAuthAppResponse"]; + }; + }; }; }; /** Update an oauth app */ @@ -9875,11 +10022,15 @@ export interface operations { }; requestBody: { content: { - "application/json": components["schemas"]["UpdateOAuthAppBody"]; + "application/json": components["schemas"]["CreateOAuthAppBody"]; }; }; responses: { - 200: never; + 200: { + content: { + "application/json": components["schemas"]["PutOAuthAppResponse"]; + }; + }; }; }; /** Remove a published oauth app */ @@ -9891,7 +10042,11 @@ export interface operations { }; }; responses: { - 200: never; + 200: { + content: { + "application/json": components["schemas"]["DeleteOAuthAppResponse"]; + }; + }; }; }; /** Revoke an authorized oauth app */ @@ -9903,7 +10058,11 @@ export interface operations { }; }; responses: { - 201: never; + 201: { + content: { + "application/json": components["schemas"]["RevokeAuthorizedOAuthAppResponse"]; + }; + }; }; }; /** Authorize user through oauth */ @@ -9921,18 +10080,22 @@ export interface operations { }; }; responses: { - 200: never; + 303: never; }; }; /** Exchange auth code for user's access and refresh token */ OAuthController_token: { requestBody: { content: { - "application/x-www-form-urlencoded": components["schemas"]["TokenDTO"]; + "application/x-www-form-urlencoded": components["schemas"]["OAuthTokenBody"]; }; }; responses: { - 201: never; + 201: { + content: { + "application/json": components["schemas"]["OAuthTokenResponse"]; + }; + }; }; }; AuthorizationsController_getAuthorizationRequest: { @@ -9942,7 +10105,11 @@ export interface operations { }; }; responses: { - 200: never; + 200: { + content: { + "application/json": components["schemas"]["GetAuthorizationResponse"]; + }; + }; }; }; /** Approve oauth app authorization request */ @@ -9958,7 +10125,11 @@ export interface operations { }; }; responses: { - 201: never; + 201: { + content: { + "application/json": components["schemas"]["ApproveAuthorizationResponse"]; + }; + }; }; }; /** Decline oauth app authorization request */ @@ -9969,7 +10140,11 @@ export interface operations { }; }; responses: { - 200: never; + 200: { + content: { + "application/json": components["schemas"]["DeclineAuthorizationResponse"]; + }; + }; }; }; } diff --git a/studio/data/integrations/github-integration-create-mutation.ts b/studio/data/integrations/github-integration-create-mutation.ts index 668e2880e4b..6b03c5ce22c 100644 --- a/studio/data/integrations/github-integration-create-mutation.ts +++ b/studio/data/integrations/github-integration-create-mutation.ts @@ -1,6 +1,8 @@ import { useMutation, UseMutationOptions, useQueryClient } from '@tanstack/react-query' +import { toast } from 'react-hot-toast' import { post } from 'data/fetchers' +import { ResponseError } from 'types' import { integrationKeys } from './keys' export type GitHubIntegrationCreateVariables = { @@ -30,13 +32,14 @@ type GitHubIntegrationCreateData = Awaited, + UseMutationOptions, 'mutationFn' > = {}) => { const queryClient = useQueryClient() - return useMutation( + return useMutation( (vars) => createGitHubIntegration(vars), { async onSuccess(data, variables, context) { @@ -47,6 +50,13 @@ export const useGitHubIntegrationCreateMutation = ({ ]) await onSuccess?.(data, variables, context) }, + async onError(data, variables, context) { + if (onError === undefined) { + toast.error(`Failed to mutate: ${data.message}`) + } else { + onError(data, variables, context) + } + }, ...options, } ) diff --git a/studio/data/integrations/integrations-github-connection-delete-mutation.ts b/studio/data/integrations/integrations-github-connection-delete-mutation.ts index f61d2495a13..0a1160fe359 100644 --- a/studio/data/integrations/integrations-github-connection-delete-mutation.ts +++ b/studio/data/integrations/integrations-github-connection-delete-mutation.ts @@ -1,6 +1,8 @@ import { useMutation, UseMutationOptions, useQueryClient } from '@tanstack/react-query' +import { toast } from 'react-hot-toast' import { del } from 'data/fetchers' +import { ResponseError } from 'types' import { integrationKeys } from './keys' type DeleteVariables = { @@ -23,10 +25,14 @@ type DeleteContentData = Awaited> export const useIntegrationsGitHubInstalledConnectionDeleteMutation = ({ onSuccess, + onError, ...options -}: Omit, 'mutationFn'> = {}) => { +}: Omit< + UseMutationOptions, + 'mutationFn' +> = {}) => { const queryClient = useQueryClient() - return useMutation( + return useMutation( (args) => deleteConnection(args), { async onSuccess(data, variables, context) { @@ -40,6 +46,13 @@ export const useIntegrationsGitHubInstalledConnectionDeleteMutation = ({ ]) await onSuccess?.(data, variables, context) }, + async onError(data, variables, context) { + if (onError === undefined) { + toast.error(`Failed to mutate: ${data.message}`) + } else { + onError(data, variables, context) + } + }, ...options, } ) diff --git a/studio/data/integrations/integrations-github-connections-create-mutation.ts b/studio/data/integrations/integrations-github-connections-create-mutation.ts index 6a924b9e509..5f532ac4437 100644 --- a/studio/data/integrations/integrations-github-connections-create-mutation.ts +++ b/studio/data/integrations/integrations-github-connections-create-mutation.ts @@ -1,6 +1,8 @@ import { useMutation, UseMutationOptions, useQueryClient } from '@tanstack/react-query' -import { post } from 'lib/common/fetch' -import { API_URL } from 'lib/constants' +import { toast } from 'react-hot-toast' + +import { post } from 'data/fetchers' +import { ResponseError } from 'types' import { integrationKeys } from './keys' import { IntegrationConnectionsCreateVariables } from './types' @@ -8,15 +10,17 @@ export async function createIntegrationGitHubConnections({ organizationIntegrationId, connection, }: IntegrationConnectionsCreateVariables) { - const response = await post(`${API_URL}/integrations/github/connections`, { - organization_integration_id: organizationIntegrationId, - connection, + const { data, error } = await post('/platform/integrations/github/connections', { + body: { + organization_integration_id: organizationIntegrationId, + connection, + }, }) - if (response.error) { - throw response.error + if (error) { + throw error } - return response + return data } export type IntegrationGitHubConnectionsCreateData = Awaited< @@ -25,11 +29,12 @@ export type IntegrationGitHubConnectionsCreateData = Awaited< export const useIntegrationGitHubConnectionsCreateMutation = ({ onSuccess, + onError, ...options }: Omit< UseMutationOptions< IntegrationGitHubConnectionsCreateData, - unknown, + ResponseError, IntegrationConnectionsCreateVariables >, 'mutationFn' @@ -37,7 +42,7 @@ export const useIntegrationGitHubConnectionsCreateMutation = ({ const queryClient = useQueryClient() return useMutation< IntegrationGitHubConnectionsCreateData, - unknown, + ResponseError, IntegrationConnectionsCreateVariables >((vars) => createIntegrationGitHubConnections(vars), { async onSuccess(data, variables, context) { @@ -53,6 +58,13 @@ export const useIntegrationGitHubConnectionsCreateMutation = ({ ]) await onSuccess?.(data, variables, context) }, + async onError(data, variables, context) { + if (onError === undefined) { + toast.error(`Failed to mutate: ${data.message}`) + } else { + onError(data, variables, context) + } + }, ...options, }) } diff --git a/studio/data/integrations/integrations-github-repos-query.ts b/studio/data/integrations/integrations-github-repos-query.ts index 5bbc2be894c..ea09b8be7f8 100644 --- a/studio/data/integrations/integrations-github-repos-query.ts +++ b/studio/data/integrations/integrations-github-repos-query.ts @@ -1,17 +1,13 @@ import { useQuery, UseQueryOptions } from '@tanstack/react-query' -import { get } from 'lib/common/fetch' -import { API_URL } from 'lib/constants' + +import { get } from 'data/fetchers' +import { ResponseError } from 'types' import { integrationKeys } from './keys' export type GitHubReposVariables = { integrationId: string | undefined } -export type GitHubReposResponse = { - id: number - full_name: string -} - export async function getGitHubRepos( { integrationId }: GitHubReposVariables, signal?: AbortSignal @@ -20,18 +16,26 @@ export async function getGitHubRepos( throw new Error('integrationId is required') } - const response = await get(`${API_URL}/integrations/github/repos/${integrationId}`, { - signal, - }) - if (response.error) { - throw response.error + const { data, error } = await get( + '/platform/integrations/github/repos/{organization_integration_id}', + { + params: { + path: { + organization_integration_id: integrationId, + }, + }, + signal, + } + ) + if (error) { + throw error } - return response as GitHubReposResponse[] + return data } export type GitHubReposData = Awaited> -export type GitHubReposError = unknown +export type GitHubReposError = ResponseError export const useGitHubReposQuery = ( { integrationId }: GitHubReposVariables, diff --git a/studio/data/integrations/integrations-query-org-only.ts b/studio/data/integrations/integrations-query-org-only.ts index 664f4aced96..6db941d69bc 100644 --- a/studio/data/integrations/integrations-query-org-only.ts +++ b/studio/data/integrations/integrations-query-org-only.ts @@ -1,8 +1,9 @@ -import { useQuery, useQueryClient, UseQueryOptions } from '@tanstack/react-query' +import { useQuery, UseQueryOptions } from '@tanstack/react-query' + import { get } from 'lib/common/fetch' import { API_URL } from 'lib/constants' +import { Integration, IntegrationsVariables } from './integrations.types' import { integrationKeys } from './keys' -import { IntegrationsVariables, Integration } from './integrations.types' export type IntegrationsResponse = Integration[] diff --git a/studio/data/integrations/integrations-query.ts b/studio/data/integrations/integrations-query.ts index 4549f2d6bf0..9ec6b5a0353 100644 --- a/studio/data/integrations/integrations-query.ts +++ b/studio/data/integrations/integrations-query.ts @@ -1,25 +1,24 @@ import { useQuery, UseQueryOptions } from '@tanstack/react-query' -import { get } from 'lib/common/fetch' -import { API_URL } from 'lib/constants' -import { Integration } from './integrations.types' + +import { get } from 'data/fetchers' +import { ResponseError } from 'types' import { integrationKeys } from './keys' -export type IntegrationsResponse = Integration[] - export async function getIntegrations(signal?: AbortSignal) { - const response = await get(`${API_URL}/integrations`, { + const { data, error } = await get('/platform/integrations', { + params: { query: { integration_name: '' } }, signal, }) - if (response.error) { - throw response.error + if (error) { + throw error } - return response as IntegrationsResponse + return data } export type IntegrationsData = Awaited> export type ProjectIntegrationConnectionsData = Awaited> -export type IntegrationsError = unknown +export type IntegrationsError = ResponseError export const useIntegrationsQuery = ({ enabled = true, diff --git a/studio/pages/integrations/github/[integrationId]/choose-project.tsx b/studio/pages/integrations/github/[integrationId]/choose-project.tsx index cf3fbdb6be3..2bf35deb49b 100644 --- a/studio/pages/integrations/github/[integrationId]/choose-project.tsx +++ b/studio/pages/integrations/github/[integrationId]/choose-project.tsx @@ -8,7 +8,7 @@ import GitHubIntegrationWindowLayout from 'components/layouts/IntegrationsLayout import { ScaffoldContainer, ScaffoldDivider } from 'components/layouts/Scaffold' import { useIntegrationGitHubConnectionsCreateMutation } from 'data/integrations/integrations-github-connections-create-mutation' import { useGitHubReposQuery } from 'data/integrations/integrations-github-repos-query' -import { useIntegrationsQuery } from 'data/integrations/integrations-query' +import { useOrgIntegrationsQuery } from 'data/integrations/integrations-query-org-only' import { useOrganizationsQuery } from 'data/organizations/organizations-query' import { useProjectsQuery } from 'data/projects/projects-query' import { BASE_PATH } from 'lib/constants' @@ -26,15 +26,17 @@ const GITHUB_ICON = ( const ChooseProjectGitHubPage: NextPageWithLayout = () => { const router = useRouter() - const { integrationId } = useParams() + const { integrationId, slug, organizationSlug } = useParams() + const orgSlug = slug ?? organizationSlug - const { data: integrations } = useIntegrationsQuery() + const { data: integrations } = useOrgIntegrationsQuery({ + orgSlug, + }) const { data: organizations } = useOrganizationsQuery() const { data: allProjects } = useProjectsQuery() const { data: allRepos } = useGitHubReposQuery({ integrationId }) const integration = integrations?.find((integration) => integration.id === integrationId) - const orgSlug = integration?.organization.slug const organization = organizations?.find((organization) => organization.slug === orgSlug) const projects = useMemo( () => diff --git a/studio/pages/integrations/github/install.tsx b/studio/pages/integrations/github/install.tsx index a6ee6256a4a..e79813ce15b 100644 --- a/studio/pages/integrations/github/install.tsx +++ b/studio/pages/integrations/github/install.tsx @@ -55,7 +55,7 @@ const GitHubIntegration: NextPageWithLayout = () => { router.push({ pathname: `/integrations/github/${id}/choose-project`, - query: router.query, + query: { ...router.query, slug: selectedOrg?.slug }, }) }, onError(error: any) { diff --git a/studio/pages/integrations/vercel/[slug]/deploy-button/new-project.tsx b/studio/pages/integrations/vercel/[slug]/deploy-button/new-project.tsx index b0a8b6806ae..248126f21ff 100644 --- a/studio/pages/integrations/vercel/[slug]/deploy-button/new-project.tsx +++ b/studio/pages/integrations/vercel/[slug]/deploy-button/new-project.tsx @@ -13,7 +13,6 @@ import { useIntegrationsQuery } from 'data/integrations/integrations-query' import { useIntegrationsVercelConnectionSyncEnvsMutation } from 'data/integrations/integrations-vercel-connection-sync-envs-mutation' import { useIntegrationVercelConnectionsCreateMutation } from 'data/integrations/integrations-vercel-connections-create-mutation' import { useVercelProjectsQuery } from 'data/integrations/integrations-vercel-projects-query' -import { Integration } from 'data/integrations/integrations.types' import { useOrganizationsQuery } from 'data/organizations/organizations-query' import { useProjectCreateMutation } from 'data/projects/project-create-mutation' import { useSelectedOrganization, useStore } from 'hooks' @@ -108,9 +107,7 @@ const CreateProject = ({ /** * the vercel integration installed for organization chosen */ - const organizationIntegration: Integration | undefined = integrationData?.find( - (x) => x.organization.slug === slug - ) + const organizationIntegration = integrationData?.find((x) => x.organization.slug === slug) /** * Vercel projects available for this integration diff --git a/studio/pages/integrations/vercel/install.tsx b/studio/pages/integrations/vercel/install.tsx index 6df4078cf81..95419081f5b 100644 --- a/studio/pages/integrations/vercel/install.tsx +++ b/studio/pages/integrations/vercel/install.tsx @@ -1,5 +1,6 @@ import { useRouter } from 'next/router' import { useEffect, useMemo, useState } from 'react' +import { toast } from 'react-hot-toast' import { useParams } from 'common' import OrganizationPicker from 'components/interfaces/Integrations/OrganizationPicker' @@ -109,11 +110,8 @@ const VercelIntegration: NextPageWithLayout = () => { handleRouteChange() }, - onError(error: any) { - ui.setNotification({ - category: 'error', - message: `Creating Vercel integration failed: ${error.message}`, - }) + onError(error) { + toast.error(`Creating Vercel integration failed: ${error.message}`) }, }) From 45cdd2bba33f40ec91d80bd811bf9228466a5a31 Mon Sep 17 00:00:00 2001 From: Alaister Young Date: Tue, 1 Aug 2023 17:38:24 +1000 Subject: [PATCH 50/61] better error messages --- .../data/integrations/github-integration-create-mutation.ts | 2 +- .../integrations-github-connection-delete-mutation.ts | 2 +- .../integrations-github-connections-create-mutation.ts | 2 +- studio/pages/integrations/github/install.tsx | 6 ------ 4 files changed, 3 insertions(+), 9 deletions(-) diff --git a/studio/data/integrations/github-integration-create-mutation.ts b/studio/data/integrations/github-integration-create-mutation.ts index 6b03c5ce22c..6439bb68665 100644 --- a/studio/data/integrations/github-integration-create-mutation.ts +++ b/studio/data/integrations/github-integration-create-mutation.ts @@ -52,7 +52,7 @@ export const useGitHubIntegrationCreateMutation = ({ }, async onError(data, variables, context) { if (onError === undefined) { - toast.error(`Failed to mutate: ${data.message}`) + toast.error(`Failed to create Github integration: ${data.message}`) } else { onError(data, variables, context) } diff --git a/studio/data/integrations/integrations-github-connection-delete-mutation.ts b/studio/data/integrations/integrations-github-connection-delete-mutation.ts index 0a1160fe359..f3bd4f08cfd 100644 --- a/studio/data/integrations/integrations-github-connection-delete-mutation.ts +++ b/studio/data/integrations/integrations-github-connection-delete-mutation.ts @@ -48,7 +48,7 @@ export const useIntegrationsGitHubInstalledConnectionDeleteMutation = ({ }, async onError(data, variables, context) { if (onError === undefined) { - toast.error(`Failed to mutate: ${data.message}`) + toast.error(`Failed to delete Github connection: ${data.message}`) } else { onError(data, variables, context) } diff --git a/studio/data/integrations/integrations-github-connections-create-mutation.ts b/studio/data/integrations/integrations-github-connections-create-mutation.ts index 5f532ac4437..66133d432d5 100644 --- a/studio/data/integrations/integrations-github-connections-create-mutation.ts +++ b/studio/data/integrations/integrations-github-connections-create-mutation.ts @@ -60,7 +60,7 @@ export const useIntegrationGitHubConnectionsCreateMutation = ({ }, async onError(data, variables, context) { if (onError === undefined) { - toast.error(`Failed to mutate: ${data.message}`) + toast.error(`Failed to create Github connection: ${data.message}`) } else { onError(data, variables, context) } diff --git a/studio/pages/integrations/github/install.tsx b/studio/pages/integrations/github/install.tsx index e79813ce15b..54eca73be8c 100644 --- a/studio/pages/integrations/github/install.tsx +++ b/studio/pages/integrations/github/install.tsx @@ -58,12 +58,6 @@ const GitHubIntegration: NextPageWithLayout = () => { query: { ...router.query, slug: selectedOrg?.slug }, }) }, - onError(error: any) { - ui.setNotification({ - category: 'error', - message: `Creating GitHub integration failed: ${error.message}`, - }) - }, }) const installed = useMemo( From a49ec74cccb335c1a1d7d30fffbb34e223f4879e Mon Sep 17 00:00:00 2001 From: Alaister Young Date: Tue, 1 Aug 2023 17:41:01 +1000 Subject: [PATCH 51/61] fix spelling --- packages/ui/src/components/shadcn/stories/Select.stories.tsx | 2 +- studio/components/interfaces/Integrations/ProjectLinker.tsx | 2 +- studio/data/__templates/README.md | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/ui/src/components/shadcn/stories/Select.stories.tsx b/packages/ui/src/components/shadcn/stories/Select.stories.tsx index da44645c8b6..3a63c0598fc 100644 --- a/packages/ui/src/components/shadcn/stories/Select.stories.tsx +++ b/packages/ui/src/components/shadcn/stories/Select.stories.tsx @@ -51,7 +51,7 @@ export function Default() { ) } -export function withSeperators() { +export function withSeparators() { return (