Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,60 @@ In the Supabase Dashboard:
6. Configure the other options as needed to automate your GitHub connection.
7. Click **Enable integration**.

## Preparing your Git repository

You will be using the [Supabase CLI](/docs/guides/cli) to initialise your local `./supabase` directory:

<StepHikeCompact>
<StepHikeCompact.Step step={1}>
<StepHikeCompact.Details title="Initialize Supabase locally" fullWidth>

If you don't have a `./supabase` directory, you can create one:

```markdown
supabase init
```

</StepHikeCompact.Details>
</StepHikeCompact.Step>

<StepHikeCompact.Step step={2}>
<StepHikeCompact.Details title="Pull your database migration" fullWidth>

Pull your database changes using `supabase db pull`. To get your database connection string, go to your project dashboard, click [Connect](https://supabase.com/dashboard/project/_?showConnect=true) and look for the Session pooler connection string.

```markdown
supabase db pull --db-url <db_connection_string>

# Your Database connection string will look like this:
# postgres://postgres.xxxx:password@xxxx.pooler.supabase.com:5432/postgres
```
<Admonition type="note">

If you're in an [IPv6 environment](https://github.com/orgs/supabase/discussions/27034) or have the IPv4 Add-On, you can use the direct connection string instead of Supavisor in Session mode.

</Admonition>

</StepHikeCompact.Details>
</StepHikeCompact.Step>

<StepHikeCompact.Step step={3}>
<StepHikeCompact.Details title="Commit the `supabase` directory to Git" fullWidth>

Commit the `supabase` directory to Git, and push your changes to your remote repository.

```bash
git add supabase
git commit -m "Initial migration"
git push
```


</StepHikeCompact.Details>
</StepHikeCompact.Step>

</StepHikeCompact>

## Syncing GitHub branches

Enable the **Automatic branching** option in your GitHub Integration configuration to automatically sync GitHub branches with Supabase branches.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,7 @@ export const CreateCronJobSheet = ({
const { project } = useProjectContext()
const { data: org } = useSelectedOrganizationQuery()
const [searchQuery] = useQueryState('search', parseAsString.withDefault(''))
const [isLoadingGetCronJob, setIsLoadingGetCronJob] = useState(false)

const isEditing = !!selectedCronJob?.jobname
const [showEnableExtensionModal, setShowEnableExtensionModal] = useState(false)
Expand All @@ -215,7 +216,8 @@ export const CreateCronJobSheet = ({
const pgNetExtensionInstalled = pgNetExtension?.installed_version != undefined

const { mutate: sendEvent } = useSendEventMutation()
const { mutate: upsertCronJob, isLoading } = useDatabaseCronJobCreateMutation()
const { mutate: upsertCronJob, isLoading: isUpserting } = useDatabaseCronJobCreateMutation()
const isLoading = isLoadingGetCronJob || isUpserting

const canToggleExtensions = useCheckPermissions(
PermissionAction.TENANT_SQL_ADMIN_WRITE,
Expand Down Expand Up @@ -306,18 +308,25 @@ export const CreateCronJobSheet = ({
if (!project) return console.error('Project is required')

if (!isEditing) {
const checkExistingJob = await getDatabaseCronJob({
projectRef: project.ref,
connectionString: project.connectionString,
name,
})
const nameExists = !!checkExistingJob

if (nameExists) {
return form.setError('name', {
type: 'manual',
message: 'A cron job with this name already exists',
try {
setIsLoadingGetCronJob(true)
const checkExistingJob = await getDatabaseCronJob({
projectRef: project.ref,
connectionString: project.connectionString,
name,
})
const nameExists = !!checkExistingJob

if (nameExists) {
return form.setError('name', {
type: 'manual',
message: 'A cron job with this name already exists',
})
}
} catch (error: any) {
toast.error(`Failed to validate cron job name: ${error.message}`)
} finally {
setIsLoadingGetCronJob(false)
}
}

Expand Down Expand Up @@ -369,6 +378,7 @@ export const CreateCronJobSheet = ({
},
}
)
setIsLoadingGetCronJob(false)
}

return (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -193,9 +193,10 @@ export const CronjobsTab = () => {
}}
onScroll={handleScroll}
renderers={{
renderRow(_, props) {
renderRow(key, props) {
return (
<Row
key={props.row.jobid}
{...props}
onClick={(e) => {
const { jobid, jobname } = props.row
Expand Down
11 changes: 5 additions & 6 deletions apps/studio/components/layouts/Integrations/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,20 @@
import { useRouter } from 'next/router'
import { PropsWithChildren, useEffect, useRef, useState } from 'react'

import { IntegrationDefinition } from 'components/interfaces/Integrations/Landing/Integrations.constants'
import { useInstalledIntegrations } from 'components/interfaces/Integrations/Landing/useInstalledIntegrations'
import { Header } from 'components/layouts/Integrations/header'
import ProjectLayout from 'components/layouts/ProjectLayout/ProjectLayout'
import AlertError from 'components/ui/AlertError'
import { ProductMenu } from 'components/ui/ProductMenu'
import { ProductMenuGroup } from 'components/ui/ProductMenu/ProductMenu.types'
import ProductMenuItem from 'components/ui/ProductMenu/ProductMenuItem'
import { useScroll } from 'framer-motion'
import { useSelectedProject } from 'hooks/misc/useSelectedProject'
import { useSelectedProject, useSelectedProjectQuery } from 'hooks/misc/useSelectedProject'
import { withAuth } from 'hooks/misc/withAuth'
import { useFlag } from 'hooks/ui/useFlag'
import { IntegrationTabs } from './tabs'
import { Menu, Separator } from 'ui'
import ProductMenuItem from 'components/ui/ProductMenu/ProductMenuItem'
import { GenericSkeletonLoader } from 'ui-patterns'
import AlertError from 'components/ui/AlertError'
import { IntegrationTabs } from './tabs'

/**
* Layout component for the Integrations section
Expand Down Expand Up @@ -156,7 +155,7 @@ const IntegrationTopHeaderLayout = ({ ...props }: PropsWithChildren) => {
const IntegrationsLayoutSide = ({ ...props }: PropsWithChildren) => {
const router = useRouter()
const page = router.pathname.split('/')[4]
const project = useSelectedProject()
const { data: project } = useSelectedProjectQuery()

const {
installedIntegrations: integrations,
Expand Down
4 changes: 3 additions & 1 deletion apps/studio/components/layouts/Integrations/tabs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,9 @@ export const IntegrationTabs = ({ scroll, isSticky }: IntegrationTabsProps) => {
>
<NavMenuItem active={true} className="flex items-center gap-2">
{tab.childIcon}
<Link href={`${tabUrl}/${childId}`}>
<Link
href={`${tabUrl}/${childId}${childLabel ? `?child-label=${childLabel}` : ''}`}
>
{childLabel ? childLabel : childId}
</Link>
</NavMenuItem>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ export type CronJob = {
status: string
}

// [Joshen] Just to call out that I had AI help me with this, so please let me know if this can be optimized
const getCronJobSql = ({ searchTerm, page }: { searchTerm?: string; page: number }) =>
`
WITH latest_runs AS (
Expand All @@ -31,20 +32,31 @@ WITH latest_runs AS (
MAX(start_time) AS latest_run
FROM cron.job_run_details
GROUP BY jobid, status
), most_recent_runs AS (
SELECT
jobid,
status,
latest_run
FROM latest_runs lr1
WHERE latest_run = (
SELECT MAX(latest_run)
FROM latest_runs lr2
WHERE lr2.jobid = lr1.jobid
)
)
SELECT
job.jobid,
job.jobname,
job.schedule,
job.command,
job.active,
lr.latest_run,
lr.status
mr.latest_run,
mr.status
FROM
cron.job job
LEFT JOIN latest_runs lr ON job.jobid = lr.jobid
${!!searchTerm ? `WHERE job.jobname ILIKE '%${searchTerm}%'` : ''}
LEFT JOIN most_recent_runs mr ON job.jobid = mr.jobid
ORDER BY job.jobid
${!!searchTerm ? `WHERE job.jobname ILIKE '%${searchTerm}%'` : ''}
LIMIT ${CRON_JOBS_PAGE_LIMIT}
OFFSET ${page * CRON_JOBS_PAGE_LIMIT};
`.trim()
Expand Down
Loading