From 67a01b36254b041498a3e2b593fc025931690f9c Mon Sep 17 00:00:00 2001 From: "v.pavlov" Date: Fri, 10 Aug 2018 14:42:28 +0300 Subject: [PATCH] Dashboard: endless scroll --- src/actions/dataset.ts | 10 ++ src/actions/descriptorList.ts | 10 ++ src/actions/descriptors.ts | 14 +++ src/ui/pages/dashboard/DashboardPage.tsx | 40 +++++--- src/ui/pages/dashboard/MyDataPage.tsx | 97 +++++++++++-------- .../pages/dashboard/c/DashboardTableRow.tsx | 50 ++++++++++ src/ui/pages/dashboard/c/MyDataTable.tsx | 68 +++++-------- 7 files changed, 194 insertions(+), 95 deletions(-) create mode 100644 src/ui/pages/dashboard/c/DashboardTableRow.tsx diff --git a/src/actions/dataset.ts b/src/actions/dataset.ts index 43807fd..d35b67e 100644 --- a/src/actions/dataset.ts +++ b/src/actions/dataset.ts @@ -38,6 +38,16 @@ function editDataset(uuid: string) { }; } +export const promiseListMyDatasets = (page?, results?, sortBy?, filter?, order?) => (dispatch, getState) => { + const token = getState().login.access_token; + + return DatasetService.listMyDatasets(token, page, results, sortBy, filter, order) + .catch((error) => { + log('Error', error); + return error; + }); +}; + function listMyDatasets(page?, results?, sortBy?, filter?: string | IDatasetFilter, order?) { return (dispatch, getState) => { const token = getState().login.access_token; diff --git a/src/actions/descriptorList.ts b/src/actions/descriptorList.ts index b8f2c6d..e2298aa 100644 --- a/src/actions/descriptorList.ts +++ b/src/actions/descriptorList.ts @@ -56,6 +56,16 @@ export const loadDescriptorList = (uuid: string, success?: (d) => any, fail?: (e }); }; +export const promiseListMyDescriptorLists = (page?, results?, sortBy?, filter?, order?) => (dispatch, getState) => { + const token = getState().login.access_token; + + return DescriptorListService.listMyDescriptorLists(token, page, results, sortBy, filter, order) + .catch((error) => { + log('Error', error); + return error; + }); +}; + // List current user's descriptor lists export const listMyDescriptorLists = (page?, results?, sortBy?, filter?: string | IDescriptorListFilter, order?) => (dispatch, getState) => { log('Loading my descriptor lists'); diff --git a/src/actions/descriptors.ts b/src/actions/descriptors.ts index 0a9820d..9745c4d 100644 --- a/src/actions/descriptors.ts +++ b/src/actions/descriptors.ts @@ -125,6 +125,20 @@ export const deleteDescriptor = (descriptor: Descriptor) => (dispatch, getState) }); }; +export const promiseListMyDescriptors = (page?, results?, sortBy?, filter?, order?) => (dispatch, getState) => { + const token = getState().login.access_token; + + return DescriptorService.listMyDescriptors(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 listMyDescriptors(page?, results?, sortBy?, filter?: string | IDescriptorFilter, order?) { return (dispatch, getState) => { const token = getState().login.access_token; diff --git a/src/ui/pages/dashboard/DashboardPage.tsx b/src/ui/pages/dashboard/DashboardPage.tsx index 73a8886..f342501 100644 --- a/src/ui/pages/dashboard/DashboardPage.tsx +++ b/src/ui/pages/dashboard/DashboardPage.tsx @@ -4,9 +4,9 @@ import { bindActionCreators } from 'redux'; import { parse } from 'query-string'; import { filterCodeToUrl } from 'actions/filterCode'; -import { listMyDatasets } from 'actions/dataset'; -import { listMyDescriptors } from 'actions/descriptors'; -import { listMyDescriptorLists } from 'actions/descriptorList'; +import { listMyDatasets, promiseListMyDatasets } from 'actions/dataset'; +import { listMyDescriptors, promiseListMyDescriptors} from 'actions/descriptors'; +import { listMyDescriptorLists, promiseListMyDescriptorLists } from 'actions/descriptorList'; import { setPageTitle } from 'actions/pageTitle'; import { Page } from 'model/common.model'; import { Dataset } from 'model/dataset.model'; @@ -52,28 +52,39 @@ class AdministrationDashboard extends BaseMyDataPage { public render() { - const {tab, datasets, descriptors, descriptorLists, filter, filterCode} = this.props; + const {tab, datasets, descriptors, descriptorLists, pagination, promiseListMyDatasets, promiseListMyDescriptors, promiseListMyDescriptorLists} = this.props; // console.log('Dash', tab, filterCode, filter); let paged: Page = datasets as Page; + let promiseListData; switch (tab) { case 'descriptorlists': paged = descriptorLists as Page; + promiseListData = promiseListMyDescriptorLists; break; case 'descriptors': paged = descriptors as Page; + promiseListData = promiseListMyDescriptors; break; case 'datasets': default: + promiseListData = promiseListMyDatasets; break; } return (
- +
); @@ -81,14 +92,16 @@ class AdministrationDashboard extends BaseMyDataPage { } const mapStateToProps = (state, ownProps) => ({ + pagination: { + page: +parse(ownProps.location.search).p || 0, // current page + size: +parse(ownProps.location.search).l || 100, // page size + sort: parse(ownProps.location.search).s || 'lastModifiedDate', // page sort + dir: parse(ownProps.location.search).d, // page sort directions + filter: state.filterCode.filters && parse(ownProps.location.search).filter && state.filterCode.filters[parse(ownProps.location.search).filter] || null, + filterCode: parse(ownProps.location.search).filter, + }, title: ownProps.route.extraProps.title, // route-configured tab: ownProps.match.params.tab || 'datasets', // current tab, or ownProps.location.pathname - pageCurrent: +parse(ownProps.location.search).p || 0, // current page - pageSize: +parse(ownProps.location.search).l || 20, // page size - pageSort: parse(ownProps.location.search).s || 'lastModifiedDate', // page sort - pageDir: parse(ownProps.location.search).d || 'DESC', // page sort direction - filterCode: parse(ownProps.location.search).filter, // filter code - filter: state.filterCode.filters && parse(ownProps.location.search).filter && state.filterCode.filters[parse(ownProps.location.search).filter] || null, datasets: state.datasets.paged, descriptors: state.descriptors.paged, descriptorLists: state.descriptorList.paged, @@ -98,6 +111,9 @@ const mapDispatchToProps = (dispatch) => bindActionCreators({ listDatasets: listMyDatasets, listDescriptors: listMyDescriptors, listDescriptorLists: listMyDescriptorLists, + promiseListMyDatasets, + promiseListMyDescriptors, + promiseListMyDescriptorLists, setPageTitle, filterCodeToUrl, }, dispatch); diff --git a/src/ui/pages/dashboard/MyDataPage.tsx b/src/ui/pages/dashboard/MyDataPage.tsx index 8d5bc17..96768ea 100644 --- a/src/ui/pages/dashboard/MyDataPage.tsx +++ b/src/ui/pages/dashboard/MyDataPage.tsx @@ -9,9 +9,9 @@ import {Page} from 'model/common.model'; import { parse } from 'query-string'; import { filterCodeToUrl } from 'actions/filterCode'; -import {listMyDatasets} from 'actions/dataset'; -import {listMyDescriptors} from 'actions/descriptors'; -import {listMyDescriptorLists} from 'actions/descriptorList'; +import {listMyDatasets, promiseListMyDatasets} from 'actions/dataset'; +import {listMyDescriptors, promiseListMyDescriptors} from 'actions/descriptors'; +import {listMyDescriptorLists, promiseListDescriptorLists} from 'actions/descriptorList'; import {setPageTitle} from 'actions/pageTitle'; import ContentHeaderWithButton from 'ui/common/heading/ContentHeaderWithButton'; @@ -22,12 +22,7 @@ import DashboardActionsButton from './c/DashboardActionsButton'; interface IDataPublishedContainerProps extends React.ClassAttributes { title: string; tab?: string; - pageCurrent: number; - pageSize: number; - pageSort?: string; - pageDir?: string; - filterCode?: string; - filter: any; + pagination: any; datasets: Page; descriptors: Page; descriptorLists: Page; @@ -37,6 +32,9 @@ interface IDataPublishedContainerProps extends React.ClassAttributes { listDescriptorLists: any; listDescriptors: any; listDatasets: any; + promiseListMyDatasets: any; + promiseListDescriptors: any; + promiseListDescriptorLists: any; setPageTitle: (title: string) => void; } @@ -45,8 +43,8 @@ class BaseMyDataPage extends React.Component { - const pageCurrent = parse(search).p; - const pageSize = parse(search).l; + const pageCurrent = parse(search).p || 0; + const pageSize = parse(search).l || 100; const pageSort = parse(search).s; const pageDir = parse(search).d; const filterCode = parse(search).filter; @@ -61,7 +59,7 @@ class BaseMyDataPage extends React.Component extends React.Component extends React.Component extends React.Component { this.setState({...this.state, filter: newFilters}); - const {tab, pageCurrent, pageSize, pageSort, pageDir} = this.props; - this.loadData(newFilters, tab, pageCurrent, pageSize, pageSort, pageDir); + const {tab, pagination } = this.props; + this.loadData(newFilters, tab, pagination.page, pagination.size, pagination.sort, pagination.dir); } protected loadData(filter, tab, page, size, sortBy, dir) { - const {listDatasets, listDescriptors, listDescriptorLists, preFilter, filterCode} = this.props; + const {listDatasets, listDescriptors, listDescriptorLists, preFilter, pagination } = this.props; const newFilters = filter && { ...preFilter, ...filter }; // console.log(`Filters code=${filterCode}`, newFilters, preFilter); - if (newFilters || this.state.tab !== tab || this.state.pageCurrent !== page || this.state.pageSize !== size || this.state.pageSort !== sortBy || this.state.pageDir !== dir) { + if (newFilters || this.state.tab !== tab || this.state.pagination.page !== page || this.state.pagination.size !== size || this.state.pagination.sort !== sortBy || this.state.pagination.dir !== dir) { // console.log('Reloading'); this.setState(update(this.state, { tab: {$set: tab}, - pageCurrent: {$set: page}, - pageSize: {$set: size}, - pageSort: {$set: sortBy}, - pageDir: {$set: dir}, - filterCode: {$set: filterCode}, + pagination: { + page: {$set: page}, + size: {$set: size}, + sort: {$set: sortBy}, + dir: {$set: dir}, + filterCode: {$set: pagination.filterCode}, + }, })); switch (tab) { - case 'descriptors': listDescriptors(page, size, sortBy, newFilters || filterCode, dir); break; - case 'descriptorlists': listDescriptorLists(page, size, sortBy, newFilters || filterCode, dir); break; + case 'descriptors': listDescriptors(page, size, sortBy, newFilters || pagination.filterCode, dir); break; + case 'descriptorlists': listDescriptorLists(page, size, sortBy, newFilters || pagination.filterCode, dir); break; case 'datasets': - default: listDatasets(page, size, sortBy, newFilters || filterCode, dir); break; + default: listDatasets(page, size, sortBy, newFilters || pagination.filterCode, dir); break; } } else { // noop @@ -177,32 +177,50 @@ class DP extends BaseMyDataPage { } public render() { - const {title, tab, basePath, filterCode, filter} = this.props; + const {title, tab, basePath, pagination, promiseListMyDatasets, promiseListMyDescriptors, promiseListDescriptorLists} = this.props; const paged = this.getPaged(this.props); + let promiseListData; + + switch (tab) { + case 'descriptors': promiseListData = promiseListMyDescriptors; break; + case 'descriptorlists': promiseListData = promiseListDescriptorLists; break; + case 'datasets': + default: promiseListData = promiseListMyDatasets; break; + } + return (
}/> - - + +
); } } const mapStateToProps = (state, ownProps) => ({ + pagination: { + page: +parse(ownProps.location.search).p || 0, // current page + size: +parse(ownProps.location.search).l || 100, // page size + sort: parse(ownProps.location.search).s, // page sorts + dir: parse(ownProps.location.search).d, // page sort directions + filter: state.filterCode.filters && parse(ownProps.location.search).filter && state.filterCode.filters[parse(ownProps.location.search).filter] || null, + filterCode: parse(ownProps.location.search).filter, + }, title: ownProps.route.extraProps.title || 'Data', // route-configured basePath: ownProps.route.extraProps.basePath, // route-configured preFilter: ownProps.route.extraProps.filter || {}, // route-configured tab: ownProps.match.params.tab || 'datasets', // current tab, or ownProps.location.pathname - pageCurrent: +parse(ownProps.location.search).p || 0, // current page - pageSize: +parse(ownProps.location.search).l || 20, // page size - pageSort: parse(ownProps.location.search).s, // page sort - pageDir: parse(ownProps.location.search).d, // page sort direction - filterCode: parse(ownProps.location.search).filter, // filter code - filter: state.filterCode.filters && parse(ownProps.location.search).filter && state.filterCode.filters[parse(ownProps.location.search).filter] || null, datasets: state.datasets.paged, descriptors: state.descriptors.paged, descriptorLists: state.descriptorList.paged, @@ -212,6 +230,9 @@ const mapDispatchToProps = (dispatch) => bindActionCreators({ listDatasets: listMyDatasets, listDescriptors: listMyDescriptors, listDescriptorLists: listMyDescriptorLists, + promiseListMyDatasets, + promiseListMyDescriptors, + promiseListDescriptorLists, setPageTitle, filterCodeToUrl, }, dispatch); diff --git a/src/ui/pages/dashboard/c/DashboardTableRow.tsx b/src/ui/pages/dashboard/c/DashboardTableRow.tsx new file mode 100644 index 0000000..eaa5867 --- /dev/null +++ b/src/ui/pages/dashboard/c/DashboardTableRow.tsx @@ -0,0 +1,50 @@ +import * as React from 'react'; + +// ui +import {TableCell, TableRow} from 'ui/common/tables'; +import PrettyDate from 'ui/common/time/PrettyDate'; +import Permissions from 'ui/common/permission/Permissions'; +import Markdown from 'ui/catalog/markdown'; +import {DatasetLink, DescriptorLink, DescriptorListLink} from 'ui/catalog/Links'; + +import Button from '@material-ui/core/Button'; + +const ResolveLink = ({tab, row, children}) => { + switch (tab) { + case 'datasets': + return { children }; + case 'descriptors': + return { children }; + case 'descriptorlists': + return { children }; + default: + return ({ children }); + } +}; + +export class DashboardTableRow extends React.Component { + + public render() { + const {row, tab, index} = this.props; + return ( + + { index + 1 } + + { || (Untitled) } + + { row.owner.shortName } + { row.createdDate && } + { row.lastModifiedDate && } + { row.published ? 'Published' : 'In progress' } + + + + + { row._permissions.manage && + + } + + + ); + } +} diff --git a/src/ui/pages/dashboard/c/MyDataTable.tsx b/src/ui/pages/dashboard/c/MyDataTable.tsx index 0a52ea1..5ae9ab7 100644 --- a/src/ui/pages/dashboard/c/MyDataTable.tsx +++ b/src/ui/pages/dashboard/c/MyDataTable.tsx @@ -7,17 +7,14 @@ import Tabs, {Tab} from 'ui/common/Tabs'; import {Table, TableRow, TableCell} from 'ui/common/tables'; import PaginationComponent from 'ui/common/pagination'; import {ContentContainer} from 'ui/layout/Container'; -import {DatasetLink, DescriptorLink, DescriptorListLink} from 'ui/catalog/Links'; -import PrettyDate from 'ui/common/time/PrettyDate'; -import Markdown from 'ui/catalog/markdown'; -import Permissions from 'ui/common/permission/Permissions'; import { ScrollToTopOnMount } from 'ui/common/page/scrollers'; +import { DashboardTableRow } from './DashboardTableRow'; import DashboardFilters from './Filters'; import Paper from '@material-ui/core/Paper'; -import Button from '@material-ui/core/Button'; import Grid from '@material-ui/core/Grid'; +import PagedLoader from 'ui/common/PagedLoader'; const styles = (theme) => ({ filterSection: theme.leftPanel.root, @@ -31,8 +28,8 @@ interface IMyDataTableProps extends React.Props { onPaginationChange: (page: number, results: number, sortBy: string, dir?: string) => void; pageSort?: string; onFilter: (filter) => void; - filter: any; - filterCode?: string; + pagination: any; + promiseListData: any; } const defaultSortOptions = { @@ -60,8 +57,8 @@ function MyDataTable({ paged, onPaginationChange, onFilter, - filter, - filterCode, + pagination, + promiseListData, }: IMyDataTableProps) { if (! paged) { @@ -77,20 +74,13 @@ function MyDataTable({ default: break; } - const ResolveLink = ({row, children}) => { - switch (tab) { - case 'datasets': - return { children }; - case 'descriptors': - return { children }; - case 'descriptorlists': - return { children }; - default: - return ({ children }); - } - }; - - const query = filterCode ? `?filter=${filterCode}` : ''; + const renderTableRow = (row, index) => ; + + const loadNextPage = (page: number, pageSize: number) => { + return promiseListData(page, pageSize, pagination.sort, pagination.filter, pagination.dir); + }; + + const query = pagination.filterCode ? `?filter=${pagination.filterCode}` : ''; // console.log(`DF initialValues ${query}`, filter); return ( @@ -103,10 +93,10 @@ function MyDataTable({ - + - + @@ -122,31 +112,19 @@ function MyDataTable({ ) }> - { paged && paged.content.map((row, i) => ( - - { paged.size * paged.number + i + 1 } - - { || (Untitled) } - - { row.owner.shortName } - { row.createdDate && } - { row.lastModifiedDate && } - { row.published ? 'Published' : 'In progress' } - - - - - { row._permissions.manage && } - - - ), - ) } + - + -- GitLab