From 65dfd228add85fb70e43f4b00fbeaf7f0a938921 Mon Sep 17 00:00:00 2001
From: Gildas Garcia <1122076+djhi@users.noreply.github.com>
Date: Wed, 25 Feb 2026 08:05:33 +0100
Subject: [PATCH 1/6] Allow filtering the list of available edge functions when
creating/editing a cron job (#43138)
## Problem
Finding a specific edge function is cumbersome when you have many of
then.
## Solution
Use a combobox instead of a select to allow filtering
## How to test
- Enable the cron extension
- Enable the pg_net extension
- Create a few edge functions
- Create a new cron job and select _Supabase edge functions_
You should be able to:
- select/unselect an edge function
- filter the list to reduce the number of edge functions displayed
---
.../CronJobs/EdgeFunctionSection.tsx | 142 ++++++++++++------
1 file changed, 99 insertions(+), 43 deletions(-)
diff --git a/apps/studio/components/interfaces/Integrations/CronJobs/EdgeFunctionSection.tsx b/apps/studio/components/interfaces/Integrations/CronJobs/EdgeFunctionSection.tsx
index bea8fed5bdcc1..39439769882cb 100644
--- a/apps/studio/components/interfaces/Integrations/CronJobs/EdgeFunctionSection.tsx
+++ b/apps/studio/components/interfaces/Integrations/CronJobs/EdgeFunctionSection.tsx
@@ -1,18 +1,29 @@
-import Link from 'next/link'
-import { UseFormReturn } from 'react-hook-form'
-
import { useParams } from 'common/hooks'
import { useEdgeFunctionsQuery } from 'data/edge-functions/edge-functions-query'
import { useSelectedProjectQuery } from 'hooks/misc/useSelectedProject'
-import { useEffect, useMemo } from 'react'
+import { Check, ChevronsUpDown } from 'lucide-react'
+import Link from 'next/link'
+import { useEffect, useId, useMemo, useState } from 'react'
+import { UseFormReturn } from 'react-hook-form'
import {
Button,
+ cn,
+ Command_Shadcn_,
+ CommandEmpty_Shadcn_,
+ CommandGroup_Shadcn_,
+ CommandInput_Shadcn_,
+ CommandItem_Shadcn_,
+ CommandList_Shadcn_,
FormControl_Shadcn_,
FormField_Shadcn_,
FormItem_Shadcn_,
FormLabel_Shadcn_,
FormMessage_Shadcn_,
Input,
+ Popover_Shadcn_,
+ PopoverContent_Shadcn_,
+ PopoverTrigger_Shadcn_,
+ ScrollArea,
Select_Shadcn_,
SelectContent_Shadcn_,
SelectItem_Shadcn_,
@@ -21,6 +32,7 @@ import {
SheetSection,
} from 'ui'
import { FormItemLayout } from 'ui-patterns/form/FormItemLayout/FormItemLayout'
+
import { CreateCronJobForm } from './CreateCronJobSheet/CreateCronJobSheet.constants'
interface HTTPRequestFieldsProps {
@@ -41,19 +53,22 @@ export const EdgeFunctionSection = ({ form }: HTTPRequestFieldsProps) => {
isSuccess,
isPending: isLoading,
} = useEdgeFunctionsQuery({ projectRef: ref })
-
- const edgeFunctions = useMemo(() => functions ?? [], [functions])
+ const [open, setOpen] = useState(false)
+ const listboxId = useId()
+ const edgeFunctions = useMemo(
+ () =>
+ functions?.map((fn) => ({
+ ...fn,
+ url: buildFunctionUrl(fn.slug, selectedProject?.ref || '', selectedProject?.restUrl),
+ })) ?? [],
+ [functions, selectedProject]
+ )
// Only set a default value if the field is empty
useEffect(() => {
if (isSuccess && edgeFunctions.length > 0 && !form.getValues('values.edgeFunctionName')) {
const fn = edgeFunctions[0]
- const functionUrl = buildFunctionUrl(
- fn.slug,
- selectedProject?.ref || '',
- selectedProject?.restUrl
- )
- form.setValue('values.edgeFunctionName', functionUrl)
+ form.setValue('values.edgeFunctionName', fn.url)
}
}, [edgeFunctions, form, isSuccess, selectedProject?.ref, selectedProject?.restUrl])
@@ -84,47 +99,88 @@ export const EdgeFunctionSection = ({ form }: HTTPRequestFieldsProps) => {
{edgeFunctions.length === 0 ? (
Select which edge function to trigger
-
-
No edge functions created yet
-
+ ) : (
+
+
No edge functions created yet
+
+ Create an edge function
+
+
+ )}
) : edgeFunctions.length > 0 ? (
{
+ const selectedFunction = edgeFunctions.find((fn) => fn.url === field.value)
+
return (
Edge Function
-
-
-
-
-
-
-
- {edgeFunctions.map((fn) => {
- const functionUrl = buildFunctionUrl(
- fn.slug,
- selectedProject?.ref || '',
- selectedProject?.restUrl
- )
-
- return (
-
- {fn.name}
-
- )
- })}
-
-
+
+
+
+
+ }
+ >
+ {selectedFunction
+ ? selectedFunction.name
+ : 'Select which edge function to trigger'}
+
+
+
+
+
+
+
+ No edge function found.
+
+ 7 ? 'h-[210px]' : ''}>
+ {edgeFunctions.map((fn) => {
+ return (
+ {
+ field.onChange(fn.url === field.value ? '' : fn.url)
+ setOpen(false)
+ }}
+ >
+
+ {fn.name}
+
+ )
+ })}
+
+
+
+
+
+
)
From d727d33db9bff333478f0e380935848c9e18f361 Mon Sep 17 00:00:00 2001
From: slegarraga <64795732+slegarraga@users.noreply.github.com>
Date: Wed, 25 Feb 2026 04:30:14 -0300
Subject: [PATCH 2/6] docs: replace deprecated getSession with getClaims in
SolidJS tutorial (#43034)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Fixes #42192
Replaces the deprecated `getSession` call with `getClaims` in the
SolidJS tutorial documentation (`with-solidjs.mdx`).
Changes:
- `supabase.auth.getSession()` → `supabase.auth.getClaims()`
- `data.session` → `data.claims`
This follows the recommended migration pattern per the Supabase auth
docs, and is consistent with the same fix applied to the Refine tutorial
in #43006.
---------
Co-authored-by: Chris Chinchilla
---
.../tutorials/with-solidjs.mdx | 389 +-
.../solid-user-management/.env.example | 2 +-
.../solid-user-management/package-lock.json | 3887 +++++++----------
.../solid-user-management/package.json | 12 +-
.../solid-user-management/src/Account.tsx | 14 +-
.../solid-user-management/src/App.tsx | 20 +-
.../src/supabaseClient.tsx | 4 +-
7 files changed, 1583 insertions(+), 2745 deletions(-)
diff --git a/apps/docs/content/guides/getting-started/tutorials/with-solidjs.mdx b/apps/docs/content/guides/getting-started/tutorials/with-solidjs.mdx
index 6eef0ff067b0b..3970482811221 100644
--- a/apps/docs/content/guides/getting-started/tutorials/with-solidjs.mdx
+++ b/apps/docs/content/guides/getting-started/tutorials/with-solidjs.mdx
@@ -17,278 +17,94 @@ If you get stuck while working through this guide, refer to the [full example on
## Building the app
-Let's start building the SolidJS app from scratch.
+Start building the SolidJS app from scratch.
### Initialize a SolidJS app
-We can use [degit](https://github.com/Rich-Harris/degit) to initialize an app called `supabase-solid`:
+You can use [degit](https://github.com/Rich-Harris/degit) to initialize an app called `supabase-solid`:
```bash
npx degit solidjs/templates/ts supabase-solid
cd supabase-solid
```
-Then let's install the only additional dependency: [supabase-js](https://github.com/supabase/supabase-js)
+Then 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 key that you copied [earlier](#get-api-details).
+And finally save the environment variables in a `.env` with the API URL and the key that you copied [earlier](#get-api-details).
<$CodeTabs>
-```bash name=.env
-VITE_SUPABASE_URL=YOUR_SUPABASE_URL
-VITE_SUPABASE_PUBLISHABLE_KEY=YOUR_SUPABASE_PUBLISHABLE_KEY
-```
+<$CodeSample
+ path="/user-management/solid-user-management/.env.example"
+ lines={[[1, -1]]}
+ meta="name=.env"
+/>
$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 that 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 completely fine since you have [Row Level Security](/docs/guides/auth#row-level-security) enabled on the Database.
<$CodeTabs>
-```tsx name=src/supabaseClient.tsx
-import { createClient } from '@supabase/supabase-js'
-
-const supabaseUrl = import.meta.env.VITE_SUPABASE_URL
-const supabasePublishableKey = import.meta.env.VITE_SUPABASE_PUBLISHABLE_KEY
-
-export const supabase = createClient(supabaseUrl, supabasePublishableKey)
-```
+<$CodeSample
+ path="/user-management/solid-user-management/src/supabaseClient.tsx"
+ lines={[[1, -1]]}
+ meta="name=src/supabaseClient.tsx"
+/>
$CodeTabs>
### App styling (optional)
-An optional step is to update the CSS file `src/index.css` to make the app look nice.
+An optional step is to update the CSS file `src/index.css` to make the app look better.
You can find the full contents of this file [here](https://raw.githubusercontent.com/supabase/supabase/master/examples/user-management/solid-user-management/src/index.css).
### Set up a login component
-Let's set up a SolidJS 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 SolidJS component to manage logins and sign ups using Magic Links, so users can sign in with their email without using passwords.
<$CodeTabs>
-```jsx name=src/Auth.tsx
-import { createSignal } from 'solid-js'
-import { supabase } from './supabaseClient'
-
-export default function Auth() {
- const [loading, setLoading] = createSignal(false)
- const [email, setEmail] = createSignal('')
-
- const handleLogin = async (e: SubmitEvent) => {
- e.preventDefault()
-
- try {
- setLoading(true)
- const { error } = await supabase.auth.signInWithOtp({ email: email() })
- if (error) throw error
- alert('Check your email for the login link!')
- } catch (error) {
- if (error instanceof Error) {
- alert(error.message)
- }
- } finally {
- setLoading(false)
- }
- }
-
- return (
-
-
-
Supabase + SolidJS
-
Sign in via magic link with your email below
-
-
-
- )
-}
-```
+<$CodeSample
+ path="/user-management/solid-user-management/src/Auth.tsx"
+ lines={[[1, -1]]}
+ meta="name=src/Auth.tsx"
+/>
$CodeTabs>
### Account page
-After a user is signed in we can allow them to edit their profile details and manage their account.
+After a user is signed in allow them to edit their profile details and manage their account.
-Let's create a new component for that called `Account.tsx`.
+Create a new component for that called `Account.tsx`.
<$CodeTabs>
-```tsx name=src/Account.tsx
-import { AuthSession } from '@supabase/supabase-js'
-import { Component, createEffect, createSignal } from 'solid-js'
-import { supabase } from './supabaseClient'
-
-interface Props {
- session: AuthSession
-}
-
-const Account: Component = ({ session }) => {
- const [loading, setLoading] = createSignal(true)
- const [username, setUsername] = createSignal(null)
- const [website, setWebsite] = createSignal(null)
- const [avatarUrl, setAvatarUrl] = createSignal(null)
-
- createEffect(() => {
- getProfile()
- })
-
- const getProfile = async () => {
- try {
- setLoading(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) {
- setUsername(data.username)
- setWebsite(data.website)
- setAvatarUrl(data.avatar_url)
- }
- } catch (error) {
- if (error instanceof Error) {
- alert(error.message)
- }
- } finally {
- setLoading(false)
- }
- }
-
- const updateProfile = async (e: Event) => {
- e.preventDefault()
-
- try {
- setLoading(true)
- const { user } = session
-
- const updates = {
- id: user.id,
- username: username(),
- website: 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 {
- setLoading(false)
- }
- }
-
- return (
-
-
-
- )
-}
-
-export default Account
-```
+<$CodeSample
+ path="/user-management/solid-user-management/src/Account.tsx"
+ lines={[[1, 1], [3, 78], [87, -1]]}
+ meta="name=src/Account.tsx"
+/>
$CodeTabs>
### Launch!
-Now that we have all the components in place, let's update `App.tsx`:
+Now that you have all the components in place, update `App.tsx`:
<$CodeTabs>
-```jsx name=src/App.tsx
-import { Component, createEffect, createSignal } from 'solid-js'
-import { supabase } from './supabaseClient'
-import { AuthSession } from '@supabase/supabase-js'
-import Account from './Account'
-import Auth from './Auth'
-
-const App: Component = () => {
- const [session, setSession] = createSignal(null)
-
- createEffect(() => {
- supabase.auth.getSession().then(({ data: { session } }) => {
- setSession(session)
- })
-
- supabase.auth.onAuthStateChange((_event, session) => {
- setSession(session)
- })
- })
-
- return (
-
- {!session() ? : }
-
- )
-}
-
-export default App
-```
+<$CodeSample
+ path="/user-management/solid-user-management/src/App.tsx"
+ lines={[[1, -1]]}
+ meta="name=src/App.tsx"
+/>
$CodeTabs>
@@ -308,138 +124,29 @@ 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>
-```jsx name=src/Avatar.tsx
-import { Component, createEffect, createSignal, JSX } from 'solid-js'
-import { supabase } from './supabaseClient'
-
-interface Props {
- size: number
- url: string | null
- onUpload: (event: Event, filePath: string) => void
-}
-
-const Avatar: Component = (props) => {
- const [avatarUrl, setAvatarUrl] = createSignal(null)
- const [uploading, setUploading] = createSignal(false)
-
- createEffect(() => {
- if (props.url) downloadImage(props.url)
- })
-
- 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)
- setAvatarUrl(url)
- } catch (error) {
- if (error instanceof Error) {
- console.log('Error downloading image: ', error.message)
- }
- }
- }
-
- const uploadAvatar: JSX.EventHandler = async (event) => {
- try {
- setUploading(true)
-
- const target = event.currentTarget
- if (!target?.files || target.files.length === 0) {
- throw new Error('You must select an image to upload.')
- }
-
- const file = target.files[0]
- const fileExt = file.name.split('.').pop()
- const fileName = `${Math.random()}.${fileExt}`
- const filePath = `${fileName}`
-
- const { error: uploadError } = await supabase.storage.from('avatars').upload(filePath, file)
-
- if (uploadError) {
- throw uploadError
- }
-
- props.onUpload(event, filePath)
- } catch (error) {
- if (error instanceof Error) {
- alert(error.message)
- }
- } finally {
- setUploading(false)
- }
- }
-
- return (
-
- {avatarUrl() ? (
-
- ) : (
-
- )}
-
-
-
-
-
-
-
- )
-}
-
-export default Avatar
-```
+<$CodeSample
+ path="/user-management/solid-user-management/src/Avatar.tsx"
+ lines={[[1, -1]]}
+ meta="name=src/Avatar.tsx"
+/>
$CodeTabs>
### Add the new widget
-And then we can add the widget to the Account page:
+And then add the widget to the Account page:
<$CodeTabs>
-```jsx name=src/Account.tsx
-// Import the new component
-import Avatar from './Avatar'
-
-// ...
-
-return (
-