Commit 73d166b2 authored by Oleksii Savran's avatar Oleksii Savran

Merge branch '293-upgrade-autocompleters' into 'master'

Resolve "Upgrade autocompleters"

Closes #293

See merge request genesys-pgr/genesys-ui!307
parents e587c396 e0076b14
import * as React from 'react';
import { Field } from 'redux-form';
import { translate } from 'react-i18next';
import { debounce } from 'debounce';
import MenuItem from '@material-ui/core/MenuItem';
import Menu from '@material-ui/core/Menu';
import TextField from '@material-ui/core/TextField';
import FormControl from 'ui/common/forms/FormControl';
import Select from '@material-ui/core/Select';
import Input from '@material-ui/core/Input';
import MaterialAutosuggest from 'ui/common/material-autosuggest';
interface IDatasetCreatorAutocompleteFieldProps extends React.ClassAttributes<any> {
label: any;
input: any;
meta?: any;
t: any;
autocompleteCreators: (text: any) => Promise<any>;
updateDatasetCreator: (newDatasetCreator: string) => void;
......@@ -20,87 +18,64 @@ interface IDatasetCreatorAutocompleteFieldProps extends React.ClassAttributes<an
class DatasetCreatorAutocompleteField extends React.Component<IDatasetCreatorAutocompleteFieldProps> {
public state = {
disabled: false,
searchText: null,
suggestions: [],
open: false,
anchorEl: null,
};
public render() {
const { label, input, t } = this.props;
return (
<FormControl fullWidth label={ label }>
<Select
onClick={ this.handleOpen }
value={ input.value }
input={ <Input/> }
MenuProps={ {
open: false,
} }
classes={ { select: 'mui-select-rtl', icon: 'mui-select-icon-rtl' } }
>
{
<MenuItem value={ input.value }>{ input.value }</MenuItem>
}
</Select>
<Menu
anchorEl={ this.state.anchorEl }
open={ this.state.open }
onClose={ this.handleClose }
>
<MenuItem>
<TextField
fullWidth
value={ input.value }
label={ t('datasets.dashboard.p.stepper.creators.autocomplete') }
onChange={ this.handleInputChange }
/>
</MenuItem>
{
this.state.suggestions.filter((item, index, self) => self.findIndex((tmp) => tmp.fullName === item.fullName) === index).map((dCr, index) => (
<MenuItem
onClick={ () => this.select(dCr) }
key={ `dataset-creator-${ index }` }
>
<div>
<b>{ `${index + 1}. ` }</b>
<b>{ `${ dCr.fullName }` }</b>
<i>{ dCr.email && ` - ${ dCr.email }` }</i>
<div>
{ dCr.institutionalAffiliation && `${ dCr.institutionalAffiliation } - ` }
<i>{ dCr.role && `${ t(`datasets.common.creator.role.${dCr.role}`)}` }</i>
</div>
</div>
</MenuItem>
))
private onInputChange = (e) => {
if (e.target && typeof e.target.value === 'string') {
if (e.target && (e.target.value || e.target.value === '')) {
if (e.target.value !== this.state.searchText) {
if (e.target.value.length >= 3) {
this.doAutocomplete(e.target.value);
}
</Menu>
</FormControl>
);
}
private handleInputChange = (e) => {
const { input } = this.props;
this.doAutocomplete(e.target.value);
input.onChange(e.target.value);
}
this.setState({searchText: e.target.value});
}
}
}
private doAutocomplete = debounce((value) => {
this.props.autocompleteCreators(value)
.then((creators) => this.setState({ suggestions: creators }));
}, 1000);
this.props.autocompleteCreators(value).then((terms) => {
// this.updateMenuPosition();
const suggestions = terms.map((dCr, index) => ({
value: dCr.fullName,
label: `${index + 1}. ${ dCr.fullName } ${ dCr.email && `- ${dCr.email}` } ${dCr.role && this.props.t(`datasets.common.creator.role.${dCr.role}`)}`,
creator: dCr,
}));
private select = (datasetCreator) => {
const { updateDatasetCreator } = this.props;
updateDatasetCreator(datasetCreator);
this.setState({open: false});
}
this.setState({suggestions});
});
}, 1000);
private handleOpen = (e) => {
this.setState({open: true, anchorEl: e.target});
private onSuggestionSelected = (e, data, autocompleteInput, that) => {
const {updateDatasetCreator} = this.props;
this.setState({searchText: data.suggestion.value});
updateDatasetCreator(this.state.suggestions.find((creator) => creator.value === data.suggestion.value).creator);
}
private handleClose = () => {
this.setState({open: false});
public render() {
const {label, meta, input} = this.props;
const {disabled, searchText} = this.state;
return (
<FormControl fullWidth meta={ meta } disabled={ disabled }>
<Field
name={ `auto-${ input.name }` }
component={ MaterialAutosuggest }
label={ label }
suggestions={ this.state.suggestions }
onSuggestionSelected={ this.onSuggestionSelected }
suggestionLabel="label"
className="full-width"
input={ {
...input,
value: searchText || searchText === '' ? searchText : input && input.value,
onChange: this.onInputChange,
} }
/>
</FormControl>
);
}
}
......
......@@ -11,162 +11,77 @@ import VocabularyTerm from 'model/vocabulary/VocabularyTerm';
import { autocompleteGeoTerm } from 'vocabulary/actions/dashboard';
import { getCountry } from 'geo/actions/public';
// ui
import Menu from '@material-ui/core/Menu';
import MenuItem from '@material-ui/core/MenuItem';
import Input from '@material-ui/core/Input';
import TextField from '@material-ui/core/TextField';
import FormControl from 'ui/common/forms/FormControl';
import Select from '@material-ui/core/Select';
import MaterialAutosuggest from 'ui/common/material-autosuggest';
interface ISelectCountryCodeInternal extends React.ClassAttributes<any> {
interface ICountryCodePicker extends React.ClassAttributes<any> {
input: any;
listVocabularyTerms: VocabularyTerm[];
autocomplete: (term: string) => Promise<VocabularyTerm[]>;
getCountry: (code: string) => Promise<any>;
label: string;
meta?: any;
className?: string;
autocomplete: (term: string) => Promise<VocabularyTerm[]>;
t: any;
}
class SelectCountryInternal extends React.Component<ISelectCountryCodeInternal, any> {
protected handleInputChange = (event) => {
this.setState({ searchText: event.target.value });
if (event.target.value) {
this.doAutocomplete(event.target.value);
}
}
private doAutocomplete = debounce((value) => {
this.props.autocomplete(value).then((suggestions) => {
this.setState({ suggestions });
});
}, 1000);
protected handleClick = (event) => {
this.setState({ open: true, anchorEl: event.currentTarget });
}
protected handleRequestClose = () => {
this.setState({ open: false });
}
protected select = (value) => (event) => {
const { input } = this.props;
const countryCodeTerm = this.state.suggestions.find((dl) => dl.code === value);
if (countryCodeTerm) {
input.onChange(countryCodeTerm.code);
this.setState({
open: false,
pickerList: { code: countryCodeTerm.code, title: countryCodeTerm.title },
});
} else {
input.onChange('');
this.setState({
open: false,
pickerList: null,
});
}
}
class CountryCodePicker extends React.Component<ICountryCodePicker, any> {
private constructor(props, context) {
super(props, context);
this.state = {
pickerList: null,
open: false,
anchorEl: null,
searchText: '',
disabled: false,
searchText: null,
suggestions: [],
};
}
public componentWillMount() {
if (this.props.input.value) {
this.setState({ pickerList: { code: this.props.input.value } });
}
}
public componentWillReceiveProps(nextProps) {
const {getCountry} = this.props;
if (!nextProps.input.value) {
return this.setState({ pickerList: null });
}
if (nextProps.input.value !== this.props.input.value) {
const code = nextProps.input.value;
const countryCodeTerm = this.state.suggestions.find((dl) => dl.code === code);
if (countryCodeTerm) {
this.setState({ pickerList: { code: countryCodeTerm.code, title: countryCodeTerm.title } });
} else {
getCountry(code).then((dl) => {
this.setState({ pickerList: { code: dl.code, title: dl.title } });
});
private onInputChange = (e) => {
if (e.target && typeof e.target.value === 'string') {
if (e.target && (e.target.value || e.target.value === '')) {
if (e.target.value !== this.state.searchText) {
if (e.target.value.length >= 3) {
this.doAutocomplete(e.target.value);
}
}
this.setState({searchText: e.target.value});
}
}
}
public render() {
const { label, meta, t } = this.props;
const inputValue = this.state.pickerList && this.state.pickerList.code ? this.state.pickerList.code : '';
return (
<FormControl fullWidth meta={ meta } label={ label }>
<Select
onClick={ this.handleClick }
value={ inputValue }
input={ <Input/> }
MenuProps={ {
open: false,
} }
classes={ { select: 'mui-select-rtl', icon: 'mui-select-icon-rtl' } }
>
{
this.state.pickerList ? <MenuItem value={ inputValue }>{ this.state.pickerList.code }</MenuItem> : null
}
</Select>
<Menu
anchorEl={ this.state.anchorEl }
open={ this.state.open }
onClose={ this.handleRequestClose }
>
<MenuItem>
<TextField
fullWidth
value={ this.state.searchText }
label={ t('datasets.dashboard.p.stepper.location.search') }
onChange={ this.handleInputChange }
/>
</MenuItem>
{
this.state.suggestions.map((cCT, index) => (
<MenuItem onClick={ this.select(cCT.code) } key={ `country-iso3-${index}` }>{ `${cCT.code} - ${cCT.title}` }</MenuItem>
))
}
</Menu>
</FormControl>
);
}
}
private doAutocomplete = debounce((value) => {
this.props.autocomplete(value).then((terms) => {
// this.updateMenuPosition();
const suggestions = terms.map((term) => ({value: term.code, label: `${ term.code } - ${ term.title }`}));
interface ICountryCodePicker extends React.ClassAttributes<any> {
input: any;
label: string;
className?: string;
autocomplete: (term: string) => Promise<VocabularyTerm[]>;
t: any;
}
this.setState({suggestions});
});
}, 1000);
class CountryCodePicker extends React.Component<ICountryCodePicker, any> {
private onSuggestionSelected = (e, data, autocompleteInput, that) => {
const {input} = this.props;
this.setState({searchText: data.suggestion.value});
input.onChange(data.suggestion.value);
}
public render() {
const { input: { name }, label, className, autocomplete, t } = this.props;
const {label, meta, input} = this.props;
const {disabled, searchText} = this.state;
return (
<div className={ className }>
<FormControl fullWidth meta={ meta } disabled={ disabled }>
<Field
name={ name }
component={ SelectCountryInternal }
name={ `auto-${ input.name }` }
component={ MaterialAutosuggest }
label={ label }
autocomplete={ autocomplete }
t={ t }
suggestions={ this.state.suggestions }
onSuggestionSelected={ this.onSuggestionSelected }
suggestionLabel="label"
className="full-width"
input={ {
...input,
value: searchText || searchText === '' ? searchText : input && input.value,
onChange: this.onInputChange,
} }
/>
</div>
</FormControl>
);
}
}
......
......@@ -55,7 +55,7 @@ export const updateRoute = (paged: FilteredPage<Descriptor>) => (dispatch) => {
s: paged.sort[0].property === Descriptor.DEFAULT_SORT.property ? undefined : paged.sort[0].property,
d: paged.sort[0].direction === Descriptor.DEFAULT_SORT.direction ? undefined : paged.sort[0].direction,
};
dispatch(filterCodeToUrl(`/descriptors/`, paged.filterCode, qs));
dispatch(filterCodeToUrl(`/descriptors`, paged.filterCode, qs));
};
export const applyFilters = (filters: string | DescriptorFilter, page: IPageRequest = { page: 0 }) => (dispatch) => {
......
......@@ -8,13 +8,8 @@ import DescriptorList from 'model/catalog/DescriptorList';
import { autocomplete, promiseDescriptorList } from 'descriptorlists/actions/public';
import { Field } from 'redux-form';
import Menu from '@material-ui/core/Menu';
import MenuItem from '@material-ui/core/MenuItem';
import Input from '@material-ui/core/Input';
import TextField from '@material-ui/core/TextField';
import FormControl from 'ui/common/forms/FormControl';
import Select from '@material-ui/core/Select';
import Markdown from 'ui/common/markdown';
import MaterialAutosuggest from 'ui/common/material-autosuggest';
interface ISelectDescriptorListInternal extends React.ClassAttributes<any> {
input: any;
......@@ -28,119 +23,82 @@ interface ISelectDescriptorListInternal extends React.ClassAttributes<any> {
class SelectDescriptorListInternal extends React.Component<ISelectDescriptorListInternal, any> {
protected handleInputChange = (event) => {
this.setState({ searchText: event.target.value });
this.doAutocomplete(event.target.value);
}
private doAutocomplete = debounce((value) => {
this.props.autocomplete(value).then((suggestions) => {
this.setState({ suggestions });
});
}, 1000);
protected handleClick = (event) => {
this.setState({ open: true, anchorEl: event.currentTarget });
}
protected handleRequestClose = () => {
this.setState({ open: false });
}
protected select = (value) => (event) => {
const { input } = this.props;
const descriptorList = this.state.suggestions.find((dl) => dl.uuid === value);
if (descriptorList) {
input.onChange({ uuid: [descriptorList.uuid] });
this.setState({
open: false,
pickerList: { uuid: descriptorList.uuid, title: descriptorList.title },
});
} else {
input.onChange('');
this.setState({
open: false,
pickerList: null,
});
}
}
private constructor(props, context) {
super(props, context);
this.state = {
pickerList: null,
open: false,
anchorEl: null,
searchText: '',
disabled: false,
searchText: null,
suggestions: [],
};
}
public componentWillMount() {
if (this.props.input.value && this.props.input.value.uuid) {
this.props.loadDescriptorList(this.props.input.value.uuid[0]).then((dl) => {
this.setState({ pickerList: { uuid: dl.uuid, title: dl.title } });
});
private onInputChange = (e) => {
if (e.target && typeof e.target.value === 'string') {
if (e.target && (e.target.value || e.target.value === '')) {
if (e.target.value !== this.state.text) {
if (e.target.value.length >= 3) {
this.doAutocomplete(e.target.value);
}
}
this.setState({searchText: e.target.value});
}
}
this.props.autocomplete('').then((data) => {
this.setState({ suggestions: data });
}
private doAutocomplete = debounce((value) => {
this.props.autocomplete(value).then((terms) => {
// this.updateMenuPosition();
const suggestions = terms.map((term) => ({value: term.uuid, label: `${ term.title }`}));
this.setState({suggestions});
});
}, 1000);
public componentWillMount() {
const {input: {value}, loadDescriptorList} = this.props;
if (value) {
loadDescriptorList(value[0])
.then((term) => this.setState({searchText: `${term.title}`}));
this.setState({disabled: true});
}
}
public componentWillReceiveProps(nextProps) {
if (nextProps.input.value && nextProps.input.value.uuid && nextProps.input.value.uuid.length > 0) {
const uuid = nextProps.input.value.uuid[0];
const descriptorList = this.state.suggestions.find((dl) => dl.uuid === uuid);
if (descriptorList) {
this.setState({ pickerList: { uuid: descriptorList.uuid, title: descriptorList.title } });
} else {
this.props.loadDescriptorList(uuid).then((dl) => {
this.setState({ pickerList: { uuid: dl.uuid, title: dl.title } });
});
}
const {input: {value}, loadDescriptorList} = nextProps;
if (value) {
loadDescriptorList(value[0])
.then((term) => this.setState({searchText: `${term.title}`}));
this.setState({disabled: true});
} else {
this.setState({ pickerList: null });
this.setState({searchText: ''});
}
}
private onSuggestionSelected = (e, data, autocompleteInput, that) => {
const {input} = this.props;
e.preventDefault();
this.setState({searchText: data.suggestion.label});
input.onChange([data.suggestion.value]);
}
public render() {
const { label, meta, t } = this.props;
const inputValue = this.state.pickerList && this.state.pickerList.uuid ? this.state.pickerList.uuid : '';
const {label, meta, input} = this.props;
const {disabled, searchText} = this.state;
return (
<FormControl fullWidth meta={ meta } label={ label }>
<Select
onClick={ this.handleClick }
value={ inputValue }
input={ <Input/> }
MenuProps={ {
open: false,
<FormControl fullWidth meta={ meta } disabled={ disabled }>
<MaterialAutosuggest
name={ `auto-${ input.name }` }
label={ label }
suggestions={ this.state.suggestions }
onSuggestionSelected={ this.onSuggestionSelected }
suggestionLabel="label"
className="full-width"
input={ {
value: searchText || searchText === '' ? searchText : input && input.value && input.value[0],
onChange: this.onInputChange,
} }
classes={ { select: 'mui-select-rtl', icon: 'mui-select-icon-rtl' } }
>
{
this.state.pickerList ? (
<MenuItem value={ inputValue }>
<Markdown basic source={ this.state.pickerList.title }/>
</MenuItem>) : null
}
</Select>
<Menu
anchorEl={ this.state.anchorEl }
open={ this.state.open }
onClose={ this.handleRequestClose }
>
<MenuItem>
<TextField
fullWidth
value={ this.state.searchText }
label={ t('descriptors.dashboard.c.listPicker.search') }
onChange={ this.handleInputChange }
/>
</MenuItem>
{
this.state.suggestions.map((dl, index) => (
<MenuItem onClick={ this.select(dl.uuid) } key={ `descriptor-list-${index}` }>
<Markdown basic source={ dl.title }/>
</MenuItem>
))
}
</Menu>
/>
</FormControl>
);
}
......
......@@ -18,7 +18,7 @@ const DescriptorFilters = ({ handleSubmit, initialize, t, ...other }) => (
<FiltersBlock title={ t('descriptors.common.modelName_plural') } handleSubmit={ handleSubmit } initialize={ initialize } { ...other }>
<TextFilter name="_text" label={ t('common:f.keyword') } placeholder={ t('descriptors.public.f.rice') } className="p-20"/>
<PartnerFilter name="owner" label={ t('descriptors.public.f.partner') } className="p-20"/>
<DescriptorListPicker name="descriptorLists" label={ t('descriptors.public.f.select') } className="p-20"/>
<DescriptorListPicker name="descriptorLists.uuid" label={ t('descriptors.public.f.select') } className="p-20"/>
<CollapsibleComponentSearch title={ t('descriptors.public.f.crop') }>
<CropFilter/>
</CollapsibleComponentSearch>
......
......@@ -44,10 +44,9 @@ class PartnerEditPage extends React.Component<IPartnerEditPageProps, any> {
savePartner(partner)
.then((newPartner) => {
return partner.institutes && partner.institutes.length > 0 ?
addPartnerInstitutes(newPartner.uuid, partner.institutes.map((inst) => inst.code))
.then((partnerWithSavedInstitutes) => navigateTo(`/partners/${partnerWithSavedInstitutes.uuid}`))
: navigateTo(`/partners/${newPartner.uuid}`);
navigateTo(`/partners/${newPartner.uuid}`);
return partner.institutes && partner.institutes.length > 0 &&
addPartnerInstitutes(newPartner.uuid, partner.institutes);
});
}
......@@ -89,8 +88,8 @@ class PartnerEditPage extends React.Component<IPartnerEditPageProps, any> {
<Paper className="p-20">
{ partner ?
<PartnerForm
initialValues={ {...partner, institutes} }
initialInstitutes={ institutes }
initialValues={ {...partner, institutes: institutes && institutes.map((inst) => inst.code)} }
initialInstitutes={ institutes && institutes.map((inst) => inst.code) }
onSubmit={ this.onSave }
removePartnerInstitute={ removePartnerInstitute }
t={ t }
......
......@@ -7,179 +7,92 @@ import { debounce } from 'debounce';
import {autocompleteWiewsTerm, loadWiewsTerm} from 'vocabulary/actions/public';
import { Field } from 'redux-form';
import Menu from '@material-ui/core/Menu';
import MenuItem from '@material-ui/core/MenuItem';
import Input from '@material-ui/core/Input';
import TextField from '@material-ui/core/TextField';
import FormControl from 'ui/common/forms/FormControl';
import Select from '@material-ui/core/Select';
import Markdown from 'ui/common/markdown';
import MaterialAutosuggest from 'ui/common/material-autosuggest';
interface ISelectFaoInstituteInternal extends React.ClassAttributes<any> {
interface IFaoInstitutePicker extends React.ClassAttributes<any> {
input: any;
name: string;
meta?: any;
label: string;
loadWiewsTerm: (code) => Promise<any>;
autocompleteWiewsTerm: (code) => Promise<any>;
meta?: any;
className?: string;
t: any;
}
class SelectFaoInstituteInternal extends React.Component<ISelectFaoInstituteInternal, any> {
public updateMenuPosition = null;
class FaoInstitutePicker extends React.Component<IFaoInstitutePicker, any> {
protected handleInputChange = (event) => {
this.setState({searchText: event.target.value});
if (event.target.value) {
this.doAutocomplete(event.target.value);
private onInputChange = (e) => {
if (e.target && typeof e.target.value === 'string') {
if (e.target && (e.target.value || e.target.value === '')) {
if (e.target.value !== this.state.text) {
if (e.target.value.length >= 3) {
this.doAutocomplete(e.target.value);
}
}
this.setState({searchText: e.target.value});
}
}
}
private doAutocomplete = debounce((value) => {
this.props.autocompleteWiewsTerm(value).then((suggestions) => {
this.updateMenuPosition();
this.props.autocompleteWiewsTerm(value).then((terms) => {
// this.updateMenuPosition();
const suggestions = terms.map((term) => ({value: term.code, label: `${term.code}, ${term.title}`}));
this.setState({suggestions});
});
}, 1000);
protected handleClick = (event) => {
this.setState({open: true, anchorEl: event.currentTarget});
}
protected handleRequestClose = () => {
this.setState({open: false});
}
protected select = (value) => (event) => {
const {input} = this.