adminjs icon indicating copy to clipboard operation
adminjs copied to clipboard

Support for arbitrary keys in JSON/JSONB

Open bakkerthehacker opened this issue 3 years ago • 7 comments

Describe the problem feature solves Support for JSON/JSONB in version 3.3 seems to only supports explicit columns. While this is useful in some situations, there are JSONBs that contain arbitrary keys and it would be useful to have this data available in admin bro.

Describe the solution you'd like All the JSONB keys and values are shown, nested as deep as the JSONB itself.

For the show action, the data should be shown like an array, but nested.

The edit action also seem possible, it could be similar to the array edit.

Describe alternatives you've considered I already have a custom component that can show the JSONB nested, although I have not gotten a custom edit component working:

Click for Custom JSONB component
import React, { ReactNode } from 'react'
import _ from 'lodash'
import { unflatten } from 'flat'
import { Badge, Section, FormGroup, Label } from '@admin-bro/design-system'
import mapBoolean  from 'admin-bro/lib/frontend/components/property-type/boolean/map-value'

class JSONBEntry extends React.PureComponent {
  render() {
    const { paramObject } = this.props;

    if(typeof paramObject === 'boolean'){
      return (
        <Badge outline size="sm">{mapBoolean(paramObject)}</Badge>
      )
    }

    if(_.isNil(paramObject)){
      return <Badge outline size="sm">null</Badge>
    }

    if(typeof paramObject !== 'object'){
      return paramObject;
    }

    return (
      <Section>
        {Object.entries(paramObject).map(([key, value]) => (
          <FormGroup>
            <Label>{key}</Label>
            <JSONBEntry paramObject={value}/>
          </FormGroup>
        ))}
      </Section>
    );
  }
}

export default class ShowJSONB extends React.PureComponent {
  render() {
    const { property, record } = this.props;

    const matchingParams = _.chain(record.params)
      .omitBy(_.isNil)
      .pickBy((value, key) => key.startsWith(property.name))
      .value();

    const paramObject = unflatten(matchingParams)[property.name];

    return (
      <FormGroup>
        <Label>{property.label}</Label>
        <JSONBEntry paramObject={paramObject}/>
      </FormGroup>
    );
  }
}

This implementation isn't super robust, it just does very simple checks on the data types. It is also affected by https://github.com/SoftwareBrothers/admin-bro/issues/525

It would be great if this could be integrated into adminbro itself. Is there a better way to do this? I am just getting familiar with all the changes in verision 3.3

Acceptance criteria All nested JSON/JSONB data is shown without explicitly listing where in the JSONB it is

Nested JSON/JSONB data could be editable as well, similar to arrays.

bakkerthehacker avatar Nov 16 '20 18:11 bakkerthehacker

Are there any news on this feature?

Dima-Kevanishvili avatar Jan 27 '21 12:01 Dima-Kevanishvili

+1

chakritp avatar Jun 01 '21 13:06 chakritp

My edit component based on @bakkerthehacker code:

import * as React from 'react';
import { Box, Label } from '@admin-bro/design-system';
import ReactJson from 'react-json-view';
import * as _ from 'lodash';
import { unflatten } from 'flat';

const EditJSONB = (props: any) => {
  const { property, record, onChange } = props;
  const matchingParams = _.chain(record.params)
    .omitBy(_.isNil)
    .pickBy((value, key) => key.startsWith(property.name))
    .value();

  const object: any = unflatten(matchingParams);
  const paramObject = object?.[property.name];

  const saveData = (data: any): void => {
    onChange(property.name, data);
  };

  const onEdit = (event: any) => {
    const updated_src = event?.updated_src;
    saveData(updated_src);
  };

  const onAdd = (event: any) => {
    const updated_src = event?.updated_src;
    saveData(updated_src);
  };

  const onDelete = (event: any) => {
    const updated_src = event?.updated_src;
    saveData(updated_src);
  };

  return (
    <Box mb="xl">
      <Label>{property.label}</Label>
      <ReactJson
        name={property.name}
        collapsed={false}
        src={paramObject}
        onEdit={onEdit}
        onAdd={onAdd}
        onDelete={onDelete}
      />
    </Box>
  );
};

export default EditJSONB;

id3er0 avatar Jun 09 '21 20:06 id3er0

Is there any plans to implement this? The component that was shared in the original issue is out of date

AshotN avatar Aug 04 '22 20:08 AshotN

We don't yet started to work on this issue, however it is on our mind while planning work for the future

krzysztofstudniarek avatar Aug 16 '22 09:08 krzysztofstudniarek

@dziraf Hi! Do you think it would be a great opportunity to add these components to https://github.com/SoftwareBrothers/adminjs-custom-components?

marciondg avatar Mar 15 '23 18:03 marciondg

Currently we also have a key-value property type which allows you to add new JSON keys and it's values dynamically. However, it's very simple as it doesn't support types (all values, including numeric, are saved as text), it doesn't allow you to add predefined fields and you cannot nest it's fields.

Potential improvements to which contributions are welcome:

  • type conversion on save
  • add support for predefined fields
  • add support for nesting dynamic JSONs
  • theoretically it can be merged with mixed type for more flexibility

dziraf avatar Jul 04 '23 09:07 dziraf