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

Custom properties for the resource #491

Closed
andrui opened this issue Jun 25, 2020 · 10 comments
Closed

Custom properties for the resource #491

andrui opened this issue Jun 25, 2020 · 10 comments

Comments

@andrui
Copy link

andrui commented Jun 25, 2020

Describe the bug
I have sequelizejs Model "User" with field "externalId".
I have "User" resource where I have "after" hook for "list" action. In this hook additional external resources are loaded by "externalId" and added to the original response records (e.g. "customField1" is added to the each record.params object ).
I want to display "customField1" in the table. By default it is not displayed because "customField1" is not included into list properties. But when I add it into the list properties i receive error "there is no property by the name of 'customField1' in resource Users". Then I have tried to add it into "properties" object of the resource. In this case SQL query is failed because "customField1" is included into "SELECT" properties and I get error "SequelizeDatabaseError: column User.customField1 does not exist"

Installed libraries and their versions

  • admin-bro@2.4.3
  • admin-bro-expressjs@2.1.0
  • admin-bro-sequelizejs@0.5.0
@leibowitz
Copy link
Contributor

leibowitz commented Jul 8, 2020

So far I have only managed to do it by using a custom component.

For example, given two tables (user and address), to add the email property from the user model to the address list view, one would have to create a custom field. For instance, let's call it user__email, and let's customise the component to display it.

I am using sequelize, and this is my resource config:

{
  resource: db.sequelize.models.address,
  options: {
    actions: {
      list: {
        after: async (response, request, context) => {
          return await augmentListResponseWithData(context, response, 'user_id', 'user')
        },
      },
    },
    listProperties: [
      'id',
      'user__email',
    ],
    properties: {
    	user__email: {
    		components: {
    			list: AdminBro.bundle('./components/property.view.jsx')
    		}
    	}
    }
   }
}

The user_id field in address is what links both tables.

The augmentListResponseWithData function fetches the records from the user table, and augment each address record with the associated user data. There is probably a better way of doing this (via sequelize joins), but this is just to illustrate the custom views

const augmentListResponseWithData = async (context, response, foreignKey, resourceId) => {
  // find all ids to fetch from the resource
  const ids = response.records.map(record => record.params[foreignKey]).filter(v => v);
  const resource = context._admin.findResource(resourceId)
  // Retrieve records
  const results = await resource.findMany(ids);
  const data = results.map(result => result.params)
  const fields = resource.properties().map(property => property.name());
  const schema = await db[resourceId].describe();
  const keys = Object.keys(schema)
  // Which field is the primary key, to join both tables
  const primaryKey = keys.find(field => schema[field].primaryKey);
  return {
    ...response,
    records: response.records.map(record => {
      if (!record.params[foreignKey]) {
        return record
      }
      const dataRow = data.find(row => row[primaryKey] === record.params[foreignKey])
      if (!dataRow) {
        return record
      }
      fields.map(field => {
        // add a new field to the results
        record.params[resourceId + '__' + field] = dataRow[field]
      })
      return record;
    })
  }
};

components/property.view.jsx is just a simple example component:

import React from 'react'
import { Box } from 'admin-bro'

const PropertyComponentShow = (props) => {
  const { record, property } = props;
  return (
    <Box>{record.params[property.name]}</Box>
  )
  )
}

export default PropertyComponentShow

This sort of works.

Ideally a better way to show the related fields would be to re-use the PropertyType – which already handles all the various data types. If anyone knows how to achieve the same in a better way, please comment!

@cloudratha
Copy link

You can try this:

const setCustom: After<ActionResponse> = async (
  response,
  request,
  context
) => {
  const records: RecordJSON[] = response.records || [];
  response.records = records.map((record) => ({
    ...record,
    params: {
      ...record.params,
      custom: `${record.params.firstName} ${record.params.lastName}`,
    },
  }));
  return response;
};

new AdminBro({
  resources: [
    {
      resource: User,
      options: {
        actions: {
          list: {
            after: setCustom,
          },
        },
        properties: {
          custom: {
            isVisible: {
              list: true,
              edit: false,
              new: false,
              filter: false,
            },
          },
        },
      },
    }
  ]
})

@andrui
Copy link
Author

andrui commented Jul 8, 2020

@leibowitz , @cloudratha thx, but there is a problem with such solutions which I have already mentioned: when I add custom propery into the "list properties", adminbro composes query with custom property in the "SELECT" statement, like "SELECT existing_prop_1, existing_prop_2, custom_prop, ..." which leads to the "column does not exist" SQL error.

@leibowitz
Copy link
Contributor

leibowitz commented Jul 8, 2020

@andrui I don't get this issue. I'm using a slightly newer version, but I don't think that has anything to do with it.
admin-bro@2.6.0
admin-bro-sequelizejs@0.5.1

The only difference in admin-bro-sequelizejs seems to be this PR SoftwareBrothers/adminjs-sequelizejs#36

And admin-bro differences between 2.4.3 and 2.6.0 doesn't seem to include anything related to this

You could try upgrading to latest, but I doubt it would change anything

Are you sure you have not specified the properties key twice? I definitely did this before

Could you paste your resource config in here?

@andrui
Copy link
Author

andrui commented Jul 8, 2020

@leibowitz thx I will check with a new version

@leibowitz
Copy link
Contributor

leibowitz commented Jul 8, 2020

@cloudratha I just found out sequelize has something called Virtual columns, which can do something similar to your example.

@cloudratha
Copy link

@andrui do you mind sharing you list after hook method. Altering the response shouldn’t trigger further selects.

@leibowitz
Copy link
Contributor

@andrui any updates?

@wojtek-krysiak
Copy link
Contributor

@andrui can you add customField1 to record.populated instead of record.params? - it should solve this problem

wojtek-krysiak added a commit that referenced this issue Oct 8, 2020
Along with that
* deprecate property.name
* remove not needed array helpers in favour of flat module

It fixes: #631, #628, #491, #444
github-actions bot pushed a commit that referenced this issue Oct 8, 2020
# [3.3.0-beta.18](v3.3.0-beta.17...v3.3.0-beta.18) (2020-10-08)

### Features

* support for jsonb fields ([bb9de77](bb9de77)), closes [#631](#631) [#628](#628) [#491](#491) [#444](#444)
@wojtek-krysiak
Copy link
Contributor

adding custom properties to the list has been solved, regarding limiting the payload - you can use after hook - but there is a task to simplify this: #430

github-actions bot pushed a commit that referenced this issue Oct 30, 2020
# [3.3.0-rc-cf.1](v3.2.5...v3.3.0-rc-cf.1) (2020-10-30)

### Bug Fixes

* add new release tag rc-cf ([66dd243](66dd243))
* allow to bundle slatejs ([26d2c52](26d2c52))
* bring back design-system as a dependency ([cb3fa32](cb3fa32))
* clear BaseRecord#populated when value is undefined ([54dae81](54dae81))
* clicking nav closes the sidebar ([ffc92a6](ffc92a6)), closes [#601](#601)
* create new release ([cbb40cd](cbb40cd))
* duplicated virtual properties for nested keys ([8043757](8043757))
* edit action updates context.record ([d18f296](d18f296))
* error when passing prop: undefined ([748d2ee](748d2ee))
* export missing PropertyType ([1063365](1063365))
* export missing types ([5e9308f](5e9308f))
* filter params set by setRecord in useRecord ([82ea4d5](82ea4d5))
* fix performance issues in large records ([05ea7ee](05ea7ee))
* handle Date when coverting to formData ([5cdd80d](5cdd80d))
* improve filtering params in useRecord ([49da96e](49da96e))
* improve styling for a section in edit component ([6dea8c0](6dea8c0))
* initialize i18n only if its not already, extend otherwise ([e05b2f9](e05b2f9))
* logout button now skips react router ([37cd486](37cd486))
* merging params and customParam in useRecord ([a580eb7](a580eb7))
* missing actions ([c74615b](c74615b))
* multiple style issues ([3161436](3161436))
* new action populates record before returning ([19dd439](19dd439))
* populator fetched references for wrong types ([0528057](0528057))
* pssing params to richtext ([fd6a3b1](fd6a3b1)), closes [#603](#603)
* remove useEffect causing useRecord to reset ([8760ab0](8760ab0)), closes [#624](#624)
* rename data to context ([3d19230](3d19230))
* search by not searchable property ([31bf9d2](31bf9d2))
* sidebar width when content was too big ([18265b7](18265b7))
* wrong company url when assetsCDN is set ([1027e05](1027e05))
* wrong npmignore ignoring all `app` folders ([ed3be71](ed3be71))

### Features

* ability to move resource on top in the navigation ([28e0a5d](28e0a5d))
* add custom property to Action ([9d9f0cc](9d9f0cc))
* add filterOutParams, selectParams to flat ([4ba1552](4ba1552))
* add flat module ([ec7e53d](ec7e53d))
* add isArray to PropertyOptions ([3e21cba](3e21cba)), closes [#576](#576)
* add new get and set functions to BaseRecord ([438b7f1](438b7f1)), closes [#566](#566)
* add new options to useRecord hook ([323ea9a](323ea9a))
* add new props property ([607de55](607de55))
* add new shortcut methods to ViewHelpers ([6915056](6915056)), closes [#294](#294)
* add new useResource hook ([3fe39f7](3fe39f7)), closes [#325](#325)
* add option to create nested schemas in JSONB ([fe543d2](fe543d2)), closes [#157](#157) [#444](#444)
* add useAction hook and rewrite action button ([f1b0123](f1b0123))
* bump design-system version ([ee12a81](ee12a81))
* bump desing-system ([1f306ee](1f306ee))
* change buttons in record in list ([a9bac06](a9bac06))
* change show components ([20cc6a6](20cc6a6))
* define reference in PropertyOptions ([052661d](052661d)), closes [#583](#583) [#416](#416)
* handling onverriding params in BaseRecord ([3dd1747](3dd1747))
* migrate to ButtonGroup ([6ddd2d7](6ddd2d7))
* move populator logic to the adminbro core ([bf7055e](bf7055e)), closes [#587](#587)
* move state of sidebar visibility to the local store ([221fcfa](221fcfa))
* option to nest actions under parents ([0c064c3](0c064c3))
* pass multiple arguments to flat.selectParams ([046292d](046292d))
* pass property.custom to all edit renderers ([7592239](7592239)), closes [#258](#258)
* show/hide label in PropertyOptions ([df110c6](df110c6))
* style post settings ([2680cae](2680cae))
* support for jsonb fields ([bb9de77](bb9de77)), closes [#631](#631) [#628](#628) [#491](#491) [#444](#444)
* update design system ([cae3b84](cae3b84))
* update sidebar to the latest design system ([9cdb33c](9cdb33c))
* wrap bulk actions with ButtonGroup ([203268f](203268f))
github-actions bot pushed a commit that referenced this issue Nov 1, 2020
# [3.3.0](v3.2.5...v3.3.0) (2020-11-01)

### Bug Fixes

* allow to bundle slatejs ([26d2c52](26d2c52))
* array manipulaton in deeply nested propertiescloses: [#645](#645) ([7f0bb71](7f0bb71))
* bring back design-system as a dependency ([cb3fa32](cb3fa32))
* chaning Date to objects in flat.set error ([291cb83](291cb83))
* clear BaseRecord#populated when value is undefined ([54dae81](54dae81))
* clicking nav closes the sidebar ([ffc92a6](ffc92a6)), closes [#601](#601)
* duplicated virtual properties for nested keys ([8043757](8043757))
* edit action updates context.record ([d18f296](d18f296))
* error when passing prop: undefined ([748d2ee](748d2ee))
* export missing PropertyType ([1063365](1063365))
* export missing types ([5e9308f](5e9308f))
* filter params set by setRecord in useRecord ([82ea4d5](82ea4d5))
* fix performance issues in large records ([05ea7ee](05ea7ee))
* handle Date when coverting to formData ([5cdd80d](5cdd80d))
* handle wrong value in BaseRecord#populated ([75acbf6](75acbf6))
* improve filtering params in useRecord ([49da96e](49da96e))
* improve styling for a section in edit component ([6dea8c0](6dea8c0))
* initialize i18n only if its not already, extend otherwise ([e05b2f9](e05b2f9))
* logout button now skips react router ([37cd486](37cd486))
* memoize property in BasePropertyComponent ([b7ac269](b7ac269))
* merging params and customParam in useRecord ([a580eb7](a580eb7))
* missing actions ([c74615b](c74615b))
* multiple style issues ([3161436](3161436))
* new action populates record before returning ([19dd439](19dd439))
* old record being rendered in recordAction ([09ebcd0](09ebcd0))
* overlapping error message ([d3d61c1](d3d61c1))
* population logic for deeply nested properties ([1ada282](1ada282)), closes [#645](#645)
* populator fetched references for wrong types ([0528057](0528057))
* pssing params to richtext ([fd6a3b1](fd6a3b1)), closes [#603](#603)
* remove useEffect causing useRecord to reset ([8760ab0](8760ab0)), closes [#624](#624)
* rename data to context ([3d19230](3d19230))
* search by not searchable property ([31bf9d2](31bf9d2))
* sidebar big zIndex don't overlap eveything ([1872408](1872408))
* sidebar width when content was too big ([18265b7](18265b7))
* wrong company url when assetsCDN is set ([1027e05](1027e05))
* wrong npmignore ignoring all `app` folders ([ed3be71](ed3be71))
* **babel:** add babel plugin for styled components ([fa9fb8f](fa9fb8f))
* **bundle:** exit with no zero code on bundle error ([29cabb1](29cabb1))
* **bundle:** fix babel input paths ([b516e9f](b516e9f))
* **bundle:** move to default import ([2660f56](2660f56))

### Features

* ability to move resource on top in the navigation ([28e0a5d](28e0a5d))
* add custom property to Action ([9d9f0cc](9d9f0cc))
* add filterOutParams, selectParams to flat ([4ba1552](4ba1552))
* add flat module ([ec7e53d](ec7e53d))
* add isArray to PropertyOptions ([3e21cba](3e21cba)), closes [#576](#576)
* add new get and set functions to BaseRecord ([438b7f1](438b7f1)), closes [#566](#566)
* add new options to useRecord hook ([323ea9a](323ea9a))
* add new props property ([607de55](607de55))
* add new shortcut methods to ViewHelpers ([6915056](6915056)), closes [#294](#294)
* add new useResource hook ([3fe39f7](3fe39f7)), closes [#325](#325)
* add option to create nested schemas in JSONB ([fe543d2](fe543d2)), closes [#157](#157) [#444](#444)
* add useAction hook and rewrite action button ([f1b0123](f1b0123))
* bump bundled dependencies ([f108eaa](f108eaa))
* bump design system to the latest version ([8c690f9](8c690f9))
* bump design-system version ([ee12a81](ee12a81))
* bump desing-system ([1f306ee](1f306ee))
* change buttons in record in list ([a9bac06](a9bac06))
* change show components ([20cc6a6](20cc6a6))
* define reference in PropertyOptions ([052661d](052661d)), closes [#583](#583) [#416](#416)
* flat.filterOutParams takes more properties ([478af85](478af85))
* handling onverriding params in BaseRecord ([3dd1747](3dd1747))
* migrate to ButtonGroup ([6ddd2d7](6ddd2d7))
* move populator logic to the adminbro core ([bf7055e](bf7055e)), closes [#587](#587)
* move state of sidebar visibility to the local store ([221fcfa](221fcfa))
* option to nest actions under parents ([0c064c3](0c064c3))
* pass multiple arguments to flat.selectParams ([046292d](046292d))
* pass property.custom to all edit renderers ([7592239](7592239)), closes [#258](#258)
* show/hide label in PropertyOptions ([df110c6](df110c6))
* style post settings ([2680cae](2680cae))
* support for jsonb fields ([bb9de77](bb9de77)), closes [#631](#631) [#628](#628) [#491](#491) [#444](#444)
* update design system ([cae3b84](cae3b84))
* update sidebar to the latest design system ([9cdb33c](9cdb33c))
* wrap bulk actions with ButtonGroup ([203268f](203268f))
* **bundle:** allow any external dependecy in custom components ([f069b70](f069b70))
* **bundle:** migrate to new rollup plugins ([3ef7f0b](3ef7f0b))
* **bundler:** allow use jsnext modules ([922e2f7](922e2f7))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants