Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Supabase Storage file saving support #51

Open
kav opened this issue Feb 2, 2024 · 1 comment · May be fixed by #52
Open

Supabase Storage file saving support #51

kav opened this issue Feb 2, 2024 · 1 comment · May be fixed by #52
Labels
enhancement New feature or request

Comments

@kav
Copy link
Contributor

kav commented Feb 2, 2024

I know this is already on the list. Adding an issue to discuss what to expose exactly. Something like the following could be pushed into the provider.

We'll likely want to offer a function to get a bucket name from a record/field/file.
Further the below uses public urls which is probably not ideal but alternatives might require a SignedImageField.
We also might want to offer the opportunity to remove previous files as new ones are uploaded.

Any thoughts on all this before I carry anything further?

export const dataProvider = withLifecycleCallbacks(
  supabaseDataProvider({
    instanceUrl: REACT_APP_SUPABASE_URL,
    apiKey: REACT_APP_SUPABASE_KEY,
    supabaseClient,
  }),
  [
    {
      resource: "*", // Note * support is unreleased so we'll want to wait on that
      beforeSave: async (data: any, dataProvider: any) => {
        const newFiles = (
          await Promise.all(
            Object.keys(data)
              .filter((key) => data[key]?.rawFile instanceof File)
              .map((key) => [key, data[key]])
              .map(async ([key, file]: any) => {
                const { data, error } = await supabaseClient.storage
                  .from("<bucket name>")
                  .upload(file.rawFile.name, file.rawFile)
                if (error) throw error
                const path = `${REACT_APP_SUPABASE_URL}/storage/v1/object/public/<bucket name>/${data?.path}`
                return { [key]: path }
              })
          )
        ).reduce((acc, val) => ({ ...acc, ...val }), {})
        return { ...data, ...newFiles }
      },
    },
  ]
)
@slax57
Copy link
Contributor

slax57 commented Feb 19, 2024

Hi,

Thank you so much for this suggestion, and for offering to work on this feature! 🙏

Further the below uses public urls which is probably not ideal but alternatives might require a SignedImageField.

True. Creating a SignedImageField component would certainly be a valid option. I guess it would take a supabaseClient prop?
Alternatively, we could also call supabase.storage.from('bucket').createSignedUrl('private-document.pdf', 3600) and directly return a time-limited URL.

In any case, for a first version of the implementation, it's OK to support only public URL for now IMO.

We also might want to offer the opportunity to remove previous files as new ones are uploaded.

It would be very nice indeed, but it would go even further than what we documented in the OSS docs and, again, for a first version, this is not a requirement IMHO.

Note * support is unreleased so we'll want to wait on that

* support is scheduled for RA v5 if I'm not mistaken, so it will probably take some more weeks to be available. In the docs we can simply give examples with resource: "posts" and people will probably figure out how to generalize that when the * feature is available.

Now a question of my own: what API do you have in mind for that feature? Something like this?

import { supabaseDataProvider, storeInSupabase } from 'ra-supabase';
import { supabaseClient } from './supabase';

export const dataProvider = withLifecycleCallbacks(
  supabaseDataProvider({
    instanceUrl: REACT_APP_SUPABASE_URL,
    apiKey: REACT_APP_SUPABASE_KEY,
    supabaseClient,
  }),
  [
    {
      resource: "posts",
      beforeSave: async (data: any, dataProvider: any) => {
        const newFiles = await storeInSupabase({
          supabaseClient,
          bucket: 'my-bucket',
          data,
        });
        return { ...data, ...newFiles }
      },
    },
  ]
)

(not very found of the name storeInSupabase but can't find a better one right now...)

In any case, a PR implementing file storage with supabase would be most welcome, and the implementation you suggest seems like a very promising start!

@slax57 slax57 added the enhancement New feature or request label Feb 19, 2024
@kav kav linked a pull request Feb 20, 2024 that will close this issue
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants