Add metadata to draft entry fields (#196)
* Add metadata to draft entry fields * Do not render widget if value is null * Pass along metadata * Namespace queries to avoid conflict * Query relational field on mount (for when editing entries) * Make sure metadata is Immutable * Added collection name as metadata keys
This commit is contained in:
@ -10,10 +10,11 @@ function isHidden(field) {
|
||||
export default class ControlPane extends Component {
|
||||
|
||||
controlFor(field) {
|
||||
const { entry, getMedia, onChange, onAddMedia, onRemoveMedia } = this.props;
|
||||
const { entry, fieldsMetaData, getMedia, onChange, onAddMedia, onRemoveMedia } = this.props;
|
||||
const widget = resolveWidget(field.get('widget'));
|
||||
const fieldName = field.get('name');
|
||||
const value = entry.getIn(['data', fieldName]);
|
||||
const metadata = fieldsMetaData.get(fieldName);
|
||||
if (entry.size === 0 || entry.get('partial') === true) return null;
|
||||
return (
|
||||
<div className={styles.control}>
|
||||
@ -22,7 +23,8 @@ export default class ControlPane extends Component {
|
||||
React.createElement(widget.control, {
|
||||
field,
|
||||
value,
|
||||
onChange: val => onChange(entry.setIn(['data', fieldName], val)),
|
||||
metadata,
|
||||
onChange: (newValue, newMetadata) => onChange(fieldName, newValue, newMetadata),
|
||||
onAddMedia,
|
||||
onRemoveMedia,
|
||||
getMedia,
|
||||
@ -57,6 +59,7 @@ ControlPane.propTypes = {
|
||||
collection: ImmutablePropTypes.map.isRequired,
|
||||
entry: ImmutablePropTypes.map.isRequired,
|
||||
fields: ImmutablePropTypes.list.isRequired,
|
||||
fieldsMetaData: ImmutablePropTypes.map.isRequired,
|
||||
getMedia: PropTypes.func.isRequired,
|
||||
onAddMedia: PropTypes.func.isRequired,
|
||||
onChange: PropTypes.func.isRequired,
|
||||
|
@ -25,6 +25,7 @@ class EntryEditor extends Component {
|
||||
collection,
|
||||
entry,
|
||||
fields,
|
||||
fieldsMetaData,
|
||||
getMedia,
|
||||
onChange,
|
||||
onAddMedia,
|
||||
@ -51,6 +52,7 @@ class EntryEditor extends Component {
|
||||
collection={collection}
|
||||
entry={entry}
|
||||
fields={fields}
|
||||
fieldsMetaData={fieldsMetaData}
|
||||
getMedia={getMedia}
|
||||
onChange={onChange}
|
||||
onAddMedia={onAddMedia}
|
||||
@ -64,6 +66,7 @@ class EntryEditor extends Component {
|
||||
collection={collection}
|
||||
entry={entry}
|
||||
fields={fields}
|
||||
fieldsMetaData={fieldsMetaData}
|
||||
getMedia={getMedia}
|
||||
/>
|
||||
</div>
|
||||
@ -87,6 +90,7 @@ EntryEditor.propTypes = {
|
||||
collection: ImmutablePropTypes.map.isRequired,
|
||||
entry: ImmutablePropTypes.map.isRequired,
|
||||
fields: ImmutablePropTypes.list.isRequired,
|
||||
fieldsMetaData: ImmutablePropTypes.map.isRequired,
|
||||
getMedia: PropTypes.func.isRequired,
|
||||
onAddMedia: PropTypes.func.isRequired,
|
||||
onChange: PropTypes.func.isRequired,
|
||||
|
@ -29,20 +29,23 @@ export default class PreviewPane extends React.Component {
|
||||
}
|
||||
|
||||
widgetFor = (name) => {
|
||||
const { fields, entry, getMedia } = this.props;
|
||||
const { fields, entry, fieldsMetaData, getMedia } = this.props;
|
||||
const field = fields.find(f => f.get('name') === name);
|
||||
let value = entry.getIn(['data', field.get('name')]);
|
||||
const metadata = fieldsMetaData.get(field.get('name'));
|
||||
const labelledWidgets = ['string', 'text', 'number'];
|
||||
if (Object.keys(this.inferedFields).indexOf(name) !== -1) {
|
||||
value = this.inferedFields[name].defaultPreview(value);
|
||||
} else if (value && labelledWidgets.indexOf(field.get('widget')) !== -1 && value.toString().length < 50) {
|
||||
value = <div><strong>{field.get('label')}:</strong> {value}</div>;
|
||||
}
|
||||
if (!value) return null;
|
||||
const widget = resolveWidget(field.get('widget'));
|
||||
return React.createElement(widget.preview, {
|
||||
key: field.get('name'),
|
||||
value,
|
||||
field,
|
||||
metadata,
|
||||
getMedia,
|
||||
});
|
||||
};
|
||||
@ -100,5 +103,6 @@ PreviewPane.propTypes = {
|
||||
collection: ImmutablePropTypes.map.isRequired,
|
||||
fields: ImmutablePropTypes.list.isRequired,
|
||||
entry: ImmutablePropTypes.map.isRequired,
|
||||
fieldsMetaData: ImmutablePropTypes.map.isRequired,
|
||||
getMedia: PropTypes.func.isRequired,
|
||||
};
|
||||
|
@ -83,10 +83,10 @@ export default class ListControl extends Component {
|
||||
};
|
||||
|
||||
handleChangeFor(index) {
|
||||
return (newValue) => {
|
||||
return (newValue, newMetadata) => {
|
||||
const { value, onChange } = this.props;
|
||||
const parsedValue = (this.valueType === valueTypes.SINGLE) ? newValue.first() : newValue;
|
||||
onChange(value.set(index, parsedValue));
|
||||
onChange(value.set(index, parsedValue), newMetadata);
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -25,8 +25,8 @@ export default class ObjectControl extends Component {
|
||||
React.createElement(widget.control, {
|
||||
field,
|
||||
value: fieldValue,
|
||||
onChange: (val) => {
|
||||
onChange((value || Map()).set(field.get('name'), val));
|
||||
onChange: (val, metadata) => {
|
||||
onChange((value || Map()).set(field.get('name'), val), metadata);
|
||||
},
|
||||
onAddMedia,
|
||||
onRemoveMedia,
|
||||
|
@ -1,5 +1,7 @@
|
||||
import React, { Component, PropTypes } from 'react';
|
||||
import Autosuggest from 'react-autosuggest';
|
||||
import uuid from 'uuid';
|
||||
import { Map } from 'immutable';
|
||||
import { connect } from 'react-redux';
|
||||
import { debounce } from 'lodash';
|
||||
import { Loader } from '../../components/UI/index';
|
||||
@ -15,22 +17,57 @@ class RelationControl extends Component {
|
||||
onChange: PropTypes.func.isRequired,
|
||||
value: PropTypes.node,
|
||||
field: PropTypes.node,
|
||||
isFetching: PropTypes.bool,
|
||||
isFetching: PropTypes.node,
|
||||
query: PropTypes.func.isRequired,
|
||||
clearSearch: PropTypes.func.isRequired,
|
||||
queryHits: PropTypes.array, // eslint-disable-line
|
||||
queryHits: PropTypes.oneOfType([
|
||||
PropTypes.array,
|
||||
PropTypes.object,
|
||||
]),
|
||||
};
|
||||
|
||||
constructor(props, ctx) {
|
||||
super(props, ctx);
|
||||
this.controlID = uuid.v4();
|
||||
this.didInitialSearch = false;
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
const { value, field } = this.props;
|
||||
if (value) {
|
||||
const collection = field.get('collection');
|
||||
const searchFields = field.get('searchFields').map(f => `data.${ f }`).toJS();
|
||||
this.props.query(this.controlID, collection, searchFields, value);
|
||||
}
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps) {
|
||||
if (this.didInitialSearch) return;
|
||||
if (nextProps.queryHits !== this.props.queryHits && nextProps.queryHits.get && nextProps.queryHits.get(this.controlID)) {
|
||||
this.didInitialSearch = true;
|
||||
const suggestion = nextProps.queryHits.get(this.controlID);
|
||||
if (suggestion && suggestion.length === 1) {
|
||||
const val = this.getSuggestionValue(suggestion[0]);
|
||||
this.props.onChange(val, { [nextProps.field.get('collection')]: { [val]: suggestion[0].data } });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onChange = (event, { newValue }) => {
|
||||
this.props.onChange(newValue);
|
||||
};
|
||||
|
||||
onSuggestionSelected = (event, { suggestion }) => {
|
||||
const value = this.getSuggestionValue(suggestion);
|
||||
this.props.onChange(value, { [this.props.field.get('collection')]: { [value]: suggestion.data } });
|
||||
};
|
||||
|
||||
onSuggestionsFetchRequested = debounce(({ value }) => {
|
||||
if (value.length < 3) return;
|
||||
if (value.length < 2) return;
|
||||
const { field } = this.props;
|
||||
const collection = field.get('collection');
|
||||
const searchFields = field.get('searchFields').map(f => `data.${ f }`).toJS();
|
||||
this.props.query(collection, searchFields, value);
|
||||
this.props.query(this.controlID, collection, searchFields, value);
|
||||
}, 80);
|
||||
|
||||
onSuggestionsClearRequested = () => {
|
||||
@ -46,8 +83,7 @@ class RelationControl extends Component {
|
||||
if (escapedValue === '') {
|
||||
return [];
|
||||
}
|
||||
|
||||
return queryHits.filter((hit) => {
|
||||
return queryHits.get(this.controlID).filter((hit) => {
|
||||
let testResult = false;
|
||||
searchFields.forEach((f) => {
|
||||
testResult = testResult || regex.test(hit.data[f]);
|
||||
@ -77,17 +113,20 @@ class RelationControl extends Component {
|
||||
onChange: this.onChange,
|
||||
};
|
||||
|
||||
const suggestions = (queryHits.get) ? queryHits.get(this.controlID, []) : [];
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Autosuggest
|
||||
suggestions={queryHits}
|
||||
onSuggestionsFetchRequested={this.onSuggestionsFetchRequested} // eslint-disable-line
|
||||
onSuggestionsClearRequested={this.onSuggestionsClearRequested} // eslint-disable-line
|
||||
suggestions={suggestions}
|
||||
onSuggestionsFetchRequested={this.onSuggestionsFetchRequested}
|
||||
onSuggestionsClearRequested={this.onSuggestionsClearRequested}
|
||||
onSuggestionSelected={this.onSuggestionSelected}
|
||||
getSuggestionValue={this.getSuggestionValue}
|
||||
renderSuggestion={this.renderSuggestion}
|
||||
inputProps={inputProps}
|
||||
/>
|
||||
<Loader active={isFetching} />
|
||||
<Loader active={isFetching === this.controlID} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
Reference in New Issue
Block a user