chore(package): update react-virtualized (#2556)

`form/select` has been redeveloped for the occasion with the following features:
- not clearable when required and not multiple
- when no options available, marked as loading
- when required and only one option, it is automatically selected
This commit is contained in:
Julien Fontanet 2018-01-24 14:51:12 +01:00 committed by GitHub
parent 23e992de85
commit dc12896b19
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 290 additions and 406 deletions

View File

@ -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",

View File

@ -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
}

View File

@ -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'
// ===================================================================

View File

@ -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 (
<Select
autoFocus={props.autoFocus}
disabled={props.disabled}
multi={props.multi}
onChange={this._handleChange}
openOnFocus
optionRenderer={this._renderOption}
options={state.options}
placeholder={props.placeholder}
required={props.required}
value={state.value}
valueRenderer={this._renderOption}
/>
)
}
}

View File

@ -1,138 +1,160 @@
import map from 'lodash/map'
import React, { Component } from 'react'
import classNames from 'classnames'
import isEmpty from 'lodash/isEmpty'
import PropTypes from 'prop-types'
import React from 'react'
import ReactSelect from 'react-select'
import sum from 'lodash/sum'
import { AutoSizer, CellMeasurer, List } from 'react-virtualized'
import propTypes from '../prop-types-decorator'
const SELECT_MENU_STYLE = {
overflow: 'hidden',
}
import uncontrollableInput from 'uncontrollable-input'
import {
AutoSizer,
CellMeasurer,
CellMeasurerCache,
List,
} from 'react-virtualized'
const SELECT_STYLE = {
minWidth: '10em',
}
const LIST_STYLE = {
whiteSpace: 'normal',
const MENU_STYLE = {
overflow: 'hidden',
}
const MAX_OPTIONS = 5
// See: https://github.com/bvaughn/react-virtualized-select/blob/master/source/VirtualizedSelect/VirtualizedSelect.js
@propTypes({
maxHeight: propTypes.number,
})
export default class Select extends Component {
@uncontrollableInput()
export default class Select extends React.PureComponent {
static defaultProps = {
maxHeight: 200,
optionRenderer: (option, labelKey) => option[labelKey],
multi: ReactSelect.defaultProps.multi,
options: [],
required: ReactSelect.defaultProps.required,
valueKey: ReactSelect.defaultProps.valueKey,
}
_renderMenu = ({ focusedOption, options, ...otherOptions }) => {
const { maxHeight } = this.props
static propTypes = {
autoSelectSingleOption: PropTypes.bool, // default to props.required
maxHeight: PropTypes.number,
options: PropTypes.array.isRequired, // cannot be an object
}
const focusedOptionIndex = options.indexOf(focusedOption)
let height = options.length > MAX_OPTIONS && maxHeight
const wrappedRowRenderer = ({ index, key, style }) =>
this._optionRenderer({
...otherOptions,
focusedOption,
focusedOptionIndex,
key,
option: options[index],
options,
style,
_cellMeasurerCache = new CellMeasurerCache({
fixedWidth: true,
})
// https://github.com/JedWatson/react-select/blob/dd32c27d7ea338a93159da5e40bc06697d0d86f9/src/utils/defaultMenuRenderer.js#L4
_renderMenu (opts) {
const { focusOption, options, selectValue } = opts
const focusFromEvent = event =>
focusOption(options[event.currentTarget.dataset.index])
const selectFromEvent = event =>
selectValue(options[event.currentTarget.dataset.index])
const renderRow = opts2 =>
this._renderRow(opts, opts2, focusFromEvent, selectFromEvent)
let focusedOptionIndex = options.indexOf(opts.focusedOption)
if (focusedOptionIndex === -1) {
focusedOptionIndex = undefined
}
const { length } = options
const { maxHeight } = this.props
const { rowHeight } = this._cellMeasurerCache
let height = 0
for (let i = 0; i < length; ++i) {
height += rowHeight({ index: i })
if (height > maxHeight) {
height = maxHeight
break
}
}
return (
<AutoSizer disableHeight>
{({ width }) =>
width ? (
<CellMeasurer
cellRenderer={({ rowIndex }) =>
wrappedRowRenderer({ index: rowIndex })
}
columnCount={1}
rowCount={options.length}
// FIXME: 16 px: ugly workaround to take into account the scrollbar
// during the offscreen render to measure the row height
// See https://github.com/bvaughn/react-virtualized/issues/401
width={width - 16}
>
{({ getRowHeight }) => {
if (options.length <= MAX_OPTIONS) {
height = sum(
map(options, (_, index) => getRowHeight({ index }))
)
}
return (
{({ width }) => (
<List
deferredMeasurementCache={this._cellMeasurerCache}
height={height}
rowCount={options.length}
rowHeight={getRowHeight}
rowRenderer={wrappedRowRenderer}
rowCount={length}
rowHeight={rowHeight}
rowRenderer={renderRow}
scrollToIndex={focusedOptionIndex}
style={LIST_STYLE}
width={width}
/>
)
}}
</CellMeasurer>
) : null
}
)}
</AutoSizer>
)
}
_renderMenu = this._renderMenu.bind(this)
_optionRenderer = ({
_renderRow (
{
focusedOption,
focusOption,
key,
labelKey,
option,
style,
inputValue,
optionClassName,
optionRenderer,
options,
selectValue,
}) => {
let className = 'Select-option'
if (option === focusedOption) {
className += ' is-focused'
}
},
{ index, key, parent, style },
focusFromEvent,
selectFromEvent
) {
const option = options[index]
const { disabled } = option
if (disabled) {
className += ' is-disabled'
}
const { props } = this
return (
<div
className={className}
onClick={disabled ? undefined : () => selectValue(option)}
onMouseOver={disabled ? undefined : () => focusOption(option)}
style={style}
<CellMeasurer
cache={this._cellMeasurerCache}
columnIndex={0}
key={key}
parent={parent}
rowIndex={index}
>
{props.optionRenderer(option, labelKey)}
<div
className={classNames('Select-option', optionClassName, {
'is-disabled': disabled,
'is-focused': option === focusedOption,
})}
data-index={index}
onClick={disabled ? undefined : selectFromEvent}
onMouseEnter={disabled ? undefined : focusFromEvent}
style={style}
title={option.title}
>
{optionRenderer(option, index, inputValue)}
</div>
</CellMeasurer>
)
}
componentDidMount () {
this.componentDidUpdate()
}
componentDidUpdate () {
const { props } = this
const { autoSelectSingleOption = props.required, options } = props
if (autoSelectSingleOption && options != null && options.length === 1) {
const value = options[0][props.valueKey]
props.onChange(props.multi ? [value] : value)
}
}
render () {
const { props } = this
const { multi } = props
return (
<ReactSelect
closeOnSelect={!this.props.multi}
{...this.props}
backspaceToRemoveMessage=''
menuRenderer={this._renderMenu}
menuStyle={SELECT_MENU_STYLE}
clearable={multi || !props.required}
closeOnSelect={!multi}
isLoading={!props.disabled && isEmpty(props.options)}
style={SELECT_STYLE}
valueRenderer={props.optionRenderer}
{...props}
menuRenderer={this._renderMenu}
menuStyle={MENU_STYLE}
/>
)
}

View File

@ -1,5 +1,5 @@
import React from 'react'
import classNames from 'classnames'
import PropTypes from 'prop-types'
import { parse as parseRemote } from 'xo-remote-parser'
import {
assign,
@ -23,14 +23,12 @@ import {
import _ from './intl'
import Button from './button'
import Component from './base-component'
import Icon from './icon'
import propTypes from './prop-types-decorator'
import renderXoItem from './render-xo-item'
import Select from './form/select'
import store from './store'
import Tooltip from './tooltip'
import uncontrollableInput from 'uncontrollable-input'
import { Select } from './form'
import {
createCollectionWrapper,
createFilter,
@ -112,23 +110,18 @@ const options = props => ({
* ]
* }
*/
@propTypes({
autoFocus: propTypes.bool,
clearable: propTypes.bool,
disabled: propTypes.bool,
hasSelectAll: propTypes.bool,
multi: propTypes.bool,
onChange: propTypes.func,
placeholder: propTypes.any.isRequired,
required: propTypes.bool,
value: propTypes.any,
xoContainers: propTypes.array,
xoObjects: propTypes.oneOfType([
propTypes.array,
propTypes.objectOf(propTypes.array),
class GenericSelect extends React.Component {
static propTypes = {
hasSelectAll: PropTypes.bool,
multi: PropTypes.bool,
onChange: PropTypes.func.isRequired,
xoContainers: PropTypes.array,
xoObjects: PropTypes.oneOfType([
PropTypes.array,
PropTypes.objectOf(PropTypes.array),
]).isRequired,
})
export class GenericSelect extends Component {
}
_getObjectsById = createSelector(
() => this.props.xoObjects,
objects =>
@ -142,8 +135,8 @@ export class GenericSelect extends Component {
// createCollectionWrapper with a depth?
const { name } = this.constructor
let options = []
if (!containers) {
let options
if (containers === undefined) {
if (__DEV__ && !isArray(objects)) {
throw new Error(
`${name}: without xoContainers, xoObjects must be an array`
@ -151,12 +144,14 @@ export class GenericSelect extends Component {
}
options = map(objects, getOption)
} else if (__DEV__ && isArray(objects)) {
} else {
if (__DEV__ && isArray(objects)) {
throw new Error(
`${name}: with xoContainers, xoObjects must be an object`
)
}
options = []
forEach(containers, container => {
options.push({
disabled: true,
@ -167,11 +162,11 @@ export class GenericSelect extends Component {
options.push(getOption(object, container))
})
})
}
const values = this._getSelectValue()
const objectsById = this._getObjectsById()
const addIfMissing = val => {
if (val && !objectsById[val]) {
if (val != null && !(val in objectsById)) {
options.push({
disabled: true,
id: val,
@ -185,6 +180,7 @@ export class GenericSelect extends Component {
}
}
const values = this._getSelectedIds()
if (isArray(values)) {
forEach(values, addIfMissing)
} else {
@ -195,27 +191,25 @@ export class GenericSelect extends Component {
}
)
_getSelectValue = createSelector(
_getSelectedIds = createSelector(
() => this.props.value,
createCollectionWrapper(getIds)
)
_getNewSelectedObjects = createSelector(
_getSelectedObjects = (() => {
const helper = createSelector(
this._getObjectsById,
value => value,
(objectsById, value) =>
value == null
? value
: isArray(value)
isArray(value)
? map(value, value => objectsById[value.value])
: objectsById[value.value]
)
return value => (value == null ? value : helper(value))
})()
_onChange = value => {
const { onChange } = this.props
if (onChange) {
onChange(this._getNewSelectedObjects(value))
}
this.props.onChange(this._getSelectedObjects(value))
}
_selectAll = () => {
@ -225,46 +219,31 @@ export class GenericSelect extends Component {
// GroupBy: Display option with margin if not disabled and containers exists.
_renderOption = option => (
<span
className={classNames(
!option.disabled && this.props.xoContainers && 'ml-1'
)}
className={
!option.disabled && this.props.xoContainers !== undefined
? 'ml-1'
: undefined
}
>
{renderXoItem(option.xoItem)}
</span>
)
render () {
const {
autoFocus,
disabled,
hasSelectAll,
multi,
placeholder,
required,
clearable = Boolean(multi || !required),
} = this.props
const { hasSelectAll, xoContainers, xoObjects, ...props } = this.props
const select = (
<Select
{...{
autoFocus,
clearable,
disabled,
multi,
placeholder,
required,
}}
{...props}
onChange={this._onChange}
openOnFocus
optionRenderer={this._renderOption}
options={this._getOptions()}
value={this._getSelectValue()}
valueRenderer={this._renderOption}
value={this._getSelectedIds()}
/>
)
if (!multi || !hasSelectAll) {
if (!props.multi || !hasSelectAll) {
return select
}
@ -295,16 +274,15 @@ 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(
_getFilteredXoContainers = createFilter(
() => this.state.xoContainers,
() => this.props.containerPredicate
)
this._getFilteredXoObjects = createSelector(
_getFilteredXoObjects = createSelector(
() => this.state.xoObjects,
() => this.state.xoContainers && this._getFilteredXoContainers(),
() => this.props.predicate,
@ -324,7 +302,6 @@ const makeSubscriptionSelect = (subscribe, props) =>
}
}
)
}
componentWillMount () {
this.componentWillUnmount = subscribe(::this.setState)
@ -577,10 +554,7 @@ export const SelectHighLevelObject = makeStoreSelect(
// ===================================================================
export const SelectVdi = propTypes({
srPredicate: propTypes.func,
})(
makeStoreSelect(
export const SelectVdi = makeStoreSelect(
() => {
const getSrs = createGetObjectsOfType('SR').filter(
(_, props) => props.srPredicate
@ -605,8 +579,10 @@ export const SelectVdi = propTypes({
}
},
{ 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
}

View File

@ -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 (
<div>
<SelectPlainObject
<Select
labelKey='name'
onChange={this._onBackupChange}
optionKey='id'
optionRenderer={backupOptionRenderer}
options={backups}
placeholder={_('restoreFilesSelectBackup')}
value={backup}
valueKey='id'
/>
{backup && [
<br />,
<SelectPlainObject
<Select
labelKey='name'
onChange={this._onDiskChange}
optionKey='id'
optionRenderer={diskOptionRenderer}
options={backup.disks}
placeholder={_('restoreFilesSelectDisk')}
value={disk}
valueKey='id'
/>,
]}
{scanDiskError && (
@ -279,13 +281,14 @@ export default class RestoreFileModalBody extends Component {
!scanDiskError &&
!noPartitions && [
<br />,
<SelectPlainObject
<Select
labelKey='name'
onChange={this._onPartitionChange}
optionKey='id'
optionRenderer={partitionOptionRenderer}
options={partitions}
placeholder={_('restoreFilesSelectPartition')}
value={partition}
valueKey='id'
/>,
]}
{(partition || (disk && !scanDiskError && noPartitions)) && [
@ -311,13 +314,14 @@ export default class RestoreFileModalBody extends Component {
</Col>
</Row>
</Container>,
<SelectPlainObject
<Select
labelKey='name'
onChange={this._onFileChange}
optionKey='id'
optionRenderer={fileOptionRenderer}
options={this._getSelectableFiles()}
placeholder={_('restoreFilesSelectFiles')}
value={null}
valueKey='id'
/>,
<br />,
<div>

View File

@ -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 (
<div>
<SelectPlainObject
<Select
labelKey='name'
onChange={this.linkState('backup')}
optionKey='path'
optionRenderer={backupOptionRenderer}
options={props.backups}
placeholder={props.intl.formatMessage(
messages.importBackupModalSelectBackup
)}
valueKey='path'
/>
<br />
<ChooseSrForEachVdisModal

View File

@ -3,6 +3,7 @@ import ActionButton from 'action-button'
import ActionRowButton from 'action-row-button'
import Button from 'button'
import Component from 'base-component'
import defined from 'xo-defined'
import delay from 'lodash/delay'
import find from 'lodash/find'
import forEach from 'lodash/forEach'
@ -13,6 +14,7 @@ import isEmpty from 'lodash/isEmpty'
import map from 'lodash/map'
import mapValues from 'lodash/mapValues'
import React from 'react'
import Select from 'form/select'
import size from 'lodash/size'
import Tooltip from 'tooltip'
import Upgrade from 'xoa-upgrade'
@ -21,7 +23,6 @@ import { createSelector } from 'selectors'
import { error } from 'notification'
import { generateUiSchema } from 'xo-json-schema-input'
import { injectIntl } from 'react-intl'
import { SelectPlainObject } from 'form'
import { SelectSubject } from 'select-objects'
import {
@ -119,17 +120,7 @@ export default class Jobs extends Component {
})
}
componentWillReceiveProps (props) {
const { currentUser } = props
const { owner } = this.state
if (currentUser && !owner) {
this.setState({ owner: currentUser.id })
}
}
componentWillMount () {
this.setState({ owner: this.props.user && this.props.user.id })
this.componentWillUnmount = subscribeJobs(jobs => {
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)}
/>
<input
type='text'
@ -397,12 +388,13 @@ export default class Jobs extends Component {
pattern='[^_]+'
required
/>
<SelectPlainObject
ref='method'
options={actions}
optionKey='method'
<Select
labelKey='method'
onChange={this._handleSelectMethod}
options={actions}
placeholder={_('jobActionPlaceHolder')}
ref='method'
valueKey='method'
/>
<input
type='number'

View File

@ -10,7 +10,7 @@ import React, { Component } from 'react'
import Scheduler, { SchedulePreview } from 'scheduling'
import { error } from 'notification'
import { injectIntl } from 'react-intl'
import { SelectPlainObject, Toggle } from 'form'
import { Select, Toggle } from 'form'
import {
createSchedule,
deleteSchedule,
@ -223,10 +223,11 @@ export default class Schedules extends Component {
/>
</div>
<div className='form-group'>
<SelectPlainObject
<Select
labelKey='name'
ref='job'
options={map(jobs)}
optionKey='id'
valueKey='id'
placeholder={this.props.intl.formatMessage(
messages.jobScheduleJobPlaceHolder
)}

View File

@ -381,6 +381,7 @@ export class Edit extends Component {
</Col>
<Col mediumSize={4}>
<SelectSubject
autoSelectSingleOption={false}
hasSelectAll
multi
onChange={this.linkState('subjects')}
@ -390,6 +391,7 @@ export class Edit extends Component {
</Col>
<Col mediumSize={4}>
<SelectPool
autoSelectSingleOption={false}
hasSelectAll
multi
onChange={this._updateSelectedPools}
@ -414,6 +416,7 @@ export class Edit extends Component {
<Row>
<Col mediumSize={4}>
<SelectVmTemplate
autoSelectSingleOption={false}
disabled={!state.nPools}
hasSelectAll
multi
@ -425,6 +428,7 @@ export class Edit extends Component {
</Col>
<Col mediumSize={4}>
<SelectSr
autoSelectSingleOption={false}
disabled={!state.nPools}
hasSelectAll
multi
@ -436,6 +440,7 @@ export class Edit extends Component {
</Col>
<Col mediumSize={4}>
<SelectNetwork
autoSelectSingleOption={false}
disabled={!state.nSrs}
hasSelectAll
multi
@ -535,8 +540,8 @@ export class Edit extends Component {
<Col mediumSize={7}>
<SelectIpPool
onChange={this._onChangeIpPool}
value=''
predicate={this._getIpPoolPredicate()}
value={null}
/>
</Col>
</Row>

View File

@ -166,7 +166,7 @@ export default class Acls extends Component {
constructor (props) {
super(props)
this.state = {
action: '',
action: null,
objects: [],
subjects: [],
typeFilters: {},

View File

@ -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"