mirror of
https://github.com/supabase/supabase.git
synced 2026-10-14 05:39:11 +03:00
Merge branch 'master' into feature/database-tests
This commit is contained in:
commit
b66d71dc02
489 files changed
+6547
-4952
No files matched your search
@@ -5,9 +5,6 @@
|
||||
|
||||
/apps/studio/ @supabase/Dashboard
|
||||
|
||||
# temporary until we've ironed out all the problems with sync workflow
|
||||
/apps/docs/content/troubleshooting/ @charislam
|
||||
|
||||
/apps/www/ @supabase/marketing
|
||||
/apps/www/public/images/blog @supabase/marketing
|
||||
/apps/www/lib/redirects.js
|
||||
|
||||
@@ -4,8 +4,8 @@ import {
|
||||
genGuidesStaticParams,
|
||||
} from '~/features/docs/GuidesMdx.utils'
|
||||
import { GuideTemplate } from '~/features/docs/GuidesMdx.template'
|
||||
|
||||
export const dynamicParams = false
|
||||
import { IS_PROD } from 'common'
|
||||
import { getEmptyArray } from '~/features/helpers.fn'
|
||||
|
||||
type Params = { slug?: string[] }
|
||||
|
||||
@@ -17,7 +17,7 @@ const AiGuidePage = async (props: { params: Promise<Params> }) => {
|
||||
return <GuideTemplate {...data!} />
|
||||
}
|
||||
|
||||
const generateStaticParams = genGuidesStaticParams('ai')
|
||||
const generateStaticParams = IS_PROD ? genGuidesStaticParams('ai') : getEmptyArray
|
||||
const generateMetadata = genGuideMeta((params: { slug?: string[] }) =>
|
||||
getGuidesMarkdown(['ai', ...(params.slug ?? [])])
|
||||
)
|
||||
|
||||
@@ -4,8 +4,8 @@ import {
|
||||
genGuidesStaticParams,
|
||||
} from '~/features/docs/GuidesMdx.utils'
|
||||
import { GuideTemplate } from '~/features/docs/GuidesMdx.template'
|
||||
|
||||
export const dynamicParams = false
|
||||
import { IS_PROD } from 'common'
|
||||
import { getEmptyArray } from '~/features/helpers.fn'
|
||||
|
||||
type Params = { slug?: string[] }
|
||||
|
||||
@@ -17,7 +17,7 @@ const ApiGuidePage = async (props: { params: Promise<Params> }) => {
|
||||
return <GuideTemplate {...data!} />
|
||||
}
|
||||
|
||||
const generateStaticParams = genGuidesStaticParams('api')
|
||||
const generateStaticParams = IS_PROD ? genGuidesStaticParams('api') : getEmptyArray
|
||||
const generateMetadata = genGuideMeta((params: { slug?: string[] }) =>
|
||||
getGuidesMarkdown(['api', ...(params.slug ?? [])])
|
||||
)
|
||||
|
||||
@@ -4,8 +4,8 @@ import {
|
||||
genGuidesStaticParams,
|
||||
} from '~/features/docs/GuidesMdx.utils'
|
||||
import { GuideTemplate } from '~/features/docs/GuidesMdx.template'
|
||||
|
||||
export const dynamicParams = false
|
||||
import { IS_PROD } from 'common'
|
||||
import { getEmptyArray } from '~/features/helpers.fn'
|
||||
|
||||
type Params = { slug?: string[] }
|
||||
|
||||
@@ -17,7 +17,7 @@ const AuthGuidePage = async (props: { params: Promise<Params> }) => {
|
||||
return <GuideTemplate {...data!} />
|
||||
}
|
||||
|
||||
const generateStaticParams = genGuidesStaticParams('auth')
|
||||
const generateStaticParams = IS_PROD ? genGuidesStaticParams('auth') : getEmptyArray
|
||||
const generateMetadata = genGuideMeta((params: { slug?: string[] }) =>
|
||||
getGuidesMarkdown(['auth', ...(params.slug ?? [])])
|
||||
)
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
import SectionTroubleshootingPage, {
|
||||
generateSectionTroubleshootingMetadata,
|
||||
} from '~/features/docs/TroubleshootingSection.page'
|
||||
|
||||
export default async function AuthTroubleshootingPage() {
|
||||
return (
|
||||
<SectionTroubleshootingPage
|
||||
topic="auth"
|
||||
sectionName="Auth"
|
||||
description="Search or browse troubleshooting guides for common authentication issues, including login problems, session management, and provider configuration."
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
export const metadata = generateSectionTroubleshootingMetadata('auth', 'Auth')
|
||||
@@ -4,8 +4,8 @@ import {
|
||||
genGuidesStaticParams,
|
||||
} from '~/features/docs/GuidesMdx.utils'
|
||||
import { GuideTemplate } from '~/features/docs/GuidesMdx.template'
|
||||
|
||||
export const dynamicParams = false
|
||||
import { IS_PROD } from 'common'
|
||||
import { getEmptyArray } from '~/features/helpers.fn'
|
||||
|
||||
type Params = { slug?: string[] }
|
||||
|
||||
@@ -17,7 +17,7 @@ const CronGuidePage = async (props: { params: Promise<Params> }) => {
|
||||
return <GuideTemplate {...data!} />
|
||||
}
|
||||
|
||||
const generateStaticParams = genGuidesStaticParams('cron')
|
||||
const generateStaticParams = IS_PROD ? genGuidesStaticParams('cron') : getEmptyArray
|
||||
const generateMetadata = genGuideMeta((params: { slug?: string[] }) =>
|
||||
getGuidesMarkdown(['cron', ...(params.slug ?? [])])
|
||||
)
|
||||
|
||||
@@ -4,8 +4,8 @@ import {
|
||||
genGuidesStaticParams,
|
||||
} from '~/features/docs/GuidesMdx.utils'
|
||||
import { GuideTemplate } from '~/features/docs/GuidesMdx.template'
|
||||
|
||||
export const dynamicParams = false
|
||||
import { IS_PROD } from 'common'
|
||||
import { getEmptyArray } from '~/features/helpers.fn'
|
||||
|
||||
type Params = { slug?: string[] }
|
||||
|
||||
@@ -17,7 +17,7 @@ const DatabaseGuidePage = async (props: { params: Promise<Params> }) => {
|
||||
return <GuideTemplate {...data!} />
|
||||
}
|
||||
|
||||
const generateStaticParams = genGuidesStaticParams('database')
|
||||
const generateStaticParams = IS_PROD ? genGuidesStaticParams('database') : getEmptyArray
|
||||
const generateMetadata = genGuideMeta((params: { slug?: string[] }) =>
|
||||
getGuidesMarkdown(['database', ...(params.slug ?? [])])
|
||||
)
|
||||
|
||||
@@ -22,8 +22,7 @@ import { removeTitle } from '~/lib/mdx/plugins/remarkRemoveTitle'
|
||||
import remarkPyMdownTabs from '~/lib/mdx/plugins/remarkTabs'
|
||||
import { octokit } from '~/lib/octokit'
|
||||
import { SerializeOptions } from '~/types/next-mdx-remote-serialize'
|
||||
|
||||
export const dynamicParams = false
|
||||
import { IS_PROD } from 'common'
|
||||
|
||||
// We fetch these docs at build time from an external repo
|
||||
const org = 'supabase'
|
||||
@@ -416,6 +415,10 @@ const urlTransform: UrlTransformFunction = (url) => {
|
||||
}
|
||||
|
||||
const generateStaticParams = async () => {
|
||||
if (IS_PROD) {
|
||||
return []
|
||||
}
|
||||
|
||||
const mdxPaths = await genGuidesStaticParams('database/extensions/wrappers')()
|
||||
const federatedPaths = pageMap.map(({ slug }) => ({
|
||||
slug: [slug],
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
import SectionTroubleshootingPage, {
|
||||
generateSectionTroubleshootingMetadata,
|
||||
} from '~/features/docs/TroubleshootingSection.page'
|
||||
|
||||
export default async function DatabaseTroubleshootingPage() {
|
||||
return (
|
||||
<SectionTroubleshootingPage
|
||||
topic="database"
|
||||
sectionName="Database"
|
||||
description="Search or browse troubleshooting guides for common database issues, including connection problems, query optimization, and configuration."
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
export const metadata = generateSectionTroubleshootingMetadata('database', 'Database')
|
||||
@@ -4,8 +4,8 @@ import {
|
||||
genGuidesStaticParams,
|
||||
} from '~/features/docs/GuidesMdx.utils'
|
||||
import { GuideTemplate } from '~/features/docs/GuidesMdx.template'
|
||||
|
||||
export const dynamicParams = false
|
||||
import { IS_PROD } from 'common'
|
||||
import { getEmptyArray } from '~/features/helpers.fn'
|
||||
|
||||
type Params = { slug?: string[] }
|
||||
|
||||
@@ -17,7 +17,7 @@ const DeploymentGuidePage = async (props: { params: Promise<Params> }) => {
|
||||
return <GuideTemplate {...data!} />
|
||||
}
|
||||
|
||||
const generateStaticParams = genGuidesStaticParams('deployment')
|
||||
const generateStaticParams = IS_PROD ? genGuidesStaticParams('deployment') : getEmptyArray
|
||||
const generateMetadata = genGuideMeta((params: { slug?: string[] }) =>
|
||||
getGuidesMarkdown(['deployment', ...(params.slug ?? [])])
|
||||
)
|
||||
|
||||
@@ -17,8 +17,8 @@ import {
|
||||
terraformDocsRepo,
|
||||
} from '../terraformConstants'
|
||||
import { SerializeOptions } from '~/types/next-mdx-remote-serialize'
|
||||
|
||||
export const dynamicParams = false
|
||||
import { IS_PROD } from 'common'
|
||||
import { getEmptyArray } from '~/features/helpers.fn'
|
||||
|
||||
// Each external docs page is mapped to a local page
|
||||
const pageMap = [
|
||||
@@ -142,7 +142,9 @@ const getContent = async ({ slug }: Params) => {
|
||||
}
|
||||
}
|
||||
|
||||
const generateStaticParams = async () => pageMap.map(({ slug }) => ({ slug: slug ? [slug] : [] }))
|
||||
const generateStaticParams = IS_PROD
|
||||
? async () => pageMap.map(({ slug }) => ({ slug: slug ? [slug] : [] }))
|
||||
: getEmptyArray
|
||||
const generateMetadata = genGuideMeta(getContent)
|
||||
|
||||
export default TerraformDocs
|
||||
|
||||
@@ -4,8 +4,8 @@ import {
|
||||
genGuidesStaticParams,
|
||||
} from '~/features/docs/GuidesMdx.utils'
|
||||
import { GuideTemplate } from '~/features/docs/GuidesMdx.template'
|
||||
|
||||
export const dynamicParams = false
|
||||
import { IS_PROD } from 'common'
|
||||
import { getEmptyArray } from '~/features/helpers.fn'
|
||||
|
||||
type Params = { slug?: string[] }
|
||||
|
||||
@@ -17,7 +17,7 @@ const FunctionsGuidePage = async (props: { params: Promise<Params> }) => {
|
||||
return <GuideTemplate {...data!} />
|
||||
}
|
||||
|
||||
const generateStaticParams = genGuidesStaticParams('functions')
|
||||
const generateStaticParams = IS_PROD ? genGuidesStaticParams('functions') : getEmptyArray
|
||||
const generateMetadata = genGuideMeta((params: { slug?: string[] }) =>
|
||||
getGuidesMarkdown(['functions', ...(params.slug ?? [])])
|
||||
)
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
import SectionTroubleshootingPage, {
|
||||
generateSectionTroubleshootingMetadata,
|
||||
} from '~/features/docs/TroubleshootingSection.page'
|
||||
|
||||
export default async function FunctionsTroubleshootingPage() {
|
||||
return (
|
||||
<SectionTroubleshootingPage
|
||||
topic="functions"
|
||||
sectionName="Edge Functions"
|
||||
description="Search or browse troubleshooting guides for common Edge Functions issues, including deployment problems, runtime errors, and environment configuration."
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
export const metadata = generateSectionTroubleshootingMetadata('functions', 'Edge Functions')
|
||||
@@ -4,8 +4,8 @@ import {
|
||||
genGuidesStaticParams,
|
||||
} from '~/features/docs/GuidesMdx.utils'
|
||||
import { GuideTemplate } from '~/features/docs/GuidesMdx.template'
|
||||
|
||||
export const dynamicParams = false
|
||||
import { IS_PROD } from 'common'
|
||||
import { getEmptyArray } from '~/features/helpers.fn'
|
||||
|
||||
type Params = { slug?: string[] }
|
||||
|
||||
@@ -17,7 +17,7 @@ const GettingStartedGuidePage = async (props: { params: Promise<Params> }) => {
|
||||
return <GuideTemplate {...data!} />
|
||||
}
|
||||
|
||||
const generateStaticParams = genGuidesStaticParams('getting-started')
|
||||
const generateStaticParams = IS_PROD ? genGuidesStaticParams('getting-started') : getEmptyArray
|
||||
const generateMetadata = genGuideMeta((params: { slug?: string[] }) =>
|
||||
getGuidesMarkdown(['getting-started', ...(params.slug ?? [])])
|
||||
)
|
||||
|
||||
@@ -10,8 +10,8 @@ import remarkMkDocsAdmonition from '~/lib/mdx/plugins/remarkAdmonition'
|
||||
import { removeTitle } from '~/lib/mdx/plugins/remarkRemoveTitle'
|
||||
import remarkPyMdownTabs from '~/lib/mdx/plugins/remarkTabs'
|
||||
import { SerializeOptions } from '~/types/next-mdx-remote-serialize'
|
||||
|
||||
export const dynamicParams = false
|
||||
import { IS_PROD } from 'common'
|
||||
import { getEmptyArray } from '~/features/helpers.fn'
|
||||
|
||||
// We fetch these docs at build time from an external repo
|
||||
const org = 'supabase'
|
||||
@@ -190,7 +190,9 @@ const urlTransform: UrlTransformFunction = (url) => {
|
||||
}
|
||||
}
|
||||
|
||||
const generateStaticParams = async () => pageMap.map(({ slug }) => ({ slug: slug ? [slug] : [] }))
|
||||
const generateStaticParams = IS_PROD
|
||||
? async () => pageMap.map(({ slug }) => ({ slug: slug ? [slug] : [] }))
|
||||
: getEmptyArray
|
||||
const generateMetadata = genGuideMeta(getContent)
|
||||
|
||||
export default PGGraphQLDocs
|
||||
|
||||
@@ -4,8 +4,8 @@ import {
|
||||
genGuidesStaticParams,
|
||||
} from '~/features/docs/GuidesMdx.utils'
|
||||
import { GuideTemplate } from '~/features/docs/GuidesMdx.template'
|
||||
|
||||
export const dynamicParams = false
|
||||
import { IS_PROD } from 'common'
|
||||
import { getEmptyArray } from '~/features/helpers.fn'
|
||||
|
||||
type Params = { slug?: string[] }
|
||||
|
||||
@@ -17,7 +17,7 @@ const IntegrationsGuidePage = async (props: { params: Promise<Params> }) => {
|
||||
return <GuideTemplate {...data!} />
|
||||
}
|
||||
|
||||
const generateStaticParams = genGuidesStaticParams('integrations')
|
||||
const generateStaticParams = IS_PROD ? genGuidesStaticParams('integrations') : getEmptyArray
|
||||
const generateMetadata = genGuideMeta((params: { slug?: string[] }) =>
|
||||
getGuidesMarkdown(['integrations', ...(params.slug ?? [])])
|
||||
)
|
||||
|
||||
@@ -4,8 +4,8 @@ import {
|
||||
genGuidesStaticParams,
|
||||
} from '~/features/docs/GuidesMdx.utils'
|
||||
import { GuideTemplate } from '~/features/docs/GuidesMdx.template'
|
||||
|
||||
export const dynamicParams = false
|
||||
import { IS_PROD } from 'common'
|
||||
import { getEmptyArray } from '~/features/helpers.fn'
|
||||
|
||||
type Params = { slug?: string[] }
|
||||
|
||||
@@ -17,7 +17,7 @@ const LocalDevelopmentGuidePage = async (props: { params: Promise<Params> }) =>
|
||||
return <GuideTemplate {...data!} />
|
||||
}
|
||||
|
||||
const generateStaticParams = genGuidesStaticParams('local-development')
|
||||
const generateStaticParams = IS_PROD ? genGuidesStaticParams('local-development') : getEmptyArray
|
||||
const generateMetadata = genGuideMeta((params: { slug?: string[] }) =>
|
||||
getGuidesMarkdown(['local-development', ...(params.slug ?? [])])
|
||||
)
|
||||
|
||||
@@ -4,8 +4,8 @@ import {
|
||||
genGuidesStaticParams,
|
||||
} from '~/features/docs/GuidesMdx.utils'
|
||||
import { GuideTemplate } from '~/features/docs/GuidesMdx.template'
|
||||
|
||||
export const dynamicParams = false
|
||||
import { IS_PROD } from 'common'
|
||||
import { getEmptyArray } from '~/features/helpers.fn'
|
||||
|
||||
type Params = { slug?: string[] }
|
||||
|
||||
@@ -17,7 +17,7 @@ const PlatformGuidePage = async (props: { params: Promise<Params> }) => {
|
||||
return <GuideTemplate {...data!} />
|
||||
}
|
||||
|
||||
const generateStaticParams = genGuidesStaticParams('platform')
|
||||
const generateStaticParams = IS_PROD ? genGuidesStaticParams('platform') : getEmptyArray
|
||||
const generateMetadata = genGuideMeta((params: { slug?: string[] }) =>
|
||||
getGuidesMarkdown(['platform', ...(params.slug ?? [])])
|
||||
)
|
||||
|
||||
@@ -4,8 +4,8 @@ import {
|
||||
genGuidesStaticParams,
|
||||
} from '~/features/docs/GuidesMdx.utils'
|
||||
import { GuideTemplate } from '~/features/docs/GuidesMdx.template'
|
||||
|
||||
export const dynamicParams = false
|
||||
import { IS_PROD } from 'common'
|
||||
import { getEmptyArray } from '~/features/helpers.fn'
|
||||
|
||||
type Params = { slug?: string[] }
|
||||
|
||||
@@ -17,7 +17,7 @@ const QueuesGuidePage = async (props: { params: Promise<Params> }) => {
|
||||
return <GuideTemplate {...data!} />
|
||||
}
|
||||
|
||||
const generateStaticParams = genGuidesStaticParams('queues')
|
||||
const generateStaticParams = IS_PROD ? genGuidesStaticParams('queues') : getEmptyArray
|
||||
const generateMetadata = genGuideMeta((params: { slug?: string[] }) =>
|
||||
getGuidesMarkdown(['queues', ...(params.slug ?? [])])
|
||||
)
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
import SectionTroubleshootingPage, {
|
||||
generateSectionTroubleshootingMetadata,
|
||||
} from '~/features/docs/TroubleshootingSection.page'
|
||||
|
||||
export default async function RealtimeTroubleshootingPage() {
|
||||
return (
|
||||
<SectionTroubleshootingPage
|
||||
topic="realtime"
|
||||
sectionName="Realtime"
|
||||
description="Search or browse troubleshooting guides for common realtime issues, including connection problems, subscription management, and message delivery."
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
export const metadata = generateSectionTroubleshootingMetadata('realtime', 'Realtime')
|
||||
@@ -4,8 +4,8 @@ import {
|
||||
genGuidesStaticParams,
|
||||
} from '~/features/docs/GuidesMdx.utils'
|
||||
import { GuideTemplate } from '~/features/docs/GuidesMdx.template'
|
||||
|
||||
export const dynamicParams = false
|
||||
import { IS_PROD } from 'common'
|
||||
import { getEmptyArray } from '~/features/helpers.fn'
|
||||
|
||||
type Params = { slug?: string[] }
|
||||
|
||||
@@ -17,7 +17,7 @@ const ResourcesGuidePage = async (props: { params: Promise<Params> }) => {
|
||||
return <GuideTemplate {...data!} />
|
||||
}
|
||||
|
||||
const generateStaticParams = genGuidesStaticParams('resources')
|
||||
const generateStaticParams = IS_PROD ? genGuidesStaticParams('resources') : getEmptyArray
|
||||
const generateMetadata = genGuideMeta((params: { slug?: string[] }) =>
|
||||
getGuidesMarkdown(['resources', ...(params.slug ?? [])])
|
||||
)
|
||||
|
||||
@@ -4,8 +4,8 @@ import {
|
||||
genGuidesStaticParams,
|
||||
} from '~/features/docs/GuidesMdx.utils'
|
||||
import { GuideTemplate } from '~/features/docs/GuidesMdx.template'
|
||||
|
||||
export const dynamicParams = false
|
||||
import { IS_PROD } from 'common'
|
||||
import { getEmptyArray } from '~/features/helpers.fn'
|
||||
|
||||
type Params = { slug?: string[] }
|
||||
|
||||
@@ -17,7 +17,7 @@ const SecurityGuidePage = async (props: { params: Promise<Params> }) => {
|
||||
return <GuideTemplate {...data!} />
|
||||
}
|
||||
|
||||
const generateStaticParams = genGuidesStaticParams('security')
|
||||
const generateStaticParams = IS_PROD ? genGuidesStaticParams('security') : getEmptyArray
|
||||
const generateMetadata = genGuideMeta((params: { slug?: string[] }) =>
|
||||
getGuidesMarkdown(['security', ...(params.slug ?? [])])
|
||||
)
|
||||
|
||||
@@ -4,8 +4,8 @@ import {
|
||||
genGuidesStaticParams,
|
||||
} from '~/features/docs/GuidesMdx.utils'
|
||||
import { GuideTemplate } from '~/features/docs/GuidesMdx.template'
|
||||
|
||||
export const dynamicParams = false
|
||||
import { IS_PROD } from 'common'
|
||||
import { getEmptyArray } from '~/features/helpers.fn'
|
||||
|
||||
type Params = { slug?: string[] }
|
||||
|
||||
@@ -17,7 +17,7 @@ const SelfHostingGuidePage = async (props: { params: Promise<Params> }) => {
|
||||
return <GuideTemplate {...data!} />
|
||||
}
|
||||
|
||||
const generateStaticParams = genGuidesStaticParams('self-hosting')
|
||||
const generateStaticParams = IS_PROD ? genGuidesStaticParams('self-hosting') : getEmptyArray
|
||||
const generateMetadata = genGuideMeta((params: { slug?: string[] }) =>
|
||||
getGuidesMarkdown(['self-hosting', ...(params.slug ?? [])])
|
||||
)
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
import SectionTroubleshootingPage, {
|
||||
generateSectionTroubleshootingMetadata,
|
||||
} from '~/features/docs/TroubleshootingSection.page'
|
||||
|
||||
export default async function StorageTroubleshootingPage() {
|
||||
return (
|
||||
<SectionTroubleshootingPage
|
||||
topic="storage"
|
||||
sectionName="Storage"
|
||||
description="Search or browse troubleshooting guides for common storage issues, including file upload problems, bucket configuration, and security policies."
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
export const metadata = generateSectionTroubleshootingMetadata('storage', 'Storage')
|
||||
@@ -4,8 +4,8 @@ import {
|
||||
genGuidesStaticParams,
|
||||
} from '~/features/docs/GuidesMdx.utils'
|
||||
import { GuideTemplate } from '~/features/docs/GuidesMdx.template'
|
||||
|
||||
export const dynamicParams = false
|
||||
import { IS_PROD } from 'common'
|
||||
import { getEmptyArray } from '~/features/helpers.fn'
|
||||
|
||||
type Params = { slug?: string[] }
|
||||
|
||||
@@ -17,7 +17,7 @@ const MonitoringTroubleshootingGuidePage = async (props: { params: Promise<Param
|
||||
return <GuideTemplate {...data!} />
|
||||
}
|
||||
|
||||
const generateStaticParams = genGuidesStaticParams('telemetry')
|
||||
const generateStaticParams = IS_PROD ? genGuidesStaticParams('telemetry') : getEmptyArray
|
||||
const generateMetadata = genGuideMeta((params: { slug?: string[] }) =>
|
||||
getGuidesMarkdown(['telemetry', ...(params.slug ?? [])])
|
||||
)
|
||||
|
||||
@@ -653,7 +653,10 @@ export const auth = {
|
||||
},
|
||||
{
|
||||
name: 'Debugging',
|
||||
items: [{ name: 'Error Codes', url: '/guides/auth/debugging/error-codes' }],
|
||||
items: [
|
||||
{ name: 'Error Codes', url: '/guides/auth/debugging/error-codes' },
|
||||
{ name: 'Troubleshooting', url: '/guides/auth/troubleshooting' },
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'Third-party auth',
|
||||
@@ -962,6 +965,10 @@ export const database: NavMenuConstant = {
|
||||
name: 'Supavisor',
|
||||
url: '/guides/database/supavisor',
|
||||
},
|
||||
{
|
||||
name: 'Troubleshooting',
|
||||
url: '/guides/database/troubleshooting',
|
||||
},
|
||||
],
|
||||
},
|
||||
ormQuickstarts,
|
||||
@@ -1630,7 +1637,10 @@ export const realtime: NavMenuConstant = {
|
||||
{
|
||||
name: 'Debugging',
|
||||
url: undefined,
|
||||
items: [{ name: 'Operational Error Codes', url: '/guides/realtime/error_codes', items: [] }],
|
||||
items: [
|
||||
{ name: 'Operational Error Codes', url: '/guides/realtime/error_codes', items: [] },
|
||||
{ name: 'Troubleshooting', url: '/guides/realtime/troubleshooting' },
|
||||
],
|
||||
},
|
||||
],
|
||||
}
|
||||
@@ -1752,6 +1762,7 @@ export const storage: NavMenuConstant = {
|
||||
items: [
|
||||
{ name: 'Logs', url: '/guides/storage/debugging/logs' },
|
||||
{ name: 'Error Codes', url: '/guides/storage/debugging/error-codes' },
|
||||
{ name: 'Troubleshooting', url: '/guides/storage/troubleshooting' },
|
||||
],
|
||||
},
|
||||
{
|
||||
|
||||
@@ -77,6 +77,14 @@ SUPABASE_URL=your_supabase_project_url
|
||||
SUPABASE_ANON_KEY=your_supabase_anon_key
|
||||
```
|
||||
|
||||
</TabPanel>
|
||||
<TabPanel id="react-router" label="React Router">
|
||||
|
||||
```bash .env
|
||||
SUPABASE_URL=your_supabase_project_url
|
||||
SUPABASE_ANON_KEY=your_supabase_anon_key
|
||||
```
|
||||
|
||||
</TabPanel>
|
||||
<TabPanel id="express" label="Express">
|
||||
|
||||
@@ -660,6 +668,105 @@ export default function Index() {
|
||||
|
||||
</TabPanel>
|
||||
|
||||
<TabPanel id="react-router" label="React Router">
|
||||
|
||||
<Tabs
|
||||
scrollable
|
||||
size="small"
|
||||
type="underlined"
|
||||
defaultActiveId="react-router-loader"
|
||||
queryGroup="environment"
|
||||
>
|
||||
<TabPanel id="react-router-loader" label="Loader">
|
||||
|
||||
```ts _index.tsx
|
||||
import { LoaderFunctionArgs } from 'react-router'
|
||||
import { createServerClient, parseCookieHeader, serializeCookieHeader } from '@supabase/ssr'
|
||||
|
||||
export async function loader({ request }: LoaderFunctionArgs) {
|
||||
const headers = new Headers()
|
||||
|
||||
const supabase = createServerClient(process.env.SUPABASE_URL!, process.env.SUPABASE_ANON_KEY!, {
|
||||
cookies: {
|
||||
getAll() {
|
||||
return parseCookieHeader(request.headers.get('Cookie') ?? '')
|
||||
},
|
||||
setAll(cookiesToSet) {
|
||||
cookiesToSet.forEach(({ name, value, options }) =>
|
||||
headers.append('Set-Cookie', serializeCookieHeader(name, value, options))
|
||||
)
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
return new Response('...', {
|
||||
headers,
|
||||
})
|
||||
}
|
||||
```
|
||||
|
||||
</TabPanel>
|
||||
|
||||
<TabPanel id="react-router-action" label="Action">
|
||||
|
||||
```ts _index.tsx
|
||||
import { type ActionFunctionArgs } from '@react-router'
|
||||
import { createServerClient, parseCookieHeader, serializeCookieHeader } from '@supabase/ssr'
|
||||
|
||||
export async function action({ request }: ActionFunctionArgs) {
|
||||
const headers = new Headers()
|
||||
|
||||
const supabase = createServerClient(process.env.SUPABASE_URL!, process.env.SUPABASE_ANON_KEY!, {
|
||||
cookies: {
|
||||
getAll() {
|
||||
return parseCookieHeader(request.headers.get('Cookie') ?? '')
|
||||
},
|
||||
setAll(cookiesToSet) {
|
||||
cookiesToSet.forEach(({ name, value, options }) =>
|
||||
headers.append('Set-Cookie', serializeCookieHeader(name, value, options))
|
||||
)
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
return new Response('...', {
|
||||
headers,
|
||||
})
|
||||
}
|
||||
```
|
||||
|
||||
</TabPanel>
|
||||
|
||||
<TabPanel id="react-router-component" label="Component">
|
||||
|
||||
```ts _index.tsx
|
||||
import { type LoaderFunctionArgs } from "react-router";
|
||||
import { useLoaderData } from "react-router";
|
||||
import { createBrowserClient } from "@supabase/ssr";
|
||||
|
||||
export async function loader({}: LoaderFunctionArgs) {
|
||||
return {
|
||||
env: {
|
||||
SUPABASE_URL: process.env.SUPABASE_URL!,
|
||||
SUPABASE_ANON_KEY: process.env.SUPABASE_ANON_KEY!,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export default function Index() {
|
||||
const { env } = useLoaderData<typeof loader>();
|
||||
|
||||
const supabase = createBrowserClient(env.SUPABASE_URL, env.SUPABASE_ANON_KEY);
|
||||
|
||||
return ...
|
||||
}
|
||||
```
|
||||
|
||||
</TabPanel>
|
||||
</Tabs>
|
||||
|
||||
</TabPanel>
|
||||
|
||||
<TabPanel id="express" label="Express">
|
||||
|
||||
<Tabs
|
||||
|
||||
@@ -15,7 +15,7 @@ There are three general ways to use Sign in with Apple, depending on the applica
|
||||
|
||||
- Sign in on the web or in web-based apps
|
||||
- Using an OAuth flow initiated by Supabase Auth using the [Sign in with Apple REST API](https://developer.apple.com/documentation/signinwithapplerestapi).
|
||||
- Using [Sign in with Apple JS](https://developer.apple.com/documentation/sign_in_with_apple/sign_in_with_apple_js) directly in the browser, usually suitable for websites.
|
||||
- Using [Sign in with Apple JS](https://developer.apple.com/documentation/signinwithapplejs/) directly in the browser, usually suitable for websites.
|
||||
- Sign in natively inside iOS, macOS, watchOS or tvOS apps using [Apple's Authentication Services](https://developer.apple.com/documentation/authenticationservices)
|
||||
|
||||
In some cases you're able to use the OAuth flow within web-based native apps such as with [React Native](https://reactnative.dev), [Expo](https://expo.dev) or other similar frameworks. It is best practice to use native Sign in with Apple capabilities on those platforms instead.
|
||||
@@ -95,7 +95,7 @@ curl -X PATCH "https://api.supabase.com/v1/projects/$PROJECT_REF/config/auth" \
|
||||
|
||||
## Using sign in with Apple JS
|
||||
|
||||
[Sign in with Apple JS](https://developer.apple.com/documentation/sign_in_with_apple/sign_in_with_apple_js) is an official Apple framework for authenticating Apple users on websites. Although it can be used in web-based apps, those use cases will benefit more with the OAuth flow described above. We recommend using this method on classic websites only.
|
||||
[Sign in with Apple JS](https://developer.apple.com/documentation/signinwithapplejs/) is an official Apple framework for authenticating Apple users on websites. Although it can be used in web-based apps, those use cases will benefit more with the OAuth flow described above. We recommend using this method on classic websites only.
|
||||
|
||||
You can use the `signInWithIdToken()` method from the Supabase JavaScript library on the website to obtain an access and refresh token once the user has given consent using Sign in with Apple JS:
|
||||
|
||||
|
||||
@@ -48,18 +48,24 @@ show "statement_timeout";
|
||||
|
||||
Some settings can only be modified by a superuser. Supabase pre-enables the [`supautils` extension](https://supabase.com/blog/roles-postgres-hooks#setting-up-the-supautils-extension), which allows the `postgres` role to retain certain superuser privileges. It enables modification of the below reserved configurations at the `role` level:
|
||||
|
||||
| Setting | Description |
|
||||
| ------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
||||
| `auto_explain.log_min_duration` | Logs query plans taking longer than this duration. |
|
||||
| `auto_explain.log_nested_statements` | Log nested statements' plans. |
|
||||
| `log_min_messages` | Minimum severity level of messages to log. |
|
||||
| `pg_net.ttl` | Sets how long the [pg_net extension](/docs/guides/database/extensions/pg_net) saves responses |
|
||||
| `pg_net.batch_size` | Sets how many requests the [pg_net extension](/docs/guides/database/extensions/pg_net) can make per second |
|
||||
| `pgaudit.*` | Configures the [PGAudit extension](https://supabase.com/docs/guides/database/extensions/pgaudit). The `log_parameter` is still restricted to protect secrets |
|
||||
| `pgrst.*` | [`PostgREST` settings](https://docs.postgrest.org/en/stable/references/configuration.html#db-aggregates-enabled) |
|
||||
| `plan_filter.*` | Configures the [pg_plan_filter extension](https://supabase.com/docs/guides/database/extensions/pg_plan_filter) |
|
||||
| `session_replication_role` | Sets the session's behavior for triggers and rewrite rules. |
|
||||
| `track_io_timing` | Collects timing statistics for database I/O activity. |
|
||||
| Setting | Description |
|
||||
| ---------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `auto_explain.*` | Configures the [auto_explain module](https://www.postgresql.org/docs/current/auto-explain.html). Can be configured to log execution plans for queries expected to exceed x seconds, including function queries. |
|
||||
| `log_lock_waits` | Controls whether a log message is produced when a session waits longer than [deadlock_timeout](https://www.postgresql.org/docs/current/runtime-config-locks.html#GUC-DEADLOCK-TIMEOUT) to acquire a lock. |
|
||||
| `log_min_duration_statement` | Causes the duration of each completed statement to be logged if the statement ran for at least the specified amount of time. |
|
||||
| `log_min_messages` | Minimum severity level of messages to log. |
|
||||
| `log_replication_commands` | Logs all replication commands |
|
||||
| `log_statement` | Controls which SQL statements are logged. Valid values are `none` (off), `ddl`, `mod`, and `all` (all statements). |
|
||||
| `log_temp_files` | Controls logging of temporary file names and sizes. |
|
||||
| `pg_net.ttl` | Sets how long the [pg_net extension](/docs/guides/database/extensions/pg_net) saves responses |
|
||||
| `pg_net.batch_size` | Sets how many requests the [pg_net extension](/docs/guides/database/extensions/pg_net) can make per second |
|
||||
| `pg_stat_statements.*` | Configures the [pg_stat_statements extension](https://www.postgresql.org/docs/current/pgstatstatements.html). |
|
||||
| `pgaudit.*` | Configures the [PGAudit extension](https://supabase.com/docs/guides/database/extensions/pgaudit). The `log_parameter` is still restricted to protect secrets |
|
||||
| `pgrst.*` | [`PostgREST` settings](https://docs.postgrest.org/en/stable/references/configuration.html#db-aggregates-enabled) |
|
||||
| `plan_filter.*` | Configures the [pg_plan_filter extension](https://supabase.com/docs/guides/database/extensions/pg_plan_filter) |
|
||||
| `session_replication_role` | Sets the session's behavior for triggers and rewrite rules. |
|
||||
| `track_io_timing` | Collects timing statistics for database I/O activity. |
|
||||
| `wal_compression` | This parameter enables compression of WAL using the specified compression method. |
|
||||
|
||||
For example, to enable `log_nested_statements` for the `postgres` role, execute:
|
||||
|
||||
|
||||
@@ -17,11 +17,11 @@ If you get stuck while working through this guide, refer to the [full example on
|
||||
|
||||
## Building the app
|
||||
|
||||
Let's start building the Svelte app from scratch.
|
||||
Start building the Svelte app from scratch.
|
||||
|
||||
### Initialize a Svelte app
|
||||
|
||||
We can use the Vite Svelte TypeScript Template to initialize an app called `supabase-svelte`:
|
||||
You can use the Vite Svelte TypeScript Template to initialize an app called `supabase-svelte`:
|
||||
|
||||
```bash
|
||||
npm create vite@latest supabase-svelte -- --template svelte-ts
|
||||
@@ -29,14 +29,14 @@ cd supabase-svelte
|
||||
npm install
|
||||
```
|
||||
|
||||
Then let's install the only additional dependency: [supabase-js](https://github.com/supabase/supabase-js)
|
||||
Install the only additional dependency: [supabase-js](https://github.com/supabase/supabase-js)
|
||||
|
||||
```bash
|
||||
npm install @supabase/supabase-js
|
||||
```
|
||||
|
||||
And finally we want to save the environment variables in a `.env`.
|
||||
All we need are the API URL and the `anon` key that you copied [earlier](#get-the-api-keys).
|
||||
Finally, save the environment variables in a `.env`.
|
||||
All you need are the API URL and the `anon` key that you copied [earlier](#get-the-api-keys).
|
||||
|
||||
<$CodeTabs>
|
||||
|
||||
@@ -47,221 +47,46 @@ VITE_SUPABASE_ANON_KEY=YOUR_SUPABASE_ANON_KEY
|
||||
|
||||
</$CodeTabs>
|
||||
|
||||
Now that we have the API credentials in place, let's create a helper file to initialize the Supabase client. These variables will be exposed
|
||||
on the browser, and that's completely fine since we have [Row Level Security](/docs/guides/auth#row-level-security) enabled on our Database.
|
||||
Now you have the API credentials in place, create a helper file to initialize the Supabase client. These variables will be exposed on the browser, and that's fine since you have [Row Level Security](/docs/guides/auth#row-level-security) enabled on the Database.
|
||||
|
||||
<$CodeTabs>
|
||||
|
||||
```js name=src/supabaseClient.ts
|
||||
import { createClient } from '@supabase/supabase-js'
|
||||
|
||||
const supabaseUrl = import.meta.env.VITE_SUPABASE_URL
|
||||
const supabaseAnonKey = import.meta.env.VITE_SUPABASE_ANON_KEY
|
||||
|
||||
export const supabase = createClient(supabaseUrl, supabaseAnonKey)
|
||||
```
|
||||
|
||||
</$CodeTabs>
|
||||
<$CodeSample
|
||||
path="user-management/svelte-user-management/src/supabaseClient.ts"
|
||||
meta="name=src/supabaseClient.ts"
|
||||
/>
|
||||
|
||||
### App styling (optional)
|
||||
|
||||
An optional step is to update the CSS file `src/app.css` to make the app look nice.
|
||||
You can find the full contents of this file [here](https://raw.githubusercontent.com/supabase/supabase/master/examples/user-management/svelte-user-management/src/app.css).
|
||||
Optionally, update the CSS file `src/app.css` to make the app look nice.
|
||||
You can find the full contents of this file [on GitHub](https://raw.githubusercontent.com/supabase/supabase/master/examples/user-management/svelte-user-management/src/app.css).
|
||||
|
||||
### Set up a login component
|
||||
|
||||
Let's set up a Svelte component to manage logins and sign ups. We'll use Magic Links, so users can sign in with their email without using passwords.
|
||||
Set up a Svelte component to manage logins and sign ups. It uses Magic Links, so users can sign in with their email without using passwords.
|
||||
|
||||
<$CodeTabs>
|
||||
|
||||
```html name=src/lib/Auth.svelte
|
||||
<script lang="ts">
|
||||
import { supabase } from '../supabaseClient'
|
||||
|
||||
let loading = false
|
||||
let email = ''
|
||||
|
||||
const handleLogin = async () => {
|
||||
try {
|
||||
loading = true
|
||||
const { error } = await supabase.auth.signInWithOtp({ email })
|
||||
if (error) throw error
|
||||
alert('Check your email for login link!')
|
||||
} catch (error) {
|
||||
if (error instanceof Error) {
|
||||
alert(error.message)
|
||||
}
|
||||
} finally {
|
||||
loading = false
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="row flex-center flex">
|
||||
<div class="col-6 form-widget" aria-live="polite">
|
||||
<h1 class="header">Supabase + Svelte</h1>
|
||||
<p class="description">Sign in via magic link with your email below</p>
|
||||
<form class="form-widget" on:submit|preventDefault="{handleLogin}">
|
||||
<div>
|
||||
<label for="email">Email</label>
|
||||
<input
|
||||
id="email"
|
||||
class="inputField"
|
||||
type="email"
|
||||
placeholder="Your email"
|
||||
bind:value="{email}"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<button type="submit" class="button block" aria-live="polite" disabled="{loading}">
|
||||
<span>{loading ? 'Loading' : 'Send magic link'}</span>
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
</$CodeTabs>
|
||||
<$CodeSample
|
||||
path="user-management/svelte-user-management/src/lib/Auth.svelte"
|
||||
meta="name=src/lib/Auth.svelte"
|
||||
/>
|
||||
|
||||
### Account page
|
||||
|
||||
After a user is signed in we can allow them to edit their profile details and manage their account.
|
||||
Let's create a new component for that called `Account.svelte`.
|
||||
After a user is signed in, allow them to edit their profile details and manage their account.
|
||||
Create a new component for that called `Account.svelte`.
|
||||
|
||||
<$CodeTabs>
|
||||
|
||||
```tsx name=src/lib/Account.svelte
|
||||
<script lang="ts">
|
||||
import { onMount } from 'svelte'
|
||||
import type { AuthSession } from '@supabase/supabase-js'
|
||||
import { supabase } from '../supabaseClient'
|
||||
|
||||
export let session: AuthSession
|
||||
|
||||
let loading = false
|
||||
let username: string | null = null
|
||||
let website: string | null = null
|
||||
let avatarUrl: string | null = null
|
||||
|
||||
onMount(() => {
|
||||
getProfile()
|
||||
})
|
||||
|
||||
const getProfile = async () => {
|
||||
try {
|
||||
loading = true
|
||||
const { user } = session
|
||||
|
||||
const { data, error, status } = await supabase
|
||||
.from('profiles')
|
||||
.select('username, website, avatar_url')
|
||||
.eq('id', user.id)
|
||||
.single()
|
||||
|
||||
if (error && status !== 406) throw error
|
||||
|
||||
if (data) {
|
||||
username = data.username
|
||||
website = data.website
|
||||
avatarUrl = data.avatar_url
|
||||
}
|
||||
} catch (error) {
|
||||
if (error instanceof Error) {
|
||||
alert(error.message)
|
||||
}
|
||||
} finally {
|
||||
loading = false
|
||||
}
|
||||
}
|
||||
|
||||
const updateProfile = async () => {
|
||||
try {
|
||||
loading = true
|
||||
const { user } = session
|
||||
|
||||
const updates = {
|
||||
id: user.id,
|
||||
username,
|
||||
website,
|
||||
avatar_url: avatarUrl,
|
||||
updated_at: new Date().toISOString(),
|
||||
}
|
||||
|
||||
const { error } = await supabase.from('profiles').upsert(updates)
|
||||
|
||||
if (error) {
|
||||
throw error
|
||||
}
|
||||
} catch (error) {
|
||||
if (error instanceof Error) {
|
||||
alert(error.message)
|
||||
}
|
||||
} finally {
|
||||
loading = false
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<form on:submit|preventDefault="{updateProfile}" class="form-widget">
|
||||
<div>Email: {session.user.email}</div>
|
||||
<div>
|
||||
<label for="username">Name</label>
|
||||
<input id="username" type="text" bind:value="{username}" />
|
||||
</div>
|
||||
<div>
|
||||
<label for="website">Website</label>
|
||||
<input id="website" type="text" bind:value="{website}" />
|
||||
</div>
|
||||
<div>
|
||||
<button type="submit" class="button primary block" disabled="{loading}">
|
||||
{loading ? 'Saving ...' : 'Update profile'}
|
||||
</button>
|
||||
</div>
|
||||
<button type="button" class="button block" on:click={() => supabase.auth.signOut()}> Sign Out
|
||||
</button>
|
||||
</form>
|
||||
```
|
||||
|
||||
</$CodeTabs>
|
||||
<$CodeSample
|
||||
path="/user-management/svelte-user-management/src/lib/Account.svelte"
|
||||
lines={[[1, 4], [7, 11], [14, 33], [34,53], [55,73], [75,-1]]}
|
||||
meta="src/lib/Account.svelte"
|
||||
/>
|
||||
|
||||
### Launch!
|
||||
|
||||
Now that we have all the components in place, let's update `App.svelte`:
|
||||
Now that you have all the components in place, update `App.svelte`:
|
||||
|
||||
<$CodeTabs>
|
||||
|
||||
```html name=src/App.svelte
|
||||
<script lang="ts">
|
||||
import { onMount } from 'svelte'
|
||||
import { supabase } from './supabaseClient'
|
||||
import type { AuthSession } from '@supabase/supabase-js'
|
||||
import Account from './lib/Account.svelte'
|
||||
import Auth from './lib/Auth.svelte'
|
||||
|
||||
let session: AuthSession | null
|
||||
|
||||
onMount(() => {
|
||||
supabase.auth.getSession().then(({ data }) => {
|
||||
session = data.session
|
||||
})
|
||||
|
||||
supabase.auth.onAuthStateChange((_event, _session) => {
|
||||
session = _session
|
||||
})
|
||||
})
|
||||
</script>
|
||||
|
||||
<div class="container" style="padding: 50px 0 100px 0">
|
||||
{#if !session}
|
||||
<Auth />
|
||||
{:else}
|
||||
<Account {session} />
|
||||
{/if}
|
||||
</div>
|
||||
```
|
||||
|
||||
</$CodeTabs>
|
||||
<$CodeSample
|
||||
path="user-management/svelte-user-management/src/App.svelte"
|
||||
meta="name=src/App.svelte"
|
||||
/>
|
||||
|
||||
Once that's done, run this in a terminal window:
|
||||
|
||||
@@ -273,7 +98,7 @@ And then open the browser to [localhost:5173](http://localhost:5173) and you sho
|
||||
|
||||
<Admonition type="tip">
|
||||
|
||||
Svelte uses Vite and the default port is `5173`, Supabase uses `port 3000`. To change the redirection port for Supabase go to: `Authentication > Settings` and change the `Site Url` to `http://localhost:5173/`
|
||||
Svelte uses Vite and the default port is `5173`, Supabase uses `port 3000`. To change the redirection port for Supabase go to: **Authentication > URL Configuration** and change the **Site URL** to `http://localhost:5173/`
|
||||
|
||||
</Admonition>
|
||||
|
||||
@@ -285,118 +110,21 @@ Every Supabase project is configured with [Storage](/docs/guides/storage) for ma
|
||||
|
||||
### Create an upload widget
|
||||
|
||||
Let's create an avatar for the user so that they can upload a profile photo. We can start by creating a new component:
|
||||
Create an avatar for the user so that they can upload a profile photo. Start by creating a new component:
|
||||
|
||||
<$CodeTabs>
|
||||
|
||||
```html name=src/lib/Avatar.svelte
|
||||
<script lang="ts">
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import { supabase } from '../supabaseClient'
|
||||
|
||||
export let size: number
|
||||
export let url: string | null = null
|
||||
|
||||
let avatarUrl: string | null = null
|
||||
let uploading = false
|
||||
let files: FileList
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
const downloadImage = async (path: string) => {
|
||||
try {
|
||||
const { data, error } = await supabase.storage.from('avatars').download(path)
|
||||
|
||||
if (error) {
|
||||
throw error
|
||||
}
|
||||
|
||||
const url = URL.createObjectURL(data)
|
||||
avatarUrl = url
|
||||
} catch (error) {
|
||||
if (error instanceof Error) {
|
||||
console.log('Error downloading image: ', error.message)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const uploadAvatar = async () => {
|
||||
try {
|
||||
uploading = true
|
||||
|
||||
if (!files || files.length === 0) {
|
||||
throw new Error('You must select an image to upload.')
|
||||
}
|
||||
|
||||
const file = files[0]
|
||||
const fileExt = file.name.split('.').pop()
|
||||
const filePath = `${Math.random()}.${fileExt}`
|
||||
|
||||
const { error } = await supabase.storage.from('avatars').upload(filePath, file)
|
||||
|
||||
if (error) {
|
||||
throw error
|
||||
}
|
||||
|
||||
url = filePath
|
||||
dispatch('upload')
|
||||
} catch (error) {
|
||||
if (error instanceof Error) {
|
||||
alert(error.message)
|
||||
}
|
||||
} finally {
|
||||
uploading = false
|
||||
}
|
||||
}
|
||||
|
||||
$: if (url) downloadImage(url)
|
||||
</script>
|
||||
|
||||
<div style="width: {size}px" aria-live="polite">
|
||||
{#if avatarUrl} <img src={avatarUrl} alt={avatarUrl ? 'Avatar' : 'No image'} class="avatar image"
|
||||
style="height: {size}px, width: {size}px" /> {:else}
|
||||
<div class="avatar no-image" style="height: {size}px, width: {size}px" />
|
||||
{/if}
|
||||
<div style="width: {size}px">
|
||||
<label class="button primary block" for="single">
|
||||
{uploading ? 'Uploading ...' : 'Upload avatar'}
|
||||
</label>
|
||||
<span style="display:none">
|
||||
<input
|
||||
type="file"
|
||||
id="single"
|
||||
accept="image/*"
|
||||
bind:files
|
||||
on:change={uploadAvatar}
|
||||
disabled={uploading}
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
</$CodeTabs>
|
||||
<$CodeSample
|
||||
path="user-management/svelte-user-management/src/lib/Avatar.svelte"
|
||||
meta="name=src/lib/Avatar.svelte"
|
||||
/>
|
||||
|
||||
### Add the new widget
|
||||
|
||||
And then we can add the widget to the Account page:
|
||||
And then you can add the widget to the Account page:
|
||||
|
||||
<$CodeTabs>
|
||||
|
||||
```html name=src/lib/Account.svelte
|
||||
<script lang="ts">
|
||||
// Import the new component
|
||||
import Avatar from './Avatar.svelte'
|
||||
</script>
|
||||
|
||||
<form on:submit|preventDefault="{updateProfile}" class="form-widget">
|
||||
<!-- Add to body -->
|
||||
<Avatar bind:url="{avatarUrl}" size="{150}" on:upload="{updateProfile}" />
|
||||
|
||||
<!-- Other form elements -->
|
||||
</form>
|
||||
```
|
||||
|
||||
</$CodeTabs>
|
||||
<$CodeSample
|
||||
path="/user-management/svelte-user-management/src/lib/Account.svelte"
|
||||
lines={[[1,1], [5,5], [71,73], [74,74], [92,-1]]}
|
||||
meta="src/lib/Account.svelte"
|
||||
/>
|
||||
|
||||
At this stage you have a fully functional application!
|
||||
@@ -193,7 +193,7 @@ Once you've chosen an available subdomain and have done all the necessary prepar
|
||||
Use the [`vanity-subdomains activate`](/docs/reference/cli/supabase-vanity-subdomains-activate) command to activate and claim your subdomain:
|
||||
|
||||
```bash
|
||||
supabase vanity-subdomains --project-ref abcdefghijklmnopqrst activate --desired-subdomain my-example-brand
|
||||
supabase vanity-subdomains --project-ref abcdefghijklmnopqrst activate --desired-subdomain my-example-brand --experimental
|
||||
```
|
||||
|
||||
If you wish to use the new domain in client code, you can set it up like so:
|
||||
|
||||
+6
@@ -21,6 +21,12 @@ Is the server running on that host and accepting TCP/IP connections?`, this coul
|
||||
|
||||
These bans will clear after 30mins but you can unban the IPs using the Supabase CLI https://supabase.com/docs/guides/cli following the commands below.
|
||||
|
||||
## Unban IPs using the Dashboard
|
||||
|
||||
Go to [Database Settings](https://supabase.com/dashboard/project/_/database/settings#banned-ips) and click **Unban IP**.
|
||||
|
||||
## Unban IPs using the CLI
|
||||
|
||||
How to list the banned IPs:
|
||||
|
||||
```
|
||||
|
||||
@@ -344,6 +344,8 @@ function matchLang(lang: string) {
|
||||
return 'swift'
|
||||
case 'sql':
|
||||
return 'sql'
|
||||
case 'svelte':
|
||||
return 'svelte'
|
||||
default:
|
||||
return null
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import { ChevronDown, RotateCw, Search, X } from 'lucide-react'
|
||||
import { useQueryStates } from 'nuqs'
|
||||
import { useEffect, useRef, useState, Suspense, useCallback, useMemo } from 'react'
|
||||
|
||||
import { useBreakpoint } from 'common'
|
||||
import {
|
||||
Input_Shadcn_,
|
||||
cn,
|
||||
@@ -13,22 +14,13 @@ import {
|
||||
CollapsibleContent_Shadcn_ as CollapsibleContent,
|
||||
} from 'ui'
|
||||
import ShimmeringLoader from 'ui-patterns/ShimmeringLoader'
|
||||
|
||||
import {
|
||||
MultiSelector,
|
||||
MultiSelectorContent,
|
||||
MultiSelectorInput,
|
||||
MultiSelectorItem,
|
||||
MultiSelectorList,
|
||||
MultiSelectorTrigger,
|
||||
} from 'ui-patterns/multi-select'
|
||||
import { MultiSelector } from 'ui-patterns/multi-select'
|
||||
import { type ITroubleshootingMetadata } from './Troubleshooting.utils'
|
||||
import {
|
||||
TROUBLESHOOTING_CONTAINER_ID,
|
||||
TROUBLESHOOTING_DATA_ATTRIBUTES,
|
||||
troubleshootingSearchParams,
|
||||
} from './Troubleshooting.utils.shared'
|
||||
import { useBreakpoint } from 'common'
|
||||
|
||||
function useTroubleshootingSearchState() {
|
||||
const [_state, _setState] = useQueryStates(troubleshootingSearchParams)
|
||||
@@ -115,10 +107,10 @@ function entryMatchesFilter(
|
||||
}
|
||||
|
||||
interface TroubleshootingFilterProps {
|
||||
products: string[]
|
||||
className?: string
|
||||
products?: string[]
|
||||
errors: ITroubleshootingMetadata['errors']
|
||||
keywords: string[]
|
||||
className?: string
|
||||
}
|
||||
|
||||
export function TroubleshootingFilter(props: TroubleshootingFilterProps) {
|
||||
@@ -223,18 +215,20 @@ function TroubleshootingFilterInternal({
|
||||
<>
|
||||
<h2 className="sr-only">Search and filter</h2>
|
||||
<div className={cn('flex flex-wrap gap-2 items-center', className)}>
|
||||
<MultiSelector values={selectedProducts} onValuesChange={setSelectedProducts}>
|
||||
<MultiSelector.Trigger badgeLimit={1} className="w-48" label="Products" />
|
||||
<MultiSelector.Content>
|
||||
<MultiSelector.List>
|
||||
{products?.map((product) => (
|
||||
<MultiSelector.Item key={`product-${product}`} value={product}>
|
||||
{product}
|
||||
</MultiSelector.Item>
|
||||
))}
|
||||
</MultiSelector.List>
|
||||
</MultiSelector.Content>
|
||||
</MultiSelector>
|
||||
{!!products && (
|
||||
<MultiSelector values={selectedProducts} onValuesChange={setSelectedProducts}>
|
||||
<MultiSelector.Trigger badgeLimit={1} className="w-48" label="Products" />
|
||||
<MultiSelector.Content>
|
||||
<MultiSelector.List>
|
||||
{products?.map((product) => (
|
||||
<MultiSelector.Item key={`product-${product}`} value={product}>
|
||||
{product}
|
||||
</MultiSelector.Item>
|
||||
))}
|
||||
</MultiSelector.List>
|
||||
</MultiSelector.Content>
|
||||
</MultiSelector>
|
||||
)}
|
||||
<MultiSelector values={selectedErrorCodes} onValuesChange={setSelectedErrorCodes}>
|
||||
<MultiSelector.Trigger badgeLimit={1} className="w-48" label="Error codes" />
|
||||
<MultiSelector.Content>
|
||||
|
||||
@@ -1,15 +1,19 @@
|
||||
import { Wrench } from 'lucide-react'
|
||||
import Link from 'next/link'
|
||||
import { type PropsWithChildren, useCallback } from 'react'
|
||||
import { Fragment } from 'react'
|
||||
|
||||
import { cn } from 'ui'
|
||||
import { TroubleshootingFilter } from './Troubleshooting.ui.client'
|
||||
import {
|
||||
type ITroubleshootingEntry,
|
||||
type ITroubleshootingMetadata,
|
||||
getArticleSlug,
|
||||
getTroubleshootingUpdatedDates,
|
||||
} from './Troubleshooting.utils'
|
||||
import { TroubleshootingFilter } from './Troubleshooting.ui.client'
|
||||
import { formatError, TROUBLESHOOTING_DATA_ATTRIBUTES } from './Troubleshooting.utils.shared'
|
||||
import { cn } from 'ui'
|
||||
import {
|
||||
formatError,
|
||||
TROUBLESHOOTING_DATA_ATTRIBUTES,
|
||||
TROUBLESHOOTING_CONTAINER_ID,
|
||||
} from './Troubleshooting.utils.shared'
|
||||
|
||||
export async function TroubleshootingPreview({ entry }: { entry: ITroubleshootingEntry }) {
|
||||
const dateUpdated = entry.data.database_id.startsWith('pseudo-')
|
||||
@@ -55,10 +59,10 @@ export async function TroubleshootingPreview({ entry }: { entry: ITroubleshootin
|
||||
.map(formatError)
|
||||
.filter(Boolean)
|
||||
.map((error, index) => (
|
||||
<>
|
||||
<code key={index}>{error}</code>
|
||||
<Fragment key={error}>
|
||||
<code>{error}</code>
|
||||
{index < (entry.data.errors?.length || 0) - 1 ? ', ' : ''}
|
||||
</>
|
||||
</Fragment>
|
||||
))}
|
||||
</span>
|
||||
)}
|
||||
@@ -83,3 +87,65 @@ export async function TroubleshootingPreview({ entry }: { entry: ITroubleshootin
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export function TroubleshootingHeader({
|
||||
title,
|
||||
description,
|
||||
keywords,
|
||||
products,
|
||||
errors,
|
||||
}: {
|
||||
title: string
|
||||
description: string
|
||||
keywords: Array<string>
|
||||
products?: Array<string>
|
||||
errors: ITroubleshootingMetadata['errors']
|
||||
}) {
|
||||
return (
|
||||
<div className="lg:sticky lg:top-[var(--header-height)] lg:z-10 bg-background">
|
||||
<div className="pt-8 pb-6 px-5">
|
||||
<h1 className="text-4xl tracking-tight mb-7">{title}</h1>
|
||||
<p className="text-lg text-foreground-light">{description}</p>
|
||||
<hr className="my-7" aria-hidden />
|
||||
<TroubleshootingFilter
|
||||
keywords={keywords}
|
||||
products={products}
|
||||
errors={errors}
|
||||
className="mb-0"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export function TroubleshootingEntries({
|
||||
name,
|
||||
entries,
|
||||
}: {
|
||||
name: string
|
||||
entries: Array<ITroubleshootingEntry>
|
||||
}) {
|
||||
return (
|
||||
<div id={TROUBLESHOOTING_CONTAINER_ID} className="@container/troubleshooting">
|
||||
<h2 className="sr-only">Matching troubleshooting entries</h2>
|
||||
{entries.length === 0 ? (
|
||||
<div className="text-center py-12">
|
||||
<p className="text-foreground-light text-lg">
|
||||
No troubleshooting guides available for {name} yet.
|
||||
</p>
|
||||
</div>
|
||||
) : (
|
||||
<ul className="grid @4xl/troubleshooting:grid-cols-[78%_15%_7%]">
|
||||
{entries.map((entry) => (
|
||||
<li
|
||||
key={entry.data.database_id}
|
||||
className="grid grid-cols-subgrid @4xl/troubleshooting:col-span-3"
|
||||
>
|
||||
<TroubleshootingPreview entry={entry} />
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -113,3 +113,60 @@ async function getTroubleshootingUpdatedDatesInternal() {
|
||||
}, new Map<string, Date>())
|
||||
}
|
||||
export const getTroubleshootingUpdatedDates = cache(getTroubleshootingUpdatedDatesInternal)
|
||||
|
||||
async function getTroubleshootingEntriesByTopicImpl(
|
||||
topic: ITroubleshootingMetadata['topics'][number]
|
||||
) {
|
||||
const allEntries = await getAllTroubleshootingEntries()
|
||||
return allEntries.filter((entry) => entry.data.topics.includes(topic))
|
||||
}
|
||||
export const getTroubleshootingEntriesByTopic = cache_fullProcess_withDevCacheBust(
|
||||
getTroubleshootingEntriesByTopicImpl,
|
||||
TROUBLESHOOTING_DIRECTORY,
|
||||
() => JSON.stringify([])
|
||||
)
|
||||
|
||||
export async function getTroubleshootingKeywordsByTopic(
|
||||
topic: ITroubleshootingMetadata['topics'][number]
|
||||
) {
|
||||
const entries = await getTroubleshootingEntriesByTopic(topic)
|
||||
const keywords = new Set<string>()
|
||||
for (const entry of entries) {
|
||||
for (const entryTopic of entry.data.topics) {
|
||||
keywords.add(entryTopic)
|
||||
}
|
||||
for (const keyword of entry.data.keywords ?? []) {
|
||||
keywords.add(keyword)
|
||||
}
|
||||
}
|
||||
return Array.from(keywords).sort((a, b) => a.toLowerCase().localeCompare(b.toLowerCase()))
|
||||
}
|
||||
|
||||
export async function getTroubleshootingErrorsByTopic(
|
||||
topic: ITroubleshootingMetadata['topics'][number]
|
||||
) {
|
||||
const entries = await getTroubleshootingEntriesByTopic(topic)
|
||||
const allErrors = new Set(
|
||||
entries
|
||||
.flatMap((entry) => entry.data.errors ?? [])
|
||||
.filter((error) => error?.http_status_code || error?.code)
|
||||
)
|
||||
|
||||
const seen = new Set<string>()
|
||||
for (const error of allErrors) {
|
||||
const key = formatError(error)
|
||||
if (seen.has(key)) {
|
||||
allErrors.delete(error)
|
||||
}
|
||||
seen.add(key)
|
||||
}
|
||||
|
||||
function sortErrors(
|
||||
a: NonNullable<ITroubleshootingMetadata['errors']>[number],
|
||||
b: NonNullable<ITroubleshootingMetadata['errors']>[number]
|
||||
) {
|
||||
return formatError(a).localeCompare(formatError(b))
|
||||
}
|
||||
|
||||
return Array.from(allErrors).sort(sortErrors)
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
import { type Metadata } from 'next'
|
||||
|
||||
import { TroubleshootingHeader, TroubleshootingEntries } from '~/features/docs/Troubleshooting.ui'
|
||||
import {
|
||||
TroubleshootingFilterEmptyState,
|
||||
TroubleshootingListController,
|
||||
} from '~/features/docs/Troubleshooting.ui.client'
|
||||
import {
|
||||
type ITroubleshootingMetadata,
|
||||
getTroubleshootingEntriesByTopic,
|
||||
getTroubleshootingErrorsByTopic,
|
||||
getTroubleshootingKeywordsByTopic,
|
||||
} from '~/features/docs/Troubleshooting.utils'
|
||||
import { PROD_URL } from '~/lib/constants'
|
||||
|
||||
interface SectionTroubleshootingPageProps {
|
||||
topic: ITroubleshootingMetadata['topics'][number]
|
||||
sectionName: string
|
||||
description?: string
|
||||
}
|
||||
|
||||
export default async function SectionTroubleshootingPage({
|
||||
topic,
|
||||
sectionName,
|
||||
description,
|
||||
}: SectionTroubleshootingPageProps) {
|
||||
// All other fetches are dependent on getTroubleshootingEntriesByTopic, which
|
||||
// is cached, so it's run first to populate the cache
|
||||
const troubleshootingEntries = await getTroubleshootingEntriesByTopic(topic)
|
||||
const [keywords, errors] = await Promise.all([
|
||||
getTroubleshootingKeywordsByTopic(topic),
|
||||
getTroubleshootingErrorsByTopic(topic),
|
||||
])
|
||||
|
||||
const pageTitle = `${sectionName} Troubleshooting`
|
||||
const pageDescription =
|
||||
description || `Search or browse troubleshooting guides for common ${sectionName} issues.`
|
||||
|
||||
return (
|
||||
<div className="flex flex-col">
|
||||
<TroubleshootingHeader
|
||||
title={pageTitle}
|
||||
description={pageDescription}
|
||||
keywords={keywords}
|
||||
errors={errors}
|
||||
/>
|
||||
<div className="flex-1">
|
||||
<div className="px-5 pt-6">
|
||||
<TroubleshootingListController />
|
||||
<TroubleshootingFilterEmptyState />
|
||||
<TroubleshootingEntries name={sectionName} entries={troubleshootingEntries} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export function generateSectionTroubleshootingMetadata(
|
||||
topic: string,
|
||||
sectionName: string
|
||||
): Metadata {
|
||||
return {
|
||||
title: `Supabase Docs | ${sectionName} Troubleshooting`,
|
||||
alternates: {
|
||||
canonical: `${PROD_URL}/guides/${topic}/troubleshooting`,
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -46,6 +46,7 @@ Etienne Stalmans
|
||||
Fabrizio Fenoglio
|
||||
Felipe Stival
|
||||
Francesco Sansalvadore
|
||||
Greg Kress
|
||||
Greg P
|
||||
Greg Richardson
|
||||
Guilherme Souza
|
||||
|
||||
@@ -5,7 +5,6 @@ import { HTML5Backend } from 'react-dnd-html5-backend'
|
||||
import { createPortal } from 'react-dom'
|
||||
|
||||
import { useParams } from 'common'
|
||||
import { useProjectContext } from 'components/layouts/ProjectLayout/ProjectContext'
|
||||
import { useTableRowsQuery } from 'data/table-rows/table-rows-query'
|
||||
import { RoleImpersonationState } from 'lib/role-impersonation'
|
||||
import { EMPTY_ARR } from 'lib/void'
|
||||
@@ -20,6 +19,7 @@ import Header, { HeaderProps } from './components/header/Header'
|
||||
import { RowContextMenu } from './components/menu'
|
||||
import { GridProps } from './types'
|
||||
|
||||
import { useSelectedProjectQuery } from 'hooks/misc/useSelectedProject'
|
||||
import { useTableFilter } from './hooks/useTableFilter'
|
||||
import { useTableSort } from './hooks/useTableSort'
|
||||
|
||||
@@ -35,8 +35,7 @@ export const SupabaseGrid = ({
|
||||
const { id: _id } = useParams()
|
||||
const tableId = _id ? Number(_id) : undefined
|
||||
|
||||
const { project } = useProjectContext()
|
||||
|
||||
const { data: project } = useSelectedProjectQuery()
|
||||
const tableEditorSnap = useTableEditorStateSnapshot()
|
||||
const snap = useTableEditorTableStateSnapshot()
|
||||
|
||||
|
||||
@@ -4,10 +4,11 @@ import type { RenderEditCellProps } from 'react-data-grid'
|
||||
import { toast } from 'sonner'
|
||||
|
||||
import { useParams } from 'common'
|
||||
import { isValueTruncated } from 'components/interfaces/TableGridEditor/SidePanelEditor/RowEditor/RowEditor.utils'
|
||||
import { useTableEditorQuery } from 'data/table-editor/table-editor-query'
|
||||
import { isTableLike } from 'data/table-editor/table-editor-types'
|
||||
import { useGetCellValueMutation } from 'data/table-rows/get-cell-value-mutation'
|
||||
import { useSelectedProject } from 'hooks/misc/useSelectedProject'
|
||||
import { useSelectedProjectQuery } from 'hooks/misc/useSelectedProject'
|
||||
import { prettifyJSON, removeJSONTrailingComma, tryParseJson } from 'lib/helpers'
|
||||
import { useTableEditorTableStateSnapshot } from 'state/table-editor-table'
|
||||
import { Popover, Tooltip, TooltipContent, TooltipTrigger } from 'ui'
|
||||
@@ -15,7 +16,6 @@ import { BlockKeys } from '../common/BlockKeys'
|
||||
import { MonacoEditor } from '../common/MonacoEditor'
|
||||
import { NullValue } from '../common/NullValue'
|
||||
import { TruncatedWarningOverlay } from './TruncatedWarningOverlay'
|
||||
import { isValueTruncated } from 'components/interfaces/TableGridEditor/SidePanelEditor/RowEditor/RowEditor.utils'
|
||||
|
||||
const verifyJSON = (value: string) => {
|
||||
try {
|
||||
@@ -52,10 +52,10 @@ export const JsonEditor = <TRow, TSummaryRow = unknown>({
|
||||
onRowChange,
|
||||
onExpandEditor,
|
||||
}: JsonEditorProps<TRow, TSummaryRow>) => {
|
||||
const snap = useTableEditorTableStateSnapshot()
|
||||
const { id: _id } = useParams()
|
||||
const id = _id ? Number(_id) : undefined
|
||||
const project = useSelectedProject()
|
||||
const { data: project } = useSelectedProjectQuery()
|
||||
const snap = useTableEditorTableStateSnapshot()
|
||||
|
||||
const { data: selectedTable } = useTableEditorQuery({
|
||||
projectRef: project?.ref,
|
||||
|
||||
@@ -4,10 +4,11 @@ import type { RenderEditCellProps } from 'react-data-grid'
|
||||
import { toast } from 'sonner'
|
||||
|
||||
import { useParams } from 'common'
|
||||
import { isValueTruncated } from 'components/interfaces/TableGridEditor/SidePanelEditor/RowEditor/RowEditor.utils'
|
||||
import { useTableEditorQuery } from 'data/table-editor/table-editor-query'
|
||||
import { isTableLike } from 'data/table-editor/table-editor-types'
|
||||
import { useGetCellValueMutation } from 'data/table-rows/get-cell-value-mutation'
|
||||
import { useSelectedProject } from 'hooks/misc/useSelectedProject'
|
||||
import { useSelectedProjectQuery } from 'hooks/misc/useSelectedProject'
|
||||
import { useTableEditorTableStateSnapshot } from 'state/table-editor-table'
|
||||
import { Button, Popover, Tooltip, TooltipContent, TooltipTrigger, cn } from 'ui'
|
||||
import ConfirmationModal from 'ui-patterns/Dialogs/ConfirmationModal'
|
||||
@@ -16,7 +17,6 @@ import { EmptyValue } from '../common/EmptyValue'
|
||||
import { MonacoEditor } from '../common/MonacoEditor'
|
||||
import { NullValue } from '../common/NullValue'
|
||||
import { TruncatedWarningOverlay } from './TruncatedWarningOverlay'
|
||||
import { isValueTruncated } from 'components/interfaces/TableGridEditor/SidePanelEditor/RowEditor/RowEditor.utils'
|
||||
|
||||
export const TextEditor = <TRow, TSummaryRow = unknown>({
|
||||
row,
|
||||
@@ -33,7 +33,7 @@ export const TextEditor = <TRow, TSummaryRow = unknown>({
|
||||
const snap = useTableEditorTableStateSnapshot()
|
||||
const { id: _id } = useParams()
|
||||
const id = _id ? Number(_id) : undefined
|
||||
const project = useSelectedProject()
|
||||
const { data: project } = useSelectedProjectQuery()
|
||||
|
||||
const { data: selectedTable } = useTableEditorQuery({
|
||||
projectRef: project?.ref,
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { useParams } from 'common'
|
||||
import { useProjectContext } from 'components/layouts/ProjectLayout/ProjectContext'
|
||||
import { GridFooter } from 'components/ui/GridFooter'
|
||||
import TwoOptionToggle from 'components/ui/TwoOptionToggle'
|
||||
import { useTableEditorQuery } from 'data/table-editor/table-editor-query'
|
||||
import { isTableLike, isViewLike } from 'data/table-editor/table-editor-types'
|
||||
import { useSelectedProjectQuery } from 'hooks/misc/useSelectedProject'
|
||||
import { useUrlState } from 'hooks/ui/useUrlState'
|
||||
import RefreshButton from '../header/RefreshButton'
|
||||
import { Pagination } from './pagination'
|
||||
@@ -13,9 +13,9 @@ export interface FooterProps {
|
||||
}
|
||||
|
||||
const Footer = ({ isRefetching }: FooterProps) => {
|
||||
const { project } = useProjectContext()
|
||||
const { id: _id } = useParams()
|
||||
const id = _id ? Number(_id) : undefined
|
||||
const { data: project } = useSelectedProjectQuery()
|
||||
|
||||
const { data: entity } = useTableEditorQuery({
|
||||
projectRef: project?.ref,
|
||||
|
||||
@@ -3,10 +3,10 @@ import { useEffect, useState } from 'react'
|
||||
|
||||
import { useParams } from 'common'
|
||||
import { useTableFilter } from 'components/grid/hooks/useTableFilter'
|
||||
import { useProjectContext } from 'components/layouts/ProjectLayout/ProjectContext'
|
||||
import { useTableEditorQuery } from 'data/table-editor/table-editor-query'
|
||||
import { isTable } from 'data/table-editor/table-editor-types'
|
||||
import { THRESHOLD_COUNT, useTableRowsCountQuery } from 'data/table-rows/table-rows-count-query'
|
||||
import { useSelectedProjectQuery } from 'hooks/misc/useSelectedProject'
|
||||
import { RoleImpersonationState } from 'lib/role-impersonation'
|
||||
import { useRoleImpersonationStateSnapshot } from 'state/role-impersonation-state'
|
||||
import { useTableEditorStateSnapshot } from 'state/table-editor'
|
||||
@@ -27,7 +27,7 @@ const Pagination = () => {
|
||||
const { id: _id } = useParams()
|
||||
const id = _id ? Number(_id) : undefined
|
||||
|
||||
const { project } = useProjectContext()
|
||||
const { data: project } = useSelectedProjectQuery()
|
||||
const tableEditorSnap = useTableEditorStateSnapshot()
|
||||
const snap = useTableEditorTableStateSnapshot()
|
||||
|
||||
|
||||
@@ -3,11 +3,11 @@ import type { PropsWithChildren } from 'react'
|
||||
import type { RenderCellProps } from 'react-data-grid'
|
||||
|
||||
import { convertByteaToHex } from 'components/interfaces/TableGridEditor/SidePanelEditor/RowEditor/RowEditor.utils'
|
||||
import { useProjectContext } from 'components/layouts/ProjectLayout/ProjectContext'
|
||||
import { ButtonTooltip } from 'components/ui/ButtonTooltip'
|
||||
import { useTableEditorQuery } from 'data/table-editor/table-editor-query'
|
||||
import { isTableLike } from 'data/table-editor/table-editor-types'
|
||||
import { useTablesQuery } from 'data/tables/tables-query'
|
||||
import { useSelectedProjectQuery } from 'hooks/misc/useSelectedProject'
|
||||
import { Popover_Shadcn_, PopoverContent_Shadcn_, PopoverTrigger_Shadcn_ } from 'ui'
|
||||
import type { SupaRow } from '../../types'
|
||||
import { NullValue } from '../common/NullValue'
|
||||
@@ -18,9 +18,8 @@ interface Props extends PropsWithChildren<RenderCellProps<SupaRow, unknown>> {
|
||||
}
|
||||
|
||||
export const ForeignKeyFormatter = (props: Props) => {
|
||||
const { project } = useProjectContext()
|
||||
|
||||
const { tableId, row, column } = props
|
||||
const { data: project } = useSelectedProjectQuery()
|
||||
|
||||
const { data } = useTableEditorQuery({
|
||||
projectRef: project?.ref,
|
||||
|
||||
@@ -11,7 +11,7 @@ import {
|
||||
import { convertByteaToHex } from 'components/interfaces/TableGridEditor/SidePanelEditor/RowEditor/RowEditor.utils'
|
||||
import { EditorTablePageLink } from 'data/prefetchers/project.$ref.editor.$id'
|
||||
import { useTableRowsQuery } from 'data/table-rows/table-rows-query'
|
||||
import { useSelectedProject } from 'hooks/misc/useSelectedProject'
|
||||
import { useSelectedProjectQuery } from 'hooks/misc/useSelectedProject'
|
||||
import { Button, cn, Tooltip, TooltipContent, TooltipTrigger } from 'ui'
|
||||
import ShimmeringLoader from 'ui-patterns/ShimmeringLoader'
|
||||
|
||||
@@ -23,7 +23,7 @@ interface ReferenceRecordPeekProps {
|
||||
|
||||
export const ReferenceRecordPeek = ({ table, column, value }: ReferenceRecordPeekProps) => {
|
||||
const { ref } = useParams()
|
||||
const project = useSelectedProject()
|
||||
const { data: project } = useSelectedProjectQuery()
|
||||
|
||||
const { data, error, isSuccess, isError, isLoading } = useTableRowsQuery(
|
||||
{
|
||||
|
||||
@@ -3,12 +3,12 @@ import DataGrid, { CalculatedColumn, DataGridHandle } from 'react-data-grid'
|
||||
|
||||
import { handleCopyCell } from 'components/grid/SupabaseGrid.utils'
|
||||
import { formatForeignKeys } from 'components/interfaces/TableGridEditor/SidePanelEditor/ForeignKeySelector/ForeignKeySelector.utils'
|
||||
import { useProjectContext } from 'components/layouts/ProjectLayout/ProjectContext'
|
||||
import AlertError from 'components/ui/AlertError'
|
||||
import { useForeignKeyConstraintsQuery } from 'data/database/foreign-key-constraints-query'
|
||||
import { ENTITY_TYPE } from 'data/entity-types/entity-type-constants'
|
||||
import { useSendEventMutation } from 'data/telemetry/send-event-mutation'
|
||||
import { useSelectedOrganization } from 'hooks/misc/useSelectedOrganization'
|
||||
import { useSelectedOrganizationQuery } from 'hooks/misc/useSelectedOrganization'
|
||||
import { useSelectedProjectQuery } from 'hooks/misc/useSelectedProject'
|
||||
import { useTableEditorStateSnapshot } from 'state/table-editor'
|
||||
import { useTableEditorTableStateSnapshot } from 'state/table-editor-table'
|
||||
import { Button, cn } from 'ui'
|
||||
@@ -54,6 +54,9 @@ export const Grid = memo(
|
||||
const tableEditorSnap = useTableEditorStateSnapshot()
|
||||
const snap = useTableEditorTableStateSnapshot()
|
||||
|
||||
const { data: org } = useSelectedOrganizationQuery()
|
||||
const { data: project } = useSelectedProjectQuery()
|
||||
|
||||
const onRowsChange = useOnRowsChange(rows)
|
||||
|
||||
function onSelectedRowsChange(selectedRows: Set<number>) {
|
||||
@@ -71,8 +74,6 @@ export const Grid = memo(
|
||||
const tableEntityType = snap.originalTable?.entity_type
|
||||
|
||||
const { mutate: sendEvent } = useSendEventMutation()
|
||||
const org = useSelectedOrganization()
|
||||
const { project } = useProjectContext()
|
||||
const { data } = useForeignKeyConstraintsQuery({
|
||||
projectRef: project?.ref,
|
||||
connectionString: project?.connectionString,
|
||||
|
||||
@@ -5,20 +5,20 @@ import { toast } from 'sonner'
|
||||
|
||||
import { SupaRow } from 'components/grid/types'
|
||||
import { convertByteaToHex } from 'components/interfaces/TableGridEditor/SidePanelEditor/RowEditor/RowEditor.utils'
|
||||
import { useProjectContext } from 'components/layouts/ProjectLayout/ProjectContext'
|
||||
import { DocsButton } from 'components/ui/DocsButton'
|
||||
import { isTableLike } from 'data/table-editor/table-editor-types'
|
||||
import { tableRowKeys } from 'data/table-rows/keys'
|
||||
import { useTableRowUpdateMutation } from 'data/table-rows/table-row-update-mutation'
|
||||
import type { TableRowsData } from 'data/table-rows/table-rows-query'
|
||||
import { useSelectedProjectQuery } from 'hooks/misc/useSelectedProject'
|
||||
import { useGetImpersonatedRoleState } from 'state/role-impersonation-state'
|
||||
import { useTableEditorTableStateSnapshot } from 'state/table-editor-table'
|
||||
import { Dictionary } from 'types'
|
||||
|
||||
export function useOnRowsChange(rows: SupaRow[]) {
|
||||
const { project } = useProjectContext()
|
||||
const snap = useTableEditorTableStateSnapshot()
|
||||
const queryClient = useQueryClient()
|
||||
const { data: project } = useSelectedProjectQuery()
|
||||
const snap = useTableEditorTableStateSnapshot()
|
||||
const getImpersonatedRoleState = useGetImpersonatedRoleState()
|
||||
|
||||
const { mutate: mutateUpdateTableRow } = useTableRowUpdateMutation({
|
||||
|
||||
@@ -1,8 +1,13 @@
|
||||
import { useState } from 'react'
|
||||
|
||||
import { useParams } from 'common'
|
||||
import { Filter, Sort, SupaTable } from 'components/grid/types'
|
||||
import { getConnectionStrings } from 'components/interfaces/Connect/DatabaseSettings.utils'
|
||||
import { useReadReplicasQuery } from 'data/read-replicas/replicas-query'
|
||||
import { getAllTableRowsSql } from 'data/table-rows/table-rows-query'
|
||||
import { pluckObjectFields } from 'lib/helpers'
|
||||
import { useState } from 'react'
|
||||
import { RoleImpersonationState, wrapWithRoleImpersonation } from 'lib/role-impersonation'
|
||||
import { useRoleImpersonationStateSnapshot } from 'state/role-impersonation-state'
|
||||
import {
|
||||
Button,
|
||||
cn,
|
||||
@@ -22,13 +27,25 @@ import {
|
||||
import { Admonition } from 'ui-patterns'
|
||||
|
||||
interface ExportDialogProps {
|
||||
table?: { name: string; schema: string }
|
||||
table?: SupaTable
|
||||
filters?: Filter[]
|
||||
sorts?: Sort[]
|
||||
ignoreRoleImpersonation?: boolean
|
||||
|
||||
open: boolean
|
||||
onOpenChange: (open: boolean) => void
|
||||
}
|
||||
|
||||
export const ExportDialog = ({ table, open, onOpenChange }: ExportDialogProps) => {
|
||||
export const ExportDialog = ({
|
||||
table,
|
||||
filters = [],
|
||||
sorts = [],
|
||||
ignoreRoleImpersonation = false,
|
||||
open,
|
||||
onOpenChange,
|
||||
}: ExportDialogProps) => {
|
||||
const { ref: projectRef } = useParams()
|
||||
const roleImpersonationState = useRoleImpersonationStateSnapshot()
|
||||
|
||||
const [selectedTab, setSelectedTab] = useState<string>('csv')
|
||||
|
||||
@@ -48,10 +65,18 @@ export const ExportDialog = ({ table, open, onOpenChange }: ExportDialogProps) =
|
||||
})
|
||||
|
||||
const outputName = `${table?.name}_rows`
|
||||
const queryChains = !table ? undefined : getAllTableRowsSql({ table, sorts, filters })
|
||||
const query = !!queryChains
|
||||
? ignoreRoleImpersonation
|
||||
? queryChains.toSql()
|
||||
: wrapWithRoleImpersonation(
|
||||
queryChains.toSql(),
|
||||
roleImpersonationState as RoleImpersonationState
|
||||
)
|
||||
: ''
|
||||
|
||||
const csvExportCommand = `
|
||||
${connectionStrings.direct.psql} -c "COPY (SELECT * FROM "${table?.schema}"."${table?.name}") TO STDOUT WITH CSV HEADER DELIMITER ',';" > ${outputName}.csv
|
||||
`.trim()
|
||||
${connectionStrings.direct.psql} -c "COPY (${query}) TO STDOUT WITH CSV HEADER DELIMITER ',';" > ${outputName}.csv`.trim()
|
||||
|
||||
const sqlExportCommand = `
|
||||
pg_dump -h ${db_host} -p ${db_port} -d ${db_name} -U ${db_user} --table="${table?.schema}.${table?.name}" --data-only --column-inserts > ${outputName}.sql
|
||||
@@ -95,6 +120,12 @@ pg_dump -h ${db_host} -p ${db_port} -d ${db_name} -U ${db_user} --table="${table
|
||||
value={sqlExportCommand}
|
||||
className="[&_code]:text-[12px] [&_code]:text-foreground"
|
||||
/>
|
||||
<Admonition
|
||||
type="note"
|
||||
className="mt-2"
|
||||
title="Filters are not supported when exporting as SQL via pg_dump"
|
||||
description="If you'd like to export as SQL, we recommend creating a view first then exporting the data from there via pg_dump instead"
|
||||
/>
|
||||
</TabsContent_Shadcn_>
|
||||
</Tabs_Shadcn_>
|
||||
|
||||
@@ -107,15 +138,11 @@ pg_dump -h ${db_host} -p ${db_port} -d ${db_name} -U ${db_user} --table="${table
|
||||
</p>
|
||||
|
||||
{selectedTab === 'sql' && (
|
||||
<Admonition
|
||||
type="note"
|
||||
title="The pg_dump version needs to match your Postgres version"
|
||||
>
|
||||
<p className="!leading-normal">
|
||||
If you run into a server version mismatch error, you will need to update{' '}
|
||||
<code>pg_dump</code> before running the command.
|
||||
</p>
|
||||
</Admonition>
|
||||
<p className="text-sm text-foreground-light">
|
||||
Note: <code>pg_dump</code> needs to match your project's Postgres version. If you run
|
||||
into a server version mismatch error, you will need to update <code>pg_dump</code>{' '}
|
||||
before running the command.
|
||||
</p>
|
||||
)}
|
||||
</DialogSection>
|
||||
<DialogFooter>
|
||||
|
||||
@@ -11,13 +11,13 @@ import { useTableFilter } from 'components/grid/hooks/useTableFilter'
|
||||
import { useTableSort } from 'components/grid/hooks/useTableSort'
|
||||
import GridHeaderActions from 'components/interfaces/TableGridEditor/GridHeaderActions'
|
||||
import { formatTableRowsToSQL } from 'components/interfaces/TableGridEditor/TableEntity.utils'
|
||||
import { useProjectContext } from 'components/layouts/ProjectLayout/ProjectContext'
|
||||
import { ButtonTooltip } from 'components/ui/ButtonTooltip'
|
||||
import { useTableRowsCountQuery } from 'data/table-rows/table-rows-count-query'
|
||||
import { fetchAllTableRows, useTableRowsQuery } from 'data/table-rows/table-rows-query'
|
||||
import { useSendEventMutation } from 'data/telemetry/send-event-mutation'
|
||||
import { useCheckPermissions } from 'hooks/misc/useCheckPermissions'
|
||||
import { useSelectedOrganizationQuery } from 'hooks/misc/useSelectedOrganization'
|
||||
import { useSelectedProjectQuery } from 'hooks/misc/useSelectedProject'
|
||||
import { RoleImpersonationState } from 'lib/role-impersonation'
|
||||
import {
|
||||
useRoleImpersonationStateSnapshot,
|
||||
@@ -222,7 +222,7 @@ const DefaultHeader = () => {
|
||||
}
|
||||
|
||||
const RowHeader = () => {
|
||||
const { project } = useProjectContext()
|
||||
const { data: project } = useSelectedProjectQuery()
|
||||
const tableEditorSnap = useTableEditorStateSnapshot()
|
||||
const snap = useTableEditorTableStateSnapshot()
|
||||
|
||||
@@ -504,11 +504,9 @@ const RowHeader = () => {
|
||||
Export
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent className={snap.allRowsSelected ? 'w-52' : 'w-40'}>
|
||||
<DropdownMenuContent align="start" className={snap.allRowsSelected ? 'w-52' : 'w-40'}>
|
||||
<DropdownMenuItem onClick={onRowsExportCSV}>Export as CSV</DropdownMenuItem>
|
||||
<DropdownMenuItem onClick={onRowsExportSQL}>Export as SQL</DropdownMenuItem>
|
||||
{/* [Joshen] Should make this available for all cases, but that'll involve updating
|
||||
the Dialog's SQL output to be dynamic based on any filters applied */}
|
||||
{snap.allRowsSelected ? (
|
||||
<DropdownMenuItem className="group" onClick={() => setShowExportModal(true)}>
|
||||
<div>
|
||||
@@ -535,7 +533,9 @@ const RowHeader = () => {
|
||||
</div>
|
||||
|
||||
<ExportDialog
|
||||
table={{ name: snap.table.name, schema: snap.table.schema ?? '' }}
|
||||
table={snap.table}
|
||||
filters={filters}
|
||||
sorts={sorts}
|
||||
open={showExportModal}
|
||||
onOpenChange={() => setShowExportModal(false)}
|
||||
/>
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
import { useCallback } from 'react'
|
||||
|
||||
import { saveTableEditorStateToLocalStorage } from 'components/grid/SupabaseGrid.utils'
|
||||
import { useProjectContext } from 'components/layouts/ProjectLayout/ProjectContext'
|
||||
import { useSelectedProjectQuery } from 'hooks/misc/useSelectedProject'
|
||||
import { useTableEditorTableStateSnapshot } from 'state/table-editor-table'
|
||||
|
||||
/**
|
||||
* Hook for saving state and triggering side effects.
|
||||
*/
|
||||
export function useSaveTableEditorState() {
|
||||
const { project } = useProjectContext()
|
||||
const { data: project } = useSelectedProjectQuery()
|
||||
const snap = useTableEditorTableStateSnapshot()
|
||||
|
||||
const saveDataAndTriggerSideEffects = useCallback(
|
||||
|
||||
@@ -9,7 +9,7 @@ import { DocsButton } from 'components/ui/DocsButton'
|
||||
import { useLintRuleDeleteMutation } from 'data/lint/delete-lint-rule-mutation'
|
||||
import { useProjectLintRulesQuery } from 'data/lint/lint-rules-query'
|
||||
import { useOrganizationMembersQuery } from 'data/organizations/organization-members-query'
|
||||
import { useSelectedOrganization } from 'hooks/misc/useSelectedOrganization'
|
||||
import { useSelectedOrganizationQuery } from 'hooks/misc/useSelectedOrganization'
|
||||
import {
|
||||
Badge,
|
||||
Button,
|
||||
@@ -40,7 +40,7 @@ const SIMPLIFIED_INTERFACE = true
|
||||
|
||||
export const AdvisorRuleItem = ({ lint }: AdvisorRuleItemProps) => {
|
||||
const { ref: projectRef } = useParams()
|
||||
const organization = useSelectedOrganization()
|
||||
const { data: organization } = useSelectedOrganizationQuery()
|
||||
|
||||
const [open, setOpen] = useState(false)
|
||||
const [expandedLint, setExpandedLint] = useState<string>()
|
||||
|
||||
@@ -8,7 +8,7 @@ import * as z from 'zod'
|
||||
import { useParams } from 'common'
|
||||
import { useLintRuleCreateMutation } from 'data/lint/create-lint-rule-mutation'
|
||||
import { useOrganizationMembersQuery } from 'data/organizations/organization-members-query'
|
||||
import { useSelectedOrganization } from 'hooks/misc/useSelectedOrganization'
|
||||
import { useSelectedOrganizationQuery } from 'hooks/misc/useSelectedOrganization'
|
||||
import { useRouter } from 'next/router'
|
||||
import {
|
||||
Button,
|
||||
@@ -68,10 +68,9 @@ const defaultValues = {
|
||||
export const CreateRuleSheet = ({ lint, open, onOpenChange }: CreateRuleSheetProps) => {
|
||||
const router = useRouter()
|
||||
const { ref: projectRef } = useParams()
|
||||
// const [_, setExpandedLint] = useQueryState('lint')
|
||||
|
||||
const routeCategory = router.pathname.split('/').pop()
|
||||
const organization = useSelectedOrganization()
|
||||
const { data: organization } = useSelectedOrganizationQuery()
|
||||
const { data: members = [] } = useOrganizationMembersQuery({ slug: organization?.slug })
|
||||
|
||||
const { mutate: createRule, isLoading: isCreating } = useLintRuleCreateMutation({
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Link } from 'lucide-react'
|
||||
|
||||
import { useProjectSettingsV2Query } from 'data/config/project-settings-v2-query'
|
||||
import { useSelectedProject } from 'hooks/misc/useSelectedProject'
|
||||
import { useSelectedProjectQuery } from 'hooks/misc/useSelectedProject'
|
||||
import { Badge, copyToClipboard } from 'ui'
|
||||
import { useRegisterCommands, useSetCommandMenuOpen } from 'ui-patterns/CommandMenu'
|
||||
import { COMMAND_MENU_SECTIONS } from './CommandMenu.utils'
|
||||
@@ -10,7 +10,7 @@ import { orderCommandSectionsByPriority } from './ordering'
|
||||
export function useApiUrlCommand() {
|
||||
const setIsOpen = useSetCommandMenuOpen()
|
||||
|
||||
const project = useSelectedProject()
|
||||
const { data: project } = useSelectedProjectQuery()
|
||||
const { data: settings } = useProjectSettingsV2Query(
|
||||
{ projectRef: project?.ref },
|
||||
{ enabled: !!project }
|
||||
|
||||
@@ -11,7 +11,7 @@ import {
|
||||
} from 'react'
|
||||
|
||||
import { FeatureFlagContext, LOCAL_STORAGE_KEYS } from 'common'
|
||||
import { useSelectedOrganization } from 'hooks/misc/useSelectedOrganization'
|
||||
import { useSelectedOrganizationQuery } from 'hooks/misc/useSelectedOrganization'
|
||||
import { useFlag, useIsRealtimeSettingsFFEnabled } from 'hooks/ui/useFlag'
|
||||
import { EMPTY_OBJ } from 'lib/void'
|
||||
import { FEATURE_PREVIEWS } from './FeaturePreview.constants'
|
||||
@@ -92,7 +92,7 @@ export const useIsInlineEditorEnabled = () => {
|
||||
}
|
||||
|
||||
export const useUnifiedLogsPreview = () => {
|
||||
const organization = useSelectedOrganization()
|
||||
const { data: organization } = useSelectedOrganizationQuery()
|
||||
const { flags, onUpdateFlag } = useFeaturePreviewContext()
|
||||
|
||||
const isTeamsOrEnterprise = ['team', 'enterprise'].includes(organization?.plan.id ?? '')
|
||||
|
||||
@@ -4,7 +4,7 @@ import { ReactNode } from 'react'
|
||||
|
||||
import { LOCAL_STORAGE_KEYS, useParams } from 'common'
|
||||
import { useSendEventMutation } from 'data/telemetry/send-event-mutation'
|
||||
import { useSelectedOrganization } from 'hooks/misc/useSelectedOrganization'
|
||||
import { useSelectedOrganizationQuery } from 'hooks/misc/useSelectedOrganization'
|
||||
import { IS_PLATFORM } from 'lib/constants'
|
||||
import { Badge, Button, Modal, ScrollArea, cn } from 'ui'
|
||||
import { AdvisorRulesPreview } from './AdvisorRulesPreview'
|
||||
@@ -38,7 +38,7 @@ const FeaturePreviewModal = () => {
|
||||
closeFeaturePreviewModal,
|
||||
isFeaturePreviewReleasedToPublic,
|
||||
} = useFeaturePreviewModal()
|
||||
const org = useSelectedOrganization()
|
||||
const { data: org } = useSelectedOrganizationQuery()
|
||||
const featurePreviewContext = useFeaturePreviewContext()
|
||||
const { mutate: sendEvent } = useSendEventMutation()
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ import { useOrganizationsQuery } from 'data/organizations/organizations-query'
|
||||
import { useProjectsQuery } from 'data/projects/projects-query'
|
||||
import useLatest from 'hooks/misc/useLatest'
|
||||
import { useLocalStorageQuery } from 'hooks/misc/useLocalStorage'
|
||||
import { useSelectedOrganization } from 'hooks/misc/useSelectedOrganization'
|
||||
import { useSelectedOrganizationQuery } from 'hooks/misc/useSelectedOrganization'
|
||||
import { IS_PLATFORM } from 'lib/constants'
|
||||
import { useAppStateSnapshot } from 'state/app-state'
|
||||
|
||||
@@ -20,7 +20,7 @@ const RouteValidationWrapper = ({ children }: PropsWithChildren<{}>) => {
|
||||
const snap = useAppStateSnapshot()
|
||||
const isUserMFAEnabled = useIsMFAEnabled()
|
||||
|
||||
const organization = useSelectedOrganization()
|
||||
const { data: organization } = useSelectedOrganizationQuery()
|
||||
|
||||
const [dashboardHistory, _, { isSuccess: isSuccessStorage }] = useLocalStorageQuery(
|
||||
LOCAL_STORAGE_KEYS.DASHBOARD_HISTORY(ref ?? ''),
|
||||
|
||||
@@ -7,12 +7,13 @@ import * as z from 'zod'
|
||||
|
||||
import { useParams } from 'common'
|
||||
import { ScaffoldSection, ScaffoldSectionTitle } from 'components/layouts/Scaffold'
|
||||
import { StringNumberOrNull } from 'components/ui/Forms/Form.constants'
|
||||
import NoPermission from 'components/ui/NoPermission'
|
||||
import UpgradeToPro from 'components/ui/UpgradeToPro'
|
||||
import { useAuthConfigQuery } from 'data/auth/auth-config-query'
|
||||
import { useAuthConfigUpdateMutation } from 'data/auth/auth-config-update-mutation'
|
||||
import { useCheckPermissions } from 'hooks/misc/useCheckPermissions'
|
||||
import { useSelectedOrganization } from 'hooks/misc/useSelectedOrganization'
|
||||
import { useSelectedOrganizationQuery } from 'hooks/misc/useSelectedOrganization'
|
||||
import { IS_PLATFORM } from 'lib/constants'
|
||||
import {
|
||||
AlertDescription_Shadcn_,
|
||||
@@ -30,7 +31,6 @@ import {
|
||||
WarningIcon,
|
||||
} from 'ui'
|
||||
import { FormItemLayout } from 'ui-patterns/form/FormItemLayout/FormItemLayout'
|
||||
import { StringNumberOrNull } from 'components/ui/Forms/Form.constants'
|
||||
|
||||
const FormSchema = z.object({
|
||||
API_MAX_REQUEST_DURATION: z.coerce
|
||||
@@ -42,7 +42,7 @@ const FormSchema = z.object({
|
||||
|
||||
export const AdvancedAuthSettingsForm = () => {
|
||||
const { ref: projectRef } = useParams()
|
||||
const organization = useSelectedOrganization()
|
||||
const { data: organization } = useSelectedOrganizationQuery()
|
||||
const canReadConfig = useCheckPermissions(PermissionAction.READ, 'custom_config_gotrue')
|
||||
const canUpdateConfig = useCheckPermissions(PermissionAction.UPDATE, 'custom_config_gotrue')
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ import { useParams } from 'common'
|
||||
import { ButtonTooltip } from 'components/ui/ButtonTooltip'
|
||||
import { useAuthConfigQuery } from 'data/auth/auth-config-query'
|
||||
import { useCheckPermissions } from 'hooks/misc/useCheckPermissions'
|
||||
import { useSelectedOrganization } from 'hooks/misc/useSelectedOrganization'
|
||||
import { useSelectedOrganizationQuery } from 'hooks/misc/useSelectedOrganization'
|
||||
import {
|
||||
Button,
|
||||
DropdownMenu,
|
||||
@@ -30,7 +30,7 @@ export const AddHookDropdown = ({
|
||||
onSelectHook,
|
||||
}: AddHookDropdownProps) => {
|
||||
const { ref: projectRef } = useParams()
|
||||
const organization = useSelectedOrganization()
|
||||
const { data: organization } = useSelectedOrganizationQuery()
|
||||
|
||||
const { data: authConfig } = useAuthConfigQuery({ projectRef })
|
||||
const canUpdateAuthHook = useCheckPermissions(PermissionAction.AUTH_EXECUTE, '*')
|
||||
|
||||
@@ -9,13 +9,14 @@ import * as z from 'zod'
|
||||
|
||||
import { useParams } from 'common'
|
||||
import { convertArgumentTypes } from 'components/interfaces/Database/Functions/Functions.utils'
|
||||
import { useProjectContext } from 'components/layouts/ProjectLayout/ProjectContext'
|
||||
import CodeEditor from 'components/ui/CodeEditor/CodeEditor'
|
||||
import { DocsButton } from 'components/ui/DocsButton'
|
||||
import FunctionSelector from 'components/ui/FunctionSelector'
|
||||
import SchemaSelector from 'components/ui/SchemaSelector'
|
||||
import { AuthConfigResponse } from 'data/auth/auth-config-query'
|
||||
import { useAuthHooksUpdateMutation } from 'data/auth/auth-hooks-update-mutation'
|
||||
import { executeSql } from 'data/sql/execute-sql-query'
|
||||
import { useSelectedProjectQuery } from 'hooks/misc/useSelectedProject'
|
||||
import {
|
||||
Button,
|
||||
FormControl_Shadcn_,
|
||||
@@ -38,7 +39,6 @@ import {
|
||||
import { FormItemLayout } from 'ui-patterns/form/FormItemLayout/FormItemLayout'
|
||||
import { HOOKS_DEFINITIONS, HOOK_DEFINITION_TITLE, Hook } from './hooks.constants'
|
||||
import { extractMethod, getRevokePermissionStatements, isValidHook } from './hooks.utils'
|
||||
import { DocsButton } from 'components/ui/DocsButton'
|
||||
|
||||
interface CreateHookSheetProps {
|
||||
visible: boolean
|
||||
@@ -115,7 +115,7 @@ export const CreateHookSheet = ({
|
||||
onDelete,
|
||||
}: CreateHookSheetProps) => {
|
||||
const { ref: projectRef } = useParams()
|
||||
const { project } = useProjectContext()
|
||||
const { data: project } = useSelectedProjectQuery()
|
||||
|
||||
const definition = useMemo(
|
||||
() => HOOKS_DEFINITIONS.find((d) => d.title === title) || HOOKS_DEFINITIONS[0],
|
||||
|
||||
@@ -2,13 +2,13 @@ import { useState } from 'react'
|
||||
import { toast } from 'sonner'
|
||||
|
||||
import { useParams } from 'common'
|
||||
import { useProjectContext } from 'components/layouts/ProjectLayout/ProjectContext'
|
||||
import { ScaffoldSection, ScaffoldSectionTitle } from 'components/layouts/Scaffold'
|
||||
import AlertError from 'components/ui/AlertError'
|
||||
import CodeEditor from 'components/ui/CodeEditor/CodeEditor'
|
||||
import { useAuthConfigQuery } from 'data/auth/auth-config-query'
|
||||
import { useAuthHooksUpdateMutation } from 'data/auth/auth-hooks-update-mutation'
|
||||
import { executeSql } from 'data/sql/execute-sql-query'
|
||||
import { useSelectedProjectQuery } from 'hooks/misc/useSelectedProject'
|
||||
import { cn } from 'ui'
|
||||
import ConfirmationModal from 'ui-patterns/Dialogs/ConfirmationModal'
|
||||
import { AddHookDropdown } from './AddHookDropdown'
|
||||
@@ -19,7 +19,7 @@ import { extractMethod, getRevokePermissionStatements, isValidHook } from './hoo
|
||||
|
||||
export const HooksListing = () => {
|
||||
const { ref: projectRef } = useParams()
|
||||
const { project } = useProjectContext()
|
||||
const { data: project } = useSelectedProjectQuery()
|
||||
const { data: authConfig, error: authConfigError, isError } = useAuthConfigQuery({ projectRef })
|
||||
|
||||
const [selectedHook, setSelectedHook] = useState<HOOK_DEFINITION_TITLE | null>(null)
|
||||
|
||||
@@ -12,7 +12,7 @@ import UpgradeToPro from 'components/ui/UpgradeToPro'
|
||||
import { useAuthConfigQuery } from 'data/auth/auth-config-query'
|
||||
import { useAuthConfigUpdateMutation } from 'data/auth/auth-config-update-mutation'
|
||||
import { useCheckPermissions } from 'hooks/misc/useCheckPermissions'
|
||||
import { useSelectedOrganization } from 'hooks/misc/useSelectedOrganization'
|
||||
import { useSelectedOrganizationQuery } from 'hooks/misc/useSelectedOrganization'
|
||||
import { IS_PLATFORM } from 'lib/constants'
|
||||
import {
|
||||
AlertDescription_Shadcn_,
|
||||
@@ -26,13 +26,13 @@ import {
|
||||
FormField_Shadcn_,
|
||||
Form_Shadcn_,
|
||||
Input_Shadcn_,
|
||||
Select_Shadcn_,
|
||||
PrePostTab,
|
||||
SelectContent_Shadcn_,
|
||||
SelectItem_Shadcn_,
|
||||
SelectTrigger_Shadcn_,
|
||||
SelectValue_Shadcn_,
|
||||
Select_Shadcn_,
|
||||
WarningIcon,
|
||||
PrePostTab,
|
||||
} from 'ui'
|
||||
import { FormItemLayout } from 'ui-patterns/form/FormItemLayout/FormItemLayout'
|
||||
|
||||
@@ -90,7 +90,7 @@ const MfaAuthSettingsForm = () => {
|
||||
const canReadConfig = useCheckPermissions(PermissionAction.READ, 'custom_config_gotrue')
|
||||
const canUpdateConfig = useCheckPermissions(PermissionAction.UPDATE, 'custom_config_gotrue')
|
||||
|
||||
const organization = useSelectedOrganization()
|
||||
const { data: organization } = useSelectedOrganizationQuery()
|
||||
const isProPlanAndUp = organization?.plan?.id !== 'free'
|
||||
const promptProPlanUpgrade = IS_PLATFORM && !isProPlanAndUp
|
||||
|
||||
|
||||
@@ -11,12 +11,12 @@ import {
|
||||
PolicyTableRowProps,
|
||||
} from 'components/interfaces/Auth/Policies/PolicyTableRow'
|
||||
import { ProtectedSchemaWarning } from 'components/interfaces/Database/ProtectedSchemaWarning'
|
||||
import { useProjectContext } from 'components/layouts/ProjectLayout/ProjectContext'
|
||||
import NoSearchResults from 'components/to-be-cleaned/NoSearchResults'
|
||||
import ProductEmptyState from 'components/to-be-cleaned/ProductEmptyState'
|
||||
import InformationBox from 'components/ui/InformationBox'
|
||||
import { useDatabasePolicyDeleteMutation } from 'data/database-policies/database-policy-delete-mutation'
|
||||
import { useTableUpdateMutation } from 'data/tables/table-update-mutation'
|
||||
import { useSelectedProjectQuery } from 'hooks/misc/useSelectedProject'
|
||||
import ConfirmModal from 'ui-patterns/Dialogs/ConfirmDialog'
|
||||
|
||||
interface PoliciesProps {
|
||||
@@ -38,7 +38,7 @@ const Policies = ({
|
||||
}: PoliciesProps) => {
|
||||
const router = useRouter()
|
||||
const { ref } = useParams()
|
||||
const { project } = useProjectContext()
|
||||
const { data: project } = useSelectedProjectQuery()
|
||||
|
||||
const [selectedTableToToggleRLS, setSelectedTableToToggleRLS] = useState<{
|
||||
id: number
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { SYSTEM_ROLES } from 'components/interfaces/Database/Roles/Roles.constants'
|
||||
import { useProjectContext } from 'components/layouts/ProjectLayout/ProjectContext'
|
||||
import AlertError from 'components/ui/AlertError'
|
||||
|
||||
import MultiSelect from 'ui-patterns/MultiSelectDeprecated'
|
||||
import ShimmeringLoader from 'components/ui/ShimmeringLoader'
|
||||
import { useDatabaseRolesQuery } from 'data/database-roles/database-roles-query'
|
||||
import { useSelectedProjectQuery } from 'hooks/misc/useSelectedProject'
|
||||
import { sortBy } from 'lodash'
|
||||
import MultiSelect from 'ui-patterns/MultiSelectDeprecated'
|
||||
|
||||
interface PolicyRolesProps {
|
||||
selectedRoles: string[]
|
||||
@@ -14,7 +14,7 @@ interface PolicyRolesProps {
|
||||
type SystemRole = (typeof SYSTEM_ROLES)[number]
|
||||
|
||||
const PolicyRoles = ({ selectedRoles, onUpdateSelectedRoles }: PolicyRolesProps) => {
|
||||
const { project } = useProjectContext()
|
||||
const { data: project } = useSelectedProjectQuery()
|
||||
const { data, error, isLoading, isError, isSuccess } = useDatabaseRolesQuery({
|
||||
projectRef: project?.ref,
|
||||
connectionString: project?.connectionString,
|
||||
|
||||
+2
-2
@@ -3,10 +3,10 @@ import { useEffect, useState } from 'react'
|
||||
import { UseFormReturn } from 'react-hook-form'
|
||||
|
||||
import { PermissionAction } from '@supabase/shared-types/out/constants'
|
||||
import { useProjectContext } from 'components/layouts/ProjectLayout/ProjectContext'
|
||||
import { useDatabaseRolesQuery } from 'data/database-roles/database-roles-query'
|
||||
import { useTablesQuery } from 'data/tables/tables-query'
|
||||
import { useCheckPermissions } from 'hooks/misc/useCheckPermissions'
|
||||
import { useSelectedProjectQuery } from 'hooks/misc/useSelectedProject'
|
||||
import {
|
||||
Button,
|
||||
CommandEmpty_Shadcn_,
|
||||
@@ -60,7 +60,7 @@ export const PolicyDetailsV2 = ({
|
||||
onUpdateCommand,
|
||||
authContext,
|
||||
}: PolicyDetailsV2Props) => {
|
||||
const { project } = useProjectContext()
|
||||
const { data: project } = useSelectedProjectQuery()
|
||||
const [open, setOpen] = useState(false)
|
||||
const canUpdatePolicies = useCheckPermissions(PermissionAction.TENANT_SQL_ADMIN_WRITE, 'tables')
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ import { useDatabasePolicyUpdateMutation } from 'data/database-policies/database
|
||||
import { databasePoliciesKeys } from 'data/database-policies/keys'
|
||||
import { QueryResponseError, useExecuteSqlMutation } from 'data/sql/execute-sql-mutation'
|
||||
import { useCheckPermissions } from 'hooks/misc/useCheckPermissions'
|
||||
import { useSelectedProject } from 'hooks/misc/useSelectedProject'
|
||||
import { useSelectedProjectQuery } from 'hooks/misc/useSelectedProject'
|
||||
import {
|
||||
Button,
|
||||
Checkbox_Shadcn_,
|
||||
@@ -33,9 +33,9 @@ import {
|
||||
cn,
|
||||
} from 'ui'
|
||||
import ConfirmationModal from 'ui-patterns/Dialogs/ConfirmationModal'
|
||||
import { checkIfPolicyHasChanged, generateCreatePolicyQuery } from './PolicyEditorPanel.utils'
|
||||
import { LockedCreateQuerySection, LockedRenameQuerySection } from './LockedQuerySection'
|
||||
import { PolicyDetailsV2 } from './PolicyDetailsV2'
|
||||
import { checkIfPolicyHasChanged, generateCreatePolicyQuery } from './PolicyEditorPanel.utils'
|
||||
import { PolicyEditorPanelHeader } from './PolicyEditorPanelHeader'
|
||||
import { PolicyTemplates } from './PolicyTemplates'
|
||||
import { QueryError } from './QueryError'
|
||||
@@ -65,7 +65,7 @@ export const PolicyEditorPanel = memo(function ({
|
||||
}: PolicyEditorPanelProps) {
|
||||
const { ref } = useParams()
|
||||
const queryClient = useQueryClient()
|
||||
const selectedProject = useSelectedProject()
|
||||
const { data: selectedProject } = useSelectedProjectQuery()
|
||||
|
||||
const canUpdatePolicies = useCheckPermissions(PermissionAction.TENANT_SQL_ADMIN_WRITE, 'tables')
|
||||
|
||||
|
||||
@@ -3,11 +3,11 @@ import { PermissionAction } from '@supabase/shared-types/out/constants'
|
||||
import { noop } from 'lodash'
|
||||
import { Edit, MoreVertical, Trash } from 'lucide-react'
|
||||
|
||||
import { useProjectContext } from 'components/layouts/ProjectLayout/ProjectContext'
|
||||
import { DropdownMenuItemTooltip } from 'components/ui/DropdownMenuItemTooltip'
|
||||
import Panel from 'components/ui/Panel'
|
||||
import { useAuthConfigQuery } from 'data/auth/auth-config-query'
|
||||
import { useCheckPermissions } from 'hooks/misc/useCheckPermissions'
|
||||
import { useSelectedProjectQuery } from 'hooks/misc/useSelectedProject'
|
||||
import { useAiAssistantStateSnapshot } from 'state/ai-assistant-state'
|
||||
import {
|
||||
Badge,
|
||||
@@ -40,7 +40,7 @@ const PolicyRow = ({
|
||||
const aiSnap = useAiAssistantStateSnapshot()
|
||||
const canUpdatePolicies = useCheckPermissions(PermissionAction.TENANT_SQL_ADMIN_WRITE, 'policies')
|
||||
|
||||
const { project } = useProjectContext()
|
||||
const { data: project } = useSelectedProjectQuery()
|
||||
const { data: authConfig } = useAuthConfigQuery({ projectRef: project?.ref })
|
||||
|
||||
// override islocked for Realtime messages table
|
||||
|
||||
@@ -2,12 +2,12 @@ import type { PostgresPolicy } from '@supabase/postgres-meta'
|
||||
import { noop } from 'lodash'
|
||||
import { Info } from 'lucide-react'
|
||||
|
||||
import { useProjectContext } from 'components/layouts/ProjectLayout/ProjectContext'
|
||||
import AlertError from 'components/ui/AlertError'
|
||||
import Panel from 'components/ui/Panel'
|
||||
import { useProjectPostgrestConfigQuery } from 'data/config/project-postgrest-config-query'
|
||||
import { useDatabasePoliciesQuery } from 'data/database-policies/database-policies-query'
|
||||
import { useTableRolesAccessQuery } from 'data/tables/table-roles-access-query'
|
||||
import { useSelectedProjectQuery } from 'hooks/misc/useSelectedProject'
|
||||
import { cn, Tooltip, TooltipContent, TooltipTrigger } from 'ui'
|
||||
import ShimmeringLoader from 'ui-patterns/ShimmeringLoader'
|
||||
import PolicyRow from './PolicyRow'
|
||||
@@ -40,7 +40,7 @@ export const PolicyTableRow = ({
|
||||
onSelectEditPolicy = noop,
|
||||
onSelectDeletePolicy = noop,
|
||||
}: PolicyTableRowProps) => {
|
||||
const { project } = useProjectContext()
|
||||
const { data: project } = useSelectedProjectQuery()
|
||||
|
||||
// [Joshen] Changes here are so that warnings are more accurate and granular instead of purely relying if RLS is disabled or enabled
|
||||
// The following scenarios are technically okay if the table has RLS disabled, in which it won't be publicly readable / writable
|
||||
|
||||
+3
-3
@@ -12,7 +12,7 @@ import UpgradeToPro from 'components/ui/UpgradeToPro'
|
||||
import { useAuthConfigQuery } from 'data/auth/auth-config-query'
|
||||
import { useAuthConfigUpdateMutation } from 'data/auth/auth-config-update-mutation'
|
||||
import { useCheckPermissions } from 'hooks/misc/useCheckPermissions'
|
||||
import { useSelectedOrganization } from 'hooks/misc/useSelectedOrganization'
|
||||
import { useSelectedOrganizationQuery } from 'hooks/misc/useSelectedOrganization'
|
||||
import { IS_PLATFORM } from 'lib/constants'
|
||||
import {
|
||||
AlertDescription_Shadcn_,
|
||||
@@ -62,7 +62,7 @@ const UserSessionsSchema = z.object({
|
||||
const SessionsAuthSettingsForm = () => {
|
||||
const { ref: projectRef } = useParams()
|
||||
const { data: authConfig, error: authConfigError, isError } = useAuthConfigQuery({ projectRef })
|
||||
const { mutate: updateAuthConfig, isLoading: isUpdatingConfig } = useAuthConfigUpdateMutation()
|
||||
const { mutate: updateAuthConfig } = useAuthConfigUpdateMutation()
|
||||
|
||||
// Separate loading states for each form
|
||||
const [isUpdatingRefreshTokens, setIsUpdatingRefreshTokens] = useState(false)
|
||||
@@ -71,7 +71,7 @@ const SessionsAuthSettingsForm = () => {
|
||||
const canReadConfig = useCheckPermissions(PermissionAction.READ, 'custom_config_gotrue')
|
||||
const canUpdateConfig = useCheckPermissions(PermissionAction.UPDATE, 'custom_config_gotrue')
|
||||
|
||||
const organization = useSelectedOrganization()
|
||||
const { data: organization } = useSelectedOrganizationQuery()
|
||||
const isProPlanAndUp = organization?.plan?.id !== 'free'
|
||||
const promptProPlanUpgrade = IS_PLATFORM && !isProPlanAndUp
|
||||
|
||||
|
||||
@@ -7,7 +7,6 @@ import { toast } from 'sonner'
|
||||
|
||||
import { LOCAL_STORAGE_KEYS, useParams } from 'common'
|
||||
import { useIsAPIDocsSidePanelEnabled } from 'components/interfaces/App/FeaturePreview/FeaturePreviewContext'
|
||||
import { useProjectContext } from 'components/layouts/ProjectLayout/ProjectContext'
|
||||
import AlertError from 'components/ui/AlertError'
|
||||
import APIDocsButton from 'components/ui/APIDocsButton'
|
||||
import { ButtonTooltip } from 'components/ui/ButtonTooltip'
|
||||
@@ -18,6 +17,7 @@ import { useUserDeleteMutation } from 'data/auth/user-delete-mutation'
|
||||
import { useUsersCountQuery } from 'data/auth/users-count-query'
|
||||
import { User, useUsersInfiniteQuery } from 'data/auth/users-infinite-query'
|
||||
import { useLocalStorageQuery } from 'hooks/misc/useLocalStorage'
|
||||
import { useSelectedProjectQuery } from 'hooks/misc/useSelectedProject'
|
||||
import { isAtBottom } from 'lib/helpers'
|
||||
import {
|
||||
Button,
|
||||
@@ -61,7 +61,7 @@ export type Filter = 'all' | 'verified' | 'unverified' | 'anonymous'
|
||||
export const UsersV2 = () => {
|
||||
const queryClient = useQueryClient()
|
||||
const { ref: projectRef } = useParams()
|
||||
const { project } = useProjectContext()
|
||||
const { data: project } = useSelectedProjectQuery()
|
||||
const gridRef = useRef<DataGridHandle>(null)
|
||||
const xScroll = useRef<number>(0)
|
||||
const isNewAPIDocsEnabled = useIsAPIDocsSidePanelEnabled()
|
||||
|
||||
@@ -7,7 +7,7 @@ import { toast } from 'sonner'
|
||||
import { Modal } from 'ui'
|
||||
|
||||
import { useOrganizationPaymentMethodSetupIntent } from 'data/organizations/organization-payment-method-setup-intent-mutation'
|
||||
import { useSelectedOrganization } from 'hooks/misc/useSelectedOrganization'
|
||||
import { useSelectedOrganizationQuery } from 'hooks/misc/useSelectedOrganization'
|
||||
import { STRIPE_PUBLIC_KEY } from 'lib/constants'
|
||||
import AddPaymentMethodForm from './AddPaymentMethodForm'
|
||||
import { getStripeElementsAppearanceOptions } from './Payment.utils'
|
||||
@@ -29,7 +29,7 @@ const AddNewPaymentMethodModal = ({
|
||||
}: AddNewPaymentMethodModalProps) => {
|
||||
const { resolvedTheme } = useTheme()
|
||||
const [intent, setIntent] = useState<any>()
|
||||
const selectedOrganization = useSelectedOrganization()
|
||||
const { data: selectedOrganization } = useSelectedOrganizationQuery()
|
||||
|
||||
const [captchaToken, setCaptchaToken] = useState<string | null>(null)
|
||||
const [captchaRef, setCaptchaRef] = useState<HCaptcha | null>(null)
|
||||
|
||||
@@ -9,7 +9,7 @@ import { useOrganizationCustomerProfileUpdateMutation } from 'data/organizations
|
||||
import { useOrganizationPaymentMethodMarkAsDefaultMutation } from 'data/organizations/organization-payment-method-default-mutation'
|
||||
import { useOrganizationTaxIdQuery } from 'data/organizations/organization-tax-id-query'
|
||||
import { useOrganizationTaxIdUpdateMutation } from 'data/organizations/organization-tax-id-update-mutation'
|
||||
import { useSelectedOrganization } from 'hooks/misc/useSelectedOrganization'
|
||||
import { useSelectedOrganizationQuery } from 'hooks/misc/useSelectedOrganization'
|
||||
import { isEqual } from 'lodash'
|
||||
import { useRef, useState } from 'react'
|
||||
import { toast } from 'sonner'
|
||||
@@ -27,7 +27,7 @@ interface AddPaymentMethodFormProps {
|
||||
// Small UX annoyance here, that the page will be refreshed
|
||||
|
||||
const AddPaymentMethodForm = ({ onCancel, onConfirm }: AddPaymentMethodFormProps) => {
|
||||
const selectedOrganization = useSelectedOrganization()
|
||||
const { data: selectedOrganization } = useSelectedOrganizationQuery()
|
||||
|
||||
const { data: customerProfile, isLoading: customerProfileLoading } =
|
||||
useOrganizationCustomerProfileQuery({
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Forward, GitBranch } from 'lucide-react'
|
||||
|
||||
import { useBranchesQuery } from 'data/branches/branches-query'
|
||||
import { useSelectedProject } from 'hooks/misc/useSelectedProject'
|
||||
import { useSelectedProjectQuery } from 'hooks/misc/useSelectedProject'
|
||||
import { PageType, useRegisterCommands, useRegisterPage, useSetPage } from 'ui-patterns/CommandMenu'
|
||||
import { COMMAND_MENU_SECTIONS } from '../App/CommandMenu/CommandMenu.utils'
|
||||
import { orderCommandSectionsByPriority } from '../App/CommandMenu/ordering'
|
||||
@@ -12,7 +12,7 @@ const EMPTY_ARRAY = [] as Array<any>
|
||||
export function useBranchCommands() {
|
||||
const setPage = useSetPage()
|
||||
|
||||
const selectedProject = useSelectedProject()
|
||||
const { data: selectedProject } = useSelectedProjectQuery()
|
||||
const isBranchingEnabled = selectedProject?.is_branch_enabled === true
|
||||
|
||||
let { data: branches } = useBranchesQuery(
|
||||
|
||||
@@ -9,6 +9,7 @@ import { useForm } from 'react-hook-form'
|
||||
import { toast } from 'sonner'
|
||||
import * as z from 'zod'
|
||||
|
||||
import { PermissionAction } from '@supabase/shared-types/out/constants'
|
||||
import { useParams } from 'common'
|
||||
import { useIsBranching2Enabled } from 'components/interfaces/App/FeaturePreview/FeaturePreviewContext'
|
||||
import { BranchingPITRNotice } from 'components/layouts/AppLayout/EnableBranchingButton/BranchingPITRNotice'
|
||||
@@ -23,8 +24,10 @@ import { useGitHubConnectionsQuery } from 'data/integrations/github-connections-
|
||||
import { projectKeys } from 'data/projects/keys'
|
||||
import { useProjectAddonsQuery } from 'data/subscriptions/project-addons-query'
|
||||
import { useSendEventMutation } from 'data/telemetry/send-event-mutation'
|
||||
import { useSelectedOrganization } from 'hooks/misc/useSelectedOrganization'
|
||||
import { useSelectedProject } from 'hooks/misc/useSelectedProject'
|
||||
import { useCheckPermissions } from 'hooks/misc/useCheckPermissions'
|
||||
import { useSelectedOrganizationQuery } from 'hooks/misc/useSelectedOrganization'
|
||||
import { useSelectedProjectQuery } from 'hooks/misc/useSelectedProject'
|
||||
import { useFlag } from 'hooks/ui/useFlag'
|
||||
import { BASE_PATH, IS_PLATFORM } from 'lib/constants'
|
||||
import { useAppStateSnapshot } from 'state/app-state'
|
||||
import {
|
||||
@@ -46,22 +49,18 @@ import {
|
||||
cn,
|
||||
} from 'ui'
|
||||
import { FormItemLayout } from 'ui-patterns/form/FormItemLayout/FormItemLayout'
|
||||
import { useCheckPermissions } from 'hooks/misc/useCheckPermissions'
|
||||
import { PermissionAction } from '@supabase/shared-types/out/constants'
|
||||
import { useFlag } from 'hooks/ui/useFlag'
|
||||
|
||||
export const CreateBranchModal = () => {
|
||||
const allowDataBranching = useFlag('allowDataBranching')
|
||||
const { ref } = useParams()
|
||||
const router = useRouter()
|
||||
const queryClient = useQueryClient()
|
||||
const projectDetails = useSelectedProject()
|
||||
const selectedOrg = useSelectedOrganization()
|
||||
const { data: projectDetails } = useSelectedProjectQuery()
|
||||
const { data: selectedOrg } = useSelectedOrganizationQuery()
|
||||
const gitlessBranching = useIsBranching2Enabled()
|
||||
const { showCreateBranchModal, setShowCreateBranchModal } = useAppStateSnapshot()
|
||||
|
||||
const organization = useSelectedOrganization()
|
||||
const isProPlanAndUp = organization?.plan?.id !== 'free'
|
||||
const isProPlanAndUp = selectedOrg?.plan?.id !== 'free'
|
||||
const promptProPlanUpgrade = IS_PLATFORM && !isProPlanAndUp
|
||||
|
||||
const isBranch = projectDetails?.parent_project_ref !== undefined
|
||||
|
||||
@@ -8,15 +8,15 @@ import { toast } from 'sonner'
|
||||
import * as z from 'zod'
|
||||
|
||||
import { useParams } from 'common'
|
||||
import { useIsBranching2Enabled } from 'components/interfaces/App/FeaturePreview/FeaturePreviewContext'
|
||||
import AlertError from 'components/ui/AlertError'
|
||||
import { GenericSkeletonLoader } from 'components/ui/ShimmeringLoader'
|
||||
import { useBranchUpdateMutation } from 'data/branches/branch-update-mutation'
|
||||
import { Branch, useBranchesQuery } from 'data/branches/branches-query'
|
||||
import { useCheckGithubBranchValidity } from 'data/integrations/github-branch-check-query'
|
||||
import { useGitHubConnectionsQuery } from 'data/integrations/github-connections-query'
|
||||
import { useSelectedOrganization } from 'hooks/misc/useSelectedOrganization'
|
||||
import { useSelectedProject } from 'hooks/misc/useSelectedProject'
|
||||
import { useIsBranching2Enabled } from 'components/interfaces/App/FeaturePreview/FeaturePreviewContext'
|
||||
import { useSelectedOrganizationQuery } from 'hooks/misc/useSelectedOrganization'
|
||||
import { useSelectedProjectQuery } from 'hooks/misc/useSelectedProject'
|
||||
import { BASE_PATH } from 'lib/constants'
|
||||
import { useRouter } from 'next/router'
|
||||
import {
|
||||
@@ -48,8 +48,8 @@ interface EditBranchModalProps {
|
||||
export const EditBranchModal = ({ branch, visible, onClose }: EditBranchModalProps) => {
|
||||
const { ref } = useParams()
|
||||
const router = useRouter()
|
||||
const projectDetails = useSelectedProject()
|
||||
const selectedOrg = useSelectedOrganization()
|
||||
const { data: projectDetails } = useSelectedProjectQuery()
|
||||
const { data: selectedOrg } = useSelectedOrganizationQuery()
|
||||
const gitlessBranching = useIsBranching2Enabled()
|
||||
|
||||
const [isGitBranchValid, setIsGitBranchValid] = useState(false)
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
import { useSendEventMutation } from 'data/telemetry/send-event-mutation'
|
||||
import { useSelectedOrganizationQuery } from 'hooks/misc/useSelectedOrganization'
|
||||
import { useSelectedProjectQuery } from 'hooks/misc/useSelectedProject'
|
||||
import { GitBranchIcon } from 'lucide-react'
|
||||
import { useState } from 'react'
|
||||
import { Button } from 'ui'
|
||||
import {
|
||||
AlertDialog,
|
||||
AlertDialogAction,
|
||||
@@ -10,12 +13,9 @@ import {
|
||||
AlertDialogHeader,
|
||||
AlertDialogTitle,
|
||||
AlertDialogTrigger,
|
||||
Button,
|
||||
} from 'ui'
|
||||
import { GitBranchIcon } from 'lucide-react'
|
||||
import { Admonition } from 'ui-patterns'
|
||||
import { useSendEventMutation } from 'data/telemetry/send-event-mutation'
|
||||
import { useSelectedOrganization } from 'hooks/misc/useSelectedOrganization'
|
||||
import { useSelectedProject } from 'hooks/misc/useSelectedProject'
|
||||
|
||||
interface OutOfDateNoticeProps {
|
||||
isBranchOutOfDateMigrations: boolean
|
||||
@@ -44,8 +44,8 @@ export const OutOfDateNotice = ({
|
||||
}: OutOfDateNoticeProps) => {
|
||||
const [isDialogOpen, setIsDialogOpen] = useState(false)
|
||||
const hasOutdatedMigrations = isBranchOutOfDateMigrations && missingMigrationsCount > 0
|
||||
const selectedOrg = useSelectedOrganization()
|
||||
const project = useSelectedProject()
|
||||
const { data: selectedOrg } = useSelectedOrganizationQuery()
|
||||
const { data: project } = useSelectedProjectQuery()
|
||||
const { mutate: sendEvent } = useSendEventMutation()
|
||||
|
||||
const isBranch = project?.parent_project_ref !== undefined
|
||||
|
||||
@@ -2,10 +2,13 @@ import dayjs from 'dayjs'
|
||||
import { MoreVertical, X } from 'lucide-react'
|
||||
import { useRouter } from 'next/router'
|
||||
|
||||
import { useQueryClient } from '@tanstack/react-query'
|
||||
import { useParams } from 'common'
|
||||
import { useBranchUpdateMutation } from 'data/branches/branch-update-mutation'
|
||||
import type { Branch } from 'data/branches/branches-query'
|
||||
import { branchKeys } from 'data/branches/keys'
|
||||
import { useSelectedProjectQuery } from 'hooks/misc/useSelectedProject'
|
||||
import { toast } from 'sonner'
|
||||
import {
|
||||
Button,
|
||||
DropdownMenu,
|
||||
@@ -13,9 +16,6 @@ import {
|
||||
DropdownMenuItem,
|
||||
DropdownMenuTrigger,
|
||||
} from 'ui'
|
||||
import { toast } from 'sonner'
|
||||
import { useQueryClient } from '@tanstack/react-query'
|
||||
import { useSelectedProject } from 'hooks/misc/useSelectedProject'
|
||||
|
||||
interface ReviewRowProps {
|
||||
branch: Branch
|
||||
@@ -23,7 +23,7 @@ interface ReviewRowProps {
|
||||
|
||||
export const ReviewRow = ({ branch }: ReviewRowProps) => {
|
||||
const router = useRouter()
|
||||
const project = useSelectedProject()
|
||||
const { data: project } = useSelectedProjectQuery()
|
||||
const { ref: projectRef } = useParams()
|
||||
const queryClient = useQueryClient()
|
||||
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import { AiIconAnimation } from 'ui'
|
||||
import { useProjectByRef } from 'hooks/misc/useSelectedProject'
|
||||
import { useTablesQuery } from 'data/tables/tables-query'
|
||||
import { useAiAssistantStateSnapshot } from 'state/ai-assistant-state'
|
||||
import { Branch } from 'data/branches/branches-query'
|
||||
import { tablesToSQL } from 'lib/helpers'
|
||||
import { ButtonTooltip } from 'components/ui/ButtonTooltip'
|
||||
import { Branch } from 'data/branches/branches-query'
|
||||
import { useTablesQuery } from 'data/tables/tables-query'
|
||||
import { useSendEventMutation } from 'data/telemetry/send-event-mutation'
|
||||
import { useSelectedOrganization } from 'hooks/misc/useSelectedOrganization'
|
||||
import { useSelectedOrganizationQuery } from 'hooks/misc/useSelectedOrganization'
|
||||
import { useProjectByRefQuery } from 'hooks/misc/useSelectedProject'
|
||||
import { tablesToSQL } from 'lib/helpers'
|
||||
import { useAiAssistantStateSnapshot } from 'state/ai-assistant-state'
|
||||
import { AiIconAnimation } from 'ui'
|
||||
|
||||
interface ReviewWithAIProps {
|
||||
currentBranch?: Branch
|
||||
@@ -24,11 +24,11 @@ export const ReviewWithAI = ({
|
||||
disabled = false,
|
||||
}: ReviewWithAIProps) => {
|
||||
const aiSnap = useAiAssistantStateSnapshot()
|
||||
const selectedOrg = useSelectedOrganization()
|
||||
const { data: selectedOrg } = useSelectedOrganizationQuery()
|
||||
const { mutate: sendEvent } = useSendEventMutation()
|
||||
|
||||
// Get parent project for production schema
|
||||
const parentProject = useProjectByRef(parentProjectRef)
|
||||
const { data: parentProject } = useProjectByRefQuery(parentProjectRef)
|
||||
|
||||
// Fetch production schema tables
|
||||
const { data: productionTables } = useTablesQuery(
|
||||
|
||||
@@ -10,7 +10,7 @@ import Panel from 'components/ui/Panel'
|
||||
import { getKeys, useAPIKeysQuery } from 'data/api-keys/api-keys-query'
|
||||
import { useProjectSettingsV2Query } from 'data/config/project-settings-v2-query'
|
||||
import { useCheckPermissions } from 'hooks/misc/useCheckPermissions'
|
||||
import { useSelectedProject } from 'hooks/misc/useSelectedProject'
|
||||
import { useSelectedProjectQuery } from 'hooks/misc/useSelectedProject'
|
||||
import { PROJECT_STATUS } from 'lib/constants'
|
||||
import {
|
||||
Button,
|
||||
@@ -35,7 +35,7 @@ import ConnectTabContent from './ConnectTabContent'
|
||||
|
||||
export const Connect = () => {
|
||||
const { ref: projectRef } = useParams()
|
||||
const selectedProject = useSelectedProject()
|
||||
const { data: selectedProject } = useSelectedProjectQuery()
|
||||
const isActiveHealthy = selectedProject?.status === PROJECT_STATUS.ACTIVE_HEALTHY
|
||||
|
||||
const [showConnect, setShowConnect] = useQueryState(
|
||||
|
||||
@@ -7,7 +7,7 @@ import { useProjectSettingsV2Query } from 'data/config/project-settings-v2-query
|
||||
import { usePgbouncerConfigQuery } from 'data/database/pgbouncer-config-query'
|
||||
import { useSupavisorConfigurationQuery } from 'data/database/supavisor-configuration-query'
|
||||
import { useProjectAddonsQuery } from 'data/subscriptions/project-addons-query'
|
||||
import { useSelectedOrganization } from 'hooks/misc/useSelectedOrganization'
|
||||
import { useSelectedOrganizationQuery } from 'hooks/misc/useSelectedOrganization'
|
||||
import { pluckObjectFields } from 'lib/helpers'
|
||||
import { cn } from 'ui'
|
||||
import { getAddons } from '../Billing/Subscription/Subscription.utils'
|
||||
@@ -30,7 +30,7 @@ interface ConnectContentTabProps extends HTMLAttributes<HTMLDivElement> {
|
||||
const ConnectTabContent = forwardRef<HTMLDivElement, ConnectContentTabProps>(
|
||||
({ projectKeys, filePath, ...props }, ref) => {
|
||||
const { ref: projectRef } = useParams()
|
||||
const selectedOrg = useSelectedOrganization()
|
||||
const { data: selectedOrg } = useSelectedOrganizationQuery()
|
||||
const allowPgBouncerSelection = useMemo(() => selectedOrg?.plan.id !== 'free', [selectedOrg])
|
||||
|
||||
const { data: settings } = useProjectSettingsV2Query({ projectRef })
|
||||
|
||||
@@ -12,7 +12,7 @@ import { useSupavisorConfigurationQuery } from 'data/database/supavisor-configur
|
||||
import { useReadReplicasQuery } from 'data/read-replicas/replicas-query'
|
||||
import { useProjectAddonsQuery } from 'data/subscriptions/project-addons-query'
|
||||
import { useSendEventMutation } from 'data/telemetry/send-event-mutation'
|
||||
import { useSelectedOrganization } from 'hooks/misc/useSelectedOrganization'
|
||||
import { useSelectedOrganizationQuery } from 'hooks/misc/useSelectedOrganization'
|
||||
import { IS_PLATFORM } from 'lib/constants'
|
||||
import { pluckObjectFields } from 'lib/helpers'
|
||||
import { useDatabaseSelectorStateSnapshot } from 'state/database-selector'
|
||||
@@ -63,7 +63,7 @@ const StepLabel = ({
|
||||
*/
|
||||
export const DatabaseConnectionString = () => {
|
||||
const { ref: projectRef } = useParams()
|
||||
const org = useSelectedOrganization()
|
||||
const { data: org } = useSelectedOrganizationQuery()
|
||||
const state = useDatabaseSelectorStateSnapshot()
|
||||
|
||||
const [selectedTab, setSelectedTab] = useState<DatabaseConnectionType>('uri')
|
||||
|
||||
@@ -6,12 +6,12 @@ import { useState } from 'react'
|
||||
import { toast } from 'sonner'
|
||||
|
||||
import { useParams } from 'common'
|
||||
import { useProjectContext } from 'components/layouts/ProjectLayout/ProjectContext'
|
||||
import Panel from 'components/ui/Panel'
|
||||
import UpgradeToPro from 'components/ui/UpgradeToPro'
|
||||
import { useBackupRestoreMutation } from 'data/database/backup-restore-mutation'
|
||||
import { DatabaseBackup, useBackupsQuery } from 'data/database/backups-query'
|
||||
import { setProjectStatus } from 'data/projects/projects-query'
|
||||
import { useSelectedProjectQuery } from 'hooks/misc/useSelectedProject'
|
||||
import { PROJECT_STATUS } from 'lib/constants'
|
||||
import ConfirmationModal from 'ui-patterns/Dialogs/ConfirmationModal'
|
||||
import BackupItem from './BackupItem'
|
||||
@@ -23,7 +23,7 @@ const BackupsList = () => {
|
||||
const queryClient = useQueryClient()
|
||||
const { ref: projectRef } = useParams()
|
||||
|
||||
const { project: selectedProject } = useProjectContext()
|
||||
const { data: selectedProject } = useSelectedProjectQuery()
|
||||
const isHealthy = selectedProject?.status === PROJECT_STATUS.ACTIVE_HEALTHY
|
||||
|
||||
const [selectedBackup, setSelectedBackup] = useState<DatabaseBackup>()
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { useProjectContext } from 'components/layouts/ProjectLayout/ProjectContext'
|
||||
import Link from 'next/link'
|
||||
import React from 'react'
|
||||
|
||||
import { useSelectedProjectQuery } from 'hooks/misc/useSelectedProject'
|
||||
import { Badge, NavMenu, NavMenuItem } from 'ui'
|
||||
|
||||
type Props = {
|
||||
@@ -9,7 +8,7 @@ type Props = {
|
||||
}
|
||||
|
||||
function DatabaseBackupsNav({ active }: Props) {
|
||||
const { ref, cloud_provider } = useProjectContext()?.project || {}
|
||||
const { ref, cloud_provider } = useSelectedProjectQuery()?.data || {}
|
||||
|
||||
const navMenuItems = [
|
||||
{
|
||||
|
||||
+4
-4
@@ -1,7 +1,7 @@
|
||||
import { useProjectContext } from 'components/layouts/ProjectLayout/ProjectContext'
|
||||
import Panel from 'components/ui/Panel'
|
||||
import { useCloneBackupsQuery } from 'data/projects/clone-query'
|
||||
import { useSelectedOrganization } from 'hooks/misc/useSelectedOrganization'
|
||||
import { useSelectedOrganizationQuery } from 'hooks/misc/useSelectedOrganization'
|
||||
import { useSelectedProjectQuery } from 'hooks/misc/useSelectedProject'
|
||||
import { Badge, Button } from 'ui'
|
||||
import { TimestampInfo } from 'ui-patterns'
|
||||
import BackupsEmpty from '../BackupsEmpty'
|
||||
@@ -12,8 +12,8 @@ interface BackupsListProps {
|
||||
}
|
||||
|
||||
export const BackupsList = ({ onSelectRestore, disabled }: BackupsListProps) => {
|
||||
const { project } = useProjectContext()
|
||||
const organization = useSelectedOrganization()
|
||||
const { data: project } = useSelectedProjectQuery()
|
||||
const { data: organization } = useSelectedOrganizationQuery()
|
||||
|
||||
const isFreePlan = organization?.plan?.id === 'free'
|
||||
|
||||
|
||||
+4
-4
@@ -1,5 +1,5 @@
|
||||
import { useProjectContext } from 'components/layouts/ProjectLayout/ProjectContext'
|
||||
import { useSelectedOrganization } from 'hooks/misc/useSelectedOrganization'
|
||||
import { useSelectedOrganizationQuery } from 'hooks/misc/useSelectedOrganization'
|
||||
import { useSelectedProjectQuery } from 'hooks/misc/useSelectedProject'
|
||||
import {
|
||||
Button,
|
||||
Dialog,
|
||||
@@ -26,8 +26,8 @@ export const ConfirmRestoreDialog = ({
|
||||
onSelectContinue,
|
||||
additionalMonthlySpend,
|
||||
}: ConfirmRestoreDialogProps) => {
|
||||
const { project } = useProjectContext()
|
||||
const organization = useSelectedOrganization()
|
||||
const { data: project } = useSelectedProjectQuery()
|
||||
const { data: organization } = useSelectedOrganizationQuery()
|
||||
|
||||
return (
|
||||
<Dialog open={open} onOpenChange={onOpenChange}>
|
||||
|
||||
+4
-4
@@ -5,11 +5,11 @@ import { useForm } from 'react-hook-form'
|
||||
import { toast } from 'sonner'
|
||||
import { z } from 'zod'
|
||||
|
||||
import { useProjectContext } from 'components/layouts/ProjectLayout/ProjectContext'
|
||||
import PasswordStrengthBar from 'components/ui/PasswordStrengthBar'
|
||||
import { useProjectCloneMutation } from 'data/projects/clone-mutation'
|
||||
import { useCloneBackupsQuery } from 'data/projects/clone-query'
|
||||
import { useSelectedOrganization } from 'hooks/misc/useSelectedOrganization'
|
||||
import { useSelectedOrganizationQuery } from 'hooks/misc/useSelectedOrganization'
|
||||
import { useSelectedProjectQuery } from 'hooks/misc/useSelectedProject'
|
||||
import { passwordStrength } from 'lib/helpers'
|
||||
import { generateStrongPassword } from 'lib/project'
|
||||
import {
|
||||
@@ -48,8 +48,8 @@ export const CreateNewProjectDialog = ({
|
||||
onCloneSuccess,
|
||||
additionalMonthlySpend,
|
||||
}: CreateNewProjectDialogProps) => {
|
||||
const { project } = useProjectContext()
|
||||
const organization = useSelectedOrganization()
|
||||
const { data: project } = useSelectedProjectQuery()
|
||||
const { data: organization } = useSelectedOrganizationQuery()
|
||||
|
||||
const [passwordStrengthScore, setPasswordStrengthScore] = useState(0)
|
||||
const [passwordStrengthMessage, setPasswordStrengthMessage] = useState('')
|
||||
|
||||
+6
-6
@@ -1,9 +1,14 @@
|
||||
import { zodResolver } from '@hookform/resolvers/zod'
|
||||
import { AlertCircle, ExternalLink, Plus } from 'lucide-react'
|
||||
import Link from 'next/link'
|
||||
import { useEffect, useRef } from 'react'
|
||||
import { DragDropContext, Droppable, DroppableProvided } from 'react-beautiful-dnd'
|
||||
import { useFieldArray, useForm } from 'react-hook-form'
|
||||
import { toast } from 'sonner'
|
||||
import * as z from 'zod'
|
||||
|
||||
import { useEnumeratedTypeCreateMutation } from 'data/enumerated-types/enumerated-type-create-mutation'
|
||||
import { useSelectedProjectQuery } from 'hooks/misc/useSelectedProject'
|
||||
import {
|
||||
AlertDescription_Shadcn_,
|
||||
AlertTitle_Shadcn_,
|
||||
@@ -20,13 +25,8 @@ import {
|
||||
SidePanel,
|
||||
cn,
|
||||
} from 'ui'
|
||||
import * as z from 'zod'
|
||||
|
||||
import { useProjectContext } from 'components/layouts/ProjectLayout/ProjectContext'
|
||||
import { useEnumeratedTypeCreateMutation } from 'data/enumerated-types/enumerated-type-create-mutation'
|
||||
import EnumeratedTypeValueRow from './EnumeratedTypeValueRow'
|
||||
import { NATIVE_POSTGRES_TYPES } from './EnumeratedTypes.constants'
|
||||
import { AlertCircle, ExternalLink, Plus } from 'lucide-react'
|
||||
|
||||
interface CreateEnumeratedTypeSidePanelProps {
|
||||
visible: boolean
|
||||
@@ -41,7 +41,7 @@ const CreateEnumeratedTypeSidePanel = ({
|
||||
}: CreateEnumeratedTypeSidePanelProps) => {
|
||||
const initialValues = { name: '', description: '', values: [{ value: '' }] }
|
||||
const submitRef = useRef<HTMLButtonElement>(null)
|
||||
const { project } = useProjectContext()
|
||||
const { data: project } = useSelectedProjectQuery()
|
||||
const { mutate: createEnumeratedType, isLoading: isCreating } = useEnumeratedTypeCreateMutation({
|
||||
onSuccess: (res, vars) => {
|
||||
toast.success(`Successfully created type "${vars.name}"`)
|
||||
|
||||
+4
-3
@@ -1,6 +1,7 @@
|
||||
import { useProjectContext } from 'components/layouts/ProjectLayout/ProjectContext'
|
||||
import { useEnumeratedTypeDeleteMutation } from 'data/enumerated-types/enumerated-type-delete-mutation'
|
||||
import { toast } from 'sonner'
|
||||
|
||||
import { useEnumeratedTypeDeleteMutation } from 'data/enumerated-types/enumerated-type-delete-mutation'
|
||||
import { useSelectedProjectQuery } from 'hooks/misc/useSelectedProject'
|
||||
import ConfirmationModal from 'ui-patterns/Dialogs/ConfirmationModal'
|
||||
|
||||
interface DeleteEnumeratedTypeModalProps {
|
||||
@@ -14,7 +15,7 @@ const DeleteEnumeratedTypeModal = ({
|
||||
selectedEnumeratedType,
|
||||
onClose,
|
||||
}: DeleteEnumeratedTypeModalProps) => {
|
||||
const { project } = useProjectContext()
|
||||
const { data: project } = useSelectedProjectQuery()
|
||||
const { mutate: deleteEnumeratedType, isLoading: isDeleting } = useEnumeratedTypeDeleteMutation({
|
||||
onSuccess: () => {
|
||||
toast.success(`Successfully deleted "${selectedEnumeratedType.name}"`)
|
||||
|
||||
+8
-8
@@ -1,8 +1,15 @@
|
||||
import { zodResolver } from '@hookform/resolvers/zod'
|
||||
import { AlertCircle, ExternalLink, Plus } from 'lucide-react'
|
||||
import Link from 'next/link'
|
||||
import { useEffect, useRef } from 'react'
|
||||
import { DragDropContext, Droppable, DroppableProvided } from 'react-beautiful-dnd'
|
||||
import { useFieldArray, useForm } from 'react-hook-form'
|
||||
import { toast } from 'sonner'
|
||||
import * as z from 'zod'
|
||||
|
||||
import { useEnumeratedTypeUpdateMutation } from 'data/enumerated-types/enumerated-type-update-mutation'
|
||||
import type { EnumeratedType } from 'data/enumerated-types/enumerated-types-query'
|
||||
import { useSelectedProjectQuery } from 'hooks/misc/useSelectedProject'
|
||||
import {
|
||||
AlertDescription_Shadcn_,
|
||||
AlertTitle_Shadcn_,
|
||||
@@ -19,14 +26,7 @@ import {
|
||||
SidePanel,
|
||||
cn,
|
||||
} from 'ui'
|
||||
import * as z from 'zod'
|
||||
|
||||
import { useProjectContext } from 'components/layouts/ProjectLayout/ProjectContext'
|
||||
import { useEnumeratedTypeUpdateMutation } from 'data/enumerated-types/enumerated-type-update-mutation'
|
||||
import type { EnumeratedType } from 'data/enumerated-types/enumerated-types-query'
|
||||
import { DragDropContext, Droppable, DroppableProvided } from 'react-beautiful-dnd'
|
||||
import EnumeratedTypeValueRow from './EnumeratedTypeValueRow'
|
||||
import { AlertCircle, ExternalLink, Plus } from 'lucide-react'
|
||||
|
||||
interface EditEnumeratedTypeSidePanelProps {
|
||||
visible: boolean
|
||||
@@ -40,7 +40,7 @@ const EditEnumeratedTypeSidePanel = ({
|
||||
onClose,
|
||||
}: EditEnumeratedTypeSidePanelProps) => {
|
||||
const submitRef = useRef<HTMLButtonElement>(null)
|
||||
const { project } = useProjectContext()
|
||||
const { data: project } = useSelectedProjectQuery()
|
||||
const { mutate: updateEnumeratedType, isLoading: isCreating } = useEnumeratedTypeUpdateMutation({
|
||||
onSuccess: (_, vars) => {
|
||||
toast.success(`Successfully updated type "${vars.name.updated}"`)
|
||||
|
||||
@@ -1,18 +1,17 @@
|
||||
import { Edit, MoreVertical, Search, Trash } from 'lucide-react'
|
||||
import { useState } from 'react'
|
||||
|
||||
import { useProjectContext } from 'components/layouts/ProjectLayout/ProjectContext'
|
||||
import Table from 'components/to-be-cleaned/Table'
|
||||
import AlertError from 'components/ui/AlertError'
|
||||
import { DocsButton } from 'components/ui/DocsButton'
|
||||
import SchemaSelector from 'components/ui/SchemaSelector'
|
||||
import { GenericSkeletonLoader } from 'components/ui/ShimmeringLoader'
|
||||
import { useSchemasQuery } from 'data/database/schemas-query'
|
||||
import {
|
||||
EnumeratedType,
|
||||
useEnumeratedTypesQuery,
|
||||
} from 'data/enumerated-types/enumerated-types-query'
|
||||
import { useQuerySchemaState } from 'hooks/misc/useSchemaQueryState'
|
||||
import { useSelectedProjectQuery } from 'hooks/misc/useSelectedProject'
|
||||
import { useIsProtectedSchema } from 'hooks/useProtectedSchemas'
|
||||
import {
|
||||
Button,
|
||||
@@ -28,18 +27,13 @@ import DeleteEnumeratedTypeModal from './DeleteEnumeratedTypeModal'
|
||||
import EditEnumeratedTypeSidePanel from './EditEnumeratedTypeSidePanel'
|
||||
|
||||
const EnumeratedTypes = () => {
|
||||
const { project } = useProjectContext()
|
||||
const { data: project } = useSelectedProjectQuery()
|
||||
const [search, setSearch] = useState('')
|
||||
const { selectedSchema, setSelectedSchema } = useQuerySchemaState()
|
||||
const [showCreateTypePanel, setShowCreateTypePanel] = useState(false)
|
||||
const [selectedTypeToEdit, setSelectedTypeToEdit] = useState<EnumeratedType>()
|
||||
const [selectedTypeToDelete, setSelectedTypeToDelete] = useState<EnumeratedType>()
|
||||
|
||||
const { data: schemas } = useSchemasQuery({
|
||||
projectRef: project?.ref,
|
||||
connectionString: project?.connectionString,
|
||||
})
|
||||
|
||||
const { data, error, isLoading, isError, isSuccess } = useEnumeratedTypesQuery({
|
||||
projectRef: project?.ref,
|
||||
connectionString: project?.connectionString,
|
||||
|
||||
@@ -3,13 +3,12 @@ import { Database, ExternalLinkIcon, Plus } from 'lucide-react'
|
||||
import { useEffect, useState } from 'react'
|
||||
import { toast } from 'sonner'
|
||||
|
||||
import { useProjectContext } from 'components/layouts/ProjectLayout/ProjectContext'
|
||||
import { DocsButton } from 'components/ui/DocsButton'
|
||||
import ShimmeringLoader from 'components/ui/ShimmeringLoader'
|
||||
import { useDatabaseExtensionEnableMutation } from 'data/database-extensions/database-extension-enable-mutation'
|
||||
import { useSchemasQuery } from 'data/database/schemas-query'
|
||||
import { executeSql } from 'data/sql/execute-sql-query'
|
||||
import { useIsOrioleDb } from 'hooks/misc/useSelectedProject'
|
||||
import { useIsOrioleDb, useSelectedProjectQuery } from 'hooks/misc/useSelectedProject'
|
||||
import {
|
||||
AlertDescription_Shadcn_,
|
||||
AlertTitle_Shadcn_,
|
||||
@@ -32,7 +31,7 @@ interface EnableExtensionModalProps {
|
||||
}
|
||||
|
||||
const EnableExtensionModal = ({ visible, extension, onCancel }: EnableExtensionModalProps) => {
|
||||
const { project } = useProjectContext()
|
||||
const { data: project } = useSelectedProjectQuery()
|
||||
const isOrioleDb = useIsOrioleDb()
|
||||
const [defaultSchema, setDefaultSchema] = useState()
|
||||
const [fetchingSchemaInfo, setFetchingSchemaInfo] = useState(false)
|
||||
|
||||
@@ -4,12 +4,11 @@ import Link from 'next/link'
|
||||
import { useState } from 'react'
|
||||
import { toast } from 'sonner'
|
||||
|
||||
import { useProjectContext } from 'components/layouts/ProjectLayout/ProjectContext'
|
||||
import { ButtonTooltip } from 'components/ui/ButtonTooltip'
|
||||
import { useDatabaseExtensionDisableMutation } from 'data/database-extensions/database-extension-disable-mutation'
|
||||
import { DatabaseExtension } from 'data/database-extensions/database-extensions-query'
|
||||
import { useCheckPermissions } from 'hooks/misc/useCheckPermissions'
|
||||
import { useIsOrioleDb } from 'hooks/misc/useSelectedProject'
|
||||
import { useIsOrioleDb, useSelectedProjectQuery } from 'hooks/misc/useSelectedProject'
|
||||
import { extensions } from 'shared-data'
|
||||
import { Button, cn, Switch, Tooltip, TooltipContent, TooltipTrigger } from 'ui'
|
||||
import { Admonition } from 'ui-patterns'
|
||||
@@ -22,7 +21,7 @@ interface ExtensionCardProps {
|
||||
}
|
||||
|
||||
const ExtensionCard = ({ extension }: ExtensionCardProps) => {
|
||||
const { project } = useProjectContext()
|
||||
const { data: project } = useSelectedProjectQuery()
|
||||
const isOn = extension.installed_version !== null
|
||||
const isOrioleDb = useIsOrioleDb()
|
||||
|
||||
|
||||
@@ -4,13 +4,13 @@ import { AlertCircle, Search } from 'lucide-react'
|
||||
import { useEffect, useState } from 'react'
|
||||
|
||||
import { useParams } from 'common'
|
||||
import { useProjectContext } from 'components/layouts/ProjectLayout/ProjectContext'
|
||||
import { DocsButton } from 'components/ui/DocsButton'
|
||||
import InformationBox from 'components/ui/InformationBox'
|
||||
import NoSearchResults from 'components/ui/NoSearchResults'
|
||||
import ShimmeringLoader from 'components/ui/ShimmeringLoader'
|
||||
import { useDatabaseExtensionsQuery } from 'data/database-extensions/database-extensions-query'
|
||||
import { useCheckPermissions, usePermissionsLoaded } from 'hooks/misc/useCheckPermissions'
|
||||
import { useSelectedProjectQuery } from 'hooks/misc/useSelectedProject'
|
||||
import { Input } from 'ui'
|
||||
import ExtensionCard from './ExtensionCard'
|
||||
import ExtensionCardSkeleton from './ExtensionCardSkeleton'
|
||||
@@ -18,7 +18,7 @@ import { HIDDEN_EXTENSIONS, SEARCH_TERMS } from './Extensions.constants'
|
||||
|
||||
const Extensions = () => {
|
||||
const { filter } = useParams()
|
||||
const { project } = useProjectContext()
|
||||
const { data: project } = useSelectedProjectQuery()
|
||||
const [filterString, setFilterString] = useState<string>('')
|
||||
|
||||
const { data, isLoading } = useDatabaseExtensionsQuery({
|
||||
|
||||
@@ -7,12 +7,12 @@ import { toast } from 'sonner'
|
||||
import z from 'zod'
|
||||
|
||||
import { POSTGRES_DATA_TYPES } from 'components/interfaces/TableGridEditor/SidePanelEditor/SidePanelEditor.constants'
|
||||
import { useProjectContext } from 'components/layouts/ProjectLayout/ProjectContext'
|
||||
import SchemaSelector from 'components/ui/SchemaSelector'
|
||||
import { useDatabaseExtensionsQuery } from 'data/database-extensions/database-extensions-query'
|
||||
import { useDatabaseFunctionCreateMutation } from 'data/database-functions/database-functions-create-mutation'
|
||||
import { DatabaseFunction } from 'data/database-functions/database-functions-query'
|
||||
import { useDatabaseFunctionUpdateMutation } from 'data/database-functions/database-functions-update-mutation'
|
||||
import { useSelectedProjectQuery } from 'hooks/misc/useSelectedProject'
|
||||
import { useProtectedSchemas } from 'hooks/useProtectedSchemas'
|
||||
import type { FormSchema } from 'types'
|
||||
import {
|
||||
@@ -69,7 +69,7 @@ const FormSchema = z.object({
|
||||
})
|
||||
|
||||
const CreateFunction = ({ func, visible, setVisible }: CreateFunctionProps) => {
|
||||
const { project } = useProjectContext()
|
||||
const { data: project } = useSelectedProjectQuery()
|
||||
const [isClosingPanel, setIsClosingPanel] = useState(false)
|
||||
const [advancedSettingsShown, setAdvancedSettingsShown] = useState(false)
|
||||
// For now, there's no AI assistant for functions
|
||||
@@ -186,7 +186,7 @@ const CreateFunction = ({ func, visible, setVisible }: CreateFunctionProps) => {
|
||||
layout="horizontal"
|
||||
>
|
||||
<FormControl_Shadcn_>
|
||||
<Input_Shadcn_ {...field} />
|
||||
<Input_Shadcn_ {...field} placeholder="Name of function" />
|
||||
</FormControl_Shadcn_>
|
||||
</FormItemLayout>
|
||||
)}
|
||||
@@ -601,7 +601,7 @@ const FormFieldConfigParams = ({ readonly }: FormFieldConfigParamsProps) => {
|
||||
const ALL_ALLOWED_LANGUAGES = ['plpgsql', 'sql', 'plcoffee', 'plv8', 'plls']
|
||||
|
||||
const FormFieldLanguage = () => {
|
||||
const { project } = useProjectContext()
|
||||
const { data: project } = useSelectedProjectQuery()
|
||||
|
||||
const { data: enabledExtensions } = useDatabaseExtensionsQuery(
|
||||
{
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { toast } from 'sonner'
|
||||
|
||||
import { useProjectContext } from 'components/layouts/ProjectLayout/ProjectContext'
|
||||
import { useDatabaseFunctionDeleteMutation } from 'data/database-functions/database-functions-delete-mutation'
|
||||
import { DatabaseFunction } from 'data/database-functions/database-functions-query'
|
||||
import { useSelectedProjectQuery } from 'hooks/misc/useSelectedProject'
|
||||
import TextConfirmModal from 'ui-patterns/Dialogs/TextConfirmModal'
|
||||
|
||||
interface DeleteFunctionProps {
|
||||
@@ -12,7 +12,7 @@ interface DeleteFunctionProps {
|
||||
}
|
||||
|
||||
const DeleteFunction = ({ func, visible, setVisible }: DeleteFunctionProps) => {
|
||||
const { project } = useProjectContext()
|
||||
const { data: project } = useSelectedProjectQuery()
|
||||
const { name, schema } = func ?? {}
|
||||
|
||||
const { mutate: deleteDatabaseFunction, isLoading } = useDatabaseFunctionDeleteMutation({
|
||||
|
||||
@@ -3,11 +3,11 @@ import { includes, noop, sortBy } from 'lodash'
|
||||
import { Edit, Edit2, FileText, MoreVertical, Trash } from 'lucide-react'
|
||||
import { useRouter } from 'next/router'
|
||||
|
||||
import { useProjectContext } from 'components/layouts/ProjectLayout/ProjectContext'
|
||||
import Table from 'components/to-be-cleaned/Table'
|
||||
import { ButtonTooltip } from 'components/ui/ButtonTooltip'
|
||||
import { useDatabaseFunctionsQuery } from 'data/database-functions/database-functions-query'
|
||||
import { useCheckPermissions } from 'hooks/misc/useCheckPermissions'
|
||||
import { useSelectedProjectQuery } from 'hooks/misc/useSelectedProject'
|
||||
import { useAiAssistantStateSnapshot } from 'state/ai-assistant-state'
|
||||
import {
|
||||
Button,
|
||||
@@ -34,7 +34,7 @@ const FunctionList = ({
|
||||
deleteFunction = noop,
|
||||
}: FunctionListProps) => {
|
||||
const router = useRouter()
|
||||
const { project: selectedProject } = useProjectContext()
|
||||
const { data: selectedProject } = useSelectedProjectQuery()
|
||||
const aiSnap = useAiAssistantStateSnapshot()
|
||||
|
||||
const { data: functions } = useDatabaseFunctionsQuery({
|
||||
@@ -112,7 +112,12 @@ const FunctionList = ({
|
||||
{canUpdateFunctions ? (
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button type="default" className="px-1" icon={<MoreVertical />} />
|
||||
<Button
|
||||
aria-label="More options"
|
||||
type="default"
|
||||
className="px-1"
|
||||
icon={<MoreVertical />}
|
||||
/>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent side="left" className="w-52">
|
||||
{isApiDocumentAvailable && (
|
||||
|
||||
+2
-2
@@ -5,7 +5,6 @@ import { Search } from 'lucide-react'
|
||||
import { useRouter } from 'next/router'
|
||||
|
||||
import { useParams } from 'common'
|
||||
import { useProjectContext } from 'components/layouts/ProjectLayout/ProjectContext'
|
||||
import ProductEmptyState from 'components/to-be-cleaned/ProductEmptyState'
|
||||
import Table from 'components/to-be-cleaned/Table'
|
||||
import AlertError from 'components/ui/AlertError'
|
||||
@@ -16,6 +15,7 @@ import { useDatabaseFunctionsQuery } from 'data/database-functions/database-func
|
||||
import { useSchemasQuery } from 'data/database/schemas-query'
|
||||
import { useCheckPermissions } from 'hooks/misc/useCheckPermissions'
|
||||
import { useQuerySchemaState } from 'hooks/misc/useSchemaQueryState'
|
||||
import { useSelectedProjectQuery } from 'hooks/misc/useSelectedProject'
|
||||
import { useIsProtectedSchema } from 'hooks/useProtectedSchemas'
|
||||
import { useAiAssistantStateSnapshot } from 'state/ai-assistant-state'
|
||||
import { AiIconAnimation, Input } from 'ui'
|
||||
@@ -35,7 +35,7 @@ const FunctionsList = ({
|
||||
}: FunctionsListProps) => {
|
||||
const router = useRouter()
|
||||
const { search } = useParams()
|
||||
const { project } = useProjectContext()
|
||||
const { data: project } = useSelectedProjectQuery()
|
||||
const aiSnap = useAiAssistantStateSnapshot()
|
||||
const { selectedSchema, setSelectedSchema } = useQuerySchemaState()
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import type { PostgresTrigger } from '@supabase/postgres-meta'
|
||||
import { toast } from 'sonner'
|
||||
|
||||
import { useProjectContext } from 'components/layouts/ProjectLayout/ProjectContext'
|
||||
import { useDatabaseTriggerDeleteMutation } from 'data/database-triggers/database-trigger-delete-mutation'
|
||||
import { useSelectedProjectQuery } from 'hooks/misc/useSelectedProject'
|
||||
import TextConfirmModal from 'ui-patterns/Dialogs/TextConfirmModal'
|
||||
|
||||
interface DeleteHookModalProps {
|
||||
@@ -14,7 +14,7 @@ interface DeleteHookModalProps {
|
||||
const DeleteHookModal = ({ selectedHook, visible, onClose }: DeleteHookModalProps) => {
|
||||
const { name, schema } = selectedHook ?? {}
|
||||
|
||||
const { project } = useProjectContext()
|
||||
const { data: project } = useSelectedProjectQuery()
|
||||
const { mutate: deleteDatabaseTrigger, isLoading: isDeleting } = useDatabaseTriggerDeleteMutation(
|
||||
{
|
||||
onSuccess: () => {
|
||||
|
||||
@@ -4,11 +4,11 @@ import { useEffect, useMemo, useRef, useState } from 'react'
|
||||
import { toast } from 'sonner'
|
||||
|
||||
import { useParams } from 'common'
|
||||
import { useProjectContext } from 'components/layouts/ProjectLayout/ProjectContext'
|
||||
import { useDatabaseTriggerCreateMutation } from 'data/database-triggers/database-trigger-create-mutation'
|
||||
import { useDatabaseTriggerUpdateMutation } from 'data/database-triggers/database-trigger-update-transaction-mutation'
|
||||
import { getTableEditor } from 'data/table-editor/table-editor-query'
|
||||
import { useTablesQuery } from 'data/tables/tables-query'
|
||||
import { useSelectedProjectQuery } from 'hooks/misc/useSelectedProject'
|
||||
import { isValidHttpUrl, uuidv4 } from 'lib/helpers'
|
||||
import { Button, Form, SidePanel } from 'ui'
|
||||
import ConfirmationModal from 'ui-patterns/Dialogs/ConfirmationModal'
|
||||
@@ -85,7 +85,7 @@ export const EditHookPanel = ({ visible, selectedHook, onClose }: EditHookPanelP
|
||||
}))
|
||||
})
|
||||
|
||||
const { project } = useProjectContext()
|
||||
const { data: project } = useSelectedProjectQuery()
|
||||
const { data } = useTablesQuery({
|
||||
projectRef: project?.ref,
|
||||
connectionString: project?.connectionString,
|
||||
|
||||
@@ -6,7 +6,7 @@ import { useParams } from 'common'
|
||||
import { FormSection, FormSectionContent, FormSectionLabel } from 'components/ui/Forms/FormSection'
|
||||
import { useAPIKeysQuery } from 'data/api-keys/api-keys-query'
|
||||
import { useEdgeFunctionsQuery } from 'data/edge-functions/edge-functions-query'
|
||||
import { useSelectedProject } from 'hooks/misc/useSelectedProject'
|
||||
import { useSelectedProjectQuery } from 'hooks/misc/useSelectedProject'
|
||||
import { uuidv4 } from 'lib/helpers'
|
||||
import { Checkbox, Input, Listbox, Radio, SidePanel } from 'ui'
|
||||
import { HTTPArgument, isEdgeFunction } from './EditHookPanel'
|
||||
@@ -45,7 +45,7 @@ export const FormContents = ({
|
||||
submitRef,
|
||||
}: FormContentsProps) => {
|
||||
const { ref } = useParams()
|
||||
const project = useSelectedProject()
|
||||
const { data: project } = useSelectedProjectQuery()
|
||||
|
||||
const restUrl = project?.restUrl
|
||||
const restUrlTld = restUrl ? new URL(restUrl).hostname.split('.').pop() : 'co'
|
||||
|
||||
@@ -2,11 +2,11 @@ import { ChevronDown, Plus, X } from 'lucide-react'
|
||||
import Link from 'next/link'
|
||||
|
||||
import { useParams } from 'common'
|
||||
import { useProjectContext } from 'components/layouts/ProjectLayout/ProjectContext'
|
||||
import { ButtonTooltip } from 'components/ui/ButtonTooltip'
|
||||
import { FormSection, FormSectionContent, FormSectionLabel } from 'components/ui/Forms/FormSection'
|
||||
import { getKeys, useAPIKeysQuery } from 'data/api-keys/api-keys-query'
|
||||
import { useEdgeFunctionsQuery } from 'data/edge-functions/edge-functions-query'
|
||||
import { useSelectedProjectQuery } from 'hooks/misc/useSelectedProject'
|
||||
import { uuidv4 } from 'lib/helpers'
|
||||
import {
|
||||
Button,
|
||||
@@ -48,7 +48,7 @@ const HTTPRequestFields = ({
|
||||
onRemoveParameter,
|
||||
}: HTTPRequestFieldsProps) => {
|
||||
const { ref } = useParams()
|
||||
const { project: selectedProject } = useProjectContext()
|
||||
const { data: selectedProject } = useSelectedProjectQuery()
|
||||
|
||||
const { data: functions } = useEdgeFunctionsQuery({ projectRef: ref })
|
||||
const { data: apiKeys } = useAPIKeysQuery({ projectRef: ref, reveal: true })
|
||||
|
||||
Loaded 100 of 489 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user