@bigfishtv/cockpit
Version:
148 lines (136 loc) • 4.72 kB
JavaScript
import PropTypes from 'prop-types'
import React, { Component } from 'react'
import { withFormValue, Fieldset } from '@bigfishtv/react-forms'
import { connect } from 'react-redux'
import _get from 'lodash/get'
import MainContent from '../container/MainContent'
import Bulkhead from '../page/Bulkhead'
import Panel from '../container/panel/Panel'
import Button from '../button/Button'
import Checkbox from '../input/Checkbox'
import Field from '../form/Field'
import EditForm from '../form/EditForm'
import { notifySuccess, notifyFailure } from '../../actions/notifications'
import { titleCase } from '../../utils/stringUtils'
import {
resolveFieldInputFromColumn,
filterOutProtectedEditSchema,
getSchemaWithAssociations,
} from '../../utils/formUtils'
const DefaultToolbar = props => <Button type="submit" text="Save" style="secondary" size="large" />
/**
* Used for automatically generating an entity edit page, relies on associations, schema, and a few assumptions.
*/
()
export default class AutoEdit extends Component {
static propTypes = {
/** the lowercase plural model e.g. volunteer_applications */
model: PropTypes.string,
/** to be used for things like buttons e.g. Volunteer Application */
modelLabel: PropTypes.string,
/** array of entity assocations passed in from backend */
associations: PropTypes.array,
/** array of table schema passed in from backend */
schema: PropTypes.array,
/** the entity */
defaultValue: PropTypes.object,
/** function that receives assocations and schema column, returns a component */
componentResolver: PropTypes.func,
/** array of objects, containing schema array and title, these become panels on the right. panel schema shouldn't be in main schema */
panels: PropTypes.arrayOf(
PropTypes.shape({
title: PropTypes.string,
schema: PropTypes.arrayOf(PropTypes.object),
})
),
}
static defaultProps = {
modelLabel: 'item',
associations: [],
schema: [],
panels: [],
componentResolver: null,
Toolbar: DefaultToolbar,
}
getSubmitUrl = data => {
if (data.id) {
return '/admin/' + this.props.model + '/edit/' + data.id + '.json'
} else {
return '/admin/' + this.props.model + '/add.json'
}
}
handleSubmitSuccess = data => {
const { dispatch, model, modelLabel } = this.props
dispatch(notifySuccess('The ' + modelLabel + ' has been saved.'))
history.replaceState(null, null, '/admin/' + model + '/edit/' + data.id)
}
handleSubmitError = () => {
this.props.dispatch(notifyFailure('The ' + this.props.modelLabel + ' could not be saved.'))
}
render() {
const { schema, associations, panels, modelLabel, componentResolver, Toolbar, ...props } = this.props
const columns = getSchemaWithAssociations(filterOutProtectedEditSchema(schema), associations)
return (
<MainContent>
<EditForm
submitUrl={this.getSubmitUrl}
onSubmitSuccess={this.handleSubmitSuccess}
onSubmitError={this.handleSubmitError}
Header={withFormValue(props => (
<Bulkhead
title={
_get(props.formValue, 'value.id') ? 'Edit ' + titleCase(modelLabel) : 'New ' + titleCase(modelLabel)
}
Toolbar={Toolbar}
/>
))}
{...props}
panels={panels}
associations={associations}
componentResolver={componentResolver}
Sidebar={panels.length ? AutoEditSidebar : null}>
<Panel>
<Fieldset>
{columns.map((column, i) => {
const InputComponent =
(componentResolver && componentResolver(column)) || resolveFieldInputFromColumn(associations, column)
const fieldProps = column.fieldProps || {}
return (
<Field
key={i}
select={column.property}
autoLabel={InputComponent != Checkbox}
text={InputComponent === Checkbox && column.title}>
{InputComponent && <InputComponent {...fieldProps} />}
</Field>
)
})}
</Fieldset>
</Panel>
</EditForm>
</MainContent>
)
}
}
const AutoEditSidebar = withFormValue(({ panels, associations, componentResolver, ...props }) => (
<div>
{panels.map((panel, p) => (
<Panel key={p} title={panel.title} collapsible uncontrolled>
{panel.schema.map((column, i) => {
const InputComponent =
(componentResolver && componentResolver(column)) || resolveFieldInputFromColumn(associations, column)
const fieldProps = column.fieldProps || {}
return (
<Field
key={i}
select={column.property}
autoLabel={InputComponent != Checkbox}
text={InputComponent === Checkbox && column.title}>
{InputComponent && <InputComponent {...fieldProps} />}
</Field>
)
})}
</Panel>
))}
</div>
))