Coder Social home page Coder Social logo

marmelab / ra-supabase Goto Github PK

View Code? Open in Web Editor NEW
134.0 9.0 23.0 2.85 MB

Supabase adapter for react-admin, the frontend framework for building admin applications on top of REST/GraphQL services.

License: MIT License

TypeScript 96.02% JavaScript 0.55% Makefile 1.06% HTML 2.37%
reactjs supabase rest api react-admin

ra-supabase's Introduction

ra-supabase

This package provides a dataProvider, an authProvider, hooks and components to integrate Supabase with react-admin when using its default UI (ra-ui-materialui).

DocumentationSource Code

Projects

Roadmap

  • Add support for magic link authentication
  • Add support for uploading files to Supabase storage

Local Development

This project uses a local instance of Supabase. To set up your environment, run the following command:

make install supabase-start db-setup

This will:

  • install dependencies
  • initialize an .env file with environment variables to target the supabase instance
  • start the supabase instance
  • apply the database migration
  • seed the database with data

You can then start the application in development mode with:

make run

Testing Invitations And Password Reset

The current version of supabase CLI does not allow to customize the emails sent for invitation or password reset.

When you invite a new user through the Authentication dashboard, you can see the email sent in Inbucket. Instead of clicking the link, copy it and change the redirect_to parameter from http://localhost:8000 to http://localhost:8000/auth-callback.

Apply the same process for password reset emails.

Testing Third Party Authentication Providers

To test OAuth providers, you must configure the Supabase local instance. This is done by editing the ./supabase/config.toml file as described in the Supabase CLi documentation.

For instance, to add support for Github authentication, you have to:

  1. Create a GitHub Oauth App

Go to the GitHub Developer Settings page:

  • Click on your profile picture at the top right
  • Click Settings near the bottom of the menu
  • In the left sidebar, click Developer settings (near the bottom)
  • In the left sidebar, click OAuth Apps
  • Click Register a new application. If you've created an app before, click New OAuth App here.
  • In Application name, type the name of your app.
  • In Homepage URL, type the full URL to your app's website: http://localhost:8000
  • In Authorization callback URL, type the callback URL of your app: http://localhost:54321/auth/v1/callback
  • Click Save Changes at the bottom right.
  • Click Register Application
  • Copy and save your Client ID.
  • Click Generate a new client secret.
  • Copy and save your Client secret
  1. Update the ./supabase/config file
[auth.external.github]
enabled = true
client_id = "YOUR_GITHUB_CLIENT_ID"
secret = "YOUR_GITHUB_CLIENT_SECRET"
  1. Restart the supabase instance
make supabase-stop supabase-start db-setup
  1. Update the demo login page configuration:

Open the ./packages/demo/src/App.tsx file and update it.

<Admin
    dataProvider={dataProvider}
    authProvider={authProvider}
    i18nProvider={i18nProvider}
    layout={Layout}
    dashboard={Dashboard}
-    loginPage={LoginPage}
+    loginPage={<LoginPage providers={['github']} />}
    queryClient={queryClient}
    theme={{
        ...defaultTheme,
        palette: {
            background: {
                default: '#fafafb',
            },
        },
    }}
>

Internationalization Support

We provide two language packages:

And there are also community supported language packages:

ra-supabase already re-export ra-supabase-language-english but you must set up the i18nProvider yourself:

// in i18nProvider.js
import { mergeTranslations } from 'ra-core';
import polyglotI18nProvider from 'ra-i18n-polyglot';
import englishMessages from 'ra-language-english';
import frenchMessages from 'ra-language-french';
import { raSupabaseEnglishMessages } from 'ra-supabase-language-english';
import { raSupabaseFrenchMessages } from 'ra-supabase-language-french';

const allEnglishMessages = mergeTranslations(
    englishMessages,
    raSupabaseEnglishMessages
);
const allFrenchMessages = mergeTranslations(
    frenchMessages,
    raSupabaseFrenchMessages
);

export const i18nProvider = polyglotI18nProvider(
    locale => (locale === 'fr' ? allFrenchMessages : allEnglishMessages),
    'en'
);

// in App.js
import { Admin, Resource, ListGuesser } from 'react-admin';
import { authRoutes } from 'ra-supabase';
import { dataProvider } from './dataProvider';
import { authProvider } from './authProvider';
import { i18nProvider } from './i18nProvider';

export const MyAdmin = () => (
    <Admin
        dataProvider={dataProvider}
        authProvider={authProvider}
        i18nProvider={i18nProvider}
        customRoutes={authRoutes}
    >
        <Resource name="posts" list={ListGuesser} />
        <Resource name="authors" list={ListGuesser} />
    </Admin>
);

ra-supabase's People

Contributors

adguernier avatar djhi avatar fzaninotto avatar joel-gfdez avatar karolzlot avatar kav avatar lucasmblanco avatar mahdiarn avatar milutinovici avatar n0rmanc avatar slax57 avatar vicam001 avatar yecandir avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

ra-supabase's Issues

Running examples broken with `Array(1200)` for `generateContactNotes`

I had to reduce to Array(500) or

    console.log('Updating contacts status...');
    await Promise.all(
        persistedContactNotes
            .sort(
                (a, b) =>
                    new Date(a.date).valueOf() - new Date(b.date).valueOf()
            )
            .map(note => {
                return supabase.from('contacts').update({
                    ...persistedContacts.find(
                        contact => contact.id === note.contact_id
                    ),
                    status: note.status,
                });
            })
    );

Causes errors that breaks the subsequent calls to supabase. Initially it appeared (from the supabase help) that it should be update().eq(...) rather than simply update(), but even with other fixes I wasn't able to get Array(1200) to work. Interestingly, it appears that it isn't stable working at Array(500) either, though it appears to mostly work.

Maybe it's something invalid that gets generated and over about 500 the chance of the invalid entry getting generated goes above a threshold?

How is full text search supposed to work?

Awesome tool that just works out of the box like everything else react-admin! I'm trying to play with some more functionality but I don't understand how fullTextSearchFields is intended to operate when there are multiple fields. On the client side the search fields are added on as 'ilike()' parameters, but the standard behavior is to find any items where ALL the parameters are 'matched'.

For example, a "player" resource where I'd like to have two fields available for full text search:

{
  fields: [ "name", "where_now", ... ],
  fullTextSearchFields: ["name", "where_now"],
}

in my list component i have the following filter:

[
  <SearchInput source="q" alwaysOn />,
];

when searching for something, like the name "mason", this is the resulting query:
image

it is looking for anything where name is like 'mason' and also where_now is like 'mason'. Instead, shouldn't it be looking for an OR condition between them? I can imagine trying to build an OR( ) query like

query.or('name.ilike.("mason"),where_now.ilike.("mason")')
//idk if this is valid

Do I need to do some work on the Supabase side to deal with this condition? FWIW, the fullTextSearchFields option works as expected when there is only one field since the single ilike condition is met.

RA versions:

    "@supabase/supabase-js": "^1.31.0",
    "ra-supabase": "^1.2.1",
    "react-admin": "3.19.10",

Error: No API key found in request

Hi,
I can't connect to supabase because the api key isn't passed in the request headers.

// supabase.js
import { createClient } from '@supabase/supabase-js';

export const supabase = createClient(import.meta.env.VITE_SUPABASE_BASE_URL, import.meta.env.VITE_SUPABASE_ANON_KEY);


// dataProvider.js
import { supabaseDataProvider } from 'ra-supabase-core';
import { supabase } from './supabase';

const data = {
    instanceUrl: import.meta.env.VITE_SUPABASE_BASE_URL,
    apiKey: import.meta.env.VITE_SUPABASE_ANON_KEY,
    supabaseClient: supabase
}

export const dataProvider = supabaseDataProvider(data);

// App.jsx

import * as React from "react";
import { Admin, Resource, ListGuesser } from 'react-admin';
import { dataProvider } from "./provider/dataProvider";

const App = () => (
    <Admin dataProvider={dataProvider}>
        <Resource name="countries" list={ListGuesser} />
    </Admin>
);

export default App;

I've logged the anon key and is correctly passed.
I've checked the network request, using plain supabase-js the apikey is passed, but with the dataprovider the apikey isn't in the request.

Thanks

Using useGetList with a neq suffix causes an error

Taking the example from your demo in DealsPipeline.tsx

const { data, ids: unorderedIds, total, loaded } = useGetList<Deal>(
        'deals',
        { page: 1, perPage: 10 },
        { field: 'last_seen', order: 'DESC' },
        { stage_neq: 'lost', sales_id: identity?.id },
        { enabled: Number.isInteger(identity?.id) }
    );

When the request is made I get a 400 response with the error message: "column deals.stage_neq does not exist"

Have I misunderstood this or is this an issue?

Signup flow not working as intended

After following the example provided by the docs, after clicking the link in my email, i'm not able to set my password.

I have also tried setting the Site URL setting in supabase to http://localhost:3000/set-password, but that didn't work either. Going to the endpoint manually results in an instant redirect to the dashboard.

Supabase Storage file saving support

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 }
      },
    },
  ]
)

Can't have two filters on the same field (e.g. gte and lte)

Problem

Setting two filters with operators (like gte and lte) targeting the same field (e.g. last_seen@gte and last_seen@lte) will throw an error like:

time zone "lte.2023-12-31t16:00:00.000z" not recognized

This is due to using an old version of the underlying library ra-data-postgrest (version 2.0.0-alpha.0), which has this bug.

Solution

The issue has since been resolved in ra-data-postgrest , so we need to update to version 2.0.0.

using supabase-js client directly

would you consider using the Supabase client directly instead of @raphiniert/ra-data-postgrest or do you see any disadvantages to that?

Auth with social providers

How would one set up authentication using one of the social providers available in Supabase instead of username/password authentication?

AutocompleteInput inside of ReferenceInput

I'm currently having issues trying to get the autocomplete to search properly. I've got a currency table and a country table. The country table has a field called "currency_id".

This is what i currently have:

      <ReferenceInput source="currency_id" reference="currency">
        <AutocompleteInput name="currency_id" optionText={"code"} />
      </ReferenceInput>

The issue is the request being sent to supabase is the following:
http://localhost:54321/rest/v1/currency?order=id.desc&offset=0&limit=25&q=eq.ddf

This is a causing a 400 error from supabase stating that following:
{"code":"42703","details":null,"hint":null,"message":"column currency.q does not exist"}

I'm probably being dumb but am i forgetting to do something?
Let me know if you need more information

Release

Is there a release already? I can't install it with npm

Upload Images

I am looking to any documentation explaining how to use ImageUpload with supabase, but I can´t found.. Do you can help me?

Error: TypeError: primaryKeys is undefined

Hi everyone,

I am facing an issue using React Admin with ra-supabase. The following message appears in the logs and I can't find why:

TypeError: primaryKeys is undefined

Here are my codes:

supabase.js

import { createClient } from '@supabase/supabase-js';

export const supabaseClient = createClient(
  process.env.REACT_APP_SUPABASE_URL,
  process.env.REACT_APP_SUPABASE_ANON_KEY
)

baseDataProvider.js

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

const baseDataProvider = supabaseDataProvider({
    instanceUrl: process.env.REACT_APP_SUPABASE_URL,
    apiKey: process.env.REACT_APP_SUPABASE_ANON_KEY,
    supabaseClient
});

export default baseDataProvider;

dataProvider.js

import baseDataProvider from './baseDataProvider';
import {supabaseClient} from './supabase';

const dataProvider = {
  ...baseDataProvider,
  getList: async (resource, params) => {
    let result = null
    result = await baseDataProvider.getList(resource, params)
    return result
  },
}

App.js

import { Admin, CustomRoutes, ListGuesser } from 'react-admin';
import { LoginPage, SetPasswordPage, ForgotPasswordPage } from 'ra-supabase';
import { BrowserRouter, Route } from 'react-router-dom'
import { Resource } from '@react-admin/ra-rbac';

import dataProvider from './Database/dataProvider';

export const App = () => {
  const classes = CustomStyles();

  return (
    <BrowserRouter>
      <Admin
        dataProvider={dataProvider}
      >
        <CustomRoutes noLayout>
            <Route
                path={SetPasswordPage.path}
                element={<SetPasswordPage />}
            />
            <Route
                path={ForgotPasswordPage.path}
                element={<ForgotPasswordPage />}
            />
        </CustomRoutes>
        
        <Resource name="test" list={ListGuesser} />
      </Admin>
    </BrowserRouter>
  )
}

Finally, in supabase:

create table
  public.test (
    id bigint generated by default as identity,
    created_at timestamp with time zone not null default now(),
    first_name text null,
    last_name text null,
    constraint test_pkey primary key (id)
  ) tablespace pg_default;

Thank you in advance for your answers !

Best, R.

Can't choose other db schema than public in supabaseDataProvider

I can't change a schema different from the public one passing a parameterized supbaseClient to supabaseDataProvider.

const options: SupabaseClientOptions<"stats"> = {
    db: { schema: 'stats' }
}
export const supbaseClient =
    createClient<StatsDatabase>(process.env.NEXT_PUBLIC_SUPABASE_URL!,
        process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
        options);

Would you mind considering to use generic parameters in supabaseDataProvider?

Add support for React-admin 4.x

When installing this plugin with react-admin 4.0.1 the following errors occur in the console:

`ERROR in ../../node_modules/ra-supabase-ui-materialui/esm/AuthLayout.js 26:0-49
Module not found: Error: Can't resolve '@material-ui/core' in '/Users/cedricjacobs/Dev/camp-cooking/whats-cooking/node_modules/ra-supabase-ui-materialui/esm'

ERROR in ../../node_modules/ra-supabase-ui-materialui/esm/AuthLayout.js 27:0-67
Module not found: Error: Can't resolve '@material-ui/core/styles' in '/Users/cedricjacobs/Dev/camp-cooking/whats-cooking/node_modules/ra-supabase-ui-materialui/esm'

ERROR in ../../node_modules/ra-supabase-ui-materialui/esm/AuthLayout.js 28:0-52
Module not found: Error: Can't resolve '@material-ui/styles' in '/Users/cedricjacobs/Dev/camp-cooking/whats-cooking/node_modules/ra-supabase-ui-materialui/esm'

ERROR in ../../node_modules/ra-supabase-ui-materialui/esm/AuthLayout.js 29:0-47
Module not found: Error: Can't resolve '@material-ui/icons/Lock' in '/Users/cedricjacobs/Dev/camp-cooking/whats-cooking/node_modules/ra-supabase-ui-materialui/esm'

ERROR in ../../node_modules/ra-supabase-ui-materialui/esm/Input.js 24:0-46
Module not found: Error: Can't resolve '@material-ui/core' in '/Users/cedricjacobs/Dev/camp-cooking/whats-cooking/node_modules/ra-supabase-ui-materialui/esm'

ERROR in ../../node_modules/ra-supabase-ui-materialui/esm/LoginForm.js 3:0-47
Module not found: Error: Can't resolve 'react-final-form' in '/Users/cedricjacobs/Dev/camp-cooking/whats-cooking/node_modules/ra-supabase-ui-materialui/esm'

ERROR in ../../node_modules/ra-supabase-ui-materialui/esm/LoginForm.js 4:0-74
Module not found: Error: Can't resolve '@material-ui/core' in '/Users/cedricjacobs/Dev/camp-cooking/whats-cooking/node_modules/ra-supabase-ui-materialui/esm'

ERROR in ../../node_modules/ra-supabase-ui-materialui/esm/LoginForm.js 5:0-54
Module not found: Error: Can't resolve '@material-ui/core/styles' in '/Users/cedricjacobs/Dev/camp-cooking/whats-cooking/node_modules/ra-supabase-ui-materialui/esm'

ERROR in ../../node_modules/ra-supabase-ui-materialui/esm/SetPasswordForm.js 39:0-47
Module not found: Error: Can't resolve 'react-final-form' in '/Users/cedricjacobs/Dev/camp-cooking/whats-cooking/node_modules/ra-supabase-ui-materialui/esm'

ERROR in ../../node_modules/ra-supabase-ui-materialui/esm/SetPasswordForm.js 40:0-74
Module not found: Error: Can't resolve '@material-ui/core' in '/Users/cedricjacobs/Dev/camp-cooking/whats-cooking/node_modules/ra-supabase-ui-materialui/esm'

ERROR in ../../node_modules/ra-supabase-ui-materialui/esm/SetPasswordForm.js 41:0-54
Module not found: Error: Can't resolve '@material-ui/core/styles' in '/Users/cedricjacobs/Dev/camp-cooking/whats-cooking/node_modules/ra-supabase-ui-materialui/esm'`

I have used Nx to bootstrap the project with react 18

Can't resolve '@raphiniert/ra-data-postgrest'

Hello Marmelab team,

I installed the latest version of supabase-js to a new, clean RA project, and I have this error:

ERROR in ./node_modules/ra-supabase-core/esm/dataProvider.js 117:0-66
Module not found: Error: Can't resolve '@raphiniert/ra-data-postgrest' in 'C:\Users.......\node_modules\ra-supabase-core\esm'

So I have to add @raphiniert/ra-data-postgrest to my package, which you don't do in your demo. Why ?
Also, I cannot install the latest @raphiniert/ra-data-postgrest version (2.0.0) as it creates error. Only version 1.2.0 works.

Here is a test repo: https://github.com/Revarh/test_bug_supabase-js

Kind regards

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.