Skip to content

Commit

Permalink
Converts Catalogs > Catalog > Add/Edit to react forms
Browse files Browse the repository at this point in the history
  • Loading branch information
rvsia committed Jan 10, 2019
1 parent c10ecc3 commit 3c31286
Show file tree
Hide file tree
Showing 8 changed files with 166 additions and 54 deletions.
62 changes: 62 additions & 0 deletions app/javascript/components/catalog-form/catalog-form.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { Grid } from 'patternfly-react';
import MiqFormRenderer from '../../forms/data-driven-form';
import createSchema from './create-form-schema';


class CatalogForm extends Component {
constructor(props) {
super(props);
const { catalogItems } = this.props;
this.state = {
schema: createSchema(catalogItems),
initialValues: {
name: props.catalogName,
description: props.catalogDescription,
duallist: {},
},
};
}

componentDidMount() {
}

render() {
const { catalogName, catalogId } = this.props;
const cancelUrl = `/catalog/st_catalog_edit/${catalogId}?button=cancel`;
return (
<Grid fluid>
<MiqFormRenderer
initialValues={this.state.initialValues}
schema={this.state.schema}
onSubmit={console.log}
onCancel={() => miqAjaxButton(cancelUrl)}
onReset={() => add_flash(__('All changes have been reset'), 'warn')}
canReset={!!catalogName}
buttonsLabels={{
submitLabel: catalogName ? __('Save') : __('Add'),
}}
/>
</Grid>
);
}
}

CatalogForm.propTypes = {
catalogName: PropTypes.string,
catalogDescription: PropTypes.string,
catalogItems: PropTypes.shape({
[PropTypes.string]: PropTypes.string,
}),
catalogId: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
};

CatalogForm.defaultProps = {
catalogName: undefined,
catalogDescription: undefined,
catalogItems: {},
catalogId: undefined,
};

export default CatalogForm;
48 changes: 48 additions & 0 deletions app/javascript/components/catalog-form/create-form-schema.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { componentTypes, validatorTypes } from '@data-driven-forms/react-form-renderer';

function createSchema(options = {}) {
const fields = [{
component: componentTypes.SUB_FORM,
title: __('Basic Info'),
fields: [{
component: componentTypes.TEXT_FIELD,
name: 'name',
validate: [{
type: validatorTypes.REQUIRED,
message: __("Name can't be blank"),
}],
label: __('Name'),
maxLength: 40,
autoFocus: true,
}, {
component: componentTypes.TEXT_FIELD,
name: 'description',
label: __('Description'),
maxLength: 60,
}],
}, {
component: 'hr',
}, {
component: componentTypes.SUB_FORM,
title: __('Assign Catalog Items'),
fields: [
{
component: 'dual-list-select',
leftTitle: __('Unassigned:'),
rightTitle: __('Selected:'),
leftId: 'available_fields',
rightId: 'selected_fields',
allToRight: false,
moveLeftTitle: __('Move Selected buttons left'),
moveRightTitle: __('Move Selected buttons right'),
size: 8,
assignFieldProvider: true,
options,
name: 'duallist',
},
],
}];
return { fields };
}

export default createSchema;
22 changes: 9 additions & 13 deletions app/javascript/components/dual-list-select/helpers.jsx
Original file line number Diff line number Diff line change
@@ -1,22 +1,18 @@
export const isEmpty = (obj) => {
if (obj === '') { return true; }
return (Object.getOwnPropertyNames(obj).length === 0);
};
export const isEmpty = obj => (obj.length === 0);

/** *********** HELPERS FOR FORMS *********** */
/* returns left values of dual list select */
export const leftValues = (options, value) => Object.keys(options).filter(key => !value[key]).reduce((acc, curr) => ({
...acc,
[curr]: options[curr],
}), {});

export const getKeys = value => (Array.isArray(value) ? value.map(({ key }) => key) : []);

export const leftValues = (options, value) => options.filter(({ key }) => !getKeys(value).includes(key));

/* returns left submitted keys of dual list select */
export const leftSubmittedKeys = (originalOptions, value) => Object.keys(originalOptions).filter(e => !value[e]);
export const leftSubmittedValues = (originalOptions, value) => originalOptions.filter(({ key }) => !getKeys(value).includes(key));

/* returns new left keys (added to left) of dual list select */
export const addedLeftKeys = (originalOptions, value, originalLeftValues) => (
leftSubmittedKeys(originalOptions, value).filter(e => !originalLeftValues[e])
export const addedLeftValues = (originalOptions, value, originalLeftValues) => (
leftSubmittedValues(originalOptions, value).filter(({ key }) => !getKeys(originalLeftValues).includes(key))
);

/* return new right keys (added to right) of dual list select */
export const addedRightKeys = (value, originalRightValues) => Object.keys(value).filter(e => !originalRightValues[e]);
export const addedRighValues = (value, originalRightValues) => value.filter(({ key }) => !getKeys(originalRightValues).includes(key));
69 changes: 32 additions & 37 deletions app/javascript/components/dual-list-select/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,50 +14,42 @@ class DualListSelect extends Component {
moveLeft = (rightValues) => {
const { input: { onChange } } = this.props;
const selectedItems = Array.prototype.map.call(this.rightList.current.selectedOptions, ({ value }) => value);
const reducedItems = Object.keys(rightValues).filter(key => !selectedItems.includes(key)).reduce(
(acc, curr) => ({
...acc,
[curr]: rightValues[curr],
}), {},
);
const reducedItems = rightValues.filter(({ key }) => !selectedItems.includes(key));

onChange({
onChange([
...reducedItems,
});
]);
};

moveRight = () => {
const { input: { onChange, value }, options } = this.props;
const selectedItems = Array.prototype.map.call(this.leftList.current.selectedOptions, ({ value }) => value)
.reduce((acc, curr) => ({
...acc,
[curr]: options[curr],
}), {});
const selectedItems = Array.prototype.map.call(this.leftList.current.selectedOptions, ({ value }) => value);
const movedItems = options.filter(({ key }) => selectedItems.includes(key));

onChange({
onChange([
...value,
...selectedItems,
});
...movedItems,
]);
};

moveAllRight = (leftValues) => {
const { input: { onChange, value } } = this.props;

onChange({
onChange([
...value,
...leftValues,
});
]);
};

moveAllLeft = () => {
const { input: { onChange } } = this.props;

onChange({});
onChange([]);
};

render() {
const {
input: { value = {} },
input: { value = [] },
options,
leftId,
rightId,
Expand All @@ -75,7 +67,7 @@ class DualListSelect extends Component {
const rightValues = value;

return (
<div>
<div style={{ paddingBottom: 10 }}>
<div className="col-md-5">
{leftTitle}
<List size={size} ref={this.leftList} id={leftId} values={leftValues} />
Expand All @@ -86,18 +78,18 @@ class DualListSelect extends Component {
<Button disabled={isEmpty(leftValues)} className="btn-block" onClick={this.moveRight} title={moveRightTitle}>
<Icon type="fa" name="angle-right" size="lg" />
</Button>
{ allToRight
&& (
<Button disabled={isEmpty(leftValues)} className="btn-block" onClick={() => this.moveAllRight(leftValues)} title={moveAllRightTitle}>
<Icon type="fa" name="angle-double-right" size="lg" />
</Button>
) }
{ allToLeft
&& (
<Button disabled={isEmpty(rightValues)} className="btn-block" onClick={this.moveAllLeft} title={moveAllLeftTitle}>
<Icon type="fa" name="angle-double-left" size="lg" />
</Button>
) }
{allToRight
&& (
<Button disabled={isEmpty(leftValues)} className="btn-block" onClick={() => this.moveAllRight(leftValues)} title={moveAllRightTitle}>
<Icon type="fa" name="angle-double-right" size="lg" />
</Button>
)}
{allToLeft
&& (
<Button disabled={isEmpty(rightValues)} className="btn-block" onClick={this.moveAllLeft} title={moveAllLeftTitle}>
<Icon type="fa" name="angle-double-left" size="lg" />
</Button>
)}
<Button disabled={isEmpty(rightValues)} className="btn-block" onClick={() => this.moveLeft(rightValues)} title={moveLeftTitle}>
<Icon type="fa" name="angle-left" size="lg" />
</Button>
Expand Down Expand Up @@ -134,9 +126,12 @@ DualListSelect.propTypes = {
/* Title of move all left button */
moveAllLeftTitle: PropTypes.string,
/* Values in right select { value: "Text", value1: "Text1", ... } */
options: PropTypes.shape({
[PropTypes.string]: PropTypes.string,
}),
options: PropTypes.arrayOf(
PropTypes.shape({
[PropTypes.string]: PropTypes.string,
[PropTypes.string]: PropTypes.string,
}),
),
};

DualListSelect.defaultProps = {
Expand All @@ -151,7 +146,7 @@ DualListSelect.defaultProps = {
moveRightTitle: __('Move selected to right'),
moveAllRightTitle: __('Move all to right'),
moveAllLeftTitle: __('Move all to left'),
options: {},
options: [],
};

const WrappedDualList = ({ FieldProvider, name, ...rest }) => (
Expand Down
5 changes: 3 additions & 2 deletions app/javascript/components/dual-list-select/list.jsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React from 'react';

const List = React.forwardRef(({ id, values = {}, ...rest }, ref) => (
const List = React.forwardRef(({ id, values = [], ...rest }, ref) => (
<select
ref={ref}
id={id}
Expand All @@ -10,7 +10,8 @@ const List = React.forwardRef(({ id, values = {}, ...rest }, ref) => (
style={{ overflowX: 'scroll' }}
{...rest}
>
{ Object.entries(values).sort((a, b) => a[1].localeCompare(b[1])).map(([key, text]) => <option key={key} value={key}>{text}</option>)}
{Array.isArray(values)
&& values.sort((a, b) => a.label.localeCompare(b.label)).map(({ key, label }) => <option key={key} value={key}>{label}</option>)}
</select>
));

Expand Down
4 changes: 3 additions & 1 deletion app/javascript/forms/mappers/formsFieldsMapper.jsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import React from 'react';
import { formFieldsMapper } from '@data-driven-forms/pf3-component-mapper';
import DualListSelect from '../../components/dual-list-select';
import DualListSelect from '../../components/dual-list-select';

const fieldsMapper = {
...formFieldsMapper,
'dual-list-select': DualListSelect,
hr: () => <hr />,
};

export default fieldsMapper;
2 changes: 2 additions & 0 deletions app/javascript/packs/component-definitions-common.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import CloudTenantForm from '../components/cloud-tenant-form/cloud-tenant-form';
import ServiceForm from '../components/service-form';
import SetServiceOwnershipForm from '../components/set-service-ownership-form';
import FlavorForm from '../components/flavor-form/flavor-form';
import CatalogForm from '../components/catalog-form/catalog-form';

/**
* Add component definitions to this file.
Expand All @@ -30,3 +31,4 @@ ManageIQ.component.addReact('CloudTenantForm', CloudTenantForm);
ManageIQ.component.addReact('ServiceForm', ServiceForm);
ManageIQ.component.addReact('SetServiceOwnershipForm', SetServiceOwnershipForm);
ManageIQ.component.addReact('FlavorForm', FlavorForm);
ManageIQ.component.addReact('CatalogForm', CatalogForm);
8 changes: 7 additions & 1 deletion app/views/catalog/_stcat_form.html.haml
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
- url = url_for_only_path(:action => "st_catalog_form_field_changed", :id => (@edit[:rec_id] || "new"))

= render :partial => "layouts/flash_msg"
.col-md-12
= react('CatalogForm', { :catalogId => @edit[:rec_id] || "new",
:catalogName => @edit[:new][:name].to_s,
:catalogDescription => @edit[:new][:description],
:catalogItems => options_for_select(@edit[:new][:fields])})

#form_div
= render :partial => "layouts/flash_msg"
-# show form if Catalog bundle is being added or if it's an edit of existing catalog item, else force user to select type
%h3
= _('Basic Info')
Expand Down

0 comments on commit 3c31286

Please sign in to comment.