Coder Social home page Coder Social logo

ra-tools's Introduction

React Admin & Prisma (& Next.js)

Check the example apps to see common usages or use them as a boilerplate.

Packages

Examples

example admin app Debug, test, and develop the packages, but also use it as the admin/CMS for the website! example website A nextjs/mui boilerplate to show the data (very much under construction yet)

Development

Use the example app to test the changes.

In root folder run

pnpm dev

this will spin both the apps and package in dev mode!

Common issues

  • If there is an error in the backend regarding prisma not finding a table, run npx prisma generate

TODOs

  • Add all combos in README
  • create an amazing website showing all the data

ra-tools's People

Contributors

ogroppo avatar mshd avatar martin-fv avatar bayramkzk avatar bradchoate avatar fauh45 avatar pmegaocalc avatar morrid0 avatar heba-khazbak avatar nickman87 avatar sicarius97 avatar densyakun avatar

Stargazers

Rihards Mantejs avatar Duong Du Dinh avatar Takeo Yoshida avatar Masaya Kawai avatar Ikuko KAI avatar Olexander Popov avatar Lorenz Haase avatar Asuma Yamada avatar Emil Redzik avatar  avatar Dmitry Karpunin avatar Badrangui A avatar Loïc Mahieu avatar Muhammad Ubaid Raza avatar Andrejs Agejevs avatar ryooo avatar Ilia avatar Magarsa Gudeta avatar  avatar Yuu avatar Roman Tsegelskyi avatar Marco Della Rocca avatar Brian Charles avatar Chema avatar Harry Gallagher avatar Horace Julius Folahan FAYOMI avatar  avatar Kenn Ejima avatar Simon Peters avatar Michał Pierzchlewicz avatar Danny avatar Lucas Guilherme avatar Supratouch Suwatno avatar Alexandre Dos Reis avatar  avatar Narcis avatar  avatar  avatar Andrew Bazhanov avatar Thomas Gak-Deluen avatar Damian avatar Shea Belsky avatar Lagyu avatar Daniil Donchuk avatar  avatar Mohamed Sayed avatar Markus Ecker avatar TerjaN avatar  avatar Moishi Netzer avatar Muly Oved avatar Amgad Naiem avatar  avatar  avatar Shaun Springer avatar kompaakt avatar  avatar  avatar  avatar  avatar Entitree avatar Ludgero avatar  avatar

Watchers

 avatar  avatar Alexandre Dos Reis avatar

ra-tools's Issues

Problem with updateHandler not converting to connect

Hi!

First thank you very much for your work!

I got some issue connecting some elements to another one in an implicit many to many relationship :
I can't understand the comment on lince 70 in updateHandler.js file :
// transform an array to a connect (many-to-many)
Because just after that you put a "set" with the following code :
fields[key] = { set: (value as number[]).map((value) => ({ [foreignSet]: value, })), };
which is making my prisma update call failing. It works perfectly locally replacing "set" by "connect".
Am I missing some point or it is a mistake on your side ? I precise that I am on version 2.3.2 (latest at write time)

Thank you.
Have a nice day!
Brian

Transform may not working

I wanted to use _id field as id, so I wrote this. (I also had to remove "id" from orderBy tbh.)

import { defaultHandler, getListHandler } from 'ra-data-simple-prisma';
import { NextApiRequest, NextApiResponse } from 'next';
import { PrismaClient } from '@prisma/client';
import { retrieveDatabaseUrl } from '../../src/logic/retrieveDatabaseUrl';

const handler = async (req: NextApiRequest, res: NextApiResponse) => {
  if (!process.env['DATABASE_URL']) {
    process.env['DATABASE_URL'] = await retrieveDatabaseUrl();
  }
  const prismaClient = new PrismaClient();
  switch (req.body.method) {
    case 'getList':
      return getListHandler(req, res, prismaClient.user, {
        transform: (data: Array<any>) => {
          return data.map((entry) => ({
            ...entry,
            id: Object.entries(entry).find(([key]) => key === '_id')?.[1],
          }));
        },
      });
    default:
      return defaultHandler(req, res, prismaClient);
  }
};

export default handler;

However, this gives me an error,
The response to 'getList' must be like { data : [{ id: 123, ...}, ...] }, but the received data items do not have an 'id' key. The dataProvider is probably wrong for 'getList'.

Is transform working as intended?
Or should I use something other than transform?

Problem occurs when trying to clone the record.

Hi

Thank you for your work! I just want to report that I added CloneButton component in the List DataGrid and got following error while trying to copy record:

/app/node_modules/ra-data-simple-prisma/dist/index.js:606:27
603 const where = { id };
604 if (options == null ? void 0 : options.debug)
605   console.log("getOneHandler:where", where);
606 const row = await model.findUnique({
         where: {
             id: 'create'
                    ~~~~~~~~
         },
        select: undefined,
         include: undefined
      })

Argument id: Got invalid value 'create' on prisma.findUniquePage. Provided String, expected Int.

TypeError: options is undefined

The following code, written as per the README, throws an error when executed.

<Admin dataProvider={
  dataProvider("/api")
}>

The cause is the following code:

https://github.com/codeledge/ra-data-simple-prisma/blob/14fc97bda9be46997975ad6c3d687c003dc32118/packages/ra-data-simple-prisma/src/dataProvider.ts#L35

Replacing the cause with the following code will no longer throw an error:

{
  headers: options.headers,
}

Or use the following code:

<Admin dataProvider={
  dataProvider("/api", {})
}>

Documentation Update Suggestion (to show how to work with NextJS App Router)

Sorry for posting as an issue, i wasnt sure where else to post this.

I struggled to get this data provider working with the NextJS App Router approach. I now have it working and so i thought i'd share the code in case you want to add it to your readme.

In short, i had to create a folder and file at app/api/[resource]/route.ts

And then in route.ts, i added:

`// /api/[resource]/route.ts <= catch all resource requests
import { defaultHandler } from "ra-data-simple-prisma";
import { NextResponse } from "next/server";
import prisma from "@/utils/db";

// POST request
export async function POST(req: Request) {
let reqCloned = req.clone();
const body = await req.json();
let res = await defaultHandler({ body }, reqCloned, prisma);
return NextResponse.json(res);
}`

defaultHandler doesn't support array fields

MongoDB has support for array fields, but the defaultHandler presumes an array value is only used for updating foreign key relationships. I would just recommend doing something like this for the array case:

if (foreignConnectKey) {
    ...existing code...
} else {
    fields[key] = value;
}

Update extractWhere.ts

Hi,
I started working with ra-data-simple-prisma a time ago, it's very cool solution, thank you a lot!

I found an issue with the filter (where), as I been saw, It's is no posible to search for more than 1 column on each text input,

I find a solution, I would love to shere with you, would be great to know what do you think :)

passing a string with separate ',' for each column and ':' for the related fields

const profileFilters = [
  <TextInput key="1" label="Smart Search" source="firstName,lastName,idNumber,user:email" alwaysOn resettable={true}/>
];
const userFilters = [
  <TextInput key="1" label="Smart Search" source="name,email,companies:some:name" alwaysOn />,
];

in the extractWhere.ts

 if (colName.includes(",") || colName.includes(":")) {
        const colsName = colName.split(",");
        auxWhere = colsName.map((colName, i) => {
          const aux = {}
          setObjectProp(aux, colName.replaceAll(':','.'), {
            contains: value,
            mode: options?.filterMode ? options?.filterMode : "insensitive",
          });
          return {...aux}
        });
        setObjectProp(where, 'OR', auxWhere)
        return;
      }


Id doesn't support String data types

A lot of the methods does this kind of operation to the body params id,

where: { id: +req.body.params.id }

This will result in NaN when the id being sent is type of string. Making it doesn't support string datatypes of id. And a simple change could be done like this,

diff --git a/node_modules/ra-data-simple-prisma/dist/index.js b/node_modules/ra-data-simple-prisma/dist/index.js
index b3dbbe5..0372eec 100644
--- a/node_modules/ra-data-simple-prisma/dist/index.js
+++ b/node_modules/ra-data-simple-prisma/dist/index.js
@@ -285,7 +285,7 @@ var getManyHandler = async (req, res, table) => {
 var getOneHandler = async (req, res, table, options) => {
   var _a, _b, _c;
   const row = await table.findUnique({
-    where: { id: +req.body.params.id },
+    where: { id: /^\d+$/.test(req.body.params.id) ? +req.body.params.id : req.body.params.id },
     select: (_a = options == null ? void 0 : options.select) != null ? _a : void 0,
     include: (_b = options == null ? void 0 : options.include) != null ? _b : void 0
   });
@@ -305,7 +305,7 @@ var updateHandler = async (req, res, table, options) => {
     return fields;
   }, {});
   const updated = await table.update({
-    where: { id: +req.body.params.id },
+    where: { id: /^\d+$/.test(req.body.params.id) ? +req.body.params.id : req.body.params.id },
     data
   });
   return res.json({ data: updated });
@@ -314,12 +314,12 @@ var updateHandler = async (req, res, table, options) => {
 // src/deleteHandler.ts
 var deleteHandler = async (req, res, table, options) => {
   const deleted = (options == null ? void 0 : options.softDeleteField) ? await table.update({
-    where: { id: +req.body.params.id },
+    where: { id: /^\d+$/.test(req.body.params.id) ? +req.body.params.id : req.body.params.id },
     data: {
       [options == null ? void 0 : options.softDeleteField]: new Date()
     }
   }) : await table.delete({
-    where: { id: +req.body.params.id }
+    where: { id: /^\d+$/.test(req.body.params.id) ? +req.body.params.id : req.body.params.id }
   });
   return res.json({ data: deleted });
 };

Edit : Add RegEx test if a string is a number

Prisma error when updating a mongo record.

image

I have this error on update which prevents me from updating the model. Prisma omits the ID on the update.

(the published issue is mine to fix)

I believe the same "filter out non-schema args" treatment that is applied to the create method would do the trick here.

image

Remix Examples

You say that this can work with any node-based backend. However, it seems the whole implementation is based on next.js request handlers. Could you please provide an example for remix? Thanks!

Customizing resource names to table mappings

It took me a while to understand the naming conventions for react-admin with this integration. The example doesn't provide a lot of clarification because it only uses one model that isn't multi-word. Also, it doesn't follow the typical naming convention of the schema which would be MyUser. Why is the name pluralized too?

In order to discover what was going on with how this integration interacts with tables, I wrote a getReference function to which I passed Prisma.ModelName.* and used it in the <Resource> name field and the resource props of the UI components. I think the example should use Prisma.ModelName.* for clarity since you don't list the schema and we don't know how the tables are named.

I wanted the resource names to be kebab-cased in the urls for readability so I did that transform in the getResource function. I also kebabed my admin api route file names. I noticed that my custom admin api routes were attempting to look up the kebab-cased names as tables. Only multi-word-named models that broke because urls aren't case-sensitive.

I expected since I gave both the prisma instantiation of the table and the type of the query args, that this library could determine the table name. However, the getListHandler call throws a 500 error complaining that the table calendar-group does not exist.

app/routes/admin-api.calendar-group.ts

import { Prisma } from "@prisma/client";
import { LoaderFunction } from "@remix-run/node";
import { json } from "@remix-run/server-runtime";
import {
  defaultHandler,
  getListHandler,
  type RaPayload,
} from "ra-data-simple-prisma";

import { redirectIfAdminUnauth } from "~/lib/auth.server";
import { groupWithDetailsIncludes } from "~/lib/prisma-api";
import { prisma } from "~/lib/prisma.server";

export const loader: LoaderFunction = async ({ request }) => {
  const adminRedir = await redirectIfAdminUnauth(request);
  if (adminRedir) {
    return adminRedir;
  }
  const body = (await request.json()) as RaPayload;
  if (body.method === "getList") {
    const groups = await getListHandler<Prisma.CalendarGroupFindManyArgs>(
      body,
      prisma.calendarGroup,
      {
        include: { regions: true, ...groupWithDetailsIncludes },
      },
    );

    return json(groups);
  }
  const result = await defaultHandler(body, prisma);
  return json(result);
};

export const action = loader;

Is there any way I can explicitly tell getListHandler the proper table name or is there any other way to achieve kebab-cased admin ui/api routes?

P.S. for those of you who are curious about using remix-auth instead of the authProvider, you can see my approach above. Please comment if there's a more elegant way to do this.

Handling ID columns that end with "Id"

I'm using Prisma with MongoDB and my property names referencing external collections look like this: childId or parentId.

When I try to apply a filter in React Admin that selects for parentId="mongo-db-id-string", I get an error, because the API handler translates the filter into a where clause like this:

{
    "parentId": {
        "contains": "mongo-db-id-string",
        "mode": "insensitive"
    }
}

This causes an exception in the Prisma client, since it doesn't consider parentId a string property, but an ID property that doesn't support contains. I found the place in the API handler that applies this handling for string properties. Ideally, I would like a way to control whether such a fuzzy match is applied. Sometimes I want to select for a specific exact string match, and wouldn't want either an insensitive search OR a "contains" type of search to be used. But, in this case, simply including a test for the column name ending with Id should suffice and would be easy to apply.

Type for GetListRequest is incorrect

This type expects a top-level filter as well as a filter in the params. React Admin only sends the filter in params like:

{
  method: 'getList',
  resource: 'posts',
  params: {
    pagination: {
      page: 1,
      perPage: 10
    },
    sort: {
      field: 'id',
      order: 'ASC'
    },
    filter: {}
  }
}

The top-level filter property should be removed so type checks work properly.

extractWhere is incorrectly identifying enum types as a string

I have encountered a situation where an enum is incorrectly being as a string and, as such, the query to getList is being populated with a contains field which is causing an error to throw.

Looking a the code it seems as though the plugin is iterating over the keys in the filter which is passed via param and looking to see if the column ends with _enum I am not sure if this is the result of old behaviour or not but, when I inspect the value passed to the filter it is not appending the field type to the column name and, as such, the value is being treated as a string.

I've solved this in my resource handler with a bit of jugaad but it would be good to see this resolved:

    if (
      body.resource === "trend" &&
      body.params?.filter?.peak_month &&
    ) {
      body.params.filter.peak_month = undefined;
      getList.where.peak_month = body.params?.filter?.peak_month as Month;
    }

Add more docs please

I think documentation needs improvement, i found out today that i can map my implicit many2many in handlers, not on client, so i think i can help add docs and share my handler improvements with l use in production like createMany support or create/createOrConnect typings and support

Support for string_contains for pgjson filter

Hi!

Firstly I would like to thank you for the recent _pgjson filter implementation!
Do you plan to go little further with string_contains filter in addition to the "equals" filter already implemented ? (and maybe startWith and endWith but less important).

Have a nice day!
Brian

findMany variant handlers should support options parameter

I'd like to have the option to use the include property for Prisma's findMany call that is used by the getMany and getManyReference API handlers. Both of these handlers should support the same set of options that are supported for the getList API handler.

How to set withCredential in Axios ?

Hi, thank you for this project 👍🏼.

I would like to pass httpOnly cookies on every subsequent requests. With Axios, it seems that it is possible with the axios.create() method, like so:

const instance = axios.create({
   withCredentials: true,
   baseURL: BASE_URL
})

However, in your package it seems unreachable:

https://github.com/codeledge/ra-data-simple-prisma/blob/8d4ae431e5074439571aeecc9e2046270be9a2a2/packages/ra-data-simple-prisma/src/dataProvider.ts#L32-L35

Any solution ?

Not Updating JSON Field

Currently I'm developing apps that require one of the field to be the type of JSON. (Prisma Reference)

The problem is every time the data is updated to the database, the JSON field would not be updated. I've done some digging and found this code at the file updateHandler.ts.

      if (!isObject(value) && !options?.skipFields?.includes(key))
        fields[key] = value;

      return fields;

Link to code

I think the problem is, that this library thinks the JSON field is actually a relation to another model, so it is skipped. I think there should be a way to differentiate it, or at least have a configuration to allow a particular field on a model to be updated.

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.