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

[RFC] Provide override functions #130

Merged
merged 3 commits into from Nov 20, 2018

Conversation

Projects
None yet
2 participants
@jfthuillier
Copy link
Contributor

jfthuillier commented Nov 8, 2018

Q A
Bug fix? no
New feature? yes
BC breaks? no
Deprecations? no
Tests pass? yes
Fixed tickets none
License MIT
Doc PR Will do after discussing

This PR is about providing some dev-friendly functions to make overriding cleaner.

Here is an example of how these functions could be used :

App.js :

import React from 'react';
import { HydraAdmin} from '@api-platform/admin';
import overrideResources from '@api-platform/admin/lib/override/functions';
import parseHydraDocumentation from '@api-platform/api-doc-parser/lib/hydra/parseHydraDocumentation';
import newResources from './override/example';

const entrypoint = process.env.REACT_APP_API_ENTRYPOINT;

const myApiDocumentationParser = entrypoint => parseHydraDocumentation(entrypoint)
  .then(({ api }) => {
    overrideResources(api.resources, newResources);
    return { api };
  })
;

export default () => <HydraAdmin apiDocumentationParser={myApiDocumentationParser} entrypoint={entrypoint} />;

So, now the developer has to provide the newResources :

import {TextInput, UrlField} from 'react-admin';
import BookList from '../books/list-1';
import BookCreate from '../books/create-2';
import BookEdit from '../books/edit-1';

const greetingsNameInput = props => (
  <TextInput label={'POC'} {...props} />
);

const greetingsNameField = props => (
  <UrlField {...props} />
);

const booksDescriptionInput = props => (
  <TextInput label={'POC'} {...props} />
);

const greetingsOverride = {
  name: 'greetings',
  fields: [
    {
      name: 'name',
      input: greetingsNameInput,
      field: greetingsNameField,
    }
  ],
  listFields: [],
};

const booksOverride = {
  name: 'books',
  list: BookList,
  create: BookCreate,
  edit: BookEdit,
  fields: [
    {
      name: 'description',
      input: booksDescriptionInput,
    }
  ]
};

export default [
  greetingsOverride,
  booksOverride,
];

And here are some examples of what overriding operations could look like :

A Create :

import React, {Component} from 'react';
import {Create, SimpleForm} from 'react-admin';
import {getResourceField} from '@api-platform/admin/src/override/functions';

/* Rearrange fields : order or div containers */

class BookCreate extends Component {
  render() {
    const {options: {inputFactory, resource}} = this.props;

    return (
      <Create {...this.props}>
        <SimpleForm>
          <div className="row">
            <div className="col-md-6">
              {inputFactory(getResourceField(resource, 'name'))}
            </div>
            <div className="col-md-6">
              {inputFactory(getResourceField(resource, 'description'))}
            </div>
          </div>
        </SimpleForm>
      </Create>
    );
  }
}

export default BookCreate;

And an Edit :

import React, {Component} from 'react';
import {Edit, SimpleForm} from 'react-admin';
import {connect} from 'react-redux';
import {formValueSelector} from 'redux-form';
import {getResourceField} from '@api-platform/admin/src/override/functions';

/* Dynamic display */

class BookEdit extends Component {
  render() {
    const {options: {inputFactory, resource}, formValueName} = this.props;

    return (
      <Edit {...this.props}>
        <SimpleForm>

          {inputFactory(getResourceField(resource, 'name'))}

          {formValueName && (
            inputFactory(getResourceField(resource, 'description'))
          )}

        </SimpleForm>
      </Edit>
    );
  }
}

const mapStateToProps = state => ({
  formValueName: formValueSelector('record-form')(state, 'name'),
});

export default connect(mapStateToProps)(BookEdit);

Do you think there is any point of include these functions into API-P or this is something that should be done inside the project using API-P ?

JF
@dunglas

This comment has been minimized.

Copy link
Member

dunglas commented Nov 9, 2018

I like the idea!

Show resolved Hide resolved src/override/functions.js Outdated
export const getResource = (resources, resourceName) =>
resources.find(({name}) => resourceName === name);

export const getResourceField = (resource, resourceFieldName) =>

This comment has been minimized.

@dunglas

dunglas Nov 9, 2018

Member

should be export function right? (same for all functions in this file)

This comment has been minimized.

@jfthuillier

jfthuillier Nov 12, 2018

Author Contributor

Done. But just curious, why using export function instead of export const an arrow function ?

This comment has been minimized.

@dunglas

dunglas Nov 13, 2018

Member

It's mainly a matter of consistency inside this project, but https://stackoverflow.com/a/39582542/1352334

Show resolved Hide resolved src/override/functions.js Outdated
Show resolved Hide resolved src/override/functions.js Outdated
Show resolved Hide resolved src/override/functions.js Outdated
Show resolved Hide resolved src/override/functions.js Outdated
JF
Show resolved Hide resolved src/docUtils/functions.js Outdated
Show resolved Hide resolved src/docUtils/functions.js Outdated
Show resolved Hide resolved src/docUtils/functions.js Outdated
Show resolved Hide resolved src/index.js Outdated
JF

@dunglas dunglas merged commit 74c9721 into api-platform:master Nov 20, 2018

1 check passed

continuous-integration/travis-ci/pr The Travis CI build passed
Details
@dunglas

This comment has been minimized.

Copy link
Member

dunglas commented Nov 20, 2018

Thanks @jfthuillier! Don't forget to update the docs to explain how to use these new helpers, or they will be very difficult to discover.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment