Giter Club home page Giter Club logo

aor-loopback's Introduction

Loopback-style REST Client for Admin-on-rest

Loopback-style REST Client for admin-on-rest, the frontend framework for building admin applications on top of REST services.

Not maintained anymore

With new react-admin, please use loopback-component-react-admin instead.

Because of recent changes of admin-on-rest, this module will only support version 0.9.0 (or later) of admin-on-rest.

Prerequisite

  • Your loopback server must response X-Total-Count header when querying list. Please use loopback3-xTotalCount on your server end.

How to use

  1. yarn add aor-loopback
  2. On your App.js, add this:
import loopbackRestClient from 'aor-loopback';

...

    <Admin restClient={loopbackRestClient('http://my.api.url/api')} ...>
  1. If you want this module handle authentication, add this:
import loopbackRestClient, {authClient} from 'aor-loopback';

...

    <Admin restClient={loopbackRestClient('http://my.api.url/api')} authClient={authClient('http://my.api.url/api/users/login')} ...>

Example

Please check example here: loopback-aor-boilerplate, you should clone it and change your model later.

License

This module is licensed under the MIT Licence.

aor-loopback's People

Contributors

afilp avatar driesvancraen avatar kimkha avatar pdesgarets 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

Watchers

 avatar  avatar  avatar  avatar  avatar

aor-loopback's Issues

AOR 2.0.0-beta1

Hi, do we need any changes for the new (BETA) version of AOR that has just been released?

Or the package can remain the same?

Thanks!

How to create a page for create new user

Hi @kimkha ,
I try to create a page for create user for admin. I set create attribute of related Resource and create a for with below content:

export const UserCreate = (props) => (
    <Create {...props}>
        <SimpleForm>
            <TextInput source="username" validate={ required }/>
            <TextInput source="email" type="email" validate={ required }/>
            <TextInput source="password" type="password" validate={ required }/>
        </SimpleForm>
    </Create>
);

But when I fill this form and click submit button my user is going to logout. What is the problem?

Auth_get_permissions with React-admin

I use ra-loopback. And I want to add a role during authorization. I tried to add a role like this:

./authClient.js
import storage from './storage';
import {decode} from 'jsonwebtoken';

export const authClient = (loginApiUrl, noAccessPage = '/login') => {

    return (type, params) => {
        if (type === 'AUTH_LOGIN') {
            const request = new Request(loginApiUrl, {
                method: 'POST',
                body: JSON.stringify(params),
                headers: new Headers({ 'Content-Type': 'application/json' }),
            });
            return fetch(request)
                .then(response => {
                    if (response.status < 200 || response.status >= 300) {
                        throw new Error(response.statusText);
                    }
                    return response.json();
                })
                .then(({token}) => {
                    const decoded = decode(token);
                    storage.save('lbtoken',token);
                    storage.save('role', decoded.role);
                });
        }
        if (type === 'AUTH_LOGOUT') {
            storage.remove('lbtoken');
            return Promise.resolve();
        }
        if (type === 'AUTH_ERROR') {
            const status  = params.message.status;
            if (status === 401 || status === 403) {
                storage.remove('lbtoken');
                return Promise.reject();
            }
            return Promise.resolve();
        }
        if (type === 'AUTH_CHECK') {
            const token = storage.load('lbtoken');
            if (token && token.id) {
                return Promise.resolve();
            } else {
                storage.remove('lbtoken');
                return Promise.reject({ redirectTo: noAccessPage });
            }
        }
        if (type === 'AUTH_GET_PERMISSIONS') {
            const role = localStorage.getItem('role');
            return role ? Promise.resolve(role) : Promise.reject();
        }
        return Promise.reject('Unknown method');
    };
};

When i tried to login, i get an error 'Cannot read property 'role' of null'

ReferenceField not working

This is my code

<ReferenceField label={'Album'} source="albumId" reference="albums" allowEmpty linkType={false}>
        <TextField source="name" />
</ReferenceField>

This is the error

11:36:46.115 Navigated to http://localhost:3000/
11:36:48.902 proxyConsole.js:54 uncaught at handleFetch TypeError: Cannot read property 'data' of undefined
    at Function.mapStateToProps [as mapToProps] (http://localhost:3000/static/js/bundle.js:6873:64)
    at mapToPropsProxy (http://localhost:3000/static/js/bundle.js:128653:46)
    at Function.detectFactoryAndVerify (http://localhost:3000/static/js/bundle.js:128662:19)
    at mapToPropsProxy (http://localhost:3000/static/js/bundle.js:128653:46)
    at handleFirstCall (http://localhost:3000/static/js/bundle.js:128487:18)
    at pureFinalPropsSelector (http://localhost:3000/static/js/bundle.js:128535:81)
    at Object.runComponentSelector [as run] (http://localhost:3000/static/js/bundle.js:127933:25)
    at Connect.initSelector (http://localhost:3000/static/js/bundle.js:128085:23)
    at new Connect (http://localhost:3000/static/js/bundle.js:128026:15)
    at http://localhost:3000/static/js/bundle.js:108118:18
    at measureLifeCyclePerf (http://localhost:3000/static/js/bundle.js:107899:12)
    at ReactCompositeComponentWrapper._constructComponentWithoutOwner (http://localhost:3000/static/js/bundle.js:108117:16)
    at ReactCompositeComponentWrapper._constructComponent (http://localhost:3000/static/js/bundle.js:108108:19)
    at ReactCompositeComponentWrapper.mountComponent (http://localhost:3000/static/js/bundle.js:108011:21)
    at Object.mountComponent (http://localhost:3000/static/js/bundle.js:114771:35)
    at ReactDOMComponent.mountChildren (http://localhost:3000/static/js/bundle.js:114109:44)
    at ReactDOMComponent._createInitialChildren (http://localhost:3000/static/js/bundle.js:109556:32)
    at ReactDOMComponent.mountComponent (http://localhost:3000/static/js/bundle.js:109375:12)
    at Object.mountComponent (http://localhost:3000/static/js/bundle.js:114771:35)
    at ReactCompositeComponentWrapper.performInitialMount (http://localhost:3000/static/js/bundle.js:108194:34)
    at ReactCompositeComponentWrapper.mountComponent (http://localhost:3000/static/js/bundle.js:108081:21)
    at Object.mountComponent (http://localhost:3000/static/js/bundle.js:114771:35)
    at ReactCompositeComponentWrapper.performInitialMount (http://localhost:3000/static/js/bundle.js:108194:34)
    at ReactCompositeComponentWrapper.mountComponent (http://localhost:3000/static/js/bundle.js:108081:21)
    at Object.mountComponent (http://localhost:3000/static/js/bundle.js:114771:35)
    at ReactDOMComponent.mountChildren (http://localhost:3000/static/js/bundle.js:114109:44)
    at ReactDOMComponent._createInitialChildren (http://localhost:3000/static/js/bundle.js:109556:32)
    at ReactDOMComponent.mountComponent (http://localhost:3000/static/js/bundle.js:109375:12)
    at Object.mountComponent (http://localhost:3000/static/js/bundle.js:114771:35)
    at ReactCompositeComponentWrapper.performInitialMount (http://localhost:3000/static/js/bundle.js:108194:34)
    at ReactCompositeComponentWrapper.mountComponent (http://localhost:3000/static/js/bundle.js:108081:21)
    at Object.mountComponent (http://localhost:3000/static/js/bundle.js:114771:35)
    at Object.updateChildren (http://localhost:3000/static/js/bundle.js:107692:51)
    at ReactDOMComponent._reconcilerUpdateChildren (http://localhost:3000/static/js/bundle.js:114079:32)
    at ReactDOMComponent._updateChildren (http://localhost:3000/static/js/bundle.js:114183:31)
    at ReactDOMComponent.updateChildren (http://localhost:3000/static/js/bundle.js:114170:12)
    at ReactDOMComponent._updateDOMChildren (http://localhost:3000/static/js/bundle.js:109799:12)
    at ReactDOMComponent.updateComponent (http://localhost:3000/static/js/bundle.js:109613:10)
    at ReactDOMComponent.receiveComponent (http://localhost:3000/static/js/bundle.js:109575:10)
    at Object.receiveComponent (http://localhost:3000/static/js/bundle.js:114850:22)
    at ReactCompositeComponentWrapper._updateRenderedComponent (http://localhost:3000/static/js/bundle.js:108577:23)
    at ReactCompositeComponentWrapper._performComponentUpdate (http://localhost:3000/static/js/bundle.js:108547:10)
    at ReactCompositeComponentWrapper.updateComponent (http://localhost:3000/static/js/bundle.js:108468:12)
    at ReactCompositeComponentWrapper.receiveComponent (http://localhost:3000/static/js/bundle.js:108370:10)
    at Object.receiveComponent (http://localhost:3000/static/js/bundle.js:114850:22)
    at ReactCompositeComponentWrapper._updateRenderedComponent (http://localhost:3000/static/js/bundle.js:108577:23)
    at ReactCompositeComponentWrapper._performComponentUpdate (http://localhost:3000/static/js/bundle.js:108547:10)
    at ReactCompositeComponentWrapper.updateComponent (http://localhost:3000/static/js/bundle.js:108468:12)
    at ReactCompositeComponentWrapper.receiveComponent (http://localhost:3000/static/js/bundle.js:108370:10)
    at Object.receiveComponent (http://localhost:3000/static/js/bundle.js:114850:22)
__stack_frame_overlay_proxy_console__ @ proxyConsole.js:54
log @ utils.js:225
(anonymous) @ proc.js:483
exec @ scheduler.js:19
flush @ scheduler.js:60
asap @ scheduler.js:33
runPutEffect @ proc.js:476
runEffect @ proc.js:425
next @ proc.js:306
currCb @ proc.js:378

The X-Total-Count header is missing in the HTTP Response.

Hi @kimkha I try using your RestClient but it's return below error:

The X-Total-Count header is missing in the HTTP Response. The jsonServer REST client expects responses for lists of resources to contain this header with the total number of results to build the pagination. If you are using CORS, did you declare X-Total-Count in the Access-Control-Expose-Headers header?

Do you have any idea?

Problem to use a partial data info in where filter

I suggest the code block below to add 'like' statement:

if (query['where'] ) { var json = query['where']; query['where'] = {}; Object.keys(json).forEach(function(key) { query['where'][key] = { "like" : json[key], "options":"i" } ; }); }

in src/index.js after

query['where'] = {...params.filter}; //line 41

So this doesn't work with react-admin?

I understand it says the plugin will only work with older versions of Admin on Rest.

Is there any chance this can be updated to work with the new react-admin?

GET_LIST response is not being handled in index.js

Hello.
First of all thanks a lot of writing this code. Saved me a lot of time.

However I see that the getList case is not being handled by the code in index.js

cannot really move forward as my first page is a list view of posts.

Any suggestions?

How to use authorization?

I need to set some authorization rule for my admin Resource for example hide some Resource from side menu and prevent access to it.
I read https://marmelab.com/admin-on-rest/Authorization.html and see this package https://github.com/marmelab/aor-permissions and also try this:

const App = () => (
    <Admin
       theme={ myTheme }
       restClient={loopbackRestClient('http://0.0.0.0:3001/api')}
       authClient={authClient('http://0.0.0.0:3001/api/Employees/login')}
    >
        { permissions => [
            permissions === 'admin' ? <Resource name="employees" icon={ EmployeeIcon } list={EmployeeList} show={EmployeeShow} create={EmployeeCreate} edit={EmployeeEdit} remove={Delete} /> : null,
            <Resource name="projects" icon={ ProjectIcon } list={ProjectList} show={ProjectShow} create={ProjectCreate} edit={ProjectEdit} remove={Delete} />
        ]}

    </Admin>
);

export default App;

I used below code in my LoopBack boot script to create my roles:

Role.create({
      name: 'admin',
    }, function(err, role) {
      if (err) throw err;
...

But it's render below page after login with any user:
screenshot from 2018-02-21 10-29-23

and this is my console error logs:

Warning: Accessing PropTypes via the main React package is deprecated. Use the prop-types package from npm instead.
bundle.js:11865:10
Warning: Missing translation for key: "aor.page.not_found"
browser.js:49
Warning: Missing translation for key: "aor.message.not_found"
browser.js:49
Warning: Missing translation for key: "aor.action.back"
browser.js:49
uncaught exception: Unkown method

Use PATCH instead of PUT for update

E.g. if I want to update the default loopback user model I have to specify all the attributes when using PUT, which is not even possible as I can not have my user re-enter the password every time.

I created a fork under Zoom7/aor-loopback for the time being that does simply replace PUT with PATCH, so I can proceed. Maybe this is also an option for aor-loopback.

the objective of this line

return (new Date().getTime() < record.timestamp && record.value);

Hello, first of all, thank you very much for your work, it has been excellent and it works well with admin on rest, but I do not understand the objective of this line, because I do not simply return the token? Thank you

Uploading Images With aor-loopback

Hello

Am using aor-loopback to connect with my API.

ON trying to create image upload capability I used the following aor guide to create a wrapper on aor-loopback

https://marmelab.com/admin-on-rest/RestClients.html#decorating-your-rest-client-example-of-file-upload

Here is my wrapper code.

const fileUploadRESTWrapper = requestHandler => (type, resource, params) => {
    if (type === 'UPDATE' && resource === 'tales') {
      if (params.data.faceBookImage && params.data.faceBookImage.length) {
        let form = new FormData()
        form.append('file', params.data.faceBookImage[0]);
        delete params.data.faceBookImage
        form.append('model', JSON.stringify(params.data))
        return requestHandler(type, resource, {
            ...params,
            data: form
          },
        )
      }
    }
    return requestHandler(type, resource, params);
};

export default fileUploadRESTWrapper;


I encountered some issues. After looking through the aor-loopback source code I found that

            case _types.UPDATE:
                url = apiUrl + '/' + resource + '/' + params.id;
                options.method = 'PUT';
                options.body = JSON.stringify(params.data);
                break;

aor-loopback is JSON.stringifying the entire response body. Stringifying is removing the image from the FormData object.

Suggestions: It would be great if you could also export the fetchJson method from the package. Someone like me could then create a case in the wrapper above.

                url = apiUrl + '/' + resource + '/' + params.id;
                options.method = 'PUT';
                options.body = params.data
                fetchJson(url, options)

This should solve a number of other use cases including create etc.

Above is just a suggestion and you may choose any other idea to account for the image upload use case as well.

Thanks and regards

ReferenceArrayInput doesn't seem to work

Hi kimkha,

first of all thanks a lot for writing this client. This is really helpful and speeds up the development process.

I'm having trouble getting the ReferenceArrayInput to work. I implemented it as described here

Displaying the same property in a ReferenceArrayField works as expected. Also, the ReferenceArrayInput correctly displays the possible Choices (Tags, in my case). However when i click on one of them, nothing happens (they don't get added to the list of Tags). When i add them manually through the Loopback Explorer, they get displayed correctly and i can also remove them.

I don't see any console output or network traffic. One thing that is different from the examples is that my IDs are not numbers but strings. Could that be the issue? Let me know if there's anything i can do to help debug/fix the problem.

Regards

create user form not working

Hi @kimkha, I create a simple create form for my users and it's worked well but when I try to add a repeatPassword field it's not working with this error on browser console:

Unprocessable Entity
Warning: Missing translation for key: "Unprocessable Entity"

This is my form code:

const passwordsMatch = ({ password, confirmPassword }) => {
       return password === confirmPassword;
};

export const EmployeeCreate = (props) => (
    <Create {...props}>
        <SimpleForm validate={passwordsMatch}>
            <TextInput source="username" validate={ required }/>
            <TextInput source="email" type="email" validate={ required }/>
            <TextInput source="name" validate={ required }/>
            <TextInput source="family" validate={ required }/>
            <TextInput source="password" type="password" validate={ required }/>
            <TextInput source="repeatPassword" type="password" validate={ required }/>
        </SimpleForm>
    </Create>
);

Are you any suggestion to fix it?
SO question: https://stackoverflow.com/questions/48898743/prevent-field-to-send-in-request

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.