Skip to content

Parameter forms

Jonathan Stray edited this page Apr 5, 2019 · 11 revisions

Each Step has a <form> with a bunch of Parameters. The parameters can have different types (see Parameter types); each field type implies a React component.

Here are those React components' conventions:

PropTypes

All components will be rendered with:

{
    name: PropTypes.string.isRequired,
    fieldId: PropTypes.string.isRequired,
    label: PropTypes.string.isRequired, // maybe ''
    isReadOnly: PropTypes.bool.isRequired,
    isZenMode: PropTypes.bool.isRequired,
    upstreamValue: PropTypes.string.isRequired,
    onChange: PropTypes.func.isRequired, // onChange(newValue) => undefined
    value: PropTypes.string.isRequired,
    inputColumns: PropTypes.arrayOf(PropTypes.shape({
      name: PropTypes.string.isRequired,
      type: PropTypes.oneOf([ 'text', 'number', 'datetime' ]).isRequired
    }).isRequired),
    tabs: PropTypes.arrayOf(PropTypes.shape({
      slug: PropTypes.string.isRequired,
      name: PropTypes.string.isRequired,
      outputColumns: PropTypes.arrayOf(PropTypes.shape({
        name: PropTypes.string.isRequired,
        type: PropTypes.oneOf([ 'text', 'number', 'datetime' ]).isRequired
      }).isRequired)
    }).isRequired).isRequired
}

isReadOnly

Each component must have isReadOnly: PropTypes.boolean.isRequired. When set, the user cannot edit.

value and onChange

Each component manipulates a value: PropTypes.xxx.isRequired. The component shouldn't keep value in its internal state: rather, it should call onChange(newValue) with every keypress. The form itself maintains parameters.

upstreamValue vs value

When the user runs onChange(), that manipulates the form's state. When the user submits the form, the changes to "upstream" to the server. When other users (different people with their browser windows open on the same Workflow) write values, those "upstream" changes arrive in the user's form.

Basically, upstreamValue means: "the value on the server."

During editing, the user may want to see which fields have been modified. Components should check whether value == upstreamValue and set className="edited" to indicate to the user that the value is different.

The component may also offer a "reset" feature that calls onChange(upstreamValue). (When value === upstreamValue, value will automatically update whenever a new upstreamValue comes from the server.)

name

To help with testing and communication, every HTML5 form field should have a name. This will bet set to parameter's id_name from the module definition JSON. The component needs name: PropTypes.string.isRequired. If the compoment has multiple HTML5 form fields, their names should use square brackets. For instance:

<input type='number' name={`${name}[subfield]`} .../>
<input type='number' name={`${name}[otherfield]`} .../>

label and fieldId

This text should appear always, whether value is empty or not.

Prefer an HTML5 <label>. If the user clicks the label, the user will expect a form field to gain focus. To do that, you'll probably want htmlFor=[SOME ID], and for that we supply fieldId, which is guaranteed to be unique across the entire HTML page.

There's a <MaybeLabel> helper you can use. It does everything.

placeholder

What does the user see when a components value is "empty"? That depends on the component, of course; but in general, it should be:

  1. The "effective" or "default" value, grayed out. For instance, a field for "output column name" should predict what the output column name will be.
  2. A "prompt", grayed out. For instance: Select a column

inputColumns

Should the component need to know input-dataframe columns, it can check inputColumns: PropTypes.arrayOf(PropTypes.shape({ name: PropTypes.string.isRequired, type: PropTypes.oneOf([ 'number', 'text', 'datetime' ]).isRequired })).

During rendering, inputColumns is null.

tabs

Should the component need to know about this workflow's tabs, it can check tabs. It's an ordered list of tabs.

During rendering of a tab, tabs[*].outputColumns is null; otherwise it's a list of output columns.

isZenMode

Usually false; some modules will allow it to be true and it may decide upon a different layout if that's the case.