Commit 67aaeb1d authored by Matija Obreza's avatar Matija Obreza
Browse files

Load Descriptors on demand

parent 2b0aa65d
Pipeline #4697 passed with stages
in 3 minutes and 26 seconds
......@@ -133,6 +133,20 @@ export function listMyDescriptors(page?, results?, sortBy?, filter?, order?) {
};
}
export const promiseLoadDescriptors = (page?, results?, sortBy?, filter?, order?) => (dispatch, getState) => {
const token = getState().login.access_token;
return DescriptorService.listDescriptors(token, page, results, sortBy, filter, order)
.then((paged) => {
dereferenceReferences(paged.content, 'owner', (o) => new Partner(o));
return paged;
})
.catch((error) => {
log('Error', error);
return error;
});
};
export function loadDescriptors(page?, results?, sortBy?, filter?, order?) {
return (dispatch, getState) => {
const token = getState().login.access_token;
......
import { push } from 'react-router-redux';
import { SubmissionError } from 'redux-form';
import { VocabularyService } from 'service/VocabularyService';
import {log} from 'utilities/debug';
import { log } from 'utilities/debug';
import {
CREATE_VOCABULARY, RECEIVE_VOCABULARY, RECEIVE_VOCABULARIES, RECEIVE_MY_VOCABULARYLIST,
......@@ -91,12 +91,22 @@ const listMyVocabularies = () => (dispatch, getState) => {
});
};
// Load them
export const promiseListVocabularies = (page: number = 0, results: number = 50, sortBy?: string, filter?: IVocabularyFilter, order?: string) => (dispatch, getState): Promise<Page<Vocabulary>> => {
return VocabularyService.listVocabularies(getState().login.access_token, page, results, sortBy, order, filter)
.catch((error) => {
log('Error', error);
return error;
});
};
// Load them
const listVocabularies = (page: number = 0, results: number = 50, sortBy?: string, filter?: IVocabularyFilter, order?: string) => (dispatch, getState) => {
return VocabularyService.listVocabularies(getState().login.access_token, page, results, sortBy, order, filter)
.then((paged) => {
dispatch(receiveVocabularyPage(paged));
return dispatch(receiveVocabularyPage(paged));
})
.catch((error) => {
log('Error', error);
......
......@@ -2,7 +2,7 @@ import * as React from 'react';
import { CircularProgress } from 'material-ui/Progress';
export default ({message = 'Loading data...', className}: {message?: string, className?: string}) => (
<div className={ className } style={ { textAlign: 'center', padding: '5rem', width: '100%' } }>
<div className={ className } style={ { textAlign: 'center', padding: '5rem' } }>
<CircularProgress size={ 50 }/>
{ message && <div className="font-bold uppercase">{ message }</div> }
</div>
......
......@@ -3,13 +3,14 @@ import {log} from 'utilities/debug';
import { Page } from 'model/common.model';
import * as VisibilitySensor from 'react-visibility-sensor';
import Loading from 'ui/common/Loading';
interface IProps<T> extends React.Props<any> {
paged: Page<T>;
colSpan?: number; // if in table, set the colSpan to render <tr><td colSpan=...
offsetTop?: number; // px before end of list when next page should start loading, defaults to 300px
roughItemHeight?: number; // px of height of element, defaults to 50px, determines when loadNextPage is called
itemRenderer: (item: T, index?: number) => any;
loadingIndicator: any;
loadingIndicator?: any;
loadPage: (page: number, pageSize: number) => Promise<Page<T>>;
}
......@@ -51,7 +52,7 @@ export default class PagedLoader<T> extends React.Component<IProps<T>, any> {
if (paged && isVisible) {
// we should load some stuff
if (! loading && paged.totalElements > list.length) {
// log('Calling for next page', pageNumber + 1);
log('Calling for next page', pageNumber + 1);
this.setState({
...this.state,
......@@ -75,7 +76,7 @@ export default class PagedLoader<T> extends React.Component<IProps<T>, any> {
public render() {
const { list, loading } = this.state;
const { itemRenderer, loadingIndicator, colSpan, offsetTop } = this.props;
const { itemRenderer, loadingIndicator, colSpan, roughItemHeight } = this.props;
if (! list || list.length === 0) {
return null;
......@@ -83,21 +84,21 @@ export default class PagedLoader<T> extends React.Component<IProps<T>, any> {
log(`Rendering ${list.length} items`);
const inTable = colSpan ? true : false;
const visibilityOffset = offsetTop && offsetTop || 1000;
// log(`Visibility offset ${visibilityOffset}`);
const visibilityOffset = (roughItemHeight && roughItemHeight || 50) * 10;
const myLoadingIndicator = loadingIndicator || <Loading />;
log(`Visibility offset bottom: ${-visibilityOffset}`);
const result = [
...list.map((item: T, index) => itemRenderer(item, index)),
inTable ? (
<tr key="pagedLoaderLastItem"><td colSpan={ colSpan }>
<VisibilitySensor offset={ { bottom: -visibilityOffset } } onChange={ this.endOfListVisibilityChange } />
{ loading ? <div>{ loadingIndicator }</div> : null }
{ loading ? <div>{ myLoadingIndicator }</div> : null }
</td></tr>
) : (
<div key="pagedLoaderLastItem">
<VisibilitySensor onChange={ this.endOfListVisibilityChange } />
{ loading ? loadingIndicator : null }
<VisibilitySensor offset={ { bottom: -visibilityOffset } } onChange={ this.endOfListVisibilityChange } />
{ loading ? myLoadingIndicator : null }
</div>
),
];
......
......@@ -5,10 +5,11 @@ import { withStyles } from 'material-ui/styles';
import {log} from 'utilities/debug';
import { loadDescriptors } from 'actions/descriptors';
import { loadDescriptors, promiseLoadDescriptors } from 'actions/descriptors';
import { listCrops } from 'actions/crop';
import { Descriptor, IDescriptorFilter } from 'model/descriptor.model';
import { Page, Pagination } from 'model/common.model';
import PagedLoader from 'ui/common/PagedLoader';
import Loading from 'ui/common/Loading';
import PaginationComponent from 'ui/common/pagination';
......@@ -83,10 +84,16 @@ class BrowsePage extends React.Component<IDescriptorListsPageProps & any, any> {
}
public render() {
const {classes, paged, pagination} = this.props;
const { classes, paged, pagination, promiseLoadDescriptors } = this.props;
const stillLoading: boolean = (! paged || ! paged.content);
const loadNextPage = (page: number, pageSize: number) => promiseLoadDescriptors(page, pageSize, pagination.sort, pagination.filter, pagination.dir);
const renderDescriptor = (d: Descriptor) => (
<DescriptorCard key={ d.uuid } className="mb-20" descriptor={ d } complete dataType vocabulary />
);
return (
<div className="back-gray ">
<ContentHeader title="Crop Descriptors"
......@@ -103,6 +110,7 @@ class BrowsePage extends React.Component<IDescriptorListsPageProps & any, any> {
pageObj={ paged }
onChange={ this.onPaginationChange }
displayName="descriptors"
infinite
sortOptions={ Descriptor.SORT_OPTIONS }
/>
</Grid>
......@@ -114,10 +122,11 @@ class BrowsePage extends React.Component<IDescriptorListsPageProps & any, any> {
</Grid>
{ stillLoading ? <Loading /> :
<Grid item xs={ 12 } className="p-20">
{ paged.content.map((d: Descriptor, i) => (
<DescriptorCard key={ d.uuid } className="mb-20"
descriptor={ d } complete dataType vocabulary />
)) }
<PagedLoader
paged={ paged }
loadPage={ loadNextPage }
roughItemHeight={ 600 }
itemRenderer={ renderDescriptor } />
</Grid>
}
</Grid>
......@@ -129,6 +138,7 @@ class BrowsePage extends React.Component<IDescriptorListsPageProps & any, any> {
pageObj={ paged }
onChange={ this.onPaginationChange }
displayName="descriptors"
infinite
sortOptions={ Descriptor.SORT_OPTIONS }
/>
</Grid>
......@@ -143,7 +153,7 @@ class BrowsePage extends React.Component<IDescriptorListsPageProps & any, any> {
const mapStateToProps = (state, ownProps) => ({
pagination: new Pagination<IDescriptorFilter>({
page: +ownProps.location.query.p || 0, // current page
size: +ownProps.location.query.l || 20, // page size
size: +ownProps.location.query.l || 50, // page size
sort: ownProps.location.query.s, // page sorts
dir: ownProps.location.query.d, // page sort directions
filter: state.descriptors.pagedQuery && state.descriptors.pagedQuery.filter || null,
......@@ -154,6 +164,7 @@ const mapStateToProps = (state, ownProps) => ({
const mapDispatchToProps = (dispatch) => bindActionCreators({
loadDescriptors,
promiseLoadDescriptors,
listCrops,
}, dispatch);
......
......@@ -3,10 +3,11 @@ import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import { withStyles } from 'material-ui/styles';
import { listVocabularies, createVocabulary, autoUpdate } from 'actions/vocabulary';
import { listVocabularies, promiseListVocabularies, createVocabulary, autoUpdate } from 'actions/vocabulary';
import { Vocabulary, IVocabularyFilter } from 'model/vocabulary.model';
import { Page, Pagination } from 'model/common.model';
import PagedLoader from 'ui/common/PagedLoader';
import Authorize from 'ui/common/authorized/Authorize';
import Loading from 'ui/common/Loading';
import PaginationComponent from 'ui/common/pagination';
......@@ -31,7 +32,8 @@ const styles = (theme) => ({
interface IBrowsePageProps extends React.ClassAttributes<any> {
pagination?: Pagination<IVocabularyFilter>;
paged?: Page<Vocabulary>;
listVocabularies: any;
listVocabularies: () => void;
promiseListVocabularies: () => Promise<Page<Vocabulary>>;
createVocabulary: any;
}
......@@ -78,10 +80,18 @@ class BrowsePage extends React.Component<IBrowsePageProps & any, any> {
}
public render() {
const {classes, paged, createVocabulary} = this.props;
const {classes, paged, createVocabulary, pagination, promiseListVocabularies} = this.props;
const stillLoading: boolean = (!(paged && paged.content));
const loadVocabularyPage = (page: number, pageSize: number) => promiseListVocabularies(page, pageSize, pagination.sort, pagination.filter, pagination.dir);
const renderVocabulary = (vocabulary: Vocabulary) => (
<Grid key={ vocabulary.uuid } item xs={ 12 }>
<VocabularyCard className={ classes.card } vocabulary={ vocabulary } textRows={ 3 } />
</Grid>
);
return (
<div className={ classes.root }>
<Authorize role="ROLE_ADMINISTRATOR">
......@@ -104,20 +114,22 @@ class BrowsePage extends React.Component<IBrowsePageProps & any, any> {
<PaginationComponent pageObj={ paged }
onChange={ this.onPaginationChange }
displayName="vocabularies"
infinite
sortOptions={ Vocabulary.SORT_OPTIONS }
/>
</Grid>
{ stillLoading ? <Loading /> :
paged.content.map((vocabulary: Vocabulary, index) => (
<Grid key={ index } item xs={ 12 }>
<VocabularyCard className={ classes.card } vocabulary={ vocabulary } textRows={ 3 } />
</Grid>
))
<PagedLoader
paged={ paged }
loadPage={ loadVocabularyPage }
colSpan={ 3 }
itemRenderer={ renderVocabulary } />
}
<Grid item xs={ 12 }>
<PaginationComponent pageObj={ paged }
onChange={ this.onPaginationChange }
displayName="vocabularies"
infinite
sortOptions={ Vocabulary.SORT_OPTIONS }
/>
</Grid>
......@@ -139,6 +151,7 @@ const mapStateToProps = (state, ownProps) => ({
const mapDispatchToProps = (dispatch) => bindActionCreators({
listVocabularies,
promiseListVocabularies,
createVocabulary,
autoUpdate,
}, dispatch);
......
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