diff --git a/openbis_ng_ui/src/js/components/common/grid/Grid.jsx b/openbis_ng_ui/src/js/components/common/grid/Grid.jsx index 5a71bb70454f1c43ed77f525383acf234f9ea8f2..2168ece491940843eca96820f4b0b20045e6f752 100644 --- a/openbis_ng_ui/src/js/components/common/grid/Grid.jsx +++ b/openbis_ng_ui/src/js/components/common/grid/Grid.jsx @@ -73,8 +73,11 @@ class Grid extends React.PureComponent { } componentDidUpdate(prevProps) { - if (this.props.rows !== prevProps.rows) { - this.controller.updateAllRows(this.props.rows) + if ( + this.props.rows !== prevProps.rows || + this.props.totalCount !== prevProps.totalCount + ) { + this.controller.updateRows(this.props.rows, this.props.totalCount) } if (this.props.selectedRowId !== prevProps.selectedRowId) { this.controller.updateSelectedRowId(this.props.selectedRowId) @@ -101,8 +104,8 @@ class Grid extends React.PureComponent { pageSize, columns, currentRows, - sortedRows, - selectedRow + selectedRow, + totalCount } = this.state return ( @@ -136,7 +139,7 @@ class Grid extends React.PureComponent { </div> <div className={classes.tableFooter}> <GridPaging - count={sortedRows.length} + count={totalCount} page={page} pageSize={pageSize} onPageChange={this.controller.handlePageChange} diff --git a/openbis_ng_ui/src/js/components/common/grid/GridController.js b/openbis_ng_ui/src/js/components/common/grid/GridController.js index 20208cc6ac34a9f8c05454dd8083d452cd914535..739d984717bca642ee4f840e1ea6eb7fd87aaed7 100644 --- a/openbis_ng_ui/src/js/components/common/grid/GridController.js +++ b/openbis_ng_ui/src/js/components/common/grid/GridController.js @@ -41,13 +41,14 @@ export default class GridController { page: 0, pageSize: 10, columns, - allRows: [], + rows: [], filteredRows: [], sortedRows: [], currentRows: [], selectedRow: null, sort: initialSort, - sortDirection: initialSortDirection + sortDirection: initialSortDirection, + totalCount: 0 }) this.context = context @@ -137,11 +138,8 @@ export default class GridController { } async load() { - const { rows, selectedRowId } = this.context.getProps() - await this._loadSettings() - await this.updateAllRows(rows) - await this.updateSelectedRowId(selectedRowId) + await this._loadRows() await this.context.setState(() => ({ loaded: true @@ -226,11 +224,37 @@ export default class GridController { openbis.updatePersons([update]) } - async updateAllRows(rows) { - const { allRows } = this.context.getState() + async _loadRows() { + const { load, rows } = this.context.getProps() + + if (load) { + const { + columns, + filters, + sort, + sortDirection, + page, + pageSize + } = this.context.getState() + + await load({ + columns, + filters, + page, + pageSize, + sort, + sortDirection + }) + } else { + await this.updateRows(rows, rows.length) + } + } + + async updateRows(newRows, newTotalCount) { + const { rows, totalCount } = this.context.getState() - if (allRows !== rows) { - await this._recalculateCurrentRows(rows) + if (newRows !== rows || newTotalCount !== totalCount) { + await this._recalculateCurrentRows(newRows, newTotalCount) } } @@ -242,36 +266,51 @@ export default class GridController { } } - async _recalculateCurrentRows(rows) { + async _recalculateCurrentRows(newRows, newTotalCount) { + const { load } = this.context.getProps() + const { - allRows, + rows, columns, filters, sort, sortDirection, page, - pageSize + pageSize, + totalCount } = this.context.getState() - if (!rows) { - rows = allRows - } - - const filteredRows = this._filter(rows, columns, filters) + newRows = newRows || rows + newTotalCount = newTotalCount || totalCount - const pageCount = Math.max(Math.ceil(filteredRows.length / pageSize), 1) - const newPage = Math.min(page, pageCount - 1) + if (load) { + const pageCount = Math.max(Math.ceil(newTotalCount / pageSize), 1) + const newPage = Math.min(page, pageCount - 1) - const sortedRows = this._sort(filteredRows, columns, sort, sortDirection) - const currentRows = this._page(sortedRows, newPage, pageSize) + await this.context.setState({ + rows: newRows, + filteredRows: [], + sortedRows: [], + currentRows: newRows, + page: newPage, + totalCount: newTotalCount + }) + } else { + const filteredRows = this._filter(newRows, columns, filters) + const pageCount = Math.max(Math.ceil(filteredRows.length / pageSize), 1) + const newPage = Math.min(page, pageCount - 1) + const sortedRows = this._sort(filteredRows, columns, sort, sortDirection) + const currentRows = this._page(sortedRows, newPage, pageSize) - await this.context.setState({ - allRows: rows, - filteredRows, - sortedRows, - currentRows, - page: newPage - }) + await this.context.setState({ + rows: newRows, + filteredRows, + sortedRows, + currentRows, + page: newPage, + totalCount: filteredRows.length + }) + } const { selectedRow } = this.context.getState() @@ -330,7 +369,7 @@ export default class GridController { } } - handleFilterChange(column, filter) { + async handleFilterChange(column, filter) { const state = this.context.getState() let filters = { @@ -338,17 +377,16 @@ export default class GridController { [column]: filter } - this.context - .setState(() => ({ - page: 0, - filters - })) - .then(() => { - this._recalculateCurrentRows() - }) + await this.context.setState(() => ({ + page: 0, + filters + })) + + await this._loadRows() + await this._recalculateCurrentRows() } - handleColumnVisibleChange(name) { + async handleColumnVisibleChange(name) { const state = this.context.getState() let columns = state.columns.map(column => { @@ -362,16 +400,14 @@ export default class GridController { } }) - this.context - .setState(() => ({ - columns - })) - .then(() => { - this._saveSettings() - }) + await this.context.setState(() => ({ + columns + })) + + this._saveSettings() } - handleColumnOrderChange(sourceIndex, destinationIndex) { + async handleColumnOrderChange(sourceIndex, destinationIndex) { const state = this.context.getState() let columns = [...state.columns] @@ -379,59 +415,56 @@ export default class GridController { columns.splice(sourceIndex, 1) columns.splice(destinationIndex, 0, source) - this.context - .setState(() => ({ - columns - })) - .then(() => { - this._saveSettings() - }) + await this.context.setState(() => ({ + columns + })) + + this._saveSettings() } - handleSortChange(column) { + async handleSortChange(column) { if (!column.sortable) { return } - this.context - .setState(state => { - if (column.name === state.sort) { - return { - sortDirection: state.sortDirection === 'asc' ? 'desc' : 'asc' - } - } else { - return { - sort: column.name, - sortDirection: 'asc' - } + await this.context.setState(state => { + if (column.name === state.sort) { + return { + sortDirection: state.sortDirection === 'asc' ? 'desc' : 'asc' } - }) - .then(() => { - this._saveSettings() - this._recalculateCurrentRows() - }) + } else { + return { + sort: column.name, + sortDirection: 'asc' + } + } + }) + + this._saveSettings() + + await this._loadRows() + await this._recalculateCurrentRows() } - handlePageChange(page) { - this.context - .setState(() => ({ - page - })) - .then(() => { - this._recalculateCurrentRows() - }) + async handlePageChange(page) { + await this.context.setState(() => ({ + page + })) + + await this._loadRows() + await this._recalculateCurrentRows() } - handlePageSizeChange(pageSize) { - this.context - .setState(() => ({ - page: 0, - pageSize - })) - .then(() => { - this._saveSettings() - this._recalculateCurrentRows() - }) + async handlePageSizeChange(pageSize) { + await this.context.setState(() => ({ + page: 0, + pageSize + })) + + this._saveSettings() + + await this._loadRows() + await this._recalculateCurrentRows() } handleRowSelect(row) { diff --git a/openbis_ng_ui/src/js/components/tools/common/HistoryGrid.jsx b/openbis_ng_ui/src/js/components/tools/common/HistoryGrid.jsx index 139d2db68b22867276ab21137516bc318d6c383e..e7de3370a06f2c2d8597e7bd0861120cc3cd9ce6 100644 --- a/openbis_ng_ui/src/js/components/tools/common/HistoryGrid.jsx +++ b/openbis_ng_ui/src/js/components/tools/common/HistoryGrid.jsx @@ -1,99 +1,196 @@ +import _ from 'lodash' import React from 'react' +import autoBind from 'auto-bind' import Grid from '@src/js/components/common/grid/Grid.jsx' import UserLink from '@src/js/components/common/link/UserLink.jsx' import Collapse from '@material-ui/core/Collapse' import Link from '@material-ui/core/Link' +import FormUtil from '@src/js/components/common/form/FormUtil.js' import openbis from '@src/js/services/openbis.js' import messages from '@src/js/common/messages.js' import date from '@src/js/common/date.js' import ids from '@src/js/common/consts/ids.js' +import store from '@src/js/store/store.js' +import actions from '@src/js/store/actions/actions.js' import logger from '@src/js/common/logger.js' class HistoryGrid extends React.PureComponent { constructor(props) { super(props) + autoBind(this) this.state = { - shown: {} + rows: [], + totalCount: 0 } } - handleVisibilityChange(row, fieldName) { - const { onRowChange } = this.props - if (onRowChange) { - onRowChange(row.id, { - [fieldName]: { - ...row[fieldName], - visible: !row[fieldName].visible - } - }) + async load(params) { + try { + await this.loadHistory(this.props.eventType, params) + } catch (error) { + store.dispatch(actions.errorChange(error)) } } + async loadHistory(eventType, { page, pageSize, sort, sortDirection }) { + const criteria = new openbis.EventSearchCriteria() + criteria.withEventType().thatEquals(eventType) + + const fo = new openbis.EventFetchOptions() + fo.withRegistrator() + fo.from(page * pageSize) + fo.count(pageSize) + + if (sort && sortDirection) { + fo.sortBy()[sort]()[sortDirection]() + } + + const result = await openbis.searchEvents(criteria, fo) + + const rows = result.objects.map(event => ({ + id: _.get(event, 'id'), + eventType: FormUtil.createField({ + value: _.get(event, 'eventType') + }), + entityType: FormUtil.createField({ + value: _.get(event, 'entityType') + }), + entitySpace: FormUtil.createField({ + value: _.get(event, 'entitySpace') + }), + entityProject: FormUtil.createField({ + value: _.get(event, 'entityProject') + }), + entityRegistrator: FormUtil.createField({ + value: _.get(event, 'entityRegistrator') + }), + entityRegistrationDate: FormUtil.createField({ + value: _.get(event, 'entityRegistrationDate') + }), + identifier: FormUtil.createField({ + value: _.get(event, 'identifier') + }), + description: FormUtil.createField({ + value: _.get(event, 'description') + }), + reason: FormUtil.createField({ + value: _.get(event, 'reason') + }), + content: FormUtil.createField({ + value: _.get(event, 'content'), + visible: false + }), + registrator: FormUtil.createField({ + value: _.get(event, 'registrator.userId') + }), + registrationDate: FormUtil.createField({ + value: _.get(event, 'registrationDate') + }) + })) + + this.setState({ + rows, + totalCount: result.totalCount + }) + } + + handleRowChange(row, change) { + const rows = this.state.rows + this.setState(state => { + const index = rows.findIndex(r => r.id === row.id) + if (index !== -1) { + const row = rows[index] + const newRows = Array.from(rows) + newRows[index] = { + ...row, + ...change + } + return { + ...state, + rows: newRows + } + } + }) + } + + handleVisibilityChange(row, fieldName) { + this.handleRowChange(row, { + [fieldName]: { + ...row[fieldName], + visible: !row[fieldName].visible + } + }) + } + render() { logger.log(logger.DEBUG, 'HistoryGrid.render') - const { - rows, - selectedRowId, - onSelectedRowChange, - controllerRef - } = this.props + const { rows, totalCount } = this.state return ( <Grid id={this.getId()} header={this.getHeader()} - controllerRef={controllerRef} columns={[ { name: 'eventType', label: messages.get(messages.EVENT_TYPE), + sortable: false, getValue: ({ row }) => row.eventType.value }, { name: 'entityType', label: messages.get(messages.ENTITY_TYPE), + sortable: false, getValue: ({ row }) => row.entityType.value }, { - name: 'entityIdentifier', + name: 'identifier', label: messages.get(messages.ENTITY_IDENTIFIER), + sortable: true, getValue: ({ row }) => row.identifier.value }, { name: 'entitySpace', label: messages.get(messages.ENTITY_SPACE), + sortable: false, getValue: ({ row }) => row.entitySpace.value }, { name: 'entityProject', label: messages.get(messages.ENTITY_PROJECT), + sortable: false, getValue: ({ row }) => row.entityProject.value }, { name: 'entityRegistrator', label: messages.get(messages.ENTITY_REGISTRATOR), + sortable: false, getValue: ({ row }) => row.entityRegistrator.value }, { name: 'entityRegistrationDate', label: messages.get(messages.ENTITY_REGISTRATION_DATE), + sortable: false, getValue: ({ row }) => date.format(row.entityRegistrationDate.value) }, { name: 'description', label: messages.get(messages.DESCRIPTION), + sortable: false, getValue: ({ row }) => row.description.value }, { name: 'reason', label: messages.get(messages.REASON), + sortable: false, getValue: ({ row }) => row.reason.value }, { name: 'content', label: messages.get(messages.CONTENT), + sortable: false, getValue: ({ row }) => row.content.value, renderValue: ({ row }) => { const { value, visible } = row.content @@ -124,6 +221,7 @@ class HistoryGrid extends React.PureComponent { { name: 'registrator', label: messages.get(messages.USER), + sortable: false, getValue: ({ row }) => row.registrator.value, renderValue: ({ value }) => { return <UserLink userId={value} /> @@ -132,12 +230,14 @@ class HistoryGrid extends React.PureComponent { { name: 'registrationDate', label: messages.get(messages.DATE), + sortable: true, + sort: 'desc', getValue: ({ row }) => date.format(row.registrationDate.value) } ]} rows={rows} - selectedRowId={selectedRowId} - onSelectedRowChange={onSelectedRowChange} + totalCount={totalCount} + load={this.load} /> ) } diff --git a/openbis_ng_ui/src/js/components/tools/form/history/HistoryForm.jsx b/openbis_ng_ui/src/js/components/tools/form/history/HistoryForm.jsx index 94461d1c751f92b378466fc780cdd2d77f315206..5ff1d8251ae6143aab52a9259d52b485179e5b5a 100644 --- a/openbis_ng_ui/src/js/components/tools/form/history/HistoryForm.jsx +++ b/openbis_ng_ui/src/js/components/tools/form/history/HistoryForm.jsx @@ -1,127 +1,20 @@ -import _ from 'lodash' import React from 'react' -import autoBind from 'auto-bind' -import { connect } from 'react-redux' -import { withStyles } from '@material-ui/core/styles' import GridContainer from '@src/js/components/common/grid/GridContainer.jsx' import HistoryGrid from '@src/js/components/tools/common/HistoryGrid.jsx' -import FormUtil from '@src/js/components/common/form/FormUtil.js' -import openbis from '@src/js/services/openbis.js' -import store from '@src/js/store/store.js' -import actions from '@src/js/store/actions/actions.js' import logger from '@src/js/common/logger.js' -const styles = () => ({}) - class HistoryForm extends React.PureComponent { - constructor(props) { - super(props) - autoBind(this) - - this.state = { - loaded: false, - selection: null - } - } - - componentDidMount() { - this.load() - } - - async load() { - try { - const rows = await this.loadEvents(this.props.object.id) - this.setState(() => ({ - rows, - loaded: true - })) - } catch (error) { - store.dispatch(actions.errorChange(error)) - } - } - - async loadEvents(eventType) { - const criteria = new openbis.EventSearchCriteria() - criteria.withEventType().thatEquals(eventType) - - const fo = new openbis.EventFetchOptions() - fo.withRegistrator() - - const result = await openbis.searchEvents(criteria, fo) - - return result.objects.map(event => ({ - id: _.get(event, 'id'), - eventType: FormUtil.createField({ value: _.get(event, 'eventType') }), - entityType: FormUtil.createField({ value: _.get(event, 'entityType') }), - entitySpace: FormUtil.createField({ - value: _.get(event, 'entitySpace') - }), - entityProject: FormUtil.createField({ - value: _.get(event, 'entityProject') - }), - entityRegistrator: FormUtil.createField({ - value: _.get(event, 'entityRegistrator') - }), - entityRegistrationDate: FormUtil.createField({ - value: _.get(event, 'entityRegistrationDate') - }), - identifier: FormUtil.createField({ - value: _.get(event, 'identifier') - }), - description: FormUtil.createField({ - value: _.get(event, 'description') - }), - reason: FormUtil.createField({ - value: _.get(event, 'reason') - }), - content: FormUtil.createField({ - value: _.get(event, 'content'), - visible: false - }), - registrator: FormUtil.createField({ - value: _.get(event, 'registrator.userId') - }), - registrationDate: FormUtil.createField({ - value: _.get(event, 'registrationDate') - }) - })) - } - - handleRowChange(rowId, change) { - const rows = this.state.rows - this.setState(state => { - const index = rows.findIndex(row => row.id === rowId) - if (index !== -1) { - const row = rows[index] - const newRows = Array.from(rows) - newRows[index] = { - ...row, - ...change - } - return { - ...state, - rows: newRows - } - } - }) - } - render() { logger.log(logger.DEBUG, 'HistoryForm.render') const { id } = this.props.object - const { rows } = this.state return ( <GridContainer> - <HistoryGrid - eventType={id} - rows={rows} - onRowChange={this.handleRowChange} - /> + <HistoryGrid eventType={id} /> </GridContainer> ) } } -export default _.flow(connect(), withStyles(styles))(HistoryForm) +export default HistoryForm