Skip to content
Richard Všianský edited this page Mar 9, 2020 · 20 revisions

Information about current forms in ManageIQ. For other (deprecated) kinds of forms, go to Forms (kinds).

Design Guidelines

forms

Here are the guidelines for the consistent user experience of form fields derived from PatternFly.

Form checklist

  • is it a required form? use *
  • do you have correct helper text? provide a correct format Ex. Incorrect syntax used. Example: smtp.mailserver.com
  • need a detailed description? add a popover icon next to the label
  • when to show an error message? when the field loses focus
  • vertical or horizontal? go with vertical as it's easier to scan and complete
  • what is the width of the form? wrap it in bootstrap container (not fluid container)

Migration

First step - template

  • use Data driven forms if possible
    • forms prepared to match all properties listed above
  • use form container with class container to avoid endless fields expanding
    • will require small override of pf class. Use max-width instead of width. MIQ layout does have some additional spacing that causes overflow on small devices.
    • form container width will stop expanding so there won't be extremely large inputs
<div class="container">
  <form>
    ....
  </form>
</div>
  • form field layout
    • All text field should be 100% width of its parent container.
    • Form groups should follow vertical layout.
    • Data driven forms enforce this.
    • Only exception is check box group with only one option. It should be replaced with switches or stay horizontal.
    • old haml forms should be migrated to following:
      • replacing div with .form-horizontal class with normal form tag
      • remove col-md classes from labels, inputs and help blocks
      • remove .form-horizontal div container
# before
.form-horizontal
  %div
    .form-group{...}
        %label.col-md-2.control-label{...}
          = _('Name')
        .col-md-8
          %input.form-control{...}
          %span.help-block{...}

# after
%form
  .form-group{...}
    %label.control-label
      = _('Name')
    %input.form-control{...}
    %span.help-block{...}

Second step - required validation

TBD

Cloud Network

Networks > Networks > Configuration > Add a new Cloud Network

Required parameters for each type of Provider Network

type physical_network segmentation_id
flat required
gre required (GRE ID)
vlan required required (VLAN ID)
vxlan

Custom data driven forms component

Code Editor

This component uses codemirror editor. You can use it with or without data driven forms.

import CodeEditor, { DataDrivenFormCodeEditor } from '/app/javascript/components/code-editor' // path depends where you use it

Props

name type default required description
value string undefined true value of editor
onBeforeChange func: (editor, data, value) => void undefined true function that handles value changes
mode on of ["yaml", "json"] yaml false Language mode for code editor. Changes code highlight and validation later
modes Array of strings undefined false If specified adds radio buttons which will allow you to change between modes. If a prop mode is specified it will be picked as initial language mode
hasError bool false false If true changes styling of the editor to represent error state.
options Object Object false Use at your own risk. Configuration object for code mirror component. Options can be found here.

Basic usage

import React, { useState } from 'react'
import CodeEditor from '/app/javascript/components/code-editor'

const MyComponent = () => {
  const [value, setValue] = useState('') // set initial code editor value

  const handleChange(editor, data, value) => {
    //do something with editor or data if you need
    setValue(value)
  }

  return (
    <CodeEditor
      value={value} // value displayed in editir
      onBeforeChange={handleChange} // onChange handler the.
      hasError={bool} // sets error
      mode="json" // initial language
      modes={['json', 'yaml']} // shows radio buttons which allow switching between languages
    />
  )
}

Usage with data-driven-forms

const schema = {
  fields: [
   ...
   {
    component: 'code-editor',
    name: 'content',
    label: __('Content'),
    modes: ['yaml', 'json'],
    ...any other data driven specific attributes
   }
  ]
}

Duallist select

Props

Props Type Default Decription
leftId string undefined ID passed to left select
rightId string undefined ID passed to right select
leftTitle string undefined Title above left select
rightTitle string undefined Title above right select
rightTitle string undefined Title above right select
size number 15 Size of the selects (in lines)
allToRight bool true Should show moveAllToRight button
allToLeft bool false Should show moveAllToLeft button
moveLeftTitle string __('Move selected to left') Title of moveToLeft button
moveRightTitle string __('Move selected to right') Title of moveToRight button
moveAllRightTitle string __('Move all to right') Title of moveAllToRight button
moveAllLeftTitle string __('Move all to left') Title of moveAllToLeft button
options array [ ] All options of the select
input: { value } array [ ] Selected options (subset of options)

Options/Value format

[
      {key: 'key', label: 'label'},
      {key: 'key1', label: 'label1'},
      {key: 'key2', label: 'label2'},
      ...
]

The component will split values from options to left/right select lists according to value. (All values in value are going to right, others to left)

How to use it in Data-driven form schema (example)

{   
    component: 'dual-list-select',
    name: 'duallist',
    options: [
      { key: 'key', label: 'label' }, ...
    ],
    rightId: 'child_vms',
    leftId: 'available_vms',
    rightTitle: __('Child VMs:'),
    leftTitle: __('Availables VMs'),
    moveLeftTitle: __('Move selected VMs to left'),
    moveRightTitle: __('Move selected VMs to right'),
    moveAllRightTitle: __('Move all VMs to right'),
}

How to use it in Data-driven form

By default, the value contains all options from the right side select. However, if you need left values or just added values (probably in most cases), you can use helpers in /dual-list-select/helpers to extract needed information:


1 In constructor/componentDidMount/elsewhere (where you fetch data) save these values into state: originalOptions: options originalRightValues: value


2 In your submit method (values => (...)) you can use helper methods:


filterOptions(originalOptions, values.duallist) to get all values on left filterOptions(values.duallist, originalOptions) to get added values to left select filterOptions(values.duallist, originalRightValues) to get added values to right select getKeys(values) to get keys of values


3 Then you can send values to endpoints/API!

Horizontal rule

Just a hr component for using in forms.

{   
    component: 'hr',
    name: 'name', // every component has to have an unique name!
}