Skip to content

Commit

Permalink
Add DynamicListForm component
Browse files Browse the repository at this point in the history
  • Loading branch information
skobyda committed Sep 11, 2023
1 parent 879a1e9 commit a00eaa3
Show file tree
Hide file tree
Showing 2 changed files with 133 additions and 0 deletions.
94 changes: 94 additions & 0 deletions src/components/common/DynamicListForm.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
import React from 'react';
import PropTypes from 'prop-types';
import { Button } from "@patternfly/react-core/dist/esm/components/Button";
import { EmptyState, EmptyStateBody } from "@patternfly/react-core/dist/esm/components/EmptyState";
import { FormFieldGroup, FormFieldGroupHeader } from "@patternfly/react-core/dist/esm/components/Form";
import { HelperText, HelperTextItem } from "@patternfly/react-core/dist/esm/components/HelperText";

import './DynamicListForm.scss';

export class DynamicListForm extends React.Component {
constructor(props) {
super(props);
this.state = {
list: [],
};
this.keyCounter = 0;
this.removeItem = this.removeItem.bind(this);
this.addItem = this.addItem.bind(this);
this.onItemChange = this.onItemChange.bind(this);
}

removeItem(idx, field, value) {
this.setState(state => {
const items = state.list.concat();
items.splice(idx, 1);
return { list: items };
}, () => this.props.onChange(this.state.list.concat()));
}

addItem() {
this.setState(state => {
return { list: [...state.list, Object.assign({ key: this.keyCounter++ }, this.props.default)] };
}, () => this.props.onChange(this.state.list.concat()));
}

onItemChange(idx, field, value) {
this.setState(state => {
const items = state.list.concat();
items[idx][field] = value || null;
return { list: items };
}, () => this.props.onChange(this.state.list.concat()));
}

render () {
const { id, label, actionLabel, formclass, emptyStateString, helperText } = this.props;
const dialogValues = this.state;
return (
<FormFieldGroup header={
<FormFieldGroupHeader
titleText={{ text: label }}
actions={<Button variant="secondary" className="btn-add" onClick={this.addItem}>{actionLabel}</Button>}
/>
} className={"dynamic-form-group " + formclass}>
{
dialogValues.list.length
? <>
{dialogValues.list.map((item, idx) => {
return React.cloneElement(this.props.itemcomponent, {
idx,
item,
id: id + "-" + idx,
key: idx,
onChange: this.onItemChange,
removeitem: this.removeItem,
additem: this.addItem,
options: this.props.options,
itemCount: Object.keys(dialogValues.list).length,
});
})
}
{helperText &&
<HelperText>
<HelperTextItem>{helperText}</HelperTextItem>
</HelperText>
}
</>
: <EmptyState>
<EmptyStateBody>
{emptyStateString}
</EmptyStateBody>
</EmptyState>
}
</FormFieldGroup>
);
}
}
DynamicListForm.propTypes = {
emptyStateString: PropTypes.string.isRequired,
onChange: PropTypes.func.isRequired,
id: PropTypes.string.isRequired,
itemcomponent: PropTypes.object.isRequired,
formclass: PropTypes.string,
options: PropTypes.object,
};
39 changes: 39 additions & 0 deletions src/components/common/DynamicListForm.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
@import "global-variables";

.dynamic-form-group {
.pf-v5-c-empty-state {
padding: 0;
}

.pf-v5-c-form__label {
// Don't allow labels to wrap
white-space: nowrap;
}

.remove-button-group {
// Move 'Remove' button the the end of the row
grid-column: -1;
// Move 'Remove' button to the bottom of the line so as to align with the other form fields
display: flex;
align-items: flex-end;
}

// Set check to the same height as input widgets and vertically align
.pf-v5-c-form__group-control > .pf-v5-c-check {
// Set height to the same as inputs
// Font height is font size * line height (1rem * 1.5)
// Widgets have 5px padding, 1px border (top & bottom): (5 + 1) * 2 = 12
// This all equals to 36px
height: calc(var(--pf-v5-global--FontSize--md) * var(--pf-v5-global--LineHeight--md) + 12px);
align-content: center;
}

// We use FormFieldGroup PF component for the nested look and for ability to add buttons to the header
// However we want to save space and not add indent to the left so we need to override it
.pf-v5-c-form__field-group-body {
// Stretch content fully
--pf-v5-c-form__field-group-body--GridColumn: 1 / -1;
// Reduce padding at the top
--pf-v5-c-form__field-group-body--PaddingTop: var(--pf-v5-global--spacer--xs);
}
}

0 comments on commit a00eaa3

Please sign in to comment.