From e58f2edde23a60d4d9d3501ac40aafc58749b3f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thor=20=E9=9B=B7=E7=A5=9E=20Schaeff?= <5748289+thorwebdev@users.noreply.github.com> Date: Wed, 4 Dec 2024 13:23:18 +0800 Subject: [PATCH 01/14] docs: update ef websocket codesample (#30846) update code sample. --- .../content/guides/functions/websockets.mdx | 101 +++--------------- apps/docs/features/directives/CodeSample.ts | 2 +- 2 files changed, 13 insertions(+), 90 deletions(-) diff --git a/apps/docs/content/guides/functions/websockets.mdx b/apps/docs/content/guides/functions/websockets.mdx index d606fec4a8f7a..48fd6fff028c0 100644 --- a/apps/docs/content/guides/functions/websockets.mdx +++ b/apps/docs/content/guides/functions/websockets.mdx @@ -7,7 +7,7 @@ subtitle: 'How to handle WebSocket connections in Edge Functions' Edge Functions supports hosting WebSocket servers that can facilitate bi-directional communications with browser clients. -You can also establish outgoing WebSocket client connections to another server from Edge Functions (e.g., [OpenAI Realtime API](https://platform.openai.com/docs/guides/realtime/overview)). +You can also establish outgoing WebSocket client connections to another server from Edge Functions (e.g., [OpenAI Realtime API](https://platform.openai.com/docs/guides/realtime/overview)). You can find an example OpenAI Realtime Relay Server implementation on the [supabase-community GitHub account](https://github.com/supabase-community/openai-realtime-console?tab=readme-ov-file#using-supabase-edge-functions-as-a-relay-server). ### Writing a WebSocket server @@ -92,94 +92,17 @@ server.listen(8080); You can also establish an outbound WebSocket connection to another server from an Edge Function. -Combining it with incoming WebSocket servers, it's possible to use Edge Functions as a WebSocket proxy. - -Here is an example of proxying messages to OpenAI Realtime API. - -We use [Supabase Auth](/docs/guides/functions/auth#fetching-the-user) to authenticate the user who is sending the messages. - -```ts -import { createClient } from 'jsr:@supabase/supabase-js@2' - -const supabase = createClient( - Deno.env.get('SUPABASE_URL'), - Deno.env.get('SUPABASE_SERVICE_ROLE_KEY') -) -const OPENAI_API_KEY = Deno.env.get('OPENAI_API_KEY') - -Deno.serve(async (req) => { - const upgrade = req.headers.get('upgrade') || '' - - if (upgrade.toLowerCase() != 'websocket') { - return new Response("request isn't trying to upgrade to websocket.") - } - - // WebSocket browser clients does not support sending custom headers. - // We have to use the URL query params to provide user's JWT. - // Please be aware query params may be logged in some logging systems. - const url = new URL(req.url) - const jwt = url.searchParams.get('jwt') - if (!jwt) { - console.error('Auth token not provided') - return new Response('Auth token not provided', { status: 403 }) - } - const { error, data } = await supabase.auth.getUser(jwt) - if (error) { - console.error(error) - return new Response('Invalid token provided', { status: 403 }) - } - if (!data.user) { - console.error('user is not authenticated') - return new Response('User is not authenticated', { status: 403 }) - } - - const { socket, response } = Deno.upgradeWebSocket(req) - - socket.onopen = () => { - // initiate an outbound WS connection with OpenAI - const url = 'wss://api.openai.com/v1/realtime?model=gpt-4o-realtime-preview-2024-10-01' - - // openai-insecure-api-key isn't a problem since this code runs in an Edge Function (not client browser) - const openaiWS = new WebSocket(url, [ - 'realtime', - `openai-insecure-api-key.${OPENAI_API_KEY}`, - 'openai-beta.realtime-v1', - ]) - - openaiWS.onopen = () => { - console.log('Connected to OpenAI server.') - - socket.onmessage = (e) => { - console.log('socket message:', e.data) - // only send the message if openAI ws is open - if (openaiWS.readyState === 1) { - openaiWS.send(e.data) - } else { - socket.send( - JSON.stringify({ - type: 'error', - msg: 'openAI connection not ready', - }) - ) - } - } - } - - openaiWS.onmessage = (e) => { - console.log(e.data) - socket.send(e.data) - } - - openaiWS.onerror = (e) => console.log('OpenAI error: ', e.message) - openaiWS.onclose = (e) => console.log('OpenAI session closed') - } - - socket.onerror = (e) => console.log('socket errored:', e.message) - socket.onclose = () => console.log('socket closed') - - return response // 101 (Switching Protocols) -}) -``` +Combining it with incoming WebSocket servers, it's possible to use Edge Functions as a WebSocket proxy, for example as a [relay server](https://github.com/supabase-community/openai-realtime-console?tab=readme-ov-file#using-supabase-edge-functions-as-a-relay-server) for the [OpenAI Realtime API](https://platform.openai.com/docs/guides/realtime/overview). + +<$CodeSample +external={true} +org="supabase-community" +repo="openai-realtime-console" +commit="0f93657a71670704fbf77c48cf54d6c9eb956698" +path="/supabase/functions/relay/index.ts" +meta="supabase/functions/relay/index.ts" +lines={[[1, 3], [5, -1]]} +/> ### Authentication diff --git a/apps/docs/features/directives/CodeSample.ts b/apps/docs/features/directives/CodeSample.ts index ab297b45e6b77..47d74391b5950 100644 --- a/apps/docs/features/directives/CodeSample.ts +++ b/apps/docs/features/directives/CodeSample.ts @@ -48,7 +48,7 @@ import { z, type SafeParseError } from 'zod' import { fetchWithNextOptions } from '~/features/helpers.fetch' import { EXAMPLES_DIRECTORY } from '~/lib/docs' -const ALLOW_LISTED_GITHUB_ORGS = ['supabase'] as [string, ...string[]] +const ALLOW_LISTED_GITHUB_ORGS = ['supabase', 'supabase-community'] as [string, ...string[]] const linesSchema = z.array(z.tuple([z.coerce.number(), z.coerce.number()])) const linesValidator = z From d8903d7340d37824986632aa642e55a9470bbd6b Mon Sep 17 00:00:00 2001 From: Joel Lee Date: Wed, 4 Dec 2024 14:53:37 +0800 Subject: [PATCH 02/14] fix: update cli yaml files to reflect auth LW12 features (#30830) * fix: update auth config * fix: adjust defaults * fix: add more config vars * fix: more typo corrections * fix: update docs * fix: update cli config --- apps/docs/spec/cli_v1_config.yaml | 209 ++++++++++++++++++++++++++++-- 1 file changed, 199 insertions(+), 10 deletions(-) diff --git a/apps/docs/spec/cli_v1_config.yaml b/apps/docs/spec/cli_v1_config.yaml index 2cd7a2e2e8664..d6c2cbb2d1a64 100644 --- a/apps/docs/spec/cli_v1_config.yaml +++ b/apps/docs/spec/cli_v1_config.yaml @@ -677,6 +677,17 @@ parameters: - name: 'Auth Server configuration' link: 'https://supabase.com/docs/reference/auth' + - id: 'auth.enable_manual_linking' + title: 'auth.enable_manual_linking' + tags: ['auth'] + required: false + default: 'false' + description: | + Allow testing manual linking of accounts + links: + - name: 'Anonymous Sign Ins (Manual Linking)' + link: 'https://supabase.com/docs/guides/auth/auth-anonymous?queryGroups=language&language=python#convert-an-anonymous-user-to-a-permanent-user' + - id: 'auth.enable_refresh_token_rotation' title: 'auth.enable_refresh_token_rotation' tags: ['auth'] @@ -718,8 +729,8 @@ parameters: description: | Allow/disallow anonymous sign-ins to your project. links: - - name: 'Auth Server configuration' - link: 'https://supabase.com/docs/reference/auth' + - name: 'Anonymous Sign Ins' + link: 'https://supabase.com/docs/guides/auth/auth-anonymous' - id: 'auth.email.enable_signup' title: 'auth.email.enable_signup' @@ -1063,11 +1074,11 @@ parameters: - `google` - `kakao` - `keycloak` - - `linkedin` + - `linkedin_oidc` - `notion` - `twitch` - `twitter` - - `slack` + - `slack_oidc` - `spotify` - `workos` - `zoom` @@ -1131,27 +1142,205 @@ parameters: - name: 'Auth Server configuration' link: 'https://supabase.com/docs/reference/auth' + - id: 'auth.mfa.totp.enroll_enabled' + title: 'auth.mfa.totp.enroll_enabled' + tags: ['auth'] + required: false + default: 'true' + description: | + Enable TOTP enrollment for multi-factor authentication. + links: + - name: 'Auth Multi-Factor Authentication (TOTP)' + link: 'https://supabase.com/docs/guides/auth/auth-mfa/totp' + + - id: 'auth.mfa.totp.verify_enabled' + title: 'auth.mfa.totp.verify_enabled' + tags: ['auth'] + required: false + default: 'true' + description: | + Enable TOTP verification for multi-factor authentication. + links: + - name: 'Auth Multi-Factor Authentication (TOTP)' + link: 'https://supabase.com/docs/guides/auth/auth-mfa/totp' + + - id: 'auth.mfa.max_enrolled_factors' + title: 'auth.mfa.max_enrolled_factors' + tags: ['auth'] + required: false + default: '10' + description: | + Control how many MFA factors can be enrolled at once per user. + links: + - name: 'Auth Multi-Factor Authentication (TOTP)' + link: 'https://supabase.com/docs/guides/auth/auth-mfa/totp' + + - id: 'auth.mfa.phone.enroll_enabled' + title: 'auth.mfa.phone.enroll_enabled' + tags: ['auth'] + required: false + default: 'false' + description: | + Enable Phone enrollment for multi-factor authentication. + links: + - name: 'Auth Multi-Factor Authentication (Phone)' + link: 'https://supabase.com/docs/guides/auth/auth-mfa/phone' + + - id: 'auth.mfa.phone.otp_length' + title: 'auth.mfa.phone.otp_length' + tags: ['auth'] + required: false + default: '6' + description: | + Length of OTP code sent when using phone multi-factor authentication + links: + - name: 'Auth Multi-Factor Authentication (Phone)' + link: 'https://supabase.com/docs/guides/auth/auth-mfa/phone' + + - id: 'auth.mfa.phone.max_frequency' + title: 'auth.mfa.phone.max_frequency' + tags: ['auth'] + required: false + default: '10s' + description: | + The minimum amount of time that must pass between phone requests. + Helps prevent spam by limiting how frequently messages can be sent. + Example values: "10s", "20s", "1m" + links: + - name: 'Auth Multi-Factor Authentication (Phone)' + link: 'https://supabase.com/docs/guides/auth/auth-mfa/phone' + + - id: 'auth.mfa.phone.otp_length' + title: 'auth.mfa.phone.otp_length' + tags: ['auth'] + required: false + default: '6' + description: | + Length of OTP sent when using phone multi-factor authentication + links: + - name: 'Auth Multi-Factor Authentication (Phone)' + link: 'https://supabase.com/docs/guides/auth/auth-mfa/phone' + + - id: 'auth.mfa.phone.verify_enabled' + title: 'auth.mfa.phone.verify_enabled' + tags: ['auth'] + required: false + default: 'false' + description: | + Enable Phone verification for multi-factor authentication. + links: + - name: 'Auth Multi-Factor Authentication (Phone)' + link: 'https://supabase.com/docs/guides/auth/auth-mfa/phone' + - id: 'auth.mfa.web_authn.enroll_enabled' title: 'auth.mfa.web_authn.enroll_enabled' - tags: ['auth', 'local'] + tags: ['auth'] required: false default: 'false' description: | Enable WebAuthn enrollment for multi-factor authentication. links: - - name: 'Auth Server configuration' - link: 'https://supabase.com/docs/reference/auth' + - name: 'Auth Multi-Factor Authentication' + link: 'https://supabase.com/docs/guides/auth/auth-mfa' - id: 'auth.mfa.web_authn.verify_enabled' title: 'auth.mfa.web_authn.verify_enabled' - tags: ['auth', 'local'] + tags: ['auth'] required: false default: 'false' description: | Enable WebAuthn verification for multi-factor authentication. links: - - name: 'Auth Server configuration' - link: 'https://supabase.com/docs/reference/auth' + - name: 'Auth Multi-Factor Authentication' + link: 'https://supabase.com/docs/guides/auth/auth-mfa' + + - id: 'auth.third_party.aws_cognito.enabled' + title: 'auth.third_party.aws_cognito.enabled' + tags: ['auth'] + required: false + default: 'false' + description: | + Enable third party auth with AWS Cognito (Amplify) + links: + - name: 'Third Party Auth (Cognito)' + link: 'https://supabase.com/docs/guides/auth/third-party/aws-cognito' + + - id: 'auth.third_party.aws_cognito.user_pool_id' + title: 'auth.third_party.aws_cognito.user_pool_id' + tags: ['auth'] + required: false + default: 'false' + description: | + User Pool ID for AWS Cognito (Amplify) that you are integrating with + links: + - name: 'Third Party Auth (Cognito)' + link: 'https://supabase.com/docs/guides/auth/third-party/aws-cognito' + + - id: 'auth.third_party.aws_cognito.user_pool_region' + title: 'auth.third_party.aws_cognito.user_pool_region' + tags: ['auth'] + required: false + default: 'false' + description: | + User Pool region for AWS Cognito (Amplify) that you are integrating with. Example values: 'ap-southeast-1', 'us-east-1' + links: + - name: 'Third Party Auth (Cognito)' + link: 'https://supabase.com/docs/guides/auth/third-party/aws-cognito' + + - id: 'auth.third_party.auth0.enabled' + title: 'auth.third_party.auth0.enabled' + tags: ['auth'] + required: false + default: 'false' + description: | + Enable third party auth with Auth0 + links: + - name: 'Third Party Auth (Auth0)' + link: 'https://supabase.com/docs/guides/auth/third-party/auth0' + + - id: 'auth.third_party.auth0.tenant' + title: 'auth.third_party.auth0.tenant' + tags: ['auth'] + required: false + default: 'false' + description: | + Tenant Identifier for Auth0 instance that you are integrating with + links: + - name: 'Third Party Auth (Auth0)' + link: 'https://supabase.com/docs/guides/auth/third-party/auth0' + + - id: 'auth.third_party.auth0.tenant_region' + title: 'auth.third_party.tenant_region' + tags: ['auth'] + required: false + default: 'false' + description: | + Tenant region for Auth0 instance that you are integrating with + links: + - name: 'Third Party Auth (Auth0)' + link: 'https://supabase.com/docs/guides/auth/third-party/auth0' + + - id: 'auth.third_party.firebase.enabled' + title: 'auth.third_party.firebase.enabled' + tags: ['auth'] + required: false + default: 'false' + description: | + Enable third party auth with Firebase + links: + - name: 'Third Party Auth (Firebase)' + link: 'https://supabase.com/docs/guides/auth/third-party/firebase-auth' + + - id: 'auth.third_party.firebase.project_id' + title: 'auth.third_party.firebase.project_id' + tags: ['auth'] + required: false + default: 'false' + description: | + Project ID for Firebase instance that you are integrating with + links: + - name: 'Third Party Auth (Firebase)' + link: 'https://supabase.com/docs/guides/auth/third-party/firebase-auth' - id: 'edge_runtime.enabled' title: 'edge_runtime.enabled' From 4950783ae8768d89457cf811ce1b14c32548b823 Mon Sep 17 00:00:00 2001 From: Copple <10214025+kiwicopple@users.noreply.github.com> Date: Wed, 4 Dec 2024 08:42:16 +0100 Subject: [PATCH 03/14] chore: update self-hosted image versions (#30880) chore: update image versions for docker/docker-compose.yml --- docker/docker-compose.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml index 803c5af8f3427..262f3e2ffd9dc 100644 --- a/docker/docker-compose.yml +++ b/docker/docker-compose.yml @@ -9,7 +9,7 @@ name: supabase services: studio: container_name: supabase-studio - image: supabase/studio:20241106-f29003e + image: supabase/studio:20241202-71e5240 restart: unless-stopped healthcheck: test: From 7dffdf79229a08373f798e0948cc4aa6a81be52b Mon Sep 17 00:00:00 2001 From: Copple <10214025+kiwicopple@users.noreply.github.com> Date: Wed, 4 Dec 2024 08:43:20 +0100 Subject: [PATCH 04/14] chore: update cli reference doc (#30881) --- apps/docs/spec/cli_v1_commands.yaml | 116 +++++++--------------------- 1 file changed, 29 insertions(+), 87 deletions(-) diff --git a/apps/docs/spec/cli_v1_commands.yaml b/apps/docs/spec/cli_v1_commands.yaml index 45cda3234db27..5a46fcada6f75 100644 --- a/apps/docs/spec/cli_v1_commands.yaml +++ b/apps/docs/spec/cli_v1_commands.yaml @@ -1,7 +1,7 @@ clispec: '001' info: id: cli - version: 1.226.3 + version: 2.0.0 title: Supabase CLI language: sh source: https://github.com/supabase/cli @@ -3538,10 +3538,6 @@ commands: name: --persistent description: Switch between ephemeral and persistent branch. default_value: 'false' - - id: reset-on-push - name: --reset-on-push - description: Reset the preview branch on git push. - default_value: 'false' - id: status name: --status description: Override the current branch status. @@ -3661,101 +3657,47 @@ commands: description: Select a region to deploy the branch database. default_value: '' accepted_values: - - id: ams - name: ams - type: string - - id: arn - name: arn - type: string - - id: bog - name: bog - type: string - - id: bos - name: bos - type: string - - id: cdg - name: cdg - type: string - - id: den - name: den - type: string - - id: dfw - name: dfw - type: string - - id: ewr - name: ewr - type: string - - id: fra - name: fra - type: string - - id: gdl - name: gdl - type: string - - id: gig - name: gig - type: string - - id: gru - name: gru - type: string - - id: hkg - name: hkg - type: string - - id: iad - name: iad - type: string - - id: jnb - name: jnb - type: string - - id: lax - name: lax - type: string - - id: lhr - name: lhr - type: string - - id: maa - name: maa - type: string - - id: mad - name: mad + - id: ap-northeast-1 + name: ap-northeast-1 type: string - - id: mia - name: mia + - id: ap-northeast-2 + name: ap-northeast-2 type: string - - id: nrt - name: nrt + - id: ap-south-1 + name: ap-south-1 type: string - - id: ord - name: ord + - id: ap-southeast-1 + name: ap-southeast-1 type: string - - id: otp - name: otp + - id: ap-southeast-2 + name: ap-southeast-2 type: string - - id: qro - name: qro + - id: ca-central-1 + name: ca-central-1 type: string - - id: scl - name: scl + - id: eu-central-1 + name: eu-central-1 type: string - - id: sea - name: sea + - id: eu-west-1 + name: eu-west-1 type: string - - id: sin - name: sin + - id: eu-west-2 + name: eu-west-2 type: string - - id: sjc - name: sjc + - id: eu-west-3 + name: eu-west-3 type: string - - id: syd - name: syd + - id: sa-east-1 + name: sa-east-1 type: string - - id: waw - name: waw + - id: us-east-1 + name: us-east-1 type: string - - id: yul - name: yul + - id: us-west-1 + name: us-west-1 type: string - - id: yyz - name: yyz + - id: us-west-2 + name: us-west-2 type: string - id: size name: --size From ace71494f4e81ed8297d4d1857fd2b57c10e8bb5 Mon Sep 17 00:00:00 2001 From: Joshen Lim Date: Wed, 4 Dec 2024 15:47:58 +0800 Subject: [PATCH 05/14] Add telemetry for cron (#30874) * Add telemetry for cron * Update --- .../CronJobs/CreateCronJobSheet.tsx | 21 +++++++++- .../Integrations/CronJobs/CronJobCard.tsx | 41 +++++++++++++++++-- .../Integrations/CronJobs/CronJobsTab.tsx | 31 +++++++++----- .../Integrations/CronJobs/DeleteCronJob.tsx | 12 ++++-- .../data/telemetry/send-event-mutation.ts | 1 + apps/studio/lib/constants/telemetry.ts | 13 ++++++ 6 files changed, 99 insertions(+), 20 deletions(-) diff --git a/apps/studio/components/interfaces/Integrations/CronJobs/CreateCronJobSheet.tsx b/apps/studio/components/interfaces/Integrations/CronJobs/CreateCronJobSheet.tsx index cb541d25750b7..8f19dc64f8fc6 100644 --- a/apps/studio/components/interfaces/Integrations/CronJobs/CreateCronJobSheet.tsx +++ b/apps/studio/components/interfaces/Integrations/CronJobs/CreateCronJobSheet.tsx @@ -1,10 +1,11 @@ import { zodResolver } from '@hookform/resolvers/zod' +import { PermissionAction } from '@supabase/shared-types/out/constants' import { toString as CronToString } from 'cronstrue' +import { useState } from 'react' import { SubmitHandler, useForm } from 'react-hook-form' import { toast } from 'sonner' import z from 'zod' -import { PermissionAction } from '@supabase/shared-types/out/constants' import { urlRegex } from 'components/interfaces/Auth/Auth.constants' import { useProjectContext } from 'components/layouts/ProjectLayout/ProjectContext' import { ButtonTooltip } from 'components/ui/ButtonTooltip' @@ -12,7 +13,6 @@ import { useDatabaseCronJobCreateMutation } from 'data/database-cron-jobs/databa import { CronJob } from 'data/database-cron-jobs/database-cron-jobs-query' import { useDatabaseExtensionsQuery } from 'data/database-extensions/database-extensions-query' import { useCheckPermissions } from 'hooks/misc/useCheckPermissions' -import { useState } from 'react' import { Button, Form_Shadcn_, @@ -33,6 +33,8 @@ import ConfirmationModal from 'ui-patterns/Dialogs/ConfirmationModal' import { FormItemLayout } from 'ui-patterns/form/FormItemLayout/FormItemLayout' import EnableExtensionModal from 'components/interfaces/Database/Extensions/EnableExtensionModal' +import { useSendEventMutation } from 'data/telemetry/send-event-mutation' +import { TELEMETRY_EVENTS, TELEMETRY_VALUES } from 'lib/constants/telemetry' import { CRONJOB_DEFINITIONS } from './CronJobs.constants' import { buildCronQuery, @@ -170,6 +172,7 @@ export const CreateCronJobSheet = ({ const isEditing = !!selectedCronJob?.jobname const [showEnableExtensionModal, setShowEnableExtensionModal] = useState(false) + const { mutate: sendEvent } = useSendEventMutation() const { mutate: upsertCronJob, isLoading } = useDatabaseCronJobCreateMutation() const canToggleExtensions = useCheckPermissions( @@ -243,6 +246,20 @@ export const CreateCronJobSheet = ({ } else { toast.success(`Successfully created cron job ${name}`) } + + // We should allow sending custom properties with events + sendEvent({ + action: TELEMETRY_EVENTS.CRON_JOBS, + value: isEditing + ? TELEMETRY_VALUES.CRON_JOB_UPDATED + : TELEMETRY_VALUES.CRON_JOB_CREATED, + label: isEditing ? 'Cron job was updated' : 'Cron job was created', + properties: { + cron_job_type: values.type, + cron_job_schedule: schedule, + }, + }) + onClose() }, } diff --git a/apps/studio/components/interfaces/Integrations/CronJobs/CronJobCard.tsx b/apps/studio/components/interfaces/Integrations/CronJobs/CronJobCard.tsx index f670e48bc4687..c6e473927d277 100644 --- a/apps/studio/components/interfaces/Integrations/CronJobs/CronJobCard.tsx +++ b/apps/studio/components/interfaces/Integrations/CronJobs/CronJobCard.tsx @@ -8,6 +8,8 @@ import { SQLCodeBlock } from 'components/interfaces/Auth/ThirdPartyAuthForm/SqlC import { useProjectContext } from 'components/layouts/ProjectLayout/ProjectContext' import { CronJob } from 'data/database-cron-jobs/database-cron-jobs-query' import { useDatabaseCronJobToggleMutation } from 'data/database-cron-jobs/database-cron-jobs-toggle-mutation' +import { useSendEventMutation } from 'data/telemetry/send-event-mutation' +import { TELEMETRY_EVENTS, TELEMETRY_VALUES } from 'lib/constants/telemetry' import { Button, DropdownMenu, @@ -28,9 +30,12 @@ interface CronJobCardProps { } export const CronJobCard = ({ job, onEditCronJob, onDeleteCronJob }: CronJobCardProps) => { - const [toggleConfirmationModalShown, showToggleConfirmationModal] = useState(false) const { ref } = useParams() const { project: selectedProject } = useProjectContext() + + const [toggleConfirmationModalShown, showToggleConfirmationModal] = useState(false) + + const { mutate: sendEvent } = useSendEventMutation() const { mutate: toggleDatabaseCronJob, isLoading } = useDatabaseCronJobToggleMutation() // pg_cron can also use "30 seconds" format for schedule. Cronstrue doesn't understand that format so just use the @@ -68,7 +73,17 @@ export const CronJobCard = ({ job, onEditCronJob, onDeleteCronJob }: CronJobCard checked={job.active} onCheckedChange={() => showToggleConfirmationModal(true)} /> - @@ -76,11 +91,29 @@ export const CronJobCard = ({ job, onEditCronJob, onDeleteCronJob }: CronJobCard + ) : (
@@ -82,7 +91,7 @@ export const CronjobsTab = () => { onChange={(e) => setSearchQuery(e.target.value)} /> - +
{filteredCronJobs.length === 0 ? (
void } -const DeleteCronJob = ({ cronJob, visible, onClose }: DeleteCronJobProps) => { +export const DeleteCronJob = ({ cronJob, visible, onClose }: DeleteCronJobProps) => { const { project } = useProjectContext() + const { mutate: sendEvent } = useSendEventMutation() const { mutate: deleteDatabaseCronJob, isLoading } = useDatabaseCronJobDeleteMutation({ onSuccess: () => { + sendEvent({ + action: TELEMETRY_EVENTS.CRON_JOBS, + value: TELEMETRY_VALUES.CRON_JOB_DELETED, + label: 'User deleted cron job', + }) toast.success(`Successfully removed cron job ${cronJob.jobname}`) onClose() }, @@ -56,5 +64,3 @@ const DeleteCronJob = ({ cronJob, visible, onClose }: DeleteCronJobProps) => { /> ) } - -export default DeleteCronJob diff --git a/apps/studio/data/telemetry/send-event-mutation.ts b/apps/studio/data/telemetry/send-event-mutation.ts index 45afbe6179fca..36afd7e929ccc 100644 --- a/apps/studio/data/telemetry/send-event-mutation.ts +++ b/apps/studio/data/telemetry/send-event-mutation.ts @@ -19,6 +19,7 @@ export type SendEventVariables = { label?: string /** To deprecate - seems unnecessary */ category?: string + properties?: Record } type SendEventPayload = any diff --git a/apps/studio/lib/constants/telemetry.ts b/apps/studio/lib/constants/telemetry.ts index 7dd0628238085..87f03cf95b915 100644 --- a/apps/studio/lib/constants/telemetry.ts +++ b/apps/studio/lib/constants/telemetry.ts @@ -4,6 +4,7 @@ export enum TELEMETRY_EVENTS { FEATURE_PREVIEWS = 'Dashboard UI Feature Previews', AI_ASSISTANT_V2 = 'AI Assistant V2', + CRON_JOBS = 'Cron Jobs', } // [Joshen] Values refer to the "action" of the "event" @@ -35,4 +36,16 @@ export enum TELEMETRY_VALUES { * @purpose Indication of interest for wanting to expand from a SQL suggestion, aid in deciding the priority for an inline editor * */ EDIT_IN_SQL_EDITOR = 'edit-in-sql-editor', + /** + * Track events for cron jobs + * @context Cron Jobs + * @purpose TBD (Joshen just adding these here as we needed some telemetry, but ideally we think this properly through and come up with purposes) + */ + CRON_JOB_CREATED = 'cron-job-created', + CRON_JOB_UPDATED = 'cron-job-updated', + CRON_JOB_DELETED = 'cron-job-deleted', + CRON_JOB_DELETE_CLICKED = 'cron-job-delete-clicked', + CRON_JOB_UPDATE_CLICKED = 'cron-job-update-clicked', + CRON_JOB_CREATE_CLICKED = 'cron-job-create-clicked', + CRON_JOBS_VIEW_PREVIOUS_RUNS = 'view-previous-runs-clicked', } From a014223a522e22d020c0637b2325cf746c7b4dc5 Mon Sep 17 00:00:00 2001 From: Han Qiao Date: Wed, 4 Dec 2024 15:54:07 +0800 Subject: [PATCH 06/14] docs: blogpost for cli v2 (#30876) * docs: blogpost for cli v2 * chore: update links to relative path * chore: drop experimental flag from cli command * chore: mention cli command for config push * chore: reformat with prettier * chore: unnest explanation on config as code * add thumbs and update LW page * Update 2024-12-04-cli-v2-config-as-code.mdx * Apply suggestions from code review Co-authored-by: Copple <10214025+kiwicopple@users.noreply.github.com> * chore: revert experimental flag * update tip * chore: remove unnecessary chart --------- Co-authored-by: Jonathan Summers-Muir Co-authored-by: Copple <10214025+kiwicopple@users.noreply.github.com> --- .../2024-12-04-cli-v2-config-as-code.mdx | 178 ++++++++++++++++++ .../13/Releases/data/lw13_build_stage.tsx | 20 +- apps/www/lib/mdx/mdxComponents.tsx | 11 +- .../supabase-cli-v2-config-as-code/og.jpg | Bin 0 -> 61210 bytes .../supabase-cli-v2-config-as-code/thumb.jpg | Bin 0 -> 28194 bytes 5 files changed, 201 insertions(+), 8 deletions(-) create mode 100644 apps/www/_blog/2024-12-04-cli-v2-config-as-code.mdx create mode 100644 apps/www/public/images/blog/launch-week-13/supabase-cli-v2-config-as-code/og.jpg create mode 100644 apps/www/public/images/blog/launch-week-13/supabase-cli-v2-config-as-code/thumb.jpg diff --git a/apps/www/_blog/2024-12-04-cli-v2-config-as-code.mdx b/apps/www/_blog/2024-12-04-cli-v2-config-as-code.mdx new file mode 100644 index 0000000000000..d3c4cf0f7b964 --- /dev/null +++ b/apps/www/_blog/2024-12-04-cli-v2-config-as-code.mdx @@ -0,0 +1,178 @@ +--- +title: 'Supabase CLI v2: Config as Code' +description: Commit the configuration for all of your Projects and Branches into version control. +author: qiao +image: launch-week-13/supabase-cli-v2-config-as-code/og.jpg +thumb: launch-week-13/supabase-cli-v2-config-as-code/thumb.jpg +categories: + - product +tags: + - launch-week +date: '2024-12-04' +toc_depth: 3 +launchweek: '13' +--- + +We have released Supabase CLI v2 today, adding support for Configuration as Code. + +This means you can commit the configuration for all of your Projects and Branches into version control (like git) for reproducible environments for your entire team. + +## Using the CLI in CI/CD pipelines + +The Supabase CLI started as a way to bootstrap the entire Supabase stack on your local machine. It uses exactly the same infra as our hosted platform, giving you unlimited Supabase projects for local testing and offline usage. + +In the last 2 years, the CLI has grown to more than 180,000 weekly installs. Nearly 85% of these come from Continuous Integration/Deployment environments like GitHub Actions. Some of the popular CI/CD use cases include migrating production databases, deploying functions, and running pgTAP tests. With this in mind, we started focusing on the CLI as a deployment tool for the v2 release. + +## Configuration as Code using the Supabase CLI + + + +**Configuration as Code** is a practice where infrastructure configuration is managed and versioned in source control using code or declarative files. It allows for automation, consistency, and repeatability. Some examples include Terraform and Docker Compose. It offers several key features: + +- **Version Control**: Configurations are stored in repositories like Git, enabling collaboration and history tracking. +- **Reproducibility**: You can recreate environments from code, avoiding manual drift. +- **Automation**: Tools apply configurations automatically, reducing human error. + +Our CLI’s Configuration as Code feature is an opinionated setup using a human readable `config.toml` file. + +You can make deployments consistent and repeatable by promoting Edge Functions, Storage objects, and other services from preview environments to staging and production. + +To demonstrate this workflow, let’s use the `supabase.com` website as an example. It’s hosted on Vercel with [Supabase Branching](/docs/guides/deployment/branching) enabled for development. If you are not using Branching, a similar setup can be achieved using GitHub Actions. + + + + + +Before changing any project configuration, it’s a good idea to verify that your remote config has not drifted. + +This can be done by running `supabase link` command locally which diffs your entire local `config.toml` with your remote project settings. + + + +### Managing Auth Config + +We use Vercel Previews for our frontend. To configure the Auth service of Supabase branches to support login for any Vercel preview URL, we declare a wildcard for the `additional_redirect_urls` in auth config: + +```toml +[auth] +additional_redirect_urls = [ + "https://*-supabase.vercel.app/*/*", + "https://supabase.com/*/*", + "http://localhost:3000/*/*", +] +``` + +View the [Auth config](/docs/guides/local-development/cli/config#auth-config) docs. + +### Managing Edge Functions + +The Supabase website uses several [Edge Functions](https://github.com/supabase/supabase/tree/master/supabase/functions) for AI docs, search embeddings, and image generation for launch week tickets. To configure automatic deployment of `search-embeddings` function, we add the following block to `config.toml`: + +```toml +[functions.search-embeddings] +verify_jwt = false +``` + +If you are using a monorepo (like the [@supabase/supabase](https://github.com/supabase/supabase) Github repository), you may also want to customize the paths to your function’s entrypoint and import map files. This is especially useful for code sharing between your frontend application and Edge Functions. + + + +View the [Edge Functions config](/docs/guides/local-development/cli/config#edge-functions-config) docs. + +### Managing Storage Objects + +The [images and fonts](https://supabase.com/dashboard/project/xguihxuzqibwxjnimxev/storage/buckets/images) for all launch week tickets are stored in Supabase Storage. These assets are distributed to CDNs around the world to improve latency for visitors to our website. + +When developing locally, we can add a `[storage.buckets]` block to `config.toml` so that files in `supabase/assets` directory are automatically uploaded to Supabase Storage. + +```toml +[storage.buckets.assets] +objects_path = "./assets" +``` + +In our case, the assets are small enough (< 1MB) to be committed and tracked in git. This allows branching to automatically seed these objects to Supabase Storage for preview. Larger files like videos are best uploaded to Supabase Storage via AWS S3 CLI. + +View the [Storage config](/docs/guides/local-development/cli/config#storage-config) docs. + +### Managing Database Settings and Webhooks + +While Supabase manages the Postgres default settings based on your database compute size, sometimes you need to tweak these settings yourself. Using the `config.toml` file, we can easily update and keep track of database settings. + +```toml +[db.settings] +track_commit_timestamp = true +``` + +Our Management API automatically figures out if one or more parameters require restarting the database. If not, the config will be applied by simply sending `SIGUP` to Postgres process. + +Moreover, you can now enable database webhooks using `[experimental]` config block. This feature allows your database to call HTTP endpoints directly from Postgres functions. + +```toml +[experimental.webhooks] +enabled = true +``` + +To create a webhook, simply add a new [schema migration](https://github.com/supabase/supabase/tree/master/supabase/migrations) file with the before or after triggers for the tables you want to listen on. + +View the [Database config](/docs/guides/local-development/cli/config#database-config) docs. + +## Managing Branches and multiple “remotes” + +If you have [Branching](/docs/guides/deployment/branching#enable-supabase-branching) enabled in your project, your settings in `config.toml` are automatically synced to all your ephemeral branches. This works because we maintain a one-to-one mapping between your git branch and Supabase branch. + +To make a config change to your Supabase branch, simply update config.toml and push to GitHub. Our runner will pick up the diff and apply it to the corresponding Supabase branch. + +If you need to configure specific settings for a single persistent branch, you can declare them using `[remotes]` block of your config by providing its project ID. For example, the following config declares a separate seed script just for your staging environment. + +```toml +[remotes.staging] +project_id = "your-project-ref" + +[remotes.staging.db.seed] +sql_paths = ["./seeds/staging.sql"] +``` + +Since the `project_id` field must refer to an existing branch, you won’t be able to provision and configure a persistent branch in the same commit. Instead, always provision a persistent branch first using the CLI command so you can add the project ID returned to `config.toml`. + +```bash +$ supabase --experimental branches create --persistent +Do you want to create a branch named develop? [Y/n] +``` + +When merging a PR to any persistent branch, our runner checks and logs any configuration changes before applying them to the target remote. If you didn’t declare any remotes or provided the the wrong project ID, the whole configuration step would be skipped. + +All other config options are also available in the remotes block. + +## Getting started + +To start using configuration as code, you may follow [our guide](/docs/guides/deployment/branching#how-to-use-supabase-branching) to connect a GitHub repository to your Supabase project and enable Supabase Branching. + +Alternatively, you can get started with the Supabase CLI today: `supabase config push` + +### Installing + +Install the Supabase CLI: [docs](/docs/guides/local-development/cli/getting-started#installing-the-supabase-cli). + +### Upgrading + +Upgrade your CLI: [docs](/docs/guides/local-development/cli/getting-started#updating-the-supabase-cli). + +### Breaking changes + +There are no breaking changes in v2. + +### Contributors + +The CLI Team: [Qiao](https://github.com/sweatybridge), [Andrew](https://github.com/avallete) + +The Supabase Team: [Bobbie](https://github.com/soedirgo), [Lakshan](https://github.com/laktek), [Joel](https://github.com/J0), [Filipe](https://github.com/filipecabaco), [TzeYiing](https://github.com/Ziinc), [Div](https://github.com/darora), [Ant](https://github.com/awalias), [Thor](https://github.com/thorwebdev), [Wenbo](https://github.com/w3b6x9), [Kangming](https://github.com/kangmingtay), [Ivan](https://github.com/ivasilov), [Kevin](https://github.com/KevinBrolly), [Long](https://github.com/loong), [Stojan](https://github.com/hf), [Kamil](https://github.com/kamilogorek), [Inian](https://github.com/inian), [Greg](https://github.com/gregnr), [Fabrizio](https://github.com/fenos), [Chris](https://github.com/encima), [Julien](https://github.com/jgoux), [Terry](https://github.com/saltcod), [Egor](https://github.com/egor-romanov), [Joshen](https://github.com/joshenlim), [Steve](https://github.com/steve-chavez), [Guilherme](https://github.com/grdsdev), [Crispy](https://github.com/Crispy1975), [Bo](https://github.com/burmecia), [Rodrigo](https://github.com/mansueli), [Beng](https://github.com/thebengeu), [Copple](https://github.com/kiwicopple) + +With contributions from: [@nyannyacha](https://github.com/nyannyacha), [@grschafer](https://github.com/grschafer), [@osaxma](https://github.com/osaxma), [@theo-m](https://github.com/theo-m), [@kandros](https://github.com/kandros), [@silentworks](https://github.com/silentworks), [@Ananya2001-an](https://github.com/Ananya2001-an), [@Wakeful-Cloud](https://github.com/Wakeful-Cloud), [@snorremd](https://github.com/snorremd), [@S96EA](https://github.com/S96EA), [@wilhuff](https://github.com/wilhuff), [@djhi](https://github.com/djhi), [@FelixZY](https://github.com/FelixZY), [@dagingaa](https://github.com/dagingaa), [@ibilalkayy](https://github.com/ibilalkayy), [@akoenig](https://github.com/akoenig), [@mclean25](https://github.com/mclean25), [@pvanliefland](https://github.com/pvanliefland), [@zlepper](https://github.com/zlepper), [@ruggi99](https://github.com/ruggi99), [@ryankazokas](https://github.com/ryankazokas), [@yahsan2](https://github.com/yahsan2), [@kinolaev](https://github.com/kinolaev), [@simbas](https://github.com/simbas), [@SoraKumo001](https://github.com/SoraKumo001), [@oxcabe](https://github.com/oxcabe), [@PaulRosset](https://github.com/PaulRosset), [@paolodesa](https://github.com/paolodesa), [@eifr](https://github.com/eifr), [@NixBiks](https://github.com/NixBiks), [@nrayburn-tech](https://github.com/nrayburn-tech), [@mosnicholas](https://github.com/mosnicholas), [@NatoNathan](https://github.com/NatoNathan), [@Myzel394](https://github.com/Myzel394), [@mikelhamer](https://github.com/mikelhamer), [@zaerald](https://github.com/zaerald), [@tiniscule](https://github.com/tiniscule), [@samuba](https://github.com/samuba), [@rhnaxifg4y](https://github.com/rhnaxifg4y), [@redraskal](https://github.com/redraskal), [@madx](https://github.com/madx), [@kouwasi](https://github.com/kouwasi), [@etzelc](https://github.com/etzelc), [@arvalaan](https://github.com/arvalaan), [@arika0093](https://github.com/arika0093), [@zachblume](https://github.com/zachblume), [@yashas-hm](https://github.com/yashas-hm), [@vbaluch](https://github.com/vbaluch), [@dshukertjr](https://github.com/dshukertjr), [@tmountain](https://github.com/tmountain), [@tobowers](https://github.com/tobowers), [@tim-dianahr](https://github.com/tim-dianahr), [@StanGirard](https://github.com/StanGirard), [@chreck](https://github.com/chreck), [@chaoky](https://github.com/chaoky), [@carlobeltrame](https://github.com/carlobeltrame), [@bhaan](https://github.com/bhaan), [@bastiaanv](https://github.com/bastiaanv), [@code-withAshish](https://github.com/code-withAshish), [@ashtable](https://github.com/ashtable), [@n0tank3sh](https://github.com/n0tank3sh), [@asevich](https://github.com/asevich), [@aloisklink](https://github.com/aloisklink), [@alinjie](https://github.com/alinjie), [@codesnik](https://github.com/codesnik), [@alexanderl19](https://github.com/alexanderl19), [@alex-ketch](https://github.com/alex-ketch), [@adrientiburce](https://github.com/adrientiburce), [@abeisleem](https://github.com/abeisleem), [@AaronDewes](https://github.com/AaronDewes), [@beeme1mr](https://github.com/beeme1mr), [@isaif](https://github.com/isaif), [@maxkostow](https://github.com/maxkostow), [@Marviel](https://github.com/Marviel), [@xmliszt](https://github.com/xmliszt), [@LautaroJayat](https://github.com/LautaroJayat), [@everzet](https://github.com/everzet), [@kartikk-k](https://github.com/kartikk-k), [@j1philli](https://github.com/j1philli), [@disjukr](https://github.com/disjukr), [@jibin2706](https://github.com/jibin2706), [@felixgabler](https://github.com/felixgabler), [@eleijonmarck](https://github.com/eleijonmarck), [@activenode](https://github.com/activenode), [@jibsaramnim](https://github.com/jibsaramnim), [@byudaniel](https://github.com/byudaniel), [@clarkevandenhoven](https://github.com/clarkevandenhoven) + +## Conclusion + +Managing your project environments often go beyond schema migrations when your entire backend runs on Supabase. With Supabase CLI v2, you can easily manage these development environments using a configuration file to ensure a consistent development experience between all services in staging and production. diff --git a/apps/www/components/LaunchWeek/13/Releases/data/lw13_build_stage.tsx b/apps/www/components/LaunchWeek/13/Releases/data/lw13_build_stage.tsx index 03893f1521fa1..b825a3827d308 100644 --- a/apps/www/components/LaunchWeek/13/Releases/data/lw13_build_stage.tsx +++ b/apps/www/components/LaunchWeek/13/Releases/data/lw13_build_stage.tsx @@ -2,6 +2,7 @@ import { ReactNode } from 'react' import { type ClassValue } from 'clsx' +import { GitBranch } from 'lucide-react' export interface AdventDay { icon?: ReactNode // use svg jsx with 34x34px viewport @@ -63,12 +64,19 @@ export const days: AdventDay[] = [ ), }, { - title: '', - description: '', - id: '', - is_shipped: false, - links: [], - icon: null, + title: 'Supabase CLI v2: Config as Code', + description: + 'Commit the configuration for all of your Projects and Branches into version control.', + id: 'cli', + is_shipped: true, + links: [ + { + url: '/blog/cli-v2-config-as-code', + label: 'Blog post', + target: '_blank', + }, + ], + icon: , }, { title: '', diff --git a/apps/www/lib/mdx/mdxComponents.tsx b/apps/www/lib/mdx/mdxComponents.tsx index 2f9c46f534017..c5c2a3f8c514b 100644 --- a/apps/www/lib/mdx/mdxComponents.tsx +++ b/apps/www/lib/mdx/mdxComponents.tsx @@ -37,9 +37,16 @@ const LinkComponent = (props: PropsWithChildren) => ( ) -const BlogCollapsible = ({ title, ...props }: { title: string }) => { +const BlogCollapsible = ({ + title, + containerClassName, + ...props +}: { + title: string + containerClassName?: string +}) => { return ( - + } onClick={() => { diff --git a/apps/studio/components/interfaces/Integrations/CronJobs/PreviousRunsTab.tsx b/apps/studio/components/interfaces/Integrations/CronJobs/PreviousRunsTab.tsx index d5a39b263bbdd..6b1cbf74b736b 100644 --- a/apps/studio/components/interfaces/Integrations/CronJobs/PreviousRunsTab.tsx +++ b/apps/studio/components/interfaces/Integrations/CronJobs/PreviousRunsTab.tsx @@ -181,42 +181,40 @@ export const PreviousRunsTab = () => { return (
-
- - { - const isSelected = false - return cn([ - `${isSelected ? 'bg-surface-300 dark:bg-surface-300' : 'bg-200'} `, - `${isSelected ? '[&>div:first-child]:border-l-4 border-l-secondary [&>div]:border-l-foreground' : ''}`, - '[&>.rdg-cell]:border-box [&>.rdg-cell]:outline-none [&>.rdg-cell]:shadow-none', - '[&>.rdg-cell:first-child>div]:ml-4', - ]) - }} - renderers={{ - renderRow(_idx, props) { - return - }, - noRowsFallback: isLoadingCronJobRuns ? ( -
- -
- ) : ( -
- -
- ), - }} - /> -
+ + { + const isSelected = false + return cn([ + `${isSelected ? 'bg-surface-300 dark:bg-surface-300' : 'bg-200'} `, + `${isSelected ? '[&>div:first-child]:border-l-4 border-l-secondary [&>div]:border-l-foreground' : ''}`, + '[&>.rdg-cell]:border-box [&>.rdg-cell]:outline-none [&>.rdg-cell]:shadow-none', + '[&>.rdg-cell:first-child>div]:ml-4', + ]) + }} + renderers={{ + renderRow(_idx, props) { + return + }, + noRowsFallback: isLoadingCronJobRuns ? ( +
+ +
+ ) : ( +
+ +
+ ), + }} + /> -
+
{isLoadingCronJobs ? ( ) : ( @@ -239,7 +237,7 @@ export const PreviousRunsTab = () => {

-
+

Command

@@ -266,18 +264,9 @@ export const PreviousRunsTab = () => { - {/*
- - {currentJobState?.command} - -
*/}
-
+

Explore

-
-
- - )} +
+
+

We will contact you at

+

{respondToEmail}

+
+
+

+ Please ensure you haven't blocked Hubspot in your emails +

+
+
+ +
+
) diff --git a/apps/studio/components/layouts/ProjectIntegrationsLayout/ProjectIntegrations.Commands.tsx b/apps/studio/components/layouts/ProjectIntegrationsLayout/ProjectIntegrations.Commands.tsx deleted file mode 100644 index 0601598e5a8f0..0000000000000 --- a/apps/studio/components/layouts/ProjectIntegrationsLayout/ProjectIntegrations.Commands.tsx +++ /dev/null @@ -1,107 +0,0 @@ -import { Code } from 'lucide-react' - -import { COMMAND_MENU_SECTIONS } from 'components/interfaces/App/CommandMenu/CommandMenu.utils' -import type { CommandOptions } from 'ui-patterns/CommandMenu' -import { useRegisterCommands } from 'ui-patterns/CommandMenu' -import { useParams } from 'common' -import { orderCommandSectionsByPriority } from 'components/interfaces/App/CommandMenu/ordering' - -export function useDatabaseGotoCommands(options?: CommandOptions) { - let { ref } = useParams() - ref ||= '_' - - useRegisterCommands( - COMMAND_MENU_SECTIONS.QUERY, - [ - { - id: 'run-sql', - name: 'Run SQL', - route: `/project/${ref}/sql/new`, - icon: () => , - }, - ], - { - ...options, - deps: [ref], - orderSection: orderCommandSectionsByPriority, - sectionMeta: { priority: 2 }, - } - ) - - useRegisterCommands( - COMMAND_MENU_SECTIONS.NAVIGATE, - [ - { - id: 'nav-database-tables', - name: 'Tables', - value: 'Database: Tables', - route: `/project/${ref}/database/tables`, - defaultHidden: true, - }, - { - id: 'nav-database-triggers', - name: 'Triggers', - value: 'Database: Triggers', - route: `/project/${ref}/database/triggers`, - defaultHidden: true, - }, - { - id: 'nav-database-functions', - name: 'Functions', - value: 'Database: Functions', - route: `/project/${ref}/database/functions`, - defaultHidden: true, - }, - { - id: 'nav-database-extensions', - name: 'Extensions', - value: 'Database: Extensions', - route: `/project/${ref}/database/extensions`, - defaultHidden: true, - }, - { - id: 'nav-database-roles', - name: 'Roles', - value: 'Database: Roles', - route: `/project/${ref}/database/roles`, - defaultHidden: true, - }, - { - id: 'nav-database-replication', - name: 'Replication', - value: 'Database: Replication', - route: `/project/${ref}/database/replication`, - defaultHidden: true, - }, - { - id: 'nav-database-hooks', - name: 'Webhooks', - value: 'Database: Webhooks', - route: `/project/${ref}/integrations/hooks`, - defaultHidden: true, - }, - { - id: 'nav-database-backups', - name: 'Backups', - value: 'Database: Backups', - route: `/project/${ref}/database/backups/scheduled`, - defaultHidden: true, - }, - { - id: 'nav-database-wrappers', - name: 'Wrappers', - value: 'Database: Wrappers', - route: `/project/${ref}/integrations/wrappers`, - defaultHidden: true, - }, - { - id: 'nav-database-migrations', - name: 'Migrations', - value: 'Database: Migrations', - route: `/project/${ref}/database/migrations`, - defaultHidden: true, - }, - ], - { ...options, deps: [ref] } - ) -} diff --git a/apps/studio/components/layouts/ProjectIntegrationsLayout/ProjectIntegrationsLayout.tsx b/apps/studio/components/layouts/ProjectIntegrationsLayout/ProjectIntegrationsLayout.tsx deleted file mode 100644 index b9496ba2ba6f1..0000000000000 --- a/apps/studio/components/layouts/ProjectIntegrationsLayout/ProjectIntegrationsLayout.tsx +++ /dev/null @@ -1,67 +0,0 @@ -import { useRouter } from 'next/router' -import { PropsWithChildren } from 'react' - -import { IS_PLATFORM } from 'common' -import { ProductMenu } from 'components/ui/ProductMenu' -import { useDatabaseExtensionsQuery } from 'data/database-extensions/database-extensions-query' -import { useSelectedProject } from 'hooks/misc/useSelectedProject' -import { withAuth } from 'hooks/misc/withAuth' -import { useFlag } from 'hooks/ui/useFlag' -import ProjectLayout from '../ProjectLayout/ProjectLayout' -import { generateProjectIntegrationsMenu } from './ProjectIntegrationsMenu.utils' - -export interface ProjectIntegrationsLayoutProps { - title: string -} - -const ProjectIntegrationsMenu = () => { - // if running on self-hosted, cron UI should be always enabled - const cronUiEnabled = useFlag('cronUi') || !IS_PLATFORM - const queuesUiEnabled = useFlag('queues') - const project = useSelectedProject() - - const router = useRouter() - const page = router.pathname.split('/')[4] - - const { data } = useDatabaseExtensionsQuery({ - projectRef: project?.ref, - connectionString: project?.connectionString, - }) - - const pgNetExtensionExists = (data ?? []).find((ext) => ext.name === 'pg_net') !== undefined - const graphqlExtensionExists = (data ?? []).find((ext) => ext.name === 'pg_graphql') !== undefined - const pgmqExtensionExists = (data ?? []).find((ext) => ext.name === 'pgmq') !== undefined - - return ( - <> - - - ) -} - -const ProjectIntegrationsLayout = ({ - children, - title, -}: PropsWithChildren) => { - return ( - } - isBlocking={false} - > - {children} - - ) -} - -export default withAuth(ProjectIntegrationsLayout) diff --git a/apps/studio/components/layouts/ProjectIntegrationsLayout/ProjectIntegrationsMenu.utils.tsx b/apps/studio/components/layouts/ProjectIntegrationsLayout/ProjectIntegrationsMenu.utils.tsx deleted file mode 100644 index 1811d28d2ad47..0000000000000 --- a/apps/studio/components/layouts/ProjectIntegrationsLayout/ProjectIntegrationsMenu.utils.tsx +++ /dev/null @@ -1,84 +0,0 @@ -import type { ProductMenuGroup } from 'components/ui/ProductMenu/ProductMenu.types' -import type { Project } from 'data/projects/project-detail-query' - -export const generateProjectIntegrationsMenu = ( - project?: Project, - flags?: { - pgNetExtensionExists: boolean - cronUiEnabled: boolean - queuesUiEnabled: boolean - graphqlExtensionExists: boolean - pgmqExtensionExists: boolean - } -): ProductMenuGroup[] => { - const ref = project?.ref ?? 'default' - const { - pgNetExtensionExists, - cronUiEnabled, - queuesUiEnabled, - graphqlExtensionExists, - pgmqExtensionExists, - } = flags || {} - - return [ - { - title: 'Manage', - items: [ - { - name: 'Wrappers', - key: 'wrappers', - url: `/project/${ref}/integrations/wrappers`, - items: [], - }, - ...(!!pgNetExtensionExists - ? [ - { - name: 'Webhooks', - key: 'hooks', - url: `/project/${ref}/integrations/hooks`, - items: [], - }, - ] - : []), - - ...(!!cronUiEnabled - ? [ - { - name: 'Cron', - key: 'cron-jobs', - url: `/project/${ref}/integrations/cron`, - items: [], - }, - ] - : []), - ...(!!graphqlExtensionExists - ? [ - { - name: 'GraphiQL', - key: 'graphiql', - url: `/project/${ref}/integrations/graphiql`, - items: [], - }, - ] - : []), - { - name: 'Vault', - key: 'vault', - url: `/project/${ref}/integrations/vault/secrets`, - items: [], - label: 'BETA', - }, - ...(!!(queuesUiEnabled && pgmqExtensionExists) - ? [ - { - name: 'Queues', - key: 'queues', - url: `/project/${ref}/integrations/queues`, - items: [], - }, - ] - : []), - ], - }, - ] -} diff --git a/apps/studio/components/layouts/ProjectSettingsLayout/SettingsLayout.tsx b/apps/studio/components/layouts/ProjectSettingsLayout/SettingsLayout.tsx index 8b5bdd929e3b7..81af839800a79 100644 --- a/apps/studio/components/layouts/ProjectSettingsLayout/SettingsLayout.tsx +++ b/apps/studio/components/layouts/ProjectSettingsLayout/SettingsLayout.tsx @@ -47,7 +47,6 @@ const SettingsLayout = ({ title, children }: PropsWithChildren { @@ -26,7 +25,6 @@ export const generateSettingsMenu = ( const edgeFunctionsEnabled = features?.edgeFunctions ?? true const storageEnabled = features?.storage ?? true const warehouseEnabled = features?.warehouse ?? false - const logDrainsEnabled = features?.logDrains ?? false const newDiskComputeEnabled = features?.diskAndCompute ?? false return [ @@ -136,7 +134,7 @@ export const generateSettingsMenu = ( }, ] : []), - ...(IS_PLATFORM && logDrainsEnabled + ...(IS_PLATFORM ? [ { name: `Log Drains`, diff --git a/apps/studio/pages/account/me.tsx b/apps/studio/pages/account/me.tsx index c94b58eb601ad..9c1f90281abbb 100644 --- a/apps/studio/pages/account/me.tsx +++ b/apps/studio/pages/account/me.tsx @@ -2,7 +2,6 @@ import { AccountInformation, AnalyticsSettings, ThemeSettings, - ThemeSettingsOld, } from 'components/interfaces/Account/Preferences' import { AccountDeletion } from 'components/interfaces/Account/Preferences/AccountDeletion' import { ProfileInformation } from 'components/interfaces/Account/Preferences/ProfileInformation' @@ -11,7 +10,6 @@ import AlertError from 'components/ui/AlertError' import Panel from 'components/ui/Panel' import { GenericSkeletonLoader } from 'components/ui/ShimmeringLoader' import { useIsFeatureEnabled } from 'hooks/misc/useIsFeatureEnabled' -import { useFlag } from 'hooks/ui/useFlag' import { useProfile } from 'lib/profile' import type { NextPageWithLayout } from 'types' @@ -41,11 +39,8 @@ export default User const ProfileCard = () => { const profileUpdateEnabled = useIsFeatureEnabled('profile:update') - const { profile, error, isLoading, isError, isSuccess } = useProfile() - const experimentalThemeEnabled = useFlag('enableExperimentalTheme') - return (
{isLoading && ( @@ -71,7 +66,9 @@ const ProfileCard = () => { )} -
{experimentalThemeEnabled ? : }
+
+ +
From 9edc5f500e8de8da0c946f6859bec8e3c93370a4 Mon Sep 17 00:00:00 2001 From: Terry Sutton Date: Wed, 4 Dec 2024 05:47:51 -0330 Subject: [PATCH 12/14] Shorter select widths (#30871) * Shorter select widths * Fix the width of the database function selects. --------- Co-authored-by: Ivan Vasilov --- .../interfaces/Integrations/CronJobs/SqlFunctionSection.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/studio/components/interfaces/Integrations/CronJobs/SqlFunctionSection.tsx b/apps/studio/components/interfaces/Integrations/CronJobs/SqlFunctionSection.tsx index d607b46435da9..8884afb637db9 100644 --- a/apps/studio/components/interfaces/Integrations/CronJobs/SqlFunctionSection.tsx +++ b/apps/studio/components/interfaces/Integrations/CronJobs/SqlFunctionSection.tsx @@ -14,7 +14,7 @@ export const SqlFunctionSection = ({ form }: SqlFunctionSectionProps) => { const schema = form.watch('values.schema') return ( - + { { field.onChange(name) @@ -40,6 +41,7 @@ export const SqlFunctionSection = ({ form }: SqlFunctionSectionProps) => { field.onChange(name)} From 0c8a49891325cd4afd48d4969136c67863cbb037 Mon Sep 17 00:00:00 2001 From: Han Qiao Date: Wed, 4 Dec 2024 18:05:26 +0800 Subject: [PATCH 13/14] chore: simplify config for enterprise patterns (#30887) --- .../partitions/supabase/config.toml | 79 +++++-------------- .../supachat/supabase/config.toml | 79 +++++-------------- 2 files changed, 40 insertions(+), 118 deletions(-) diff --git a/examples/enterprise-patterns/partitions/supabase/config.toml b/examples/enterprise-patterns/partitions/supabase/config.toml index 1f53e6ac273c1..967dc6ae3a54f 100644 --- a/examples/enterprise-patterns/partitions/supabase/config.toml +++ b/examples/enterprise-patterns/partitions/supabase/config.toml @@ -2,81 +2,42 @@ # directory name when running `supabase init`. project_id = "partitions" -[api] -# Port to use for the API URL. -port = 54321 -# Schemas to expose in your API. Tables, views and stored procedures in this schema will get API -# endpoints. public and storage are always included. -schemas = ["public", "storage", "graphql_public"] -# Extra schemas to add to the search_path of every request. public is always included. -extra_search_path = ["public", "extensions"] -# The maximum number of rows returns from a view, table, or stored procedure. Limits payload size -# for accidental or malicious requests. -max_rows = 1000 - [db] # Port to use for the local database URL. port = 54322 +# Port used by db diff command to initialize the shadow database. +shadow_port = 54320 # The database major version to use. This has to be the same as your remote database's. Run `SHOW # server_version;` on the remote database to check. major_version = 15 +[db.seed] +# If enabled, seeds the database after migrations during a db reset. +enabled = true +# Specifies an ordered list of seed files to load during db reset. +# Supports glob patterns relative to supabase directory: './seeds/*.sql' +sql_paths = ['./seed.sql'] + +[api] +enabled = false + +[realtime] +enabled = false + [studio] -# Port to use for Supabase Studio. -port = 54323 +enabled = false -# Email testing server. Emails sent with the local dev setup are not actually sent - rather, they -# are monitored, and you can view the emails that would have been sent from the web interface. [inbucket] -# Port to use for the email testing server web interface. -port = 54324 -smtp_port = 54325 -pop3_port = 54326 +enabled = false [storage] -# The maximum file size allowed (e.g. "5MB", "500KB"). -file_size_limit = "50MiB" +enabled = false [auth] -# The base URL of your website. Used as an allow-list for redirects and for constructing URLs used -# in emails. -site_url = "http://localhost:3000" -# A list of *exact* URLs that auth providers are permitted to redirect to post authentication. -additional_redirect_urls = ["https://localhost:3000"] -# How long tokens are valid for, in seconds. Defaults to 3600 (1 hour), maximum 604,800 seconds (one -# week). -jwt_expiry = 3600 -# Allow/disallow new user signups to your project. -enable_signup = true - -[auth.email] -# Allow/disallow new user signups via email to your project. -enable_signup = true -# If enabled, a user will be required to confirm any email change on both the old, and new email -# addresses. If disabled, only the new email is required to confirm. -double_confirm_changes = true -# If enabled, users need to confirm their email address before signing in. -enable_confirmations = false +enabled = false -# Use an external OAuth provider. The full list of providers are: `apple`, `azure`, `bitbucket`, -# `discord`, `facebook`, `github`, `gitlab`, `google`, `keycloak`, `linkedin`, `notion`, `twitch`, -# `twitter`, `slack`, `spotify`, `workos`, `zoom`. -[auth.external.apple] +[edge_runtime] enabled = false -client_id = "" -secret = "" -# Overrides the default auth redirectUrl. -redirect_uri = "" -# Overrides the default auth provider URL. Used to support self-hosted gitlab, single-tenant Azure, -# or any other third-party OIDC providers. -url = "" [analytics] enabled = false -port = 54327 -vector_port = 54328 -# Setup BigQuery project to enable log viewer on local development stack. -# See: https://supabase.com/docs/guides/getting-started/local-development#enabling-local-logging -gcp_project_id = "" -gcp_project_number = "" -gcp_jwt_path = "supabase/gcloud.json" diff --git a/examples/enterprise-patterns/supachat/supabase/config.toml b/examples/enterprise-patterns/supachat/supabase/config.toml index 116399345f601..4dc1b05e66f7d 100644 --- a/examples/enterprise-patterns/supachat/supabase/config.toml +++ b/examples/enterprise-patterns/supachat/supabase/config.toml @@ -2,81 +2,42 @@ # directory name when running `supabase init`. project_id = "supachat" -[api] -# Port to use for the API URL. -port = 65431 -# Schemas to expose in your API. Tables, views and stored procedures in this schema will get API -# endpoints. public and storage are always included. -schemas = ["public", "storage", "graphql_public"] -# Extra schemas to add to the search_path of every request. public is always included. -extra_search_path = ["public", "extensions"] -# The maximum number of rows returns from a view, table, or stored procedure. Limits payload size -# for accidental or malicious requests. -max_rows = 1000 - [db] # Port to use for the local database URL. port = 65432 +# Port used by db diff command to initialize the shadow database. +shadow_port = 65430 # The database major version to use. This has to be the same as your remote database's. Run `SHOW # server_version;` on the remote database to check. major_version = 15 +[db.seed] +# If enabled, seeds the database after migrations during a db reset. +enabled = true +# Specifies an ordered list of seed files to load during db reset. +# Supports glob patterns relative to supabase directory: './seeds/*.sql' +sql_paths = ['./seed.sql'] + +[api] +enabled = false + +[realtime] +enabled = false + [studio] -# Port to use for Supabase Studio. -port = 65433 +enabled = false -# Email testing server. Emails sent with the local dev setup are not actually sent - rather, they -# are monitored, and you can view the emails that would have been sent from the web interface. [inbucket] -# Port to use for the email testing server web interface. -port = 65434 -smtp_port = 65435 -pop3_port = 65436 +enabled = false [storage] -# The maximum file size allowed (e.g. "5MB", "500KB"). -file_size_limit = "50MiB" +enabled = false [auth] -# The base URL of your website. Used as an allow-list for redirects and for constructing URLs used -# in emails. -site_url = "http://localhost:3000" -# A list of *exact* URLs that auth providers are permitted to redirect to post authentication. -additional_redirect_urls = ["https://localhost:3000"] -# How long tokens are valid for, in seconds. Defaults to 3600 (1 hour), maximum 604,800 seconds (one -# week). -jwt_expiry = 3600 -# Allow/disallow new user signups to your project. -enable_signup = true - -[auth.email] -# Allow/disallow new user signups via email to your project. -enable_signup = true -# If enabled, a user will be required to confirm any email change on both the old, and new email -# addresses. If disabled, only the new email is required to confirm. -double_confirm_changes = true -# If enabled, users need to confirm their email address before signing in. -enable_confirmations = false +enabled = false -# Use an external OAuth provider. The full list of providers are: `apple`, `azure`, `bitbucket`, -# `discord`, `facebook`, `github`, `gitlab`, `google`, `keycloak`, `linkedin`, `notion`, `twitch`, -# `twitter`, `slack`, `spotify`, `workos`, `zoom`. -[auth.external.apple] +[edge_runtime] enabled = false -client_id = "" -secret = "" -# Overrides the default auth redirectUrl. -redirect_uri = "" -# Overrides the default auth provider URL. Used to support self-hosted gitlab, single-tenant Azure, -# or any other third-party OIDC providers. -url = "" [analytics] enabled = false -port = 65437 -vector_port = 65438 -# Setup BigQuery project to enable log viewer on local development stack. -# See: https://supabase.com/docs/guides/getting-started/local-development#enabling-local-logging -gcp_project_id = "" -gcp_project_number = "" -gcp_jwt_path = "supabase/gcloud.json" From f5894d50599544bb9d2c98c0e51e429f363d01c9 Mon Sep 17 00:00:00 2001 From: Tom Gallacher Date: Wed, 4 Dec 2024 10:09:09 +0000 Subject: [PATCH 14/14] chore: add tomg to humans txt (#30852) --- apps/docs/public/humans.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/docs/public/humans.txt b/apps/docs/public/humans.txt index ef5e340666ac7..b631dfe115cde 100644 --- a/apps/docs/public/humans.txt +++ b/apps/docs/public/humans.txt @@ -83,6 +83,7 @@ Terry Sutton Thomas E Thor Schaeff Tom Ashley +Tom G Tyler Hillery Tyler Fontaine Tyler Shukert