feat(xo-web/SortedTable): allow to change the number of items per page (#5355)
See xoa-support#3020
This commit is contained in:
parent
7961ff0785
commit
fbf906d97c
@ -16,6 +16,7 @@
|
|||||||
- [Web Hooks] `backupNg.runJob` is now triggered by scheduled runs [#5205](https://github.com/vatesfr/xen-orchestra/issues/5205) (PR [#5360](https://github.com/vatesfr/xen-orchestra/pull/5360))
|
- [Web Hooks] `backupNg.runJob` is now triggered by scheduled runs [#5205](https://github.com/vatesfr/xen-orchestra/issues/5205) (PR [#5360](https://github.com/vatesfr/xen-orchestra/pull/5360))
|
||||||
- [Licensing] Add trial end information banner (PR [#5374](https://github.com/vatesfr/xen-orchestra/pull/5374))
|
- [Licensing] Add trial end information banner (PR [#5374](https://github.com/vatesfr/xen-orchestra/pull/5374))
|
||||||
- Assign custom fields on pools, hosts, SRs, and VMs in advanced tab [#4730](https://github.com/vatesfr/xen-orchestra/issues/4730) (PR [#5387](https://github.com/vatesfr/xen-orchestra/pull/5387))
|
- Assign custom fields on pools, hosts, SRs, and VMs in advanced tab [#4730](https://github.com/vatesfr/xen-orchestra/issues/4730) (PR [#5387](https://github.com/vatesfr/xen-orchestra/pull/5387))
|
||||||
|
- Ability to change the number of items displayed per table or page (PR [#5355](https://github.com/vatesfr/xen-orchestra/pull/5355))
|
||||||
|
|
||||||
### Bug fixes
|
### Bug fixes
|
||||||
|
|
||||||
|
@ -1,13 +1,14 @@
|
|||||||
import * as CM from 'complex-matcher'
|
import * as CM from 'complex-matcher'
|
||||||
import _ from 'intl'
|
import _ from 'intl'
|
||||||
import classNames from 'classnames'
|
import classNames from 'classnames'
|
||||||
|
import cookies from 'js-cookie'
|
||||||
import defined, { ifDef } from '@xen-orchestra/defined'
|
import defined, { ifDef } from '@xen-orchestra/defined'
|
||||||
import DropdownMenu from 'react-bootstrap-4/lib/DropdownMenu' // https://phabricator.babeljs.io/T6662 so Dropdown.Menu won't work like https://react-bootstrap.github.io/components.html#btn-dropdowns-custom
|
import DropdownMenu from 'react-bootstrap-4/lib/DropdownMenu' // https://phabricator.babeljs.io/T6662 so Dropdown.Menu won't work like https://react-bootstrap.github.io/components.html#btn-dropdowns-custom
|
||||||
import DropdownToggle from 'react-bootstrap-4/lib/DropdownToggle' // https://phabricator.babeljs.io/T6662 so Dropdown.Toggle won't work https://react-bootstrap.github.io/components.html#btn-dropdowns-custom
|
import DropdownToggle from 'react-bootstrap-4/lib/DropdownToggle' // https://phabricator.babeljs.io/T6662 so Dropdown.Toggle won't work https://react-bootstrap.github.io/components.html#btn-dropdowns-custom
|
||||||
import PropTypes from 'prop-types'
|
import PropTypes from 'prop-types'
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import Shortcuts from 'shortcuts'
|
import Shortcuts from 'shortcuts'
|
||||||
import { Dropdown, MenuItem } from 'react-bootstrap-4/lib'
|
import { Dropdown, DropdownButton, MenuItem } from 'react-bootstrap-4/lib'
|
||||||
import { Portal } from 'react-overlays'
|
import { Portal } from 'react-overlays'
|
||||||
import { Set } from 'immutable'
|
import { Set } from 'immutable'
|
||||||
import { injectState, provideState } from 'reaclette'
|
import { injectState, provideState } from 'reaclette'
|
||||||
@ -38,9 +39,12 @@ import {
|
|||||||
createSelector,
|
createSelector,
|
||||||
createSort,
|
createSort,
|
||||||
} from '../selectors'
|
} from '../selectors'
|
||||||
|
import { ITEMS_PER_PAGE_OPTIONS } from '../xo'
|
||||||
|
|
||||||
import styles from './index.css'
|
import styles from './index.css'
|
||||||
|
|
||||||
|
const DEFAULT_ITEMS_PER_PAGE = 10
|
||||||
|
|
||||||
// ===================================================================
|
// ===================================================================
|
||||||
|
|
||||||
class ColumnHead extends Component {
|
class ColumnHead extends Component {
|
||||||
@ -268,7 +272,6 @@ class SortedTable extends Component {
|
|||||||
),
|
),
|
||||||
groupedActions: actionsShape,
|
groupedActions: actionsShape,
|
||||||
individualActions: actionsShape,
|
individualActions: actionsShape,
|
||||||
itemsPerPage: PropTypes.number,
|
|
||||||
onSelect: PropTypes.func,
|
onSelect: PropTypes.func,
|
||||||
paginationContainer: PropTypes.func,
|
paginationContainer: PropTypes.func,
|
||||||
rowAction: PropTypes.func,
|
rowAction: PropTypes.func,
|
||||||
@ -283,10 +286,6 @@ class SortedTable extends Component {
|
|||||||
userData: PropTypes.any,
|
userData: PropTypes.any,
|
||||||
}
|
}
|
||||||
|
|
||||||
static defaultProps = {
|
|
||||||
itemsPerPage: 10,
|
|
||||||
}
|
|
||||||
|
|
||||||
constructor(props, context) {
|
constructor(props, context) {
|
||||||
super(props, context)
|
super(props, context)
|
||||||
|
|
||||||
@ -306,6 +305,7 @@ class SortedTable extends Component {
|
|||||||
|
|
||||||
const state = (this.state = {
|
const state = (this.state = {
|
||||||
all: false, // whether all items are selected (accross pages)
|
all: false, // whether all items are selected (accross pages)
|
||||||
|
itemsPerPage: +defined(cookies.get(`${props.location.pathname}-${props.stateUrlParam}`), DEFAULT_ITEMS_PER_PAGE),
|
||||||
})
|
})
|
||||||
|
|
||||||
this._getSelectedColumn = () => this.props.columns[this._getSelectedColumnId()]
|
this._getSelectedColumn = () => this.props.columns[this._getSelectedColumnId()]
|
||||||
@ -340,7 +340,7 @@ class SortedTable extends Component {
|
|||||||
this._getSortOrder
|
this._getSortOrder
|
||||||
)
|
)
|
||||||
|
|
||||||
this._getVisibleItems = createPager(this._getItems, this._getPage, () => this.props.itemsPerPage)
|
this._getVisibleItems = createPager(this._getItems, this._getPage, () => this.state.itemsPerPage)
|
||||||
|
|
||||||
state.selectedItemsIds = new Set()
|
state.selectedItemsIds = new Set()
|
||||||
|
|
||||||
@ -468,7 +468,7 @@ class SortedTable extends Component {
|
|||||||
_setPage = this._setPage.bind(this)
|
_setPage = this._setPage.bind(this)
|
||||||
|
|
||||||
goTo(id) {
|
goTo(id) {
|
||||||
this._setPage(Math.floor(this._getItems().findIndex(item => item.id === id) / this.props.itemsPerPage) + 1)
|
this._setPage(Math.floor(this._getItems().findIndex(item => item.id === id) / this.state.itemsPerPage) + 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
_selectAllVisibleItems = event => {
|
_selectAllVisibleItems = event => {
|
||||||
@ -584,7 +584,7 @@ class SortedTable extends Component {
|
|||||||
|
|
||||||
_getNPages = createSelector(
|
_getNPages = createSelector(
|
||||||
() => this._getItems().length,
|
() => this._getItems().length,
|
||||||
() => this.props.itemsPerPage,
|
() => this.state.itemsPerPage,
|
||||||
(nItems, itemsPerPage) => ceil(nItems / itemsPerPage)
|
(nItems, itemsPerPage) => ceil(nItems / itemsPerPage)
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -727,18 +727,16 @@ class SortedTable extends Component {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_setNItemsPerPage = itemsPerPage => {
|
||||||
|
const { location, stateUrlParam } = this.props
|
||||||
|
this.setState({ itemsPerPage })
|
||||||
|
cookies.set(`${location.pathname}-${stateUrlParam}`, itemsPerPage)
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { props, state } = this
|
const { props, state } = this
|
||||||
const {
|
const { actions, filterContainer, individualActions, onSelect, paginationContainer, shortcutsTarget } = props
|
||||||
actions,
|
const { all, itemsPerPage } = state
|
||||||
filterContainer,
|
|
||||||
individualActions,
|
|
||||||
itemsPerPage,
|
|
||||||
onSelect,
|
|
||||||
paginationContainer,
|
|
||||||
shortcutsTarget,
|
|
||||||
} = props
|
|
||||||
const { all } = state
|
|
||||||
const groupedActions = this._getGroupedActions()
|
const groupedActions = this._getGroupedActions()
|
||||||
|
|
||||||
const nAllItems = this._getTotalNumberOfItems()
|
const nAllItems = this._getTotalNumberOfItems()
|
||||||
@ -860,7 +858,7 @@ class SortedTable extends Component {
|
|||||||
</table>
|
</table>
|
||||||
<Container>
|
<Container>
|
||||||
<SingleLineRow>
|
<SingleLineRow>
|
||||||
<Col mediumSize={8}>
|
<Col mediumSize={7}>
|
||||||
{displayPagination &&
|
{displayPagination &&
|
||||||
(paginationContainer !== undefined ? (
|
(paginationContainer !== undefined ? (
|
||||||
// Rebuild container function to refresh Portal component.
|
// Rebuild container function to refresh Portal component.
|
||||||
@ -872,6 +870,15 @@ class SortedTable extends Component {
|
|||||||
<Col mediumSize={4}>
|
<Col mediumSize={4}>
|
||||||
{filterContainer ? <Portal container={() => filterContainer()}>{filterInstance}</Portal> : filterInstance}
|
{filterContainer ? <Portal container={() => filterContainer()}>{filterInstance}</Portal> : filterInstance}
|
||||||
</Col>
|
</Col>
|
||||||
|
<Col mediumSize={1} className='pull-right'>
|
||||||
|
<DropdownButton bsStyle='info' title={itemsPerPage}>
|
||||||
|
{ITEMS_PER_PAGE_OPTIONS.map(nItems => (
|
||||||
|
<MenuItem key={nItems} onClick={() => this._setNItemsPerPage(nItems)}>
|
||||||
|
{nItems}
|
||||||
|
</MenuItem>
|
||||||
|
))}
|
||||||
|
</DropdownButton>
|
||||||
|
</Col>
|
||||||
</SingleLineRow>
|
</SingleLineRow>
|
||||||
</Container>
|
</Container>
|
||||||
</div>
|
</div>
|
||||||
|
@ -37,6 +37,10 @@ import parseNdJson from './_parseNdJson'
|
|||||||
|
|
||||||
// ===================================================================
|
// ===================================================================
|
||||||
|
|
||||||
|
export const ITEMS_PER_PAGE_OPTIONS = [10, 20, 50, 100]
|
||||||
|
|
||||||
|
// ===================================================================
|
||||||
|
|
||||||
export const XEN_DEFAULT_CPU_WEIGHT = 256
|
export const XEN_DEFAULT_CPU_WEIGHT = 256
|
||||||
export const XEN_DEFAULT_CPU_CAP = 0
|
export const XEN_DEFAULT_CPU_CAP = 0
|
||||||
|
|
||||||
|
@ -64,6 +64,7 @@ import {
|
|||||||
subscribeResourceSets,
|
subscribeResourceSets,
|
||||||
subscribeServers,
|
subscribeServers,
|
||||||
suspendVms,
|
suspendVms,
|
||||||
|
ITEMS_PER_PAGE_OPTIONS,
|
||||||
} from 'xo'
|
} from 'xo'
|
||||||
import { Container, Row, Col } from 'grid'
|
import { Container, Row, Col } from 'grid'
|
||||||
import { createPredicate } from 'value-matcher'
|
import { createPredicate } from 'value-matcher'
|
||||||
@ -92,7 +93,6 @@ import TemplateItem from './template-item'
|
|||||||
import SrItem from './sr-item'
|
import SrItem from './sr-item'
|
||||||
|
|
||||||
const DEFAULT_ITEMS_PER_PAGE = 20
|
const DEFAULT_ITEMS_PER_PAGE = 20
|
||||||
const ITEMS_PER_PAGE_OPTIONS = [20, 50, 100]
|
|
||||||
|
|
||||||
const OPTIONS = {
|
const OPTIONS = {
|
||||||
host: {
|
host: {
|
||||||
|
Loading…
Reference in New Issue
Block a user