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

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