# XlReactDipReduxForm

This element displays CI based on the provided type descriptor.

### Summary

* [Exports](#exports)
* [Playground](#playground)
* [Architecture](#architecture)
* [Properties](#properties)
* [Example](#example)

### Exports
```
- xlReactDipReduxFormReducer
- xlReactDipReduxFormActions
    - changePristineState: (formId, pristinity)
    - changeValidity: (formId, validity)
    - groupProperties: (formId, collapsed)
    - initialize: ({formId, ...rest})
    - mergeContext: (formId, context)
    - openCategoryGroup: (formId, categoryName)
    - setContext: (formId, context)
    - toggleCategoryGroup: (formId, categoryName)
    - unmount: (formId)
    - updateExternalProperties: (formId, model)
- getFormById (that's a selector)
- getForms (that's a selector)
- XlReactDipReduxForm

```

### Playground

Here you can choose different initial data setup for the form to play with
* [Forms](https://xebialabs.github.io/xl-react-components/kitchen-sink.html#/form)

### Architecture

The form completely is based on metadata information provided to the form. 
Metadata is a CI type descriptor (original or modified). 

[Form Architecture](form-architecture.md)

![XL React Dip Form Diagram](xl-react-dip-redux-form.png)

### Properties

- **allowLookupValues** - (bool) - if sets as `true` enables the usage of lookup fields in the form.
        Currently it allows for password fields to choose credentials from Vault.
- **children** - (element or array of elements) - allows to add extra react component to the bottom of 
        the form. It can be useful if you want to make it scrollable as a part of the form.
- **collapsed** - (bool) - Looks like outdated property, has to be removed.
- **context** - (object) - contains the context of each individual field of the form.
- **dateTimeFormat** - (string) - Default 'YYYY-MM-DDTHH:mm:ss.SSSZ'. Used as a format for all 
    date fields in the form.
- **disabled** - (bool) - if sets as `true`, makes all the fields in the form readonly.
- **displayMode** (string) - 3 options are available to choose: 
      _"creation"_ or _"edit"_ - allows to make changes
      _"display"_ - makes component readonly and user can only view the current value
- **groupedProperties** - (array of objects) - describes the grouping of properties.
    ```javascript
    "groupedProperties": [
                {
                    "category": "Common", // All properties of the category "Common"
                    "isOpen": false, // Category is collapsed
                    "properties": [...]
                },
                {
                    "category": "Advanced", // All properties of the category "Advanced"
                    "isOpen": true, // Category is opened
                    "properties": [...]
                },
            ]
    ```

- **handlers** - Through handlers you specify the API calls which will be triggered for fields having
    autosuggestion, namely
    
    ```javascript
          const handlers = {
              CI: getHandlers(),
              LIST_OF_CI: getCollectionOfCiHandlers,
              LIST_OF_STRING: {nameComponentList: getHandlers()},
              LOOKUP_CI: getHandlers(lookupSuggestedElements),
              SET_OF_CI: getCollectionOfCiHandlers
          };
    ```
    
    For each field kind you need to provide own handler. How `getHandlers` looks inside:
    
    ```javascript
    
      const addCandidates = ({value, objLabel}) => {
          // 1. Here you can call or API 
          return searchCi({idPattern: value}).then(R.propOr([], 'data'));
          // 2. Or return fixed array of your predefined data:
          return Promise.resolve([{id: 1, name: 'Apple'}, {id: 2, name: 'Orange'}]);
      };
    
      getHandlers = () => ({
          addCandidates: ({metadata, value, objLabel}) => addCandidates({...})        
      });
    ```
    
    - **metadata** - contains the metadata of the property. It can be used if you need to get some extra 
        information to make a query for suggestions. That is used in search of candidate values for CIs, WAS plugin 
        and patch dictionaries.
    - **value** - that's what user typed in a search. Based on that you can implement your filter for proposed
        suggestions.
        
        Example: 
        
    ```javascript
        const transform = (item) => ({id: item, name: item});

        const suggestOrchestrators = ({value}) => listAllOrchestrators().then((response) => {
            const filterCond = ({id}) => R.toLower(id).indexOf(R.toLower(value)) !== -1;
            return R.filter(filterCond, R.map(transform, response.data));
        });      
    ```
    
    - **objLabel** - name of the property which is going to be shown to the user in suggested dropdown. 
    For example you have a list of objects like: 
     
     ```javascript
      const suggestions = [
          {id: 1, city:'Amsterdam', country: 'Netherlands'},
          {id: 1, city:'Haarlem', country: 'Netherlands'},
          {id: 1, city:'Hilversum', country: 'Netherlands'}
      ];
     ```
     and 
    `objLabel='city'`, the list of suggestions shown to user should be `['Amsterdam', 'Haarlem', 'Hilversum']`. 
    
    That logic you need to consider when you as a developer implement `addCandidates`.
    
    
- **mergeContext** - (function) - this function is auto-injected by XlReactDipReduxForm. It applies all properties state
 changes of properties into Redux store.
 
- **messages** - (object) - that's an object which list all properties of the form and contains for each the message.
    If message is present, it will be shown instead of defined description of the field. 
    If message of type WARNING - it will be highlighted in orange color, of type ERROR to red color.
    
- **metadata** - (object) - that's an object which list all properties of the form and contains for each the metadata
    defined in type system with a possibility of modification. 
    
Example:

```javascript
    const metadata = [
      {
        "type": "it.SysAdmin",
        "deployableType": "it.Dude",
        "containerType": "it.Mainframe",
        "virtual": false,
        "icon": "icons\/types\/udm.BaseConfigurationItem.svg",
        "description": "The supertype of all Deployeds.",
        "properties": [
          {
            "name": "deployable",
            "fqn": "it.SysAdmin.deployable",
            "label": "Deployable",
            "kind": "CI",
            "description": "The deployable that this deployed is derived from.",
            "category": "Common",
            "asContainment": false,
            "inspection": false,
            "required": false,
            "requiredInspection": false,
            "password": false,
            "transient": false,
            "size": "DEFAULT",
            "referencedType": "udm.Deployable",
            "default": null
          }, ... ]
      }
    ];
```
    
- **model** - (object) - that's an object which list all properties of the form and contains for each the model (data).
    
    Example:
    
```javascript

const model = {
    name: "John",
    surname: "Doe"
};
```

- **objLabel** - (string) - if your model is not string but object you need to specify which field consider as id
- **onModelChange** - (function) - triggers once model is changed. You'll have the model of the each field of the form.
- **onPristinityChange** - (function) - triggers once pristinity is changed. 
    You'll have the model of the each field of the form.
- **onValidityChange** - (func) - triggers once validity is changed. . 
    You'll have the validity of the each field of the form.
- **openCategoryGroup** - (function) - this function is auto-injected by XlReactDipReduxForm. It opens all categories.
- **pristinity** - (object) - that's an object which list all properties of the form and 
    contains for each the pristinity state. Initially pristinity is `true` for each field. If user will try to 
    modify any field, it will be changed to `false`, even if the value was returned back to the initial value.  
    
    Example:
```javascript

const pristinity = {
    name: false,
    surname: true
};
```

- **register** - (function). That's a callback which will be called after the form will be initialized. As a parameter
    you'll get a form API. With that API you'll get an access to such functions as:
    
    - **focusFieldByName: (fieldName)** - You can change a focus to a specific form field by providing 
        a field name as a parameter.
    - **focusOnFirstInvalidField: ()** - You can focus on the first invalid field. Commonly used in XL Deploy after 
        clicking on "Save" button. To help user to find a field which has to be filled in (differently).
    - **resetPristinity: ()** - (@Deprecated) Changes the state of pristinity for each field back to pristine. 
        You can use it when you saved the form successfully and allow to the user do subsequent modifications. 
        Take in mind that after the last changes this method is preferably not to use, as pristinity state 
        of each field is stored in Redux store. So it's better to do in saga which is called when `onSave` is triggered.
- **toggleCategoryGroup** - (function) - this function is auto-injected by XlReactDipReduxForm. It changes the state of 
    the category. If it was opened it will close it, and other way around.
- **updateExternalProperties** - (function) - this function is auto-injected by XlReactDipReduxForm. Controls the 
    external properties. It's a part of type system implementation. Currently used only for password fields. 
    Password field contains a toggle button which changes password string field to 2 lines component. First line is 
    enum where you choose Vault provider, and second line - is a string field where you provide a key path. Both fields
    contain a validator.
- **validators** - (PropTypes.arrayOf(PropTypes.func)) - list of validators.
    - **condition** - if sets as `true`, means that validator found an issue.
    - **message**
        - **show** - should the found issue has to be shown to user or not. For example when you create new CI,
            and this CI contains required fields, you don't want to highlight all of them immediately, but only 
            if user filled in the form, missed some required fields, clicked on "Save" button and only then 
            highlight to him what is still wrong. For that you can keep the `show=false`.
        - **text** - is the message will be shown to the user instead of descriptor of the field.
        - **type** - is a severity of the message. Currently supported values are : ERROR, WARNING.
     
    Example:
```javascript

const validator1 = (fieldName, model) => ({
  condition: true,
  message: {
      show: validationMessage.level === ERROR,
      text: validationMessage.message,
      type: validationMessage.level
  }
});
const validators = [validator1];
```

That's an example of 1 validator. Data based on which you can decide if validator should return error/warning is 
the name of the field and the model or data which is currently assigned to that field. On example you can 
see in which format the result is expected to be returned.

If several errors/warnings were found for the same field, the first one will be shown. Warnings will be shown only 
if all errors were fixed.

- **validity** - (object) - that's an object which list all properties of the form and contains for each 
    the validity state. This state is updated each time when user changes something on the form with help 
    of internal and provided validators.
    
    Example:
    
```javascript

const validity = {
    name: true,
    surname: true
};
```

### Example

1. Register form reducer in your main reducer
```javascript

export const allReducers = {
    ...
    forms: xlReactDipReduxFormReducer({}),
    ...
};
```

2. Initialise the form

```javascript
    import {xlReactDipReduxFormActions} from 'xl-react-components/dist/dip';

    yield put(
        xlReactDipReduxFormActions.initialize({
            formId,
            handlers: {CI: createHandlersForType(descriptorForCredentials.type)},
            metadata,
            model,
            validators
        })
    );
```

3. Define the form 
```jsx harmony
    import {XlReactDipReduxForm} from 'xl-react-components/dist/dip';
    
    const formServerValidator = (fieldName, model) => ciServerValidator(this.props.deployment.application, fieldName, model);
    
    <XlReactDipReduxForm
        formId={formId}
        onModelChange={this.handleModelChange}
        onPristinityChange={onChangePristinity}
        validators={[formServerValidator]}
    />

```

