-
Notifications
You must be signed in to change notification settings - Fork 356
Forms
Information about current forms in ManageIQ. For other (deprecated) kinds of forms, go to Forms (kinds).
Here are the guidelines for the consistent user experience of form fields derived from PatternFly.
- these are PatternFly patterns: top aligned labels, error field
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)
- 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 ofwidth
. 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
- will require small override of pf class. Use
<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
- replacing div with
# 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{...}
TBD
Networks
> Networks
> Configuration
> Add a new Cloud Network
type | physical_network | segmentation_id |
---|---|---|
flat | required | |
gre | required (GRE ID) | |
vlan | required | required (VLAN ID) |
vxlan |
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
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. |
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
/>
)
}
const schema = {
fields: [
...
{
component: 'code-editor',
name: 'content',
label: __('Content'),
modes: ['yaml', 'json'],
...any other data driven specific attributes
}
]
}
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!
Just a hr
component for using in forms.
{
component: 'hr',
name: 'name', // every component has to have an unique name!
}