diff --git a/package.json b/package.json index d57166e8e..48f370d56 100644 --- a/package.json +++ b/package.json @@ -132,7 +132,7 @@ "react-shortcuts": "^2.0.0", "react-sparklines": "1.6.0", "react-test-renderer": "^15.6.2", - "react-virtualized": "^8.0.8", + "react-virtualized": "^9.15.0", "readable-stream": "^2.3.3", "redux": "^3.7.2", "redux-thunk": "^2.0.1", diff --git a/src/common/base-component.js b/src/common/base-component.js index 4405e84f2..9ee83aea9 100644 --- a/src/common/base-component.js +++ b/src/common/base-component.js @@ -10,7 +10,7 @@ import getEventValue from './get-event-value' const VERBOSE = false const get = (object, path, depth) => { - if (depth >= path.length) { + if (object == null || depth >= path.length) { return object } diff --git a/src/common/form/index.js b/src/common/form/index.js index bbda123b1..e63dcf806 100644 --- a/src/common/form/index.js +++ b/src/common/form/index.js @@ -17,7 +17,6 @@ import propTypes from '../prop-types-decorator' import { formatSizeRaw, parseSize } from '../utils' export Select from './select' -export SelectPlainObject from './select-plain-object' // =================================================================== diff --git a/src/common/form/select-plain-object.js b/src/common/form/select-plain-object.js deleted file mode 100644 index b7b71c048..000000000 --- a/src/common/form/select-plain-object.js +++ /dev/null @@ -1,118 +0,0 @@ -import uncontrollableInput from 'uncontrollable-input' -import Component from 'base-component' -import find from 'lodash/find' -import map from 'lodash/map' -import React from 'react' - -import propTypes from '../prop-types-decorator' - -import Select from './select' - -@propTypes({ - autoFocus: propTypes.bool, - disabled: propTypes.bool, - optionRenderer: propTypes.func, - multi: propTypes.bool, - onChange: propTypes.func, - options: propTypes.array, - placeholder: propTypes.node, - predicate: propTypes.func, - required: propTypes.bool, - value: propTypes.any, -}) -@uncontrollableInput() -export default class SelectPlainObject extends Component { - componentDidMount () { - const { options, value } = this.props - - this.setState({ - options: this._computeOptions(options), - value: this._computeValue(value, this.props), - }) - } - - componentWillReceiveProps (newProps) { - if (newProps !== this.props) { - this.setState({ - options: this._computeOptions(newProps.options), - value: this._computeValue(newProps.value, newProps), - }) - } - } - - _computeValue (value, props = this.props) { - let { optionKey } = props - optionKey || (optionKey = 'id') - const reduceValue = value => - value != null ? value[optionKey] || value : '' - if (props.multi) { - if (!Array.isArray(value)) { - value = [value] - } - return map(value, reduceValue) - } - - return reduceValue(value) - } - - _computeOptions (options) { - const { optionKey = 'id' } = this.props - const { optionRenderer = o => o.label || o[optionKey] || o } = this.props - return map(options, option => ({ - value: option[optionKey] || option, - label: optionRenderer(option), - })) - } - - _getObject (value) { - if (value == null) { - return undefined - } - - const { optionKey = 'id', options } = this.props - - const pickValue = value => { - value = value.value || value - return find( - options, - option => option[optionKey] === value || option === value - ) - } - - if (this.props.multi) { - return map(value, pickValue) - } - - return pickValue(value) - } - - _handleChange = value => { - const { onChange } = this.props - - if (onChange) { - onChange(this._getObject(value)) - } - } - - _renderOption = option => option.label - - render () { - const { props, state } = this - - return ( - ) - if (!multi || !hasSelectAll) { + if (!props.multi || !hasSelectAll) { return select } @@ -295,36 +274,34 @@ const makeStoreSelect = (createSelectors, defaultProps) => const makeSubscriptionSelect = (subscribe, props) => uncontrollableInput(options)( - class extends Component { - constructor (props) { - super(props) + class extends React.PureComponent { + state = {} - this._getFilteredXoContainers = createFilter( - () => this.state.xoContainers, - () => this.props.containerPredicate - ) + _getFilteredXoContainers = createFilter( + () => this.state.xoContainers, + () => this.props.containerPredicate + ) - this._getFilteredXoObjects = createSelector( - () => this.state.xoObjects, - () => this.state.xoContainers && this._getFilteredXoContainers(), - () => this.props.predicate, - (xoObjects, xoContainers, predicate) => { - if (xoContainers == null) { - return filter(xoObjects, predicate) - } else { - // Filter xoObjects with `predicate`... - const filteredObjects = mapValues(xoObjects, xoObjectsGroup => - filter(xoObjectsGroup, predicate) - ) - // ...and keep only those whose xoContainer hasn't been filtered out - return pick( - filteredObjects, - map(xoContainers, container => container.id) - ) - } + _getFilteredXoObjects = createSelector( + () => this.state.xoObjects, + () => this.state.xoContainers && this._getFilteredXoContainers(), + () => this.props.predicate, + (xoObjects, xoContainers, predicate) => { + if (xoContainers == null) { + return filter(xoObjects, predicate) + } else { + // Filter xoObjects with `predicate`... + const filteredObjects = mapValues(xoObjects, xoObjectsGroup => + filter(xoObjectsGroup, predicate) + ) + // ...and keep only those whose xoContainer hasn't been filtered out + return pick( + filteredObjects, + map(xoContainers, container => container.id) + ) } - ) - } + } + ) componentWillMount () { this.componentWillUnmount = subscribe(::this.setState) @@ -577,36 +554,35 @@ export const SelectHighLevelObject = makeStoreSelect( // =================================================================== -export const SelectVdi = propTypes({ - srPredicate: propTypes.func, -})( - makeStoreSelect( - () => { - const getSrs = createGetObjectsOfType('SR').filter( - (_, props) => props.srPredicate - ) - const getVdis = createGetObjectsOfType('VDI') - .filter( - createSelector( - getSrs, - getPredicate, - (srs, predicate) => - predicate - ? vdi => srs[vdi.$SR] && predicate(vdi) - : vdi => srs[vdi.$SR] - ) +export const SelectVdi = makeStoreSelect( + () => { + const getSrs = createGetObjectsOfType('SR').filter( + (_, props) => props.srPredicate + ) + const getVdis = createGetObjectsOfType('VDI') + .filter( + createSelector( + getSrs, + getPredicate, + (srs, predicate) => + predicate + ? vdi => srs[vdi.$SR] && predicate(vdi) + : vdi => srs[vdi.$SR] ) - .sort() - .groupBy('$SR') + ) + .sort() + .groupBy('$SR') - return { - xoObjects: getVdis, - xoContainers: getSrs.sort(), - } - }, - { placeholder: _('selectVdis') } - ) + return { + xoObjects: getVdis, + xoContainers: getSrs.sort(), + } + }, + { placeholder: _('selectVdis') } ) +SelectVdi.propTypes = { + srPredicate: PropTypes.func, +} // =================================================================== @@ -747,7 +723,7 @@ export const SelectResourceSet = makeSubscriptionSelect( // =================================================================== -export class SelectResourceSetsVmTemplate extends Component { +export class SelectResourceSetsVmTemplate extends React.PureComponent { get value () { return this.refs.select.value } @@ -782,7 +758,7 @@ export class SelectResourceSetsVmTemplate extends Component { // =================================================================== -export class SelectResourceSetsSr extends Component { +export class SelectResourceSetsSr extends React.PureComponent { get value () { return this.refs.select.value } @@ -813,7 +789,7 @@ export class SelectResourceSetsSr extends Component { // =================================================================== -export class SelectResourceSetsVdi extends Component { +export class SelectResourceSetsVdi extends React.PureComponent { get value () { return this.refs.select.value } @@ -853,7 +829,7 @@ export class SelectResourceSetsVdi extends Component { // =================================================================== -export class SelectResourceSetsNetwork extends Component { +export class SelectResourceSetsNetwork extends React.PureComponent { get value () { return this.refs.select.value } @@ -894,12 +870,13 @@ export class SelectResourceSetsNetwork extends Component { ipPools: subscribeIpPools, resourceSets: subscribeResourceSets, })) -@propTypes({ - containerPredicate: propTypes.func, - predicate: propTypes.func, - resourceSetId: propTypes.string.isRequired, -}) -export class SelectResourceSetIp extends Component { +export class SelectResourceSetIp extends React.Component { + static propTypes = { + containerPredicate: PropTypes.func, + predicate: PropTypes.func, + resourceSetId: PropTypes.string.isRequired, + } + get value () { return this.refs.select.value } @@ -958,7 +935,7 @@ export class SelectResourceSetIp extends Component { // =================================================================== -export class SelectSshKey extends Component { +export class SelectSshKey extends React.PureComponent { get value () { return this.refs.select.value } diff --git a/src/xo-app/backup/file-restore/restore-file-modal.js b/src/xo-app/backup/file-restore/restore-file-modal.js index 7fffaca2d..8fd6cd292 100644 --- a/src/xo-app/backup/file-restore/restore-file-modal.js +++ b/src/xo-app/backup/file-restore/restore-file-modal.js @@ -5,12 +5,12 @@ import endsWith from 'lodash/endsWith' import Icon from 'icon' import React from 'react' import replace from 'lodash/replace' +import Select from 'form/select' import Tooltip from 'tooltip' import { Container, Col, Row } from 'grid' import { createSelector } from 'reselect' import { formatSize } from 'utils' import { FormattedDate } from 'react-intl' -import { SelectPlainObject } from 'form' import { filter, includes, isEmpty, map } from 'lodash' import { scanDisk, scanFiles } from 'xo' @@ -251,23 +251,25 @@ export default class RestoreFileModalBody extends Component { return (
- {backup && [
, - , ]} {scanDiskError && ( @@ -279,13 +281,14 @@ export default class RestoreFileModalBody extends Component { !scanDiskError && !noPartitions && [
, - , ]} {(partition || (disk && !scanDiskError && noPartitions)) && [ @@ -311,13 +314,14 @@ export default class RestoreFileModalBody extends Component { , - ,
,
diff --git a/src/xo-app/backup/restore/index.js b/src/xo-app/backup/restore/index.js index 23a65ddae..8615fba6e 100644 --- a/src/xo-app/backup/restore/index.js +++ b/src/xo-app/backup/restore/index.js @@ -22,7 +22,7 @@ import { addSubscriptions, noop } from 'utils' import { Container, Row, Col } from 'grid' import { FormattedDate, injectIntl } from 'react-intl' import { info, error } from 'notification' -import { SelectPlainObject, Toggle } from 'form' +import { Select, Toggle } from 'form' import { importBackup, @@ -210,14 +210,15 @@ class _ModalBody extends Component { return (
-
{ const j = {} for (const id in jobs) { @@ -279,7 +270,7 @@ export default class Jobs extends Component { params.value ), }, - userId: owner, + userId: owner !== undefined ? owner : this.props.currentUser.id, timeout: timeout ? timeout * 1e3 : undefined, } @@ -372,8 +363,8 @@ export default class Jobs extends Component { type === 'user' && permission === 'admin' render () { - const { state } = this - const { action, actions, job, jobs, owner } = state + const { props, state } = this + const { action, actions, job, jobs } = state const { formatMessage } = this.props.intl const isJobUserMissing = this._getIsJobUserMissing() @@ -387,7 +378,7 @@ export default class Jobs extends Component { placeholder={_('jobOwnerPlaceholder')} predicate={this._subjectPredicate} required - value={owner} + value={defined(state.owner, () => props.currentUser.id)} /> -
- diff --git a/src/xo-app/settings/acls/index.js b/src/xo-app/settings/acls/index.js index d063e957f..f96a99f3a 100644 --- a/src/xo-app/settings/acls/index.js +++ b/src/xo-app/settings/acls/index.js @@ -166,7 +166,7 @@ export default class Acls extends Component { constructor (props) { super(props) this.state = { - action: '', + action: null, objects: [], subjects: [], typeFilters: {}, diff --git a/yarn.lock b/yarn.lock index 63b84d980..fac5b12f3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1270,7 +1270,7 @@ babel-runtime@^5.8.25: dependencies: core-js "^1.0.0" -babel-runtime@^6.11.6, babel-runtime@^6.18.0, babel-runtime@^6.2.0, babel-runtime@^6.22.0, babel-runtime@^6.23.0, babel-runtime@^6.26.0: +babel-runtime@^6.18.0, babel-runtime@^6.2.0, babel-runtime@^6.22.0, babel-runtime@^6.23.0, babel-runtime@^6.26.0: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe" dependencies: @@ -7292,14 +7292,15 @@ react-transition-group@^2.2.0: prop-types "^15.5.8" warning "^3.0.0" -react-virtualized@^8.0.8: - version "8.11.4" - resolved "https://registry.yarnpkg.com/react-virtualized/-/react-virtualized-8.11.4.tgz#0bb94f1ecbd286d07145ce63983d0a11724522c0" +react-virtualized@^9.15.0: + version "9.17.3" + resolved "https://registry.yarnpkg.com/react-virtualized/-/react-virtualized-9.17.3.tgz#3854588f067235c00ae5cd134d96508956630033" dependencies: - babel-runtime "^6.11.6" + babel-runtime "^6.26.0" classnames "^2.2.3" dom-helpers "^2.4.0 || ^3.0.0" loose-envify "^1.3.0" + prop-types "^15.5.4" react@^15.4.1: version "15.6.2"