core-resource-app-test
Version:
App that contains assets and scripts for the core apps
169 lines (148 loc) • 6.11 kB
JavaScript
import {createClass, PropTypes, default as React} from 'react';
import TextField from 'material-ui/TextField';
import Action from '../action/Action';
import {Observable, helpers, Scheduler, default as Rx} from 'rx';
import {config} from 'd2/lib/d2';
import d2Lib from 'd2/lib/d2';
import List from 'material-ui/List/List';
import ListItem from 'material-ui/List/ListItem';
import Paper from 'material-ui/Paper';
import Translate from '../i18n/Translate.mixin';
import log from 'loglevel';
config.i18n.strings.add('members');
config.i18n.strings.add('search_for_user_groups');
function searchByForModel(searchBy, modelTypeToSearch, valueToSearchFor, options = {}) {
if (!Boolean(modelTypeToSearch) || !Boolean(valueToSearchFor)) {
log.warn('forType property and value should be provided to be able to show results');
return Observable.just([]);
}
const searchQueryRequest = d2Lib.getInstance()
.then(d2 => d2.models[modelTypeToSearch])
.then(modelType => modelType.filter().on(searchBy).ilike(valueToSearchFor))
.then(modelTypeWithFilter => modelTypeWithFilter.list(options))
.then(collection => collection.toArray())
.catch(error => log.error(error));
return Observable.fromPromise(searchQueryRequest);
}
const AutoComplete = createClass({
propTypes: {
actions: PropTypes.object,
forType: PropTypes.string.isRequired,
onSuggestionClicked: PropTypes.func.isRequired,
closeOnItemClicked: PropTypes.bool,
clearValueOnItemClicked: PropTypes.bool,
filterForSuggestions: PropTypes.func,
},
mixins: [Translate],
getDefaultProps() {
return {
actions: Action.createActionsFromNames(['loadAutoCompleteSuggestions']),
debounceTime: 500,
propertyToSearchBy: 'displayName',
scheduler: Scheduler.default,
closeOnItemClicked: true,
clearValueOnItemClicked: true,
};
},
//
getInitialState() {
return {
showAutoComplete: false,
autoCompleteValues: [],
loadingSuggestions: false,
};
},
componentWillMount() {
const {actions, forType} = this.props;
let searchValue;
this.disposable = actions.loadAutoCompleteSuggestions
.map(({ data: args }) => args[1])
.tap(value => {
searchValue = value;
this.setState({
loadingSuggestions: true,
showAutoComplete: Boolean(value),
value: searchValue,
});
})
.debounce(this.props.debounceTime, this.props.scheduler)
.distinctUntilChanged()
// TODO: Do not hardcore these fields to search for
.map(valueToSearchFor => searchByForModel(this.props.propertyToSearchBy, forType, valueToSearchFor, {fields: 'id,displayName|rename(name),users::size', pageSize: 10}))
.concatAll()
.map(suggestions => Array.isArray(suggestions) ? suggestions.filter(this.props.filterForSuggestions || helpers.identity) : [])
.map(suggestions => suggestions.slice(0, 5))
.subscribe(
autoCompleteValues => this.setState({
autoCompleteValues,
loadingSuggestions: false,
value: searchValue,
}),
(errorMessage) => log.error(errorMessage)
);
},
componentWillUnmount() {
this.disposable && this.disposable.dispose();
},
onSuggestionClick(item) {
return event => {
const {
closeOnItemClicked,
clearValueOnItemClicked,
onSuggestionClicked,
} = this.props;
if (closeOnItemClicked) {
this.refs.autoCompleteField.focus();
}
if (clearValueOnItemClicked) {
this.props.actions.loadAutoCompleteSuggestions({
target: {value: ''},
});
}
this.setState({
showAutoComplete: !closeOnItemClicked,
value: clearValueOnItemClicked ? '' : this.state.value,
});
if (onSuggestionClicked) {
onSuggestionClicked(item, event);
}
};
},
// TODO: Allow the component user to specify how to render the list items or at least the primary and secondary texts
renderAutoCompleteSuggestions() {
return (
<div style={{position: 'absolute', zIndex: 100}}>
<Paper>
<List>
{this.state.autoCompleteValues.map(userGroup => {
return (
<ListItem
primaryText={userGroup.name}
secondaryText={`${userGroup.users} ${this.getTranslation('members')}`}
innerDivStyle={{paddingTop: '.5rem', paddingBottom: '.5rem'}}
onClick={this.onSuggestionClick(userGroup)}
/>
);
})}
</List>
</Paper>
</div>
);
},
render() {
const {actions, forType, ...other} = this.props;
return (
<div style={{position: 'relative'}} onClick={event => event.stopPropagation()}>
<TextField
ref="autoCompleteField" {...other}
onChange={actions.loadAutoCompleteSuggestions}
hintText={this.getTranslation('search_for_user_groups')}
value={this.state.value}
fullWidth
/>
{(this.state.showAutoComplete && !this.state.loadingSuggestions) ? this.renderAutoCompleteSuggestions() : null}
</div>
);
},
});
export default AutoComplete;