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
2 changes: 1 addition & 1 deletion apps/docs/content/guides/auth/signing-keys.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ If you wish to make your own JWTs or have access to the private key or shared se
Use the [Supabase CLI](/docs/reference/cli/introduction) to quickly and securely generate a private key ready for import:

```sh
supabase gen generate-key ES256
supabase gen signing-key --algorithm ES256
```

Make sure you store this private key in a secure location, as it will not be extractable from Supabase.
Expand Down
35 changes: 0 additions & 35 deletions apps/docs/content/guides/cron/quickstart.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,6 @@ Attempting to create a second Job with the same name (and case) will overwrite t
4. Choose a schedule for your Job by inputting cron syntax (refer to the syntax chart in the form) or natural language.
5. Input SQL snippet or select a Database function, HTTP request, or Supabase Edge Function.

<Image
alt="Cron Create"
src="/docs/img/guides/database/cron/cron-create.png"
className="max-w-[700px] !mx-auto border rounded-md"
zoomable
/>

</TabPanel>
<TabPanel id="sql-schedule-job" label="SQL">

Expand Down Expand Up @@ -99,13 +92,6 @@ You can input seconds for your Job schedule interval as long as you're on Postgr
2. Click on the three vertical dots menu on the right side of the Job and click `Edit cron job`.
3. Make your changes and then click `Save cron job`.

<Image
alt="Cron Edit"
src="/docs/img/guides/database/cron/cron-edit.png"
className="max-w-[700px] !mx-auto border rounded-md"
zoomable
/>

</TabPanel>
<TabPanel id="sql-edit-job" label="SQL">

Expand Down Expand Up @@ -148,13 +134,6 @@ It is also possible to modify a job by using the `cron.schedule()` function by i
1. Go to the [Jobs](/dashboard/project/_/integrations/cron/jobs) section and find the Job you'd like to unschedule.
2. Toggle the `Active`/`Inactive` switch next to Job name.

<Image
alt="Cron Toggle"
src="/docs/img/guides/database/cron/cron-toggle.png"
className="max-w-[700px] !mx-auto border rounded-md"
zoomable
/>

</TabPanel>
<TabPanel id="sql-unschedule-job" label="SQL">

Expand Down Expand Up @@ -190,13 +169,6 @@ select cron.alter_job(
2. Click on the three vertical dots menu on the right side of the Job and click `Delete cron job`.
3. Confirm deletion by entering the Job name.

<Image
alt="Cron Unschedule"
src="/docs/img/guides/database/cron/cron-unschedule.png"
className="max-w-[700px] !mx-auto border rounded-md"
zoomable
/>

</TabPanel>
<TabPanel id="sql-delete-job" label="SQL">

Expand Down Expand Up @@ -227,13 +199,6 @@ Unscheduling a Job will permanently delete the Job from `cron.job` table but its
1. Go to the [Jobs](/dashboard/project/_/integrations/cron/jobs) section and find the Job you want to see the runs of.
2. Click on the `History` button next to the Job name.

<Image
alt="Cron Job Runs"
src="/docs/img/guides/database/cron/cron-history.png"
className="max-w-[700px] !mx-auto border rounded-md"
zoomable
/>

</TabPanel>
<TabPanel id="sql-runs-job" label="SQL">

Expand Down
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -1,53 +1,8 @@
import { ButtonTooltip } from 'components/ui/ButtonTooltip'
import { X } from 'lucide-react'
import { Toggle } from 'ui'
import { toast } from 'sonner'
import { Alert_Shadcn_, AlertDescription_Shadcn_, AlertTitle_Shadcn_, Badge, Toggle } from 'ui'

import { useConsentState } from 'common'
import { LOCAL_STORAGE_KEYS } from 'common/constants/local-storage'
import Panel from 'components/ui/Panel'
import { useSendResetMutation } from 'data/telemetry/send-reset-mutation'
import { useLocalStorageQuery } from 'hooks/misc/useLocalStorage'

export const TermsUpdateBanner = () => {
const [termsUpdateAcknowledged, setTermsUpdateAcknowledged, { isSuccess }] = useLocalStorageQuery(
LOCAL_STORAGE_KEYS.TERMS_OF_SERVICE_ACKNOWLEDGED,
false
)

if (!isSuccess || termsUpdateAcknowledged) return null

return (
<Alert_Shadcn_ className="mb-4 relative">
<AlertTitle_Shadcn_>
<Badge variant="default" className="mr-2">
NOTICE
</Badge>
Terms of Service Update – Effective Aug 1, 2025
</AlertTitle_Shadcn_>
<AlertDescription_Shadcn_>
We’ve updated our{' '}
<a href="https://supabase.com/terms" target="_blank" className="text hover:text-brand">
Terms of Service
</a>
. The new terms take effect on August 1, 2025 and reflect changes to support our evolving
business, legal requirements, and a new arbitration-based dispute resolution process.
Questions? Contact{' '}
<a href="mailto:[email protected]" target="_blank" className="text hover:text-brand">
our team
</a>
.
</AlertDescription_Shadcn_>
<ButtonTooltip
type="text"
icon={<X />}
className="absolute top-2 right-2 px-1"
onClick={() => setTermsUpdateAcknowledged(true)}
tooltip={{ content: { side: 'bottom', text: 'Dismiss' } }}
/>
</Alert_Shadcn_>
)
}

export const AnalyticsSettings = () => {
const { hasAccepted, acceptAll, denyAll, categories } = useConsentState()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ export const ProviderForm = ({ config, provider, isActive }: ProviderFormProps)
const [open, setOpen] = useState(false)
const { mutate: updateAuthConfig, isLoading: isUpdatingConfig } = useAuthConfigUpdateMutation()

const doubleNegativeKeys = ['MAILER_AUTOCONFIRM', 'SMS_AUTOCONFIRM']
const doubleNegativeKeys = ['SMS_AUTOCONFIRM']
const canUpdateConfig: boolean = useCheckPermissions(
PermissionAction.UPDATE,
'custom_config_gotrue'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,8 @@ const BasicAuthSettingsForm = () => {
DISABLE_SIGNUP: !authConfig.DISABLE_SIGNUP,
EXTERNAL_ANONYMOUS_USERS_ENABLED: authConfig.EXTERNAL_ANONYMOUS_USERS_ENABLED,
SECURITY_MANUAL_LINKING_ENABLED: authConfig.SECURITY_MANUAL_LINKING_ENABLED,
MAILER_AUTOCONFIRM: authConfig.MAILER_AUTOCONFIRM,
// The backend uses false to represent that email confirmation is required
MAILER_AUTOCONFIRM: !authConfig.MAILER_AUTOCONFIRM,
SITE_URL: authConfig.SITE_URL,
})
}
Expand All @@ -78,6 +79,9 @@ const BasicAuthSettingsForm = () => {
payload.PASSWORD_REQUIRED_CHARACTERS = ''
}

// The backend uses false to represent that email confirmation is required
payload.MAILER_AUTOCONFIRM = !values.MAILER_AUTOCONFIRM

updateAuthConfig(
{ projectRef: projectRef!, config: payload },
{
Expand Down
5 changes: 0 additions & 5 deletions apps/studio/components/interfaces/Auth/Users/Users.utils.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import dayjs from 'dayjs'
import { Clipboard, Trash, UserIcon } from 'lucide-react'
import { UIEvent } from 'react'
import { Column, useRowSelection } from 'react-data-grid'

import { User } from 'data/auth/users-infinite-query'
Expand All @@ -22,10 +21,6 @@ import { HeaderCell } from './UsersGridComponents'
const GITHUB_AVATAR_URL = 'https://avatars.githubusercontent.com'
const SUPPORTED_CSP_AVATAR_URLS = [GITHUB_AVATAR_URL, 'https://lh3.googleusercontent.com']

export const isAtBottom = ({ currentTarget }: UIEvent<HTMLDivElement>): boolean => {
return currentTarget.scrollTop + 10 >= currentTarget.scrollHeight - currentTarget.clientHeight
}

export const formatUsersData = (users: User[]) => {
return users.map((user) => {
const provider: string = (user.raw_app_meta_data?.provider as string) ?? ''
Expand Down
3 changes: 2 additions & 1 deletion apps/studio/components/interfaces/Auth/Users/UsersV2.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,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 { isAtBottom } from 'lib/helpers'
import {
Button,
cn,
Expand Down Expand Up @@ -51,7 +52,7 @@ import {
PROVIDER_FILTER_OPTIONS,
USERS_TABLE_COLUMNS,
} from './Users.constants'
import { formatUserColumns, formatUsersData, isAtBottom } from './Users.utils'
import { formatUserColumns, formatUsersData } from './Users.utils'

export type Filter = 'all' | 'verified' | 'unverified' | 'anonymous'

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ const ExtensionCard = ({ extension }: ExtensionCardProps) => {

<div className={cn('flex h-full flex-col gap-y-3 py-3', X_PADDING)}>
<p className="text-sm text-foreground-light capitalize-sentence">{extension.comment}</p>
<div className="flex items-center gap-x-2">
<div className="flex items-center gap-2 flex-wrap">
{extensionMeta?.github_url && (
<Button asChild type="default" icon={<Github />} className="rounded-full">
<a
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { zodResolver } from '@hookform/resolvers/zod'
import { PermissionAction } from '@supabase/shared-types/out/constants'
import { toString as CronToString } from 'cronstrue'
import { parseAsString, useQueryState } from 'nuqs'
import { useEffect, useState } from 'react'
import { SubmitHandler, useForm } from 'react-hook-form'
import { toast } from 'sonner'
Expand All @@ -11,8 +12,9 @@ import { urlRegex } from 'components/interfaces/Auth/Auth.constants'
import EnableExtensionModal from 'components/interfaces/Database/Extensions/EnableExtensionModal'
import { useProjectContext } from 'components/layouts/ProjectLayout/ProjectContext'
import { ButtonTooltip } from 'components/ui/ButtonTooltip'
import { getDatabaseCronJob } from 'data/database-cron-jobs/database-cron-job-query'
import { useDatabaseCronJobCreateMutation } from 'data/database-cron-jobs/database-cron-jobs-create-mutation'
import { CronJob, useCronJobsQuery } from 'data/database-cron-jobs/database-cron-jobs-query'
import { CronJob } from 'data/database-cron-jobs/database-cron-jobs-infinite-query'
import { useDatabaseExtensionsQuery } from 'data/database-extensions/database-extensions-query'
import { useSendEventMutation } from 'data/telemetry/send-event-mutation'
import { useCheckPermissions } from 'hooks/misc/useCheckPermissions'
Expand Down Expand Up @@ -200,15 +202,11 @@ export const CreateCronJobSheet = ({
}: CreateCronJobSheetProps) => {
const { project } = useProjectContext()
const { data: org } = useSelectedOrganizationQuery()
const isEditing = !!selectedCronJob?.jobname
const [searchQuery] = useQueryState('search', parseAsString.withDefault(''))

const isEditing = !!selectedCronJob?.jobname
const [showEnableExtensionModal, setShowEnableExtensionModal] = useState(false)

const { data: cronJobs } = useCronJobsQuery({
projectRef: project?.ref,
connectionString: project?.connectionString,
})

const { data } = useDatabaseExtensionsQuery({
projectRef: project?.ref,
connectionString: project?.connectionString,
Expand Down Expand Up @@ -305,27 +303,33 @@ export const CreateCronJobSheet = ({
])

const onSubmit: SubmitHandler<CreateCronJobForm> = async ({ name, schedule, values }) => {
// job names should be unique
const nameExists = cronJobs?.some(
(job) => job.jobname === name && job.jobname !== selectedCronJob?.jobname
)
if (nameExists) {
form.setError('name', {
type: 'manual',
message: 'A cron job with this name already exists',
if (!project) return console.error('Project is required')

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

let command = `$$${values.snippet}$$`
if (nameExists) {
return form.setError('name', {
type: 'manual',
message: 'A cron job with this name already exists',
})
}
}

const command = `$$${values.snippet}$$`
const query = buildCronQuery(name, schedule, command)

upsertCronJob(
{
projectRef: project!.ref,
connectionString: project?.connectionString,
query,
searchTerm: searchQuery,
},
{
onSuccess: () => {
Expand Down
Loading
Loading