inveniosoftware / invenio-app-rdm

Turn-key research data management platform.
https://inveniordm.docs.cern.ch
MIT License
100 stars 144 forks source link

ui: prototype mechanism to import new defined widget #1782

Closed zzacharo closed 2 years ago

zzacharo commented 2 years ago

Prototype how we can import dynamically a new widget from the end user's assets folder.

At the moment, we define an alias to the end user's folder where they can drop jsx files with the same names as the files they want to override. These files are being collected during build time and are replacing the default ones.

The end goal is to be able to support new files added from the end user as part of extending the application's capabilities.

zzacharo commented 2 years ago

Example UI configuration

A potential configuration could look like as below:

export const CustomFieldsConfig = {
  "ATLAS experiment": [
    {
      fieldPath: "experiment",
      ui_widget: "CustomTextField",
      label: "Experiment",
      placeholder: "Type an experiment...",
      icon: "pencil",
      description:
        "You should fill this field with one of the experiments e.g LHC, ATLAS etc.",
    },
    {
      fieldPath: "custom",
      ui_widget: "MyCustomField",
      label: "Experiment description",
      placeholder: "Give a description for the experiment...",
      icon: "pencil",
      description: "Describe the purpose of the experiment.",
    },
  ],
  "CERN experiment": [
    {
      fieldPath: "custom",
      ui_widget: "MyCustomField",
      label: "Experiment description",
      placeholder: "Give a description for the experiment...",
      icon: "pencil",
      description: "Describe the purpose of the experiment.",
    },
    {
      fieldPath: "experiment",
      ui_widget: "CustomTextField",
      label: "Experiment",
      placeholder: "Type an experiment...",
      icon: "pencil",
      description:
        "You should fill this field with one of the experiments e.g LHC, ATLAS etc.",
    },
  ],
};

The configuration is namespaced in sections. Each section can define an array of custom fields. The order of the defined sections and their respective fields is kept in the UI. Each custom field defines a specific configuration. The different parameters are analyzed below:

Config property Type Description
fieldPath string Jsonschema path to custom field e.g experiment.
ui_widget string Name of the ui widget to use.
label string UI label to display for the field.
placeholder string Placeholder for user input.
icon string SUI icon name.
description string Description to be used as helptext for the new defined field.

Adding/Overriding custom fields

We take advantage of ES6 dynamic imports and webpack aliases so the loading mechanism for each custom field will respect the following order:

WIth the above mechanism, users can add new files/ui widgets that can then reference in the config. For example, if we want to add a new ui widget called MyCustomWidget then we need to:

/my-site/assets/templates/custom_fields/MyCustomWidget.js
import React, { Component } from "react";
import PropTypes from "prop-types";

import { FieldLabel, TextAreaField } from "react-invenio-forms";

export default class MyCustomField extends Component {
  render() {
    const { fieldPath, label, icon, placeholder, description } = this.props;

    return (
      <>
        <TextAreaField
          fieldPath={fieldPath}
          label={<FieldLabel htmlFor={fieldPath} icon={icon} label={label} />}
          placeholder={placeholder}
        />
        {description && <label className="helptext">{description}</label>}
      </>
    );
  }
}

Then the user can reference that widget in the config:

export const CustomFieldsConfig = {
  "ATLAS experiment": [
    ...
  ],
  "CERN experiment": [
    ...,
   {
      fieldPath: "experiment",
      ui_widget: "MyCustomField",
      label: "My custom label",
      placeholder: "Type a value...",
      icon: "pencil",
      description:
        "You should fill this field with values such as ...",
    },
  ],
};

In a similar fashion, if the user defines a file with a name of one of the existing widgets then they could override that widget entirely.

ppanero commented 2 years ago

The PR has not been merged to master but it has been included in custom-fields branch. Works will take over from there.