Commit d7b1eec5 authored by Oleksii Savran's avatar Oleksii Savran Committed by Viacheslav Pavlov

Add infinite loading to Select descriptors step

Fixed loadMore, moved addAllButton to pagination component
parent f8b43467
......@@ -5,14 +5,12 @@ import { bindActionCreators } from 'redux';
import { log } from 'utilities/debug';
import { parse } from 'query-string';
import { listAccessibleDescriptors } from 'descriptors/actions/dashboard';
import { listAccessibleDescriptors, moreAccessibleDescriptors, clearDescriptors } from 'descriptors/actions/dashboard';
import { addDescriptorsToDataset, removeDescriptorsFromDataset } from 'datasets/actions/editor';
import Descriptor from 'model/catalog/Descriptor';
import DescriptorFilter from 'model/catalog/DescriptorFilter';
import DescriptorPicker from 'descriptors/ui/c/DescriptorPicker';
import { loadCrops } from 'crop/actions/public';
import Pagination from 'model/Pagination';
import StepperTemplate from 'ui/common/stepper/StepperTemplate';
class Traits extends StepperTemplate<any> {
......@@ -66,6 +64,8 @@ class Traits extends StepperTemplate<any> {
protected renderContent = () => this.props.item ? (
<DescriptorPicker
loadDescriptors={ this.props.listAccessibleDescriptors }
loadMoreDescriptors={ this.props.moreAccessibleDescriptors }
clearDescriptors={ this.props.clearDescriptors }
matchingDescriptors={ this.props.matchingDescriptors }
currentDescriptors={ this.props.item.descriptors }
onAddDescriptor={ this.addDescriptor }
......@@ -74,7 +74,12 @@ class Traits extends StepperTemplate<any> {
onAddAllDescriptors={ this.addAllDescriptors }
history={ this.props.history }
location={ this.props.location }
pagination={ this.props.pagination }
pagination={ {
page: this.props.page,
size: this.props.size,
sort: this.props.sort,
dir: this.props.dir,
} }
loadCrops={ this.props.loadCrops }
classes={ {} }
/>
......@@ -90,12 +95,10 @@ class Traits extends StepperTemplate<any> {
const mapStateToProps = (state, ownProps) => ({
matchingDescriptors: state.descriptors.dashboard.paged ? state.descriptors.dashboard.paged.data : undefined,
pagination: new Pagination<DescriptorFilter>({
page: +parse(ownProps.location.search).p || 0, // current page
size: +parse(ownProps.location.search).l || 20, // page size
sort: parse(ownProps.location.search).s, // page sorts
dir: parse(ownProps.location.search).d, // page sort directions
}),
page: +parse(ownProps.location.search).p || 0, // current page
size: +parse(ownProps.location.search).l || 20, // page size
sort: parse(ownProps.location.search).s, // page sorts
dir: parse(ownProps.location.search).d, // page sort directions
});
const mapDispatchToProps = (dispatch) => bindActionCreators({
......@@ -103,6 +106,8 @@ const mapDispatchToProps = (dispatch) => bindActionCreators({
addDescriptorsToDataset,
removeDescriptorsFromDataset,
loadCrops,
moreAccessibleDescriptors,
clearDescriptors,
}, dispatch);
export default connect(
......
......@@ -6,11 +6,12 @@ import { log } from 'utilities/debug';
import DescriptorList from 'model/catalog/DescriptorList';
import Descriptor from 'model/catalog/Descriptor';
import DescriptorFilter from 'model/catalog/DescriptorFilter';
import FilteredPage from 'model/FilteredPage';
import { loadCrops } from 'crop/actions/public';
import DescriptorPicker from 'descriptors/ui/c/DescriptorPicker';
import { importDescriptor } from 'descriptors/actions/editor';
import { listAccessibleDescriptors } from 'descriptors/actions/dashboard';
import { listAccessibleDescriptors, moreAccessibleDescriptors, clearDescriptors } from 'descriptors/actions/dashboard';
import Page, { IPageRequest } from 'model/Page';
import Pagination from 'model/Pagination';
import {
......@@ -25,11 +26,18 @@ interface IDescriptorListProps extends React.ClassAttributes<any> {
pagination?: Pagination<DescriptorFilter>;
matchingDescriptors: Page<Descriptor>;
listAccessibleDescriptors: (page?: IPageRequest, filter?: DescriptorFilter) => void;
moreAccessibleDescriptors: (paged?: FilteredPage<Descriptor>, filter?: string | DescriptorFilter) => void;
clearDescriptors: () => void;
addDescriptorToDescriptorList: any;
addDescriptorsToDescriptorList: (descriptorList: DescriptorList, descriptorUuids: string[]) => void;
removeDescriptorsFromDescriptorList: (descriptorList: DescriptorList, descriptorUuids: string[]) => void;
removeDescriptorFromDescriptorList: any;
loadCrops: () => any;
filterCode: any;
page: number;
size: number;
dir: string;
sort: string;
}
class SelectDescriptorsStep extends StepperTemplate<IDescriptorListProps> {
......@@ -40,13 +48,20 @@ class SelectDescriptorsStep extends StepperTemplate<IDescriptorListProps> {
protected renderContent = () => (
<DescriptorPicker
loadDescriptors={ this.props.listAccessibleDescriptors }
loadMoreDescriptors={ this.props.moreAccessibleDescriptors }
clearDescriptors={ this.props.clearDescriptors }
matchingDescriptors={ this.props.matchingDescriptors }
currentDescriptors={ this.props.item && this.props.item.descriptors }
onAddDescriptor={ this.addDescriptor }
onRemoveAllDescriptors={ this.removeAllDescriptors }
onRemoveDescriptor={ this.removeDescriptor }
onAddAllDescriptors={ this.addAllDescriptors }
pagination={ this.props.pagination }
pagination={ {
page: this.props.page,
size: this.props.size,
sort: this.props.sort,
dir: this.props.dir,
} }
loadCrops={ this.props.loadCrops }
history={ this.props.history }
location={ this.props.location }
......@@ -104,14 +119,11 @@ class SelectDescriptorsStep extends StepperTemplate<IDescriptorListProps> {
const mapStateToProps = (state, ownProps) => ({
descriptorList: state.descriptorList.dashboard.descriptorList ? state.descriptorList.dashboard.descriptorList.data : undefined,
loading: state.descriptorList.dashboard.descriptorList ? state.descriptorList.dashboard.descriptorList.loading : false,
matchingDescriptors: state.descriptors.dashboard.paged ? state.descriptors.dashboard.paged.data : undefined,
pagination: new Pagination<DescriptorFilter>({
page: +parse(ownProps.location.search).p || 0, // current page
size: +parse(ownProps.location.search).l || 20, // page size
sort: parse(ownProps.location.search).s, // page sorts
dir: parse(ownProps.location.search).d, // page sort directions
}),
page: +parse(ownProps.location.search).p || 0, // current page
size: +parse(ownProps.location.search).l || 20, // page size
sort: parse(ownProps.location.search).s, // page sorts
dir: parse(ownProps.location.search).d, // page sort directions
});
const mapDispatchToProps = (dispatch) => bindActionCreators({
......@@ -121,9 +133,11 @@ const mapDispatchToProps = (dispatch) => bindActionCreators({
removeDescriptorFromDescriptorList,
addDescriptorToDescriptorList,
listAccessibleDescriptors,
moreAccessibleDescriptors,
loadCrops,
addDescriptorsToDescriptorList,
removeDescriptorsFromDescriptorList,
clearDescriptors,
}, dispatch);
export default connect(
......
......@@ -11,6 +11,7 @@ import {
CREATE_DESCRIPTOR,
DASHBOARD_APPEND_DESCRIPTOR_PAGE,
DASHBOARD_RECEIVE_DESCRIPTOR,
DASHBOARD_CLEAR_DESCRIPTORS,
} from 'descriptors/constants';
// Model
......@@ -44,6 +45,15 @@ export const listAccessibleDescriptors = (page?: IPageRequest, filter?: string |
.then((paged) => dispatch(addFilterCode(paged.filterCode, paged.filter)));
};
export const moreAccessibleDescriptors = (paged?: FilteredPage<Descriptor>, filter?: string | DescriptorFilter) => (dispatch) => {
return dispatch(apiListAccessibleDescriptors(filter, FilteredPage.nextPage(paged)))
.then((paged) => dispatch(addFilterCode(paged.filterCode, paged.filter)));
};
export const clearDescriptors = () => (dispatch) => {
dispatch({ type: DASHBOARD_CLEAR_DESCRIPTORS });
};
export function loadMoreDescriptors(page?: FilteredPage<Descriptor>) {
return (dispatch, getState) => {
return dispatch(apiMyDescriptors(page ? page.filterCode : '', Page.nextPage(page)))
......
......@@ -15,6 +15,7 @@ export const DASHBOARD_REMOVE_DESCRIPTOR = 'descriptor/dashboard/REMOVE_DESCRIPT
export const DASHBOARD_RECEIVE_DESCRIPTOR_PAGE = 'descriptor/dashboard/RECEIVE_DESCRIPTOR_PAGE';
export const DASHBOARD_APPEND_DESCRIPTOR_PAGE = 'descriptor/dashboard/APPEND_DESCRIPTOR_PAGE';
export const DASHBOARD_LIST_DESCRIPTORS = 'descriptor/dashboard/LIST_DESCRIPTORS';
export const DASHBOARD_CLEAR_DESCRIPTORS = 'descriptor/dashboard/DASHBOARD_CLEAR_DESCRIPTORS';
// Descriptor lists
export const RECEIVE_DESCRIPTORLIST = 'App/RECEIVE_DESCRIPTORLIST';
......
......@@ -14,6 +14,7 @@ import {
DASHBOARD_RECEIVE_DESCRIPTOR_EXTRA,
DASHBOARD_REMOVE_DESCRIPTOR,
DASHBOARD_APPEND_DESCRIPTOR_PAGE,
DASHBOARD_CLEAR_DESCRIPTORS,
} from 'descriptors/constants';
import {LOGOUT} from 'constants/login';
import {dereferenceReferences} from 'utilities';
......@@ -114,6 +115,12 @@ function descriptorsDashboard(state = INITIAL_STATE, action: IReducerAction) {
});
}
case DASHBOARD_CLEAR_DESCRIPTORS: {
return update(state, {
paged: {$set: null},
});
}
default:
return state;
}
......
......@@ -5,23 +5,27 @@ import * as classnames from 'classnames';
import Card, { CardHeader } from 'ui/common/Card';
import { translate } from 'react-i18next';
import Page, { IPageRequest, SortDirection } from 'model/Page';
import { IPageRequest, SortDirection } from 'model/Page';
import Pagination from 'model/Pagination';
import DescriptorFilter from 'model/catalog/DescriptorFilter';
import Descriptor from 'model/catalog/Descriptor';
import FilteredPage from 'model/FilteredPage';
import Button from '@material-ui/core/Button';
import DescriptorCard from 'descriptors/ui/c/DescriptorCard';
import PaginationComponent from 'ui/common/pagination';
import DescriptorFilters from 'descriptors/ui/c/Filters';
import { log } from 'utilities/debug';
import PagedLoader from 'ui/common/PagedLoader';
interface IDescriptorPickerProps extends React.ClassAttributes<any> {
classes: any;
history: any;
location: any;
loadDescriptors: (page?: IPageRequest, filter?: DescriptorFilter) => void;
matchingDescriptors: Page<Descriptor>; // results from loadDescriptors
loadDescriptors: (page?: IPageRequest, filter?: DescriptorFilter | string) => void;
loadMoreDescriptors: (paged?: FilteredPage<Descriptor>, filter?: string | DescriptorFilter) => void;
clearDescriptors: () => void;
matchingDescriptors: FilteredPage<Descriptor>; // results from loadDescriptors
onAddDescriptor: (descriptor: Descriptor) => void; // event handler
onRemoveDescriptor: (descriptor: Descriptor) => void; // event handler
onAddAllDescriptors: any; // event handler
......@@ -65,8 +69,8 @@ const styles = (theme) => ({
class DescriptorPicker extends React.Component<IDescriptorPickerProps, any> {
protected onPaginationChange = (page, results, sortBy, dir) => {
const { history, location } = this.props;
protected onPaginationChange = (sortBy, dir, page, results) => {
const { history, location, loadDescriptors } = this.props;
const params = new URLSearchParams(location.search);
params.set('p', page);
params.set('l', results);
......@@ -83,13 +87,16 @@ class DescriptorPicker extends React.Component<IDescriptorPickerProps, any> {
location.search = params.toString();
history.push(location);
loadDescriptors({ page: 0, size: 20, properties: sortBy, direction: dir as SortDirection }, null);
}
protected applyFilters = (newFilters) => {
const { loadDescriptors, pagination } = this.props;
log('Applying new filter', newFilters);
loadDescriptors({ page: pagination.page, size: pagination.size, properties: pagination.sort as string[], direction: pagination.dir as SortDirection }, newFilters);
}
private onDescriptorSelected = (select) => (descriptor: Descriptor) => {
const { onAddDescriptor, onRemoveDescriptor } = this.props;
......@@ -111,19 +118,13 @@ class DescriptorPicker extends React.Component<IDescriptorPickerProps, any> {
loadCrops();
}
public componentWillReceiveProps(nextProps) {
const { loadDescriptors, pagination: oldPagination } = this.props;
const { pagination } = nextProps;
if (!oldPagination.equals(pagination)) {
log('Paginations differ!', pagination);
loadDescriptors({ page: pagination.page, size: pagination.size, properties: pagination.sort, direction: pagination.dir }, pagination.filter);
}
public componentWillUnmount() {
this.props.clearDescriptors();
}
public render() {
const { classes, pagination, matchingDescriptors, onAddAllDescriptors, onRemoveAllDescriptors, t } = this.props;
const { classes, matchingDescriptors, onAddAllDescriptors, onRemoveAllDescriptors, loadMoreDescriptors, t } = this.props;
// handle empty current descriptors
let { currentDescriptors } = this.props;
......@@ -131,47 +132,48 @@ class DescriptorPicker extends React.Component<IDescriptorPickerProps, any> {
currentDescriptors = [];
}
const renderDescription = (descriptor: Descriptor) => (
<DescriptorCard
className="ml-20 mr-20 mb-20"
key={ descriptor.uuid }
descriptor={ descriptor }
compact
crop version
textRows={ 3 }
selectedProps={ {
selectable: true,
onSelect: this.onDescriptorSelected(true),
disabled: currentDescriptors && currentDescriptors.map((d) => d.uuid).indexOf(descriptor.uuid) !== -1,
} }
/>
);
return (
<Grid container spacing={ 0 } className={ classes.container }>
<Grid item xs={ 12 } md={ 4 } lg={ 2 } className={ classes.leftPanel }>
<DescriptorFilters initialValues={ pagination.filter } onSubmit={ this.applyFilters }/>
<DescriptorFilters initialValues={ matchingDescriptors && matchingDescriptors.filter || {} } onSubmit={ this.applyFilters }/>
</Grid>
<Grid item xs={ 12 } md={ 4 } lg={ 5 } className={ classes.grayBackground }>
{ matchingDescriptors &&
<Grid container item spacing={ 0 }>
<h4 className="pt-20 pl-20 pr-20 font-bold">{ matchingDescriptors.totalElements || 0 } { t('descriptors.dashboard.c.picker.available') }</h4>
<div className={ classes.flexGrow }/>
<div className="pt-15 pr-20 pb-20 pl-20">
<Button className={ classes.btnBlue } onClick={ onAddAllDescriptors }>
{ t('descriptors.dashboard.c.picker.addAll') }
</Button>
</div>
</Grid>
}
{ matchingDescriptors && matchingDescriptors.content && matchingDescriptors.content.map((descriptor: Descriptor) => (
<DescriptorCard
className="ml-20 mr-20 mb-20"
key={ descriptor.uuid }
descriptor={ descriptor }
compact
crop version
textRows={ 3 }
selectedProps={ {
selectable: true,
onSelect: this.onDescriptorSelected(true),
disabled: currentDescriptors && currentDescriptors.map((d) => d.uuid).indexOf(descriptor.uuid) !== -1,
} }
/>
)) }
{ matchingDescriptors && matchingDescriptors.content && matchingDescriptors.content.length < 2 ?
<div className={ classes.fake }/> :
<PaginationComponent
pageObj={ matchingDescriptors }
onChange={ this.onPaginationChange }
onSortChange={ this.onPaginationChange }
displayName={ t('descriptors.common.modelName_plural') }
sortOptions={ Descriptor.SORT_OPTIONS }
actions={
<Button className={ classes.btnBlue } onClick={ onAddAllDescriptors }>
{ t('descriptors.dashboard.c.picker.addAll') }
</Button>
}
/>
}
{ matchingDescriptors && matchingDescriptors.content &&
<PagedLoader
paged={ matchingDescriptors }
loadMore={ loadMoreDescriptors }
roughItemHeight={ 200 }
itemRenderer={ renderDescription }
/>
}
</Grid>
......
......@@ -3,7 +3,7 @@ import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import BaseMyDataPage from 'ui/catalog/dashboard/MyDataPage';
import { approveDescriptor, deleteDescriptor, unpublishDescriptor, publishDescriptor, loadMoreDescriptors } from 'descriptors/actions/dashboard';
import { approveDescriptor, deleteDescriptor, unpublishDescriptor, publishDescriptor, loadMoreDescriptors, clearDescriptors } from 'descriptors/actions/dashboard';
import Descriptor from 'model/catalog/Descriptor';
import { DescriptorLink } from 'ui/catalog/Links';
import { PublishState } from 'model/common.model';
......@@ -20,6 +20,7 @@ const mapStateToProps = (state, ownProps) => ({
filterCode: ownProps.match.params.filterCode,
filterComponent: DashboardDescriptorFilters,
renderDataLink,
shouldClearState: true,
});
const mapDispatchToProps = (dispatch) => bindActionCreators({
......@@ -28,6 +29,7 @@ const mapDispatchToProps = (dispatch) => bindActionCreators({
publishOne: publishDescriptor,
approveOne: approveDescriptor,
unpublishOne: unpublishDescriptor,
clearState: clearDescriptors,
}, dispatch);
export default connect(mapStateToProps, mapDispatchToProps)(DashboardPage);
......@@ -45,6 +45,8 @@ interface IDataPublishedContainerProps extends React.ClassAttributes<any> {
history: any;
location: any;
setEditMode: any;
clearState?: () => void;
shouldClearState?: boolean;
}
class BaseMyDataPage<T> extends React.Component<T & IDataPublishedContainerProps & any, any> {
......@@ -107,6 +109,13 @@ class BaseMyDataPage<T> extends React.Component<T & IDataPublishedContainerProps
}
}
public componentWillUnmount() {
const { shouldClearState, clearState } = this.props;
if (shouldClearState) {
clearState();
}
}
public render() {
const { tab, filterComponent, basePath, addToEditList, removeFromEditList, isEditMode, setEditMode, editList, paged, dataClassName, renderDataLink, title } = this.props;
const actionHandlers = this.getActionHandlers();
......
......@@ -21,9 +21,6 @@ const styles = (theme) => ({
color: '#81807f',
textTransform: 'uppercase',
},
titleWrapper: {
minWidth: '320px',
},
collapseArrow: theme.arrows.collapse,
arrowOpened: theme.arrows.opened,
arrowClosed: theme.arrows.closed,
......@@ -54,7 +51,7 @@ class CollapsibleComponentSearch extends React.Component<ICollapsibleComponentSe
return (
<div>
<div className={ `pl-20 pr-15 ${classes.titleWrapper}` } onClick={ this.toggleCollapsed }>
<div className="pl-20 pr-15" onClick={ this.toggleCollapsed }>
<span className={ classes.title }>{ t(title) }</span>
<PlayArrow className={ `${ classes.collapseArrow } ${ this.state.show ? classes.arrowOpened : classes.arrowClosed }` } />
</div>
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment