chore(xo-web): remove unnecessary prop-types-decorator (#3542)

This commit is contained in:
Enishowk
2018-10-17 14:30:57 +00:00
committed by Julien Fontanet
parent b940ade902
commit 64d295ee3f
67 changed files with 1052 additions and 947 deletions

View File

@@ -1,5 +1,5 @@
import ActionButton from 'action-button'
import propTypes from 'prop-types-decorator'
import PropTypes from 'prop-types'
import React, { cloneElement } from 'react'
import { noop } from 'lodash'
@@ -28,12 +28,12 @@ export const Action = ({
)
Action.propTypes = {
display: propTypes.oneOf(['icon', 'both']),
handler: propTypes.func.isRequired,
icon: propTypes.string.isRequired,
label: propTypes.node,
pending: propTypes.bool,
redirectOnSuccess: propTypes.string,
display: PropTypes.oneOf(['icon', 'both']),
handler: PropTypes.func.isRequired,
icon: PropTypes.string.isRequired,
label: PropTypes.node,
pending: PropTypes.bool,
redirectOnSuccess: PropTypes.string,
}
const ActionBar = ({ children, handlerParam = noop, display = 'both' }) => (
@@ -54,7 +54,7 @@ const ActionBar = ({ children, handlerParam = noop, display = 'both' }) => (
)
ActionBar.propTypes = {
display: propTypes.oneOf(['icon', 'both']),
handlerParam: propTypes.any,
display: PropTypes.oneOf(['icon', 'both']),
handlerParam: PropTypes.any,
}
export { ActionBar as default }

View File

@@ -1,3 +1,4 @@
import PropTypes from 'prop-types'
import React from 'react'
import { isFunction, startsWith } from 'lodash'
@@ -5,54 +6,54 @@ import Button from './button'
import Component from './base-component'
import Icon from './icon'
import logError from './log-error'
import propTypes from './prop-types-decorator'
import Tooltip from './tooltip'
import { error as _error } from './notification'
@propTypes({
// React element to use as button content
children: propTypes.node,
// whether this button is disabled (default to false)
disabled: propTypes.bool,
// form identifier
//
// if provided, this button and its action are associated to this
// form for the submit event
form: propTypes.string,
// function to call when the action is triggered (via a clik on the
// button or submit on the form)
handler: propTypes.func.isRequired,
// optional value which will be passed as first param to the handler
//
// if you need multiple values, you can provide `data-*` props instead of
// `handlerParam`
handlerParam: propTypes.any,
// XO icon to use for this button
icon: propTypes.string.isRequired,
// the color of the xo icon
iconColor: propTypes.string,
// whether the action of this action is already underway
pending: propTypes.bool,
// path to redirect to when the triggered action finish successfully
//
// if a function, it will be called with the result of the action to
// compute the path
redirectOnSuccess: propTypes.oneOfType([propTypes.func, propTypes.string]),
// React element to use tooltip for the component
tooltip: propTypes.node,
})
export default class ActionButton extends Component {
static contextTypes = {
router: propTypes.object,
router: PropTypes.object,
}
static propTypes = {
// React element to use as button content
children: PropTypes.node,
// whether this button is disabled (default to false)
disabled: PropTypes.bool,
// form identifier
//
// if provided, this button and its action are associated to this
// form for the submit event
form: PropTypes.string,
// function to call when the action is triggered (via a clik on the
// button or submit on the form)
handler: PropTypes.func.isRequired,
// optional value which will be passed as first param to the handler
//
// if you need multiple values, you can provide `data-*` props instead of
// `handlerParam`
handlerParam: PropTypes.any,
// XO icon to use for this button
icon: PropTypes.string.isRequired,
// the color of the xo icon
iconColor: PropTypes.string,
// whether the action of this action is already underway
pending: PropTypes.bool,
// path to redirect to when the triggered action finish successfully
//
// if a function, it will be called with the result of the action to
// compute the path
redirectOnSuccess: PropTypes.oneOfType([PropTypes.func, PropTypes.string]),
// React element to use tooltip for the component
tooltip: PropTypes.node,
}
async _execute () {

View File

@@ -1,7 +1,7 @@
import React from 'react'
import PropTypes from 'prop-types'
import ActionButton from './action-button'
import propTypes from './prop-types-decorator'
const ActionToggle = ({ className, value, ...props }) => (
<ActionButton
@@ -10,7 +10,8 @@ const ActionToggle = ({ className, value, ...props }) => (
icon={value ? 'toggle-on' : 'toggle-off'}
/>
)
ActionToggle.propTypes = {
value: PropTypes.bool,
}
export default propTypes({
value: propTypes.bool,
})(ActionToggle)
export { ActionToggle as default }

View File

@@ -1,8 +1,8 @@
import React from 'react'
import { routerShape } from 'react-router/lib/PropTypes'
import PropTypes from 'prop-types'
import Button from './button'
import propTypes from './prop-types-decorator'
const ButtonLink = ({ to, ...props }, { router }) => {
props.onClick = () => {
@@ -12,17 +12,12 @@ const ButtonLink = ({ to, ...props }, { router }) => {
return <Button {...props} />
}
propTypes(
{
to: propTypes.oneOfType([
propTypes.func,
propTypes.object,
propTypes.string,
]),
},
{
router: routerShape,
}
)(ButtonLink)
ButtonLink.contextTypes = {
router: routerShape,
}
ButtonLink.propTypes = {
to: PropTypes.oneOfType([PropTypes.func, PropTypes.object, PropTypes.string]),
}
export { ButtonLink as default }

View File

@@ -1,7 +1,6 @@
import classNames from 'classnames'
import React from 'react'
import propTypes from './prop-types-decorator'
import PropTypes from 'prop-types'
const Button = ({
active,
@@ -27,9 +26,9 @@ const Button = ({
return <button {...props}>{children}</button>
}
propTypes({
active: propTypes.bool,
block: propTypes.bool,
Button.propTypes = {
active: PropTypes.bool,
block: PropTypes.bool,
// Bootstrap button style
//
@@ -37,7 +36,7 @@ propTypes({
//
// The default value (secondary) is not listed here because it does
// not make sense to explicit it.
btnStyle: propTypes.oneOf([
btnStyle: PropTypes.oneOf([
'danger',
'info',
'link',
@@ -46,8 +45,8 @@ propTypes({
'warning',
]),
outline: propTypes.bool,
size: propTypes.oneOf(['large', 'small']),
})(Button)
outline: PropTypes.bool,
size: PropTypes.oneOf(['large', 'small']),
}
export { Button as default }

View File

@@ -1,6 +1,5 @@
import React from 'react'
import propTypes from './prop-types-decorator'
import PropTypes from 'prop-types'
const CARD_STYLE = {
minHeight: '100%',
@@ -16,9 +15,7 @@ const CARD_HEADER_STYLE = {
textAlign: 'center',
}
export const Card = propTypes({
shadow: propTypes.bool,
})(({ shadow, ...props }) => {
export const Card = ({ shadow, ...props }) => {
props.className = 'card'
props.style = {
...props.style,
@@ -26,18 +23,26 @@ export const Card = propTypes({
}
return <div {...props} />
})
}
export const CardHeader = propTypes({
className: propTypes.string,
})(({ children, className }) => (
Card.propTypes = {
shadow: PropTypes.bool,
}
export const CardHeader = ({ children, className }) => (
<h4 className={`card-header ${className || ''}`} style={CARD_HEADER_STYLE}>
{children}
</h4>
))
)
export const CardBlock = propTypes({
className: propTypes.string,
})(({ children, className }) => (
CardHeader.propTypes = {
className: PropTypes.string,
}
export const CardBlock = ({ children, className }) => (
<div className={`card-block ${className || ''}`}>{children}</div>
))
)
CardBlock.propTypes = {
className: PropTypes.string,
}

View File

@@ -1,18 +1,19 @@
import React from 'react'
import PropTypes from 'prop-types'
import Button from './button'
import Component from './base-component'
import Icon from './icon'
import propTypes from './prop-types-decorator'
@propTypes({
buttonText: propTypes.any.isRequired,
children: propTypes.any.isRequired,
className: propTypes.string,
defaultOpen: propTypes.bool,
size: propTypes.string,
})
export default class Collapse extends Component {
static propTypes = {
buttonText: PropTypes.any.isRequired,
children: PropTypes.any.isRequired,
className: PropTypes.string,
defaultOpen: PropTypes.bool,
size: PropTypes.string,
}
state = {
isOpened: this.props.defaultOpen,
}

View File

@@ -1,24 +1,25 @@
import React from 'react'
import PropTypes from 'prop-types'
import uncontrollableInput from 'uncontrollable-input'
import { isEmpty, map } from 'lodash'
import { DropdownButton, MenuItem } from 'react-bootstrap-4/lib'
import Component from './base-component'
import propTypes from './prop-types-decorator'
@uncontrollableInput({
defaultValue: '',
})
@propTypes({
disabled: propTypes.bool,
options: propTypes.oneOfType([
propTypes.arrayOf(propTypes.string),
propTypes.objectOf(propTypes.string),
]),
onChange: propTypes.func.isRequired,
value: propTypes.string.isRequired,
})
export default class Combobox extends Component {
static propTypes = {
disabled: PropTypes.bool,
options: PropTypes.oneOfType([
PropTypes.arrayOf(PropTypes.string),
PropTypes.objectOf(PropTypes.string),
]),
onChange: PropTypes.func.isRequired,
value: PropTypes.string.isRequired,
}
_handleChange = event => {
this.props.onChange(event.target.value)
}

View File

@@ -1,19 +1,16 @@
import CopyToClipboard from 'react-copy-to-clipboard'
import classNames from 'classnames'
import React, { createElement } from 'react'
import PropTypes from 'prop-types'
import _ from '../intl'
import Button from '../button'
import Icon from '../icon'
import propTypes from '../prop-types-decorator'
import Tooltip from '../tooltip'
import styles from './index.css'
const Copiable = propTypes({
data: propTypes.string,
tagName: propTypes.string,
})(({ className, tagName = 'span', ...props }) =>
const Copiable = ({ className, tagName = 'span', ...props }) =>
createElement(
tagName,
{
@@ -30,5 +27,10 @@ const Copiable = propTypes({
</CopyToClipboard>
</Tooltip>
)
)
Copiable.propTypes = {
data: PropTypes.string,
tagName: PropTypes.string,
}
export { Copiable as default }

View File

@@ -1,16 +1,17 @@
import Component from 'base-component'
import propTypes from 'prop-types-decorator'
import PropTypes from 'prop-types'
import React from 'react'
import ReactDropzone from 'react-dropzone'
import styles from './index.css'
@propTypes({
onDrop: propTypes.func,
message: propTypes.node,
multiple: propTypes.bool,
})
export default class Dropzone extends Component {
static propTypes = {
onDrop: PropTypes.func,
message: PropTypes.node,
multiple: PropTypes.bool,
}
render () {
const { onDrop, message, multiple } = this.props

View File

@@ -1,5 +1,6 @@
import classNames from 'classnames'
import React from 'react'
import PropTypes from 'prop-types'
import {
findKey,
isEmpty,
@@ -15,7 +16,6 @@ import Component from '../base-component'
import getEventValue from '../get-event-value'
import Icon from '../icon'
import logError from '../log-error'
import propTypes from '../prop-types-decorator'
import Tooltip from '../tooltip'
import { formatSize } from '../utils'
import { SizeInput } from '../form'
@@ -38,10 +38,11 @@ import styles from './index.css'
const LONG_CLICK = 400
@propTypes({
alt: propTypes.node.isRequired,
})
class Hover extends Component {
static propTypes = {
alt: PropTypes.node.isRequired,
}
constructor () {
super()
@@ -64,13 +65,14 @@ class Hover extends Component {
// it supports 'data-*': optional params,
// wich will be passed as an object to the 'onChange' and the 'onUndo' functions
@propTypes({
onChange: propTypes.func.isRequired,
onUndo: propTypes.oneOfType([propTypes.bool, propTypes.func]),
useLongClick: propTypes.bool,
value: propTypes.any.isRequired,
})
class Editable extends Component {
static propTypes = {
onChange: PropTypes.func.isRequired,
onUndo: PropTypes.oneOfType([PropTypes.bool, PropTypes.func]),
useLongClick: PropTypes.bool,
value: PropTypes.any.isRequired,
}
get value () {
throw new Error('not implemented')
}
@@ -221,14 +223,15 @@ class Editable extends Component {
}
}
@propTypes({
autoComplete: propTypes.string,
maxLength: propTypes.number,
minLength: propTypes.number,
pattern: propTypes.string,
value: propTypes.string.isRequired,
})
export class Text extends Editable {
static propTypes = {
autoComplete: PropTypes.string,
maxLength: PropTypes.number,
minLength: PropTypes.number,
pattern: PropTypes.string,
value: PropTypes.string.isRequired,
}
get value () {
const { input } = this.refs
@@ -302,11 +305,12 @@ export class Password extends Text {
_isPassword = true
}
@propTypes({
nullable: propTypes.bool,
value: propTypes.number,
})
export class Number extends Component {
static propTypes = {
nullable: PropTypes.bool,
value: PropTypes.number,
}
get value () {
return +this.refs.input.value
}
@@ -337,11 +341,13 @@ export class Number extends Component {
}
}
@propTypes({
options: propTypes.oneOfType([propTypes.array, propTypes.object]).isRequired,
renderer: propTypes.func,
})
export class Select extends Editable {
static propTypes = {
options: PropTypes.oneOfType([PropTypes.array, PropTypes.object])
.isRequired,
renderer: PropTypes.func,
}
componentWillReceiveProps (props) {
if (
props.value !== this.props.value ||
@@ -418,10 +424,11 @@ const MAP_TYPE_SELECT = {
'VM-template': SelectVmTemplate,
}
@propTypes({
value: propTypes.oneOfType([propTypes.string, propTypes.object]),
})
export class XoSelect extends Editable {
static propTypes = {
value: PropTypes.oneOfType([PropTypes.string, PropTypes.object]),
}
get value () {
return this.state.value
}
@@ -461,10 +468,11 @@ export class XoSelect extends Editable {
}
}
@propTypes({
value: propTypes.number.isRequired,
})
export class Size extends Editable {
static propTypes = {
value: PropTypes.number.isRequired,
}
get value () {
return this.refs.input.value
}

View File

@@ -1,18 +1,28 @@
import React from 'react'
import PropTypes from 'prop-types'
import * as Grid from './grid'
import propTypes from './prop-types-decorator'
export const LabelCol = propTypes({
children: propTypes.any.isRequired,
})(({ children }) => (
export const LabelCol = ({ children }) => (
<label className='col-md-2 form-control-label'>{children}</label>
))
)
export const InputCol = propTypes({
children: propTypes.any.isRequired,
})(({ children }) => <Grid.Col mediumSize={10}>{children}</Grid.Col>)
LabelCol.propTypes = {
children: PropTypes.any.isRequired,
}
export const Row = propTypes({
children: propTypes.arrayOf(propTypes.element).isRequired,
})(({ children }) => <Grid.Row className='form-group'>{children}</Grid.Row>)
export const InputCol = ({ children }) => (
<Grid.Col mediumSize={10}>{children}</Grid.Col>
)
InputCol.propTypes = {
children: PropTypes.any.isRequired,
}
export const Row = ({ children }) => (
<Grid.Row className='form-group'>{children}</Grid.Row>
)
Row.propTypes = {
children: PropTypes.arrayOf(PropTypes.element).isRequired,
}

View File

@@ -3,6 +3,7 @@ import classNames from 'classnames'
import defined from '@xen-orchestra/defined'
import Icon from 'icon'
import map from 'lodash/map'
import PropTypes from 'prop-types'
import randomPassword from 'random-password'
import React from 'react'
import round from 'lodash/round'
@@ -13,7 +14,6 @@ import { DropdownButton, MenuItem } from 'react-bootstrap-4/lib'
import Button from '../button'
import Component from '../base-component'
import getEventValue from '../get-event-value'
import propTypes from '../prop-types-decorator'
import { formatSizeRaw, parseSize } from '../utils'
export Number from './number'
@@ -21,10 +21,11 @@ export Select from './select'
// ===================================================================
@propTypes({
enableGenerator: propTypes.bool,
})
export class Password extends Component {
static propTypes = {
enableGenerator: PropTypes.bool,
}
get value () {
return this.refs.field.value
}
@@ -86,14 +87,15 @@ export class Password extends Component {
// ===================================================================
@propTypes({
max: propTypes.number.isRequired,
min: propTypes.number.isRequired,
onChange: propTypes.func,
step: propTypes.number,
value: propTypes.number,
})
export class Range extends Component {
static propTypes = {
max: PropTypes.number.isRequired,
min: PropTypes.number.isRequired,
onChange: PropTypes.func,
step: PropTypes.number,
value: PropTypes.number,
}
componentDidMount () {
const { min, onChange, value } = this.props
@@ -134,19 +136,21 @@ export Toggle from './toggle'
const UNITS = ['kiB', 'MiB', 'GiB']
const DEFAULT_UNIT = 'GiB'
@propTypes({
autoFocus: propTypes.bool,
className: propTypes.string,
defaultUnit: propTypes.oneOf(UNITS),
defaultValue: propTypes.number,
onChange: propTypes.func,
placeholder: propTypes.string,
readOnly: propTypes.bool,
required: propTypes.bool,
style: propTypes.object,
value: propTypes.oneOfType([propTypes.number, propTypes.oneOf([null])]),
})
export class SizeInput extends BaseComponent {
static propTypes = {
autoFocus: PropTypes.bool,
className: PropTypes.string,
defaultUnit: PropTypes.oneOf(UNITS),
defaultValue: PropTypes.number,
onChange: PropTypes.func,
placeholder: PropTypes.string,
readOnly: PropTypes.bool,
required: PropTypes.bool,
style: PropTypes.object,
value: PropTypes.oneOfType([PropTypes.number, PropTypes.oneOf([null])]),
}
constructor (props) {
super(props)

View File

@@ -1,22 +1,23 @@
import PropTypes from 'prop-types'
import React from 'react'
import classNames from 'classnames'
import uncontrollableInput from 'uncontrollable-input'
import Component from '../base-component'
import Icon from '../icon'
import propTypes from '../prop-types-decorator'
@uncontrollableInput()
@propTypes({
className: propTypes.string,
onChange: propTypes.func.isRequired,
icon: propTypes.string,
iconOn: propTypes.string,
iconOff: propTypes.string,
iconSize: propTypes.number,
value: propTypes.bool.isRequired,
})
export default class Toggle extends Component {
static propTypes = {
className: PropTypes.string,
onChange: PropTypes.func.isRequired,
icon: PropTypes.string,
iconOn: PropTypes.string,
iconOff: PropTypes.string,
iconSize: PropTypes.number,
value: PropTypes.bool.isRequired,
}
static defaultProps = {
iconOn: 'toggle-on',
iconOff: 'toggle-off',

View File

@@ -1,61 +1,64 @@
import classNames from 'classnames'
import PropTypes from 'prop-types'
import React from 'react'
import propTypes from './prop-types-decorator'
// A column can contain content or a row.
export const Col = propTypes({
className: propTypes.string,
size: propTypes.number,
smallSize: propTypes.number,
mediumSize: propTypes.number,
largeSize: propTypes.number,
offset: propTypes.number,
smallOffset: propTypes.number,
mediumOffset: propTypes.number,
largeOffset: propTypes.number,
})(
({
children,
className,
size = 12,
smallSize = size,
mediumSize,
largeSize,
offset,
smallOffset = offset,
mediumOffset,
largeOffset,
style,
}) => (
<div
className={classNames(
className,
smallSize && `col-xs-${smallSize}`,
mediumSize && `col-md-${mediumSize}`,
largeSize && `col-lg-${largeSize}`,
smallOffset && `offset-xs-${smallOffset}`,
mediumOffset && `offset-md-${mediumOffset}`,
largeOffset && `offset-lg-${largeOffset}`
)}
style={style}
>
{children}
</div>
)
export const Col = ({
children,
className,
size = 12,
smallSize = size,
mediumSize,
largeSize,
offset,
smallOffset = offset,
mediumOffset,
largeOffset,
style,
}) => (
<div
className={classNames(
className,
smallSize && `col-xs-${smallSize}`,
mediumSize && `col-md-${mediumSize}`,
largeSize && `col-lg-${largeSize}`,
smallOffset && `offset-xs-${smallOffset}`,
mediumOffset && `offset-md-${mediumOffset}`,
largeOffset && `offset-lg-${largeOffset}`
)}
style={style}
>
{children}
</div>
)
Col.propTypes = {
className: PropTypes.string,
size: PropTypes.number,
smallSize: PropTypes.number,
mediumSize: PropTypes.number,
largeSize: PropTypes.number,
offset: PropTypes.number,
smallOffset: PropTypes.number,
mediumOffset: PropTypes.number,
largeOffset: PropTypes.number,
}
// This is the root component of the grid layout, containers should not be
// nested.
export const Container = propTypes({
className: propTypes.string,
})(({ children, className }) => (
export const Container = ({ children, className }) => (
<div className={classNames(className, 'container-fluid')}>{children}</div>
))
)
Container.propTypes = {
className: PropTypes.string,
}
// Only columns can be children of a row.
export const Row = propTypes({
className: propTypes.string,
})(({ children, className }) => (
export const Row = ({ children, className }) => (
<div className={`${className || ''} row`}>{children}</div>
))
)
Row.propTypes = {
className: PropTypes.string,
}

View File

@@ -1,20 +1,21 @@
import * as CM from 'complex-matcher'
import PropTypes from 'prop-types'
import React from 'react'
import Component from './base-component'
import propTypes from './prop-types-decorator'
import Tags from './tags'
@propTypes({
labels: propTypes.arrayOf(React.PropTypes.string).isRequired,
onAdd: propTypes.func,
onChange: propTypes.func,
onDelete: propTypes.func,
type: propTypes.string,
})
export default class HomeTags extends Component {
static propTypes = {
labels: PropTypes.arrayOf(PropTypes.string).isRequired,
onAdd: PropTypes.func,
onChange: PropTypes.func,
onDelete: PropTypes.func,
type: PropTypes.string,
}
static contextTypes = {
router: React.PropTypes.object,
router: PropTypes.object,
}
_onClick = label => {

View File

@@ -1,3 +1,4 @@
import PropTypes from 'prop-types'
import React from 'react'
import { Portal } from 'react-overlays'
import { forEach, isEmpty, keys, map } from 'lodash'
@@ -6,7 +7,6 @@ import _ from './intl'
import ActionButton from './action-button'
import Component from './base-component'
import Link from './link'
import propTypes from './prop-types-decorator'
import SortedTable from './sorted-table'
import TabButton from './tab-button'
import { connectStore } from './utils'
@@ -203,21 +203,22 @@ class HostsPatchesTableByPool extends Component {
}
// ===================================================================
const HostsPatches = props =>
props.displayPools ? (
<HostsPatchesTableByPool {...props} />
) : (
<HostsPatchesTable {...props} />
)
export default propTypes({
buttonsGroupContainer: propTypes.func.isRequired,
container: propTypes.any,
displayPools: propTypes.bool,
hosts: propTypes.oneOfType([
propTypes.arrayOf(propTypes.object),
propTypes.objectOf(propTypes.object),
HostsPatches.propTypes = {
buttonsGroupContainer: PropTypes.func.isRequired,
container: PropTypes.any,
displayPools: PropTypes.bool,
hosts: PropTypes.oneOfType([
PropTypes.arrayOf(PropTypes.object),
PropTypes.objectOf(PropTypes.object),
]).isRequired,
useTabButton: propTypes.bool,
})(
props =>
props.displayPools ? (
<HostsPatchesTableByPool {...props} />
) : (
<HostsPatchesTable {...props} />
)
)
useTabButton: PropTypes.bool,
}
export { HostsPatches as default }

View File

@@ -1,9 +1,8 @@
import classNames from 'classnames'
import isInteger from 'lodash/isInteger'
import PropTypes from 'prop-types'
import React from 'react'
import propTypes from './prop-types-decorator'
const Icon = ({ icon, size = 1, color, fixedWidth, ...props }) => {
props.className = classNames(
props.className,
@@ -15,10 +14,12 @@ const Icon = ({ icon, size = 1, color, fixedWidth, ...props }) => {
return <i {...props} />
}
propTypes(Icon)({
color: propTypes.string,
fixedWidth: propTypes.bool,
icon: propTypes.string,
size: propTypes.oneOfType([propTypes.string, propTypes.number]),
})
export default Icon
Icon.propTypes = {
color: PropTypes.string,
fixedWidth: PropTypes.bool,
icon: PropTypes.string,
size: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
}
export { Icon as default }

View File

@@ -1,10 +1,10 @@
import PropTypes from 'prop-types'
import React from 'react'
import _ from 'intl'
import ActionButton from './action-button'
import Component from './base-component'
import Icon from 'icon'
import propTypes from './prop-types-decorator'
import Tooltip from 'tooltip'
import { alert } from 'modal'
import { isAdmin } from 'selectors'
@@ -18,9 +18,6 @@ import {
createSelector,
} from './selectors'
@propTypes({
vm: propTypes.object.isRequired,
})
@addSubscriptions({
resourceSets: subscribeResourceSets,
})
@@ -44,6 +41,10 @@ import {
}
})
export default class IsoDevice extends Component {
static propTypes = {
vm: PropTypes.object.isRequired,
}
_getPredicate = createSelector(
() => this.props.vm.$pool,
() => this.props.vm.$container,

View File

@@ -1,3 +1,4 @@
import PropTypes from 'prop-types'
import React from 'react'
import uncontrollableInput from 'uncontrollable-input'
import { filter, map } from 'lodash'
@@ -5,22 +6,22 @@ import { filter, map } from 'lodash'
import _ from '../intl'
import Button from '../button'
import Component from '../base-component'
import propTypes from '../prop-types-decorator'
import { EMPTY_ARRAY } from '../utils'
import GenericInput from './generic-input'
import { descriptionRender, forceDisplayOptionalAttr } from './helpers'
@propTypes({
depth: propTypes.number,
disabled: propTypes.bool,
label: propTypes.any.isRequired,
required: propTypes.bool,
schema: propTypes.object.isRequired,
uiSchema: propTypes.object,
})
@uncontrollableInput()
export default class ObjectInput extends Component {
static propTypes = {
depth: PropTypes.number,
disabled: PropTypes.bool,
label: PropTypes.any.isRequired,
required: PropTypes.bool,
schema: PropTypes.object.isRequired,
uiSchema: PropTypes.object,
}
state = {
use: this.props.required || forceDisplayOptionalAttr(this.props),
}

View File

@@ -1,7 +1,7 @@
import PropTypes from 'prop-types'
import React, { Component } from 'react'
import getEventValue from '../get-event-value'
import propTypes from '../prop-types-decorator'
import uncontrollableInput from 'uncontrollable-input'
import { EMPTY_OBJECT } from '../utils'
@@ -28,16 +28,17 @@ const InputByType = {
// ===================================================================
@propTypes({
depth: propTypes.number,
disabled: propTypes.bool,
label: propTypes.any.isRequired,
required: propTypes.bool,
schema: propTypes.object.isRequired,
uiSchema: propTypes.object,
})
@uncontrollableInput()
export default class GenericInput extends Component {
static propTypes = {
depth: PropTypes.number,
disabled: PropTypes.bool,
label: PropTypes.any.isRequired,
required: PropTypes.bool,
schema: PropTypes.object.isRequired,
uiSchema: PropTypes.object,
}
_onChange = event => {
const { name, onChange } = this.props
onChange && onChange(getEventValue(event), name)

View File

@@ -1,3 +1,4 @@
import PropTypes from 'prop-types'
import React from 'react'
import uncontrollableInput from 'uncontrollable-input'
import { createSelector } from 'reselect'
@@ -5,22 +6,22 @@ import { keyBy, map } from 'lodash'
import _ from '../intl'
import Component from '../base-component'
import propTypes from '../prop-types-decorator'
import { EMPTY_OBJECT } from '../utils'
import GenericInput from './generic-input'
import { descriptionRender, forceDisplayOptionalAttr } from './helpers'
@propTypes({
depth: propTypes.number,
disabled: propTypes.bool,
label: propTypes.any.isRequired,
required: propTypes.bool,
schema: propTypes.object.isRequired,
uiSchema: propTypes.object,
})
@uncontrollableInput()
export default class ObjectInput extends Component {
static propTypes = {
depth: PropTypes.number,
disabled: PropTypes.bool,
label: PropTypes.any.isRequired,
required: PropTypes.bool,
schema: PropTypes.object.isRequired,
uiSchema: PropTypes.object,
}
state = {
use: this.props.required || forceDisplayOptionalAttr(this.props),
}

View File

@@ -1,20 +1,21 @@
import PropTypes from 'prop-types'
import React from 'react'
import uncontrollableInput from 'uncontrollable-input'
import Combobox from '../combobox'
import Component from '../base-component'
import getEventValue from '../get-event-value'
import propTypes from '../prop-types-decorator'
import { PrimitiveInputWrapper } from './helpers'
// ===================================================================
@propTypes({
password: propTypes.bool,
})
@uncontrollableInput()
export default class StringInput extends Component {
static propTypes = {
password: PropTypes.bool,
}
// the value of this input is undefined not '' when empty to make
// it homogenous with when the user has never touched this input
_onChange = event => {

View File

@@ -1,9 +1,9 @@
import Link from 'react-router/lib/Link'
import PropTypes from 'prop-types'
import React from 'react'
import { routerShape } from 'react-router/lib/PropTypes'
import Component from './base-component'
import propTypes from './prop-types-decorator'
// ===================================================================
@@ -18,11 +18,12 @@ const _IGNORED_TAGNAMES = {
SELECT: true,
}
@propTypes({
className: propTypes.string,
tagName: propTypes.string,
})
export class BlockLink extends Component {
static propTypes = {
className: PropTypes.string,
tagName: PropTypes.string,
}
static contextTypes = {
router: routerShape,
}

View File

@@ -1,6 +1,7 @@
import isArray from 'lodash/isArray'
import isString from 'lodash/isString'
import map from 'lodash/map'
import PropTypes from 'prop-types'
import React, { Component, cloneElement } from 'react'
import { createSelector } from 'selectors'
import { injectIntl } from 'react-intl'
@@ -10,7 +11,6 @@ import _, { messages } from './intl'
import BaseComponent from './base-component'
import Button from './button'
import Icon from './icon'
import propTypes from './prop-types-decorator'
import Tooltip from './tooltip'
import { generateRandomId } from './utils'
import {
@@ -46,21 +46,22 @@ const _addRef = (component, ref) => {
// -----------------------------------------------------------------------------
@propTypes({
buttons: propTypes.arrayOf(
propTypes.shape({
btnStyle: propTypes.string,
icon: propTypes.string,
label: propTypes.node.isRequired,
tooltip: propTypes.node,
value: propTypes.any,
})
).isRequired,
children: propTypes.node.isRequired,
icon: propTypes.string,
title: propTypes.node.isRequired,
})
class GenericModal extends Component {
static propTypes = {
buttons: PropTypes.arrayOf(
PropTypes.shape({
btnStyle: PropTypes.string,
icon: PropTypes.string,
label: PropTypes.node.isRequired,
tooltip: PropTypes.node,
value: PropTypes.any,
})
).isRequired,
children: PropTypes.node.isRequired,
icon: PropTypes.string,
title: PropTypes.node.isRequired,
}
_getBodyValue = () => {
const { body } = this.refs
if (body !== undefined) {
@@ -143,16 +144,17 @@ export const chooseAction = ({ body, buttons, icon, title }) => {
})
}
@propTypes({
body: propTypes.node,
strongConfirm: propTypes.object.isRequired,
icon: propTypes.string,
reject: propTypes.func,
resolve: propTypes.func,
title: propTypes.node.isRequired,
})
@injectIntl
class StrongConfirm extends Component {
static propTypes = {
body: PropTypes.node,
strongConfirm: PropTypes.object.isRequired,
icon: PropTypes.string,
reject: PropTypes.func,
resolve: PropTypes.func,
title: PropTypes.node.isRequired,
}
state = {
buttons: [{ btnStyle: 'danger', label: _('confirmOk'), disabled: true }],
}

View File

@@ -1,8 +1,7 @@
import PropTypes from 'prop-types'
import React from 'react'
import { isEmpty } from 'lodash'
import propTypes from './prop-types-decorator'
// This component returns :
// - A loading icon when the objects are not fetched
// - A default message if the objects are fetched and the collection is empty
@@ -32,10 +31,10 @@ const NoObjects = props => {
)
}
propTypes(NoObjects)({
children: propTypes.func,
collection: propTypes.oneOfType([propTypes.array, propTypes.object]),
component: propTypes.func,
emptyMessage: propTypes.node.isRequired,
})
export default NoObjects
NoObjects.propTypes = {
children: PropTypes.func,
collection: PropTypes.oneOfType([PropTypes.array, PropTypes.object]),
component: PropTypes.func,
emptyMessage: PropTypes.node.isRequired,
}
export { NoObjects as default }

View File

@@ -1,45 +0,0 @@
import assign from 'lodash/assign'
import PropTypes from 'prop-types'
// Deprecated because :
// - unnecessary
// - not standard in the React ecosystem
if (__DEV__) {
console.warn(`DEPRECATED: use prop-types directly:
class MyComponent extends React.Component {
static propTypes = {
foo: PropTypes.string.isRequired
}
}`)
}
// Decorators to help declaring properties and context types on React
// components without using the tedious static properties syntax.
//
// ```js
// @propTypes({
// children: propTypes.node.isRequired
// }, {
// store: propTypes.object.isRequired
// })
// class MyComponent extends React.Component {}
// ```
const propTypes = (propTypes, contextTypes) => target => {
if (propTypes !== undefined) {
target.propTypes = {
...target.propTypes,
...propTypes,
}
}
if (contextTypes !== undefined) {
target.contextTypes = {
...target.contextTypes,
...contextTypes,
}
}
return target
}
assign(propTypes, PropTypes)
export { propTypes as default }

View File

@@ -1,3 +1,4 @@
import PropTypes from 'prop-types'
import React, { Component } from 'react'
import RFB from '@nraynaud/novnc/lib/rfb'
import URL from 'url-parse'
@@ -7,8 +8,6 @@ import {
disable as disableShortcuts,
} from 'shortcuts'
import propTypes from './prop-types-decorator'
const PROTOCOL_ALIASES = {
'http:': 'ws:',
'https:': 'wss:',
@@ -20,11 +19,12 @@ const fixProtocol = url => {
}
}
@propTypes({
onClipboardChange: propTypes.func,
url: propTypes.string.isRequired,
})
export default class NoVnc extends Component {
static propTypes = {
onClipboardChange: PropTypes.func,
url: PropTypes.string.isRequired,
}
constructor (props) {
super(props)
this._rfb = null

View File

@@ -6,7 +6,6 @@ import { startsWith } from 'lodash'
import Icon from './icon'
import Link from './link'
import propTypes from './prop-types-decorator'
import { addSubscriptions, connectStore, formatSize } from './utils'
import { createGetObject, createSelector } from './selectors'
import { FormattedDate } from 'react-intl'
@@ -171,27 +170,27 @@ SrResourceSetItem.propTypes = XO_ITEM_PROP_TYPES
// ===================================================================
// Host, Network, VM-template.
const PoolObjectItem = propTypes({
object: propTypes.object.isRequired,
})(
connectStore(() => {
const getPool = createGetObject((_, props) => props.object.$pool)
const PoolObjectItem = connectStore(() => {
const getPool = createGetObject((_, props) => props.object.$pool)
return (state, props) => ({
pool: getPool(state, props),
})
})(({ object, pool }) => {
const icon = OBJECT_TYPE_TO_ICON[object.type]
const { id } = object
return (
<span>
<Icon icon={icon} /> {`${object.name_label || id} `}
{pool && `(${pool.name_label || pool.id})`}
</span>
)
return (state, props) => ({
pool: getPool(state, props),
})
)
})(({ object, pool }) => {
const icon = OBJECT_TYPE_TO_ICON[object.type]
const { id } = object
return (
<span>
<Icon icon={icon} /> {`${object.name_label || id} `}
{pool && `(${pool.name_label || pool.id})`}
</span>
)
})
PoolObjectItem.propTypes = {
object: PropTypes.object.isRequired,
}
const VgpuItem = connectStore(() => ({
vgpuType: createGetObject((_, props) => props.vgpu.vgpuType),

View File

@@ -1,9 +1,9 @@
import _ from 'intl'
import PropTypes from 'prop-types'
import React from 'react'
import ActionButton from './action-button'
import ActionRowButton from './action-row-button'
import propTypes from './prop-types-decorator'
export const CAN_REPORT_BUG = process.env.XOA_PLAN > 1
@@ -41,11 +41,11 @@ const ReportBugButton = ({
)
}
propTypes(ReportBugButton)({
formatMessage: propTypes.func,
message: propTypes.string.isRequired,
rowButton: propTypes.bool,
title: propTypes.string.isRequired,
})
ReportBugButton.propTypes = {
formatMessage: PropTypes.func,
message: PropTypes.string.isRequired,
rowButton: PropTypes.bool,
title: PropTypes.string.isRequired,
}
export default ReportBugButton
export { ReportBugButton as default }

View File

@@ -1,4 +1,5 @@
import classNames from 'classnames'
import PropTypes from 'prop-types'
import React from 'react'
import { createSchedule } from '@xen-orchestra/cron'
import { forEach, includes, isArray, map, sortedIndex } from 'lodash'
@@ -7,7 +8,6 @@ import { FormattedDate, FormattedTime } from 'react-intl'
import _ from './intl'
import Button from './button'
import Component from './base-component'
import propTypes from './prop-types-decorator'
import TimezonePicker from './timezone-picker'
import Icon from './icon'
import Tooltip from './tooltip'
@@ -117,11 +117,12 @@ const getDayName = dayNum => (
// ===================================================================
@propTypes({
cronPattern: propTypes.string.isRequired,
timezone: propTypes.string,
})
export class SchedulePreview extends Component {
static propTypes = {
cronPattern: PropTypes.string.isRequired,
timezone: PropTypes.string,
}
componentDidMount () {
getXoServerTimezone.then(serverTimezone => {
this.setState({
@@ -163,13 +164,14 @@ export class SchedulePreview extends Component {
// ===================================================================
@propTypes({
children: propTypes.any.isRequired,
onChange: propTypes.func.isRequired,
tdId: propTypes.number.isRequired,
value: propTypes.bool.isRequired,
})
class ToggleTd extends Component {
static propTypes = {
children: PropTypes.any.isRequired,
onChange: PropTypes.func.isRequired,
tdId: PropTypes.number.isRequired,
value: PropTypes.bool.isRequired,
}
_onClick = () => {
const { props } = this
props.onChange(props.tdId, !props.value)
@@ -191,14 +193,15 @@ class ToggleTd extends Component {
// ===================================================================
@propTypes({
labelId: propTypes.string.isRequired,
options: propTypes.array.isRequired,
optionRenderer: propTypes.func,
onChange: propTypes.func.isRequired,
value: propTypes.array.isRequired,
})
class TableSelect extends Component {
static propTypes = {
labelId: PropTypes.string.isRequired,
options: PropTypes.array.isRequired,
optionRenderer: PropTypes.func,
onChange: PropTypes.func.isRequired,
value: PropTypes.array.isRequired,
}
static defaultProps = {
optionRenderer: value => value,
}
@@ -287,15 +290,16 @@ const valueToCron = value => {
return value.join(',')
}
@propTypes({
headerAddon: propTypes.node,
optionRenderer: propTypes.func,
onChange: propTypes.func.isRequired,
range: propTypes.array,
labelId: propTypes.string.isRequired,
value: propTypes.any.isRequired,
})
class TimePicker extends Component {
static propTypes = {
headerAddon: PropTypes.node,
optionRenderer: PropTypes.func,
onChange: PropTypes.func.isRequired,
range: PropTypes.array,
labelId: PropTypes.string.isRequired,
value: PropTypes.any.isRequired,
}
_update = cron => {
const { tableValue, rangeValue } = this.state
@@ -392,11 +396,12 @@ const isWeekDayMode = ({ monthDayPattern, weekDayPattern }) => {
return weekDayPattern !== '*'
}
@propTypes({
monthDayPattern: propTypes.string.isRequired,
weekDayPattern: propTypes.string.isRequired,
})
class DayPicker extends Component {
static propTypes = {
monthDayPattern: PropTypes.string.isRequired,
weekDayPattern: PropTypes.string.isRequired,
}
state = {
weekDayMode: isWeekDayMode(this.props),
}
@@ -461,16 +466,17 @@ class DayPicker extends Component {
// ===================================================================
@propTypes({
cronPattern: propTypes.string,
onChange: propTypes.func,
timezone: propTypes.string,
value: propTypes.shape({
cronPattern: propTypes.string.isRequired,
timezone: propTypes.string,
}),
})
export default class Scheduler extends Component {
static propTypes = {
cronPattern: PropTypes.string,
onChange: PropTypes.func,
timezone: PropTypes.string,
value: PropTypes.shape({
cronPattern: PropTypes.string.isRequired,
timezone: PropTypes.string,
}),
}
constructor (props) {
super(props)

View File

@@ -1,16 +1,17 @@
import _ from 'intl'
import Component from 'base-component'
import Icon from 'icon'
import propTypes from 'prop-types-decorator'
import PropTypes from 'prop-types'
import React from 'react'
import { omit } from 'lodash'
@propTypes({
multi: propTypes.bool,
label: propTypes.node,
onChange: propTypes.func.isRequired,
})
export default class SelectFiles extends Component {
static propTypes = {
multi: PropTypes.bool,
label: PropTypes.node,
onChange: PropTypes.func.isRequired,
}
_onChange = e => {
const { multi, onChange } = this.props
const { files } = e.target

View File

@@ -1,18 +1,20 @@
import PropTypes from 'prop-types'
import React, { cloneElement } from 'react'
import propTypes from './prop-types-decorator'
const SINGLE_LINE_STYLE = { display: 'flex' }
const COL_STYLE = { marginTop: 'auto', marginBottom: 'auto' }
const SingleLineRow = propTypes({
className: propTypes.string,
})(({ children, className }) => (
const SingleLineRow = ({ children, className }) => (
<div className={`${className || ''} row`} style={SINGLE_LINE_STYLE}>
{React.Children.map(
children,
child => child && cloneElement(child, { style: COL_STYLE })
)}
</div>
))
)
SingleLineRow.propTypes = {
className: PropTypes.string,
}
export { SingleLineRow as default }

View File

@@ -4,6 +4,7 @@ import classNames from 'classnames'
import defined, { get } 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 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 React from 'react'
import Shortcuts from 'shortcuts'
import { Input as DebouncedInput } from 'debounce-input-decorator'
@@ -28,7 +29,6 @@ import ButtonGroup from '../button-group'
import Component from '../base-component'
import Icon from '../icon'
import Pagination from '../pagination'
import propTypes from '../prop-types-decorator'
import SingleLineRow from '../single-line-row'
import Tooltip from '../tooltip'
import { BlockLink } from '../link'
@@ -46,12 +46,13 @@ import styles from './index.css'
// ===================================================================
@propTypes({
filters: propTypes.object,
onChange: propTypes.func.isRequired,
value: propTypes.string.isRequired,
})
class TableFilter extends Component {
static propTypes = {
filters: PropTypes.object,
onChange: PropTypes.func.isRequired,
value: PropTypes.string.isRequired,
}
_cleanFilter = () => this._setFilter('')
_setFilter = filterValue => {
@@ -121,13 +122,14 @@ class TableFilter extends Component {
// ===================================================================
@propTypes({
columnId: propTypes.number.isRequired,
name: propTypes.node,
sort: propTypes.func,
sortIcon: propTypes.string,
})
class ColumnHead extends Component {
static propTypes = {
columnId: PropTypes.number.isRequired,
name: PropTypes.node,
sort: PropTypes.func,
sortIcon: PropTypes.string,
}
_sort = () => {
const { props } = this
props.sort(props.columnId)
@@ -162,10 +164,11 @@ class ColumnHead extends Component {
// ===================================================================
@propTypes({
indeterminate: propTypes.bool.isRequired,
})
class Checkbox extends Component {
static propTypes = {
indeterminate: PropTypes.bool.isRequired,
}
componentDidUpdate () {
const {
props: { indeterminate },
@@ -191,16 +194,16 @@ class Checkbox extends Component {
// ===================================================================
const actionsShape = propTypes.arrayOf(
propTypes.shape({
const actionsShape = PropTypes.arrayOf(
PropTypes.shape({
// groupedActions: the function will be called with an array of the selected items in parameters
// individualActions: the function will be called with the related item in parameters
disabled: propTypes.oneOfType([propTypes.bool, propTypes.func]),
handler: propTypes.func.isRequired,
icon: propTypes.string.isRequired,
label: propTypes.oneOfType([propTypes.node, propTypes.func]).isRequired,
level: propTypes.oneOf(['primary', 'warning', 'danger']),
redirectOnSuccess: propTypes.oneOfType([propTypes.func, propTypes.string]),
disabled: PropTypes.oneOfType([PropTypes.bool, PropTypes.func]),
handler: PropTypes.func.isRequired,
icon: PropTypes.string.isRequired,
label: PropTypes.oneOfType([PropTypes.node, PropTypes.func]).isRequired,
level: PropTypes.oneOf(['primary', 'warning', 'danger']),
redirectOnSuccess: PropTypes.oneOfType([PropTypes.func, PropTypes.string]),
})
)
@@ -282,65 +285,65 @@ class GroupedAction extends Component {
// page number and sort info are optional for backward compatibility
const URL_STATE_RE = /^(?:(\d+)(?:_(\d+)(_desc)?)?-)?(.*)$/
@propTypes(
{
defaultColumn: propTypes.number,
defaultFilter: propTypes.string,
collection: propTypes.oneOfType([propTypes.array, propTypes.object])
export default class SortedTable extends Component {
static propTypes = {
defaultColumn: PropTypes.number,
defaultFilter: PropTypes.string,
collection: PropTypes.oneOfType([PropTypes.array, PropTypes.object])
.isRequired,
columns: propTypes.arrayOf(
propTypes.shape({
component: propTypes.func,
default: propTypes.bool,
name: propTypes.node,
itemRenderer: propTypes.func,
sortCriteria: propTypes.oneOfType([propTypes.func, propTypes.string]),
sortOrder: propTypes.string,
textAlign: propTypes.string,
columns: PropTypes.arrayOf(
PropTypes.shape({
component: PropTypes.func,
default: PropTypes.bool,
name: PropTypes.node,
itemRenderer: PropTypes.func,
sortCriteria: PropTypes.oneOfType([PropTypes.func, PropTypes.string]),
sortOrder: PropTypes.string,
textAlign: PropTypes.string,
})
).isRequired,
filterContainer: propTypes.func,
filters: propTypes.object,
actions: propTypes.arrayOf(
propTypes.shape({
filterContainer: PropTypes.func,
filters: PropTypes.object,
actions: PropTypes.arrayOf(
PropTypes.shape({
// regroup individual actions and grouped actions
disabled: propTypes.oneOfType([propTypes.bool, propTypes.func]),
handler: propTypes.func.isRequired,
icon: propTypes.string.isRequired,
individualDisabled: propTypes.oneOfType([
propTypes.bool,
propTypes.func,
disabled: PropTypes.oneOfType([PropTypes.bool, PropTypes.func]),
handler: PropTypes.func.isRequired,
icon: PropTypes.string.isRequired,
individualDisabled: PropTypes.oneOfType([
PropTypes.bool,
PropTypes.func,
]),
individualHandler: propTypes.func,
individualLabel: propTypes.node,
label: propTypes.node.isRequired,
level: propTypes.oneOf(['primary', 'warning', 'danger']),
individualHandler: PropTypes.func,
individualLabel: PropTypes.node,
label: PropTypes.node.isRequired,
level: PropTypes.oneOf(['primary', 'warning', 'danger']),
})
),
groupedActions: actionsShape,
individualActions: actionsShape,
itemsPerPage: propTypes.number,
paginationContainer: propTypes.func,
rowAction: propTypes.func,
rowLink: propTypes.oneOfType([propTypes.func, propTypes.string]),
rowTransform: propTypes.func,
itemsPerPage: PropTypes.number,
paginationContainer: PropTypes.func,
rowAction: PropTypes.func,
rowLink: PropTypes.oneOfType([PropTypes.func, PropTypes.string]),
rowTransform: PropTypes.func,
// DOM node selector like body or .my-class
// The shortcuts will be enabled when the node is focused
shortcutsTarget: propTypes.string,
stateUrlParam: propTypes.string,
shortcutsTarget: PropTypes.string,
stateUrlParam: PropTypes.string,
// @deprecated, use `data-${key}` instead
userData: propTypes.any,
},
{
router: routerShape,
userData: PropTypes.any,
}
)
export default class SortedTable extends Component {
static defaultProps = {
itemsPerPage: 10,
}
static contextTypes = {
router: routerShape,
}
constructor (props, context) {
super(props, context)

View File

@@ -1,9 +1,9 @@
import PropTypes from 'prop-types'
import React from 'react'
import styled from 'styled-components'
import { omit } from 'lodash'
import ActionButton from './action-button'
import propTypes from './prop-types-decorator'
// do not forward `state` to ActionButton
const Button = styled(p => <ActionButton {...omit(p, 'state')} />)`
@@ -41,6 +41,8 @@ const StateButton = ({
</Button>
)
export default propTypes({
state: propTypes.bool.isRequired,
})(StateButton)
StateButton.propTypes = {
state: PropTypes.bool.isRequired,
}
export { StateButton as default }

View File

@@ -1,11 +1,11 @@
import filter from 'lodash/filter'
import includes from 'lodash/includes'
import map from 'lodash/map'
import PropTypes from 'prop-types'
import React from 'react'
import Component from './base-component'
import Icon from './icon'
import propTypes from './prop-types-decorator'
const INPUT_STYLE = {
margin: '2px',
@@ -33,14 +33,15 @@ const REMOVE_TAG_STYLE = {
cursor: 'pointer',
}
@propTypes({
labels: propTypes.arrayOf(React.PropTypes.string).isRequired,
onAdd: propTypes.func,
onChange: propTypes.func,
onClick: propTypes.func,
onDelete: propTypes.func,
})
export default class Tags extends Component {
static propTypes = {
labels: PropTypes.arrayOf(PropTypes.string).isRequired,
onAdd: PropTypes.func,
onChange: PropTypes.func,
onClick: PropTypes.func,
onDelete: PropTypes.func,
}
componentWillMount () {
this.setState({ editing: false })
}
@@ -143,5 +144,5 @@ export const Tag = ({ type, label, onDelete, onClick }) => (
</span>
)
Tag.propTypes = {
label: React.PropTypes.string.isRequired,
label: PropTypes.string.isRequired,
}

View File

@@ -1,24 +1,25 @@
import ActionButton from 'action-button'
import map from 'lodash/map'
import moment from 'moment-timezone'
import PropTypes from 'prop-types'
import React from 'react'
import _ from './intl'
import Component from './base-component'
import propTypes from './prop-types-decorator'
import { getXoServerTimezone } from './xo'
import { Select } from './form'
const SERVER_TIMEZONE_TAG = 'server'
const LOCAL_TIMEZONE = moment.tz.guess()
@propTypes({
defaultValue: propTypes.string,
onChange: propTypes.func.isRequired,
required: propTypes.bool,
value: propTypes.string,
})
export default class TimezonePicker extends Component {
static propTypes = {
defaultValue: PropTypes.string,
onChange: PropTypes.func.isRequired,
required: PropTypes.bool,
value: PropTypes.string,
}
componentDidMount () {
getXoServerTimezone.then(serverTimezone => {
this.setState({

View File

@@ -1,11 +1,11 @@
import classNames from 'classnames'
import isString from 'lodash/isString'
import PropTypes from 'prop-types'
import React from 'react'
import ReactDOM from 'react-dom'
import Component from '../base-component'
import getPosition from './get-position'
import propTypes from '../prop-types-decorator'
import styles from './index.css'
@@ -56,14 +56,15 @@ export class TooltipViewer extends Component {
// ===================================================================
@propTypes({
children: propTypes.oneOfType([propTypes.element, propTypes.string]),
className: propTypes.string,
content: propTypes.node,
style: propTypes.object,
tagName: propTypes.string,
})
export default class Tooltip extends Component {
static propTypes = {
children: PropTypes.oneOfType([PropTypes.element, PropTypes.string]),
className: PropTypes.string,
content: PropTypes.node,
style: PropTypes.object,
tagName: PropTypes.string,
}
componentDidMount () {
this._addListeners()
}

View File

@@ -1,10 +1,10 @@
import classNames from 'classnames'
import every from 'lodash/every'
import PropTypes from 'prop-types'
import React, { Component, cloneElement } from 'react'
import _ from '../intl'
import Icon from '../icon'
import propTypes from '../prop-types-decorator'
import styles from './index.css'
@@ -25,11 +25,12 @@ const Wizard = ({ children }) => {
}
export { Wizard as default }
@propTypes({
icon: propTypes.string.isRequired,
title: propTypes.string.isRequired,
})
export class Section extends Component {
static propTypes = {
icon: PropTypes.string.isRequired,
title: PropTypes.string.isRequired,
}
componentWillMount () {
this.setState({ isActive: false })
}

View File

@@ -2,6 +2,7 @@ import ChartistGraph from 'react-chartist'
import ChartistLegend from 'chartist-plugin-legend'
import ChartistTooltip from 'chartist-plugin-tooltip'
import humanFormat from 'human-format'
import PropTypes from 'prop-types'
import React from 'react'
import { injectIntl } from 'react-intl'
import { messages } from 'intl'
@@ -18,7 +19,6 @@ import {
values,
} from 'lodash'
import propTypes from '../prop-types-decorator'
import { computeArraysSum } from '../xo-stats'
import {
formatSize,
@@ -140,11 +140,7 @@ const templateError = <div>No stats.</div>
// ===================================================================
export const CpuLineChart = injectIntl(
propTypes({
addSumSeries: propTypes.bool,
data: propTypes.object.isRequired,
options: propTypes.object,
})(({ addSumSeries, data, options = {}, intl }) => {
({ addSumSeries, data, options = {}, intl }) => {
const stats = data.stats.cpus
const length = getStatsLength(stats)
@@ -184,15 +180,16 @@ export const CpuLineChart = injectIntl(
}}
/>
)
})
}
)
CpuLineChart.propTypes = {
addSumSeries: PropTypes.bool,
data: PropTypes.object.isRequired,
options: PropTypes.object,
}
export const PoolCpuLineChart = injectIntl(
propTypes({
addSumSeries: propTypes.bool,
data: propTypes.array.isRequired,
options: propTypes.object,
})(({ addSumSeries, data, options = {}, intl }) => {
({ addSumSeries, data, options = {}, intl }) => {
const firstHostData = data[0]
const length = getStatsLength(firstHostData.stats.cpus)
@@ -234,54 +231,55 @@ export const PoolCpuLineChart = injectIntl(
}}
/>
)
})
}
)
PoolCpuLineChart.propTypes = {
addSumSeries: PropTypes.bool,
data: PropTypes.array.isRequired,
options: PropTypes.object,
}
export const MemoryLineChart = injectIntl(
propTypes({
data: propTypes.object.isRequired,
options: propTypes.object,
})(({ data, options = {}, intl }) => {
const { memory } = data.stats
const memoryUsed = getMemoryUsedMetric(data.stats)
export const MemoryLineChart = injectIntl(({ data, options = {}, intl }) => {
const { memory } = data.stats
const memoryUsed = getMemoryUsedMetric(data.stats)
if (!memory || !memoryUsed) {
return templateError
}
if (!memory || !memoryUsed) {
return templateError
}
return (
<ChartistGraph
type='Line'
data={{
series: [
{
name: 'RAM',
data: memoryUsed,
},
],
}}
options={{
...makeOptions({
intl,
nValues: memoryUsed.length,
endTimestamp: data.endTimestamp,
interval: data.interval,
valueTransform: formatSize,
}),
high: memory[memory.length - 1],
...options,
}}
/>
)
})
)
return (
<ChartistGraph
type='Line'
data={{
series: [
{
name: 'RAM',
data: memoryUsed,
},
],
}}
options={{
...makeOptions({
intl,
nValues: memoryUsed.length,
endTimestamp: data.endTimestamp,
interval: data.interval,
valueTransform: formatSize,
}),
high: memory[memory.length - 1],
...options,
}}
/>
)
})
MemoryLineChart.propTypes = {
data: PropTypes.object.isRequired,
options: PropTypes.object,
}
export const PoolMemoryLineChart = injectIntl(
propTypes({
addSumSeries: propTypes.bool,
data: propTypes.array.isRequired,
options: propTypes.object,
})(({ addSumSeries, data, options = {}, intl }) => {
({ addSumSeries, data, options = {}, intl }) => {
const firstHostData = data[0]
const { memory } = firstHostData.stats
const memoryUsed = getMemoryUsedMetric(firstHostData.stats)
@@ -331,15 +329,17 @@ export const PoolMemoryLineChart = injectIntl(
}}
/>
)
})
}
)
PoolMemoryLineChart.propTypes = {
addSumSeries: PropTypes.bool,
data: PropTypes.array.isRequired,
options: PropTypes.object,
}
export const XvdLineChart = injectIntl(
propTypes({
addSumSeries: propTypes.bool,
data: propTypes.object.isRequired,
options: propTypes.object,
})(({ addSumSeries, data, options = {}, intl }) => {
({ addSumSeries, data, options = {}, intl }) => {
const stats = data.stats.xvds
const length = stats && getStatsLength(stats.r)
@@ -365,15 +365,17 @@ export const XvdLineChart = injectIntl(
}}
/>
)
})
}
)
XvdLineChart.propTypes = {
addSumSeries: PropTypes.bool,
data: PropTypes.object.isRequired,
options: PropTypes.object,
}
export const VifLineChart = injectIntl(
propTypes({
addSumSeries: propTypes.bool,
data: propTypes.object.isRequired,
options: propTypes.object,
})(({ addSumSeries, data, options = {}, intl }) => {
({ addSumSeries, data, options = {}, intl }) => {
const stats = data.stats.vifs
const length = stats && getStatsLength(stats.rx)
@@ -399,15 +401,17 @@ export const VifLineChart = injectIntl(
}}
/>
)
})
}
)
VifLineChart.propTypes = {
addSumSeries: PropTypes.bool,
data: PropTypes.object.isRequired,
options: PropTypes.object,
}
export const PifLineChart = injectIntl(
propTypes({
addSumSeries: propTypes.bool,
data: propTypes.array.isRequired,
options: propTypes.object,
})(({ addSumSeries, data, options = {}, intl }) => {
({ addSumSeries, data, options = {}, intl }) => {
const stats = data.stats.pifs
const length = stats && getStatsLength(stats.rx)
@@ -433,16 +437,18 @@ export const PifLineChart = injectIntl(
}}
/>
)
})
}
)
PifLineChart.propTypes = {
addSumSeries: PropTypes.bool,
data: PropTypes.array.isRequired,
options: PropTypes.object,
}
const ios = ['rx', 'tx']
export const PoolPifLineChart = injectIntl(
propTypes({
addSumSeries: propTypes.bool,
data: propTypes.array.isRequired,
options: propTypes.object,
})(({ addSumSeries, data, options = {}, intl }) => {
({ addSumSeries, data, options = {}, intl }) => {
const firstHostData = data[0]
const length =
firstHostData.stats && getStatsLength(firstHostData.stats.pifs.rx)
@@ -485,53 +491,55 @@ export const PoolPifLineChart = injectIntl(
}}
/>
)
})
}
)
export const LoadLineChart = injectIntl(
propTypes({
data: propTypes.object.isRequired,
options: propTypes.object,
})(({ data, options = {}, intl }) => {
const stats = data.stats.load
const { length } = stats || {}
PoolPifLineChart.propTypes = {
addSumSeries: PropTypes.bool,
data: PropTypes.array.isRequired,
options: PropTypes.object,
}
if (!length) {
return templateError
}
export const LoadLineChart = injectIntl(({ data, options = {}, intl }) => {
const stats = data.stats.load
const { length } = stats || {}
return (
<ChartistGraph
type='Line'
data={{
series: [
{
name: 'Load average',
data: stats,
},
],
}}
options={{
...makeOptions({
intl,
nValues: length,
endTimestamp: data.endTimestamp,
interval: data.interval,
valueTransform: value => `${value.toPrecision(3)}`,
}),
...options,
}}
/>
)
})
)
if (!length) {
return templateError
}
return (
<ChartistGraph
type='Line'
data={{
series: [
{
name: 'Load average',
data: stats,
},
],
}}
options={{
...makeOptions({
intl,
nValues: length,
endTimestamp: data.endTimestamp,
interval: data.interval,
valueTransform: value => `${value.toPrecision(3)}`,
}),
...options,
}}
/>
)
})
LoadLineChart.propTypes = {
data: PropTypes.object.isRequired,
options: PropTypes.object,
}
export const PoolLoadLineChart = injectIntl(
propTypes({
addSumSeries: propTypes.bool,
data: propTypes.array.isRequired,
options: propTypes.object,
})(({ addSumSeries, data, options = {}, intl }) => {
({ addSumSeries, data, options = {}, intl }) => {
const firstHostData = data[0]
const length = firstHostData.stats && firstHostData.stats.load.length
@@ -570,9 +578,15 @@ export const PoolLoadLineChart = injectIntl(
}}
/>
)
})
}
)
PoolLoadLineChart.propTypes = {
addSumSeries: PropTypes.bool,
data: PropTypes.array.isRequired,
options: PropTypes.object,
}
const buildSrSeries = ({ stats, label, addSumSeries }) => {
const series = map(stats, (data, key) => ({
name: `${label} (${key})`,
@@ -591,11 +605,7 @@ const buildSrSeries = ({ stats, label, addSumSeries }) => {
}
export const IopsLineChart = injectIntl(
propTypes({
addSumSeries: propTypes.bool,
data: propTypes.array.isRequired,
options: propTypes.object,
})(({ addSumSeries, data, options = {}, intl }) => {
({ addSumSeries, data, options = {}, intl }) => {
const {
endTimestamp,
interval,
@@ -630,15 +640,17 @@ export const IopsLineChart = injectIntl(
}}
/>
)
})
}
)
IopsLineChart.propTypes = {
addSumSeries: PropTypes.bool,
data: PropTypes.array.isRequired,
options: PropTypes.object,
}
export const IoThroughputChart = injectIntl(
propTypes({
addSumSeries: propTypes.bool,
data: propTypes.array.isRequired,
options: propTypes.object,
})(({ addSumSeries, data, options = {}, intl }) => {
({ addSumSeries, data, options = {}, intl }) => {
const {
endTimestamp,
interval,
@@ -673,15 +685,17 @@ export const IoThroughputChart = injectIntl(
}}
/>
)
})
}
)
IoThroughputChart.propTypes = {
addSumSeries: PropTypes.bool,
data: PropTypes.array.isRequired,
options: PropTypes.object,
}
export const LatencyChart = injectIntl(
propTypes({
addSumSeries: propTypes.bool,
data: propTypes.array.isRequired,
options: propTypes.object,
})(({ addSumSeries, data, options = {}, intl }) => {
({ addSumSeries, data, options = {}, intl }) => {
const {
endTimestamp,
interval,
@@ -716,15 +730,17 @@ export const LatencyChart = injectIntl(
}}
/>
)
})
}
)
LatencyChart.propTypes = {
addSumSeries: PropTypes.bool,
data: PropTypes.array.isRequired,
options: PropTypes.object,
}
export const IowaitChart = injectIntl(
propTypes({
addSumSeries: propTypes.bool,
data: propTypes.array.isRequired,
options: propTypes.object,
})(({ addSumSeries, data, options = {}, intl }) => {
({ addSumSeries, data, options = {}, intl }) => {
const {
endTimestamp,
interval,
@@ -759,5 +775,11 @@ export const IowaitChart = injectIntl(
}}
/>
)
})
}
)
IowaitChart.propTypes = {
addSumSeries: PropTypes.bool,
data: PropTypes.array.isRequired,
options: PropTypes.object,
}

View File

@@ -1,4 +1,5 @@
import * as d3 from 'd3'
import PropTypes from 'prop-types'
import React from 'react'
import forEach from 'lodash/forEach'
import keys from 'lodash/keys'
@@ -6,7 +7,6 @@ import map from 'lodash/map'
import times from 'lodash/times'
import Component from './base-component'
import propTypes from './prop-types-decorator'
import { setStyles } from './d3-utils'
// ===================================================================
@@ -73,18 +73,19 @@ const TOOLTIP_STYLE = {
// ===================================================================
@propTypes({
dataSet: propTypes.arrayOf(
propTypes.shape({
data: propTypes.object.isRequired,
label: propTypes.string.isRequired,
objectId: propTypes.string.isRequired,
})
).isRequired,
labels: propTypes.object.isRequired,
renderers: propTypes.object,
})
export default class XoParallelChart extends Component {
static propTypes = {
dataSet: PropTypes.arrayOf(
PropTypes.shape({
data: PropTypes.object.isRequired,
label: PropTypes.string.isRequired,
objectId: PropTypes.string.isRequired,
})
).isRequired,
labels: PropTypes.object.isRequired,
renderers: PropTypes.object,
}
_line = d3.line()
_color = d3.scaleOrdinal(d3.schemeCategory10)

View File

@@ -1,7 +1,7 @@
import PropTypes from 'prop-types'
import React from 'react'
import { Sparklines, SparklinesLine } from 'react-sparklines'
import propTypes from './prop-types-decorator'
import { computeArraysAvg, computeObjectsAvg } from './xo-stats'
import { getMemoryUsedMetric } from './utils'
@@ -17,9 +17,12 @@ const templateError = <div>No stats.</div>
// ===================================================================
export const CpuSparkLines = propTypes({
data: propTypes.object.isRequired,
})(({ data, width = WIDTH, height = HEIGHT, strokeWidth = STROKE_WIDTH }) => {
export const CpuSparkLines = ({
data,
width = WIDTH,
height = HEIGHT,
strokeWidth = STROKE_WIDTH,
}) => {
const { cpus } = data.stats
if (!cpus) {
@@ -46,11 +49,18 @@ export const CpuSparkLines = propTypes({
/>
</Sparklines>
)
})
}
export const MemorySparkLines = propTypes({
data: propTypes.object.isRequired,
})(({ data, width = WIDTH, height = HEIGHT, strokeWidth = STROKE_WIDTH }) => {
CpuSparkLines.propTypes = {
data: PropTypes.object.isRequired,
}
export const MemorySparkLines = ({
data,
width = WIDTH,
height = HEIGHT,
strokeWidth = STROKE_WIDTH,
}) => {
const { memory } = data.stats
const memoryUsed = getMemoryUsedMetric(data.stats)
if (!memory || !memoryUsed) {
@@ -77,11 +87,18 @@ export const MemorySparkLines = propTypes({
/>
</Sparklines>
)
})
}
export const XvdSparkLines = propTypes({
data: propTypes.object.isRequired,
})(({ data, width = WIDTH, height = HEIGHT, strokeWidth = STROKE_WIDTH }) => {
MemorySparkLines.propTypes = {
data: PropTypes.object.isRequired,
}
export const XvdSparkLines = ({
data,
width = WIDTH,
height = HEIGHT,
strokeWidth = STROKE_WIDTH,
}) => {
const { xvds } = data.stats
if (!xvds) {
@@ -107,11 +124,18 @@ export const XvdSparkLines = propTypes({
/>
</Sparklines>
)
})
}
export const NetworkSparkLines = propTypes({
data: propTypes.object.isRequired,
})(({ data, width = WIDTH, height = HEIGHT, strokeWidth = STROKE_WIDTH }) => {
XvdSparkLines.propTypes = {
data: PropTypes.object.isRequired,
}
export const NetworkSparkLines = ({
data,
width = WIDTH,
height = HEIGHT,
strokeWidth = STROKE_WIDTH,
}) => {
const { pifs, vifs: ifs = pifs } = data.stats
return ifs === undefined ? (
@@ -135,11 +159,18 @@ export const NetworkSparkLines = propTypes({
/>
</Sparklines>
)
})
}
export const LoadSparkLines = propTypes({
data: propTypes.object.isRequired,
})(({ data, width = WIDTH, height = HEIGHT, strokeWidth = STROKE_WIDTH }) => {
NetworkSparkLines.propTypes = {
data: PropTypes.object.isRequired,
}
export const LoadSparkLines = ({
data,
width = WIDTH,
height = HEIGHT,
strokeWidth = STROKE_WIDTH,
}) => {
const { load } = data.stats
if (!load) {
@@ -159,4 +190,8 @@ export const LoadSparkLines = propTypes({
/>
</Sparklines>
)
})
}
LoadSparkLines.propTypes = {
data: PropTypes.object.isRequired,
}

View File

@@ -1,3 +1,4 @@
import PropTypes from 'prop-types'
import React from 'react'
import * as d3 from 'd3'
import forEach from 'lodash/forEach'
@@ -5,7 +6,6 @@ import map from 'lodash/map'
import Component from '../base-component'
import _ from '../intl'
import propTypes from '../prop-types-decorator'
import { Toggle } from '../form'
import { setStyles } from '../d3-utils'
import { createGetObject, createSelector } from '../selectors'
@@ -58,21 +58,6 @@ const HORIZON_AREA_PATH_STYLE = {
// ===================================================================
@propTypes({
chartHeight: propTypes.number,
chartWidth: propTypes.number,
data: propTypes.arrayOf(
propTypes.shape({
date: propTypes.number.isRequired,
value: propTypes.number.isRequired,
})
).isRequired,
maxValue: propTypes.number,
objectId: propTypes.string.isRequired,
onTooltipChange: propTypes.func.isRequired,
tooltipX: propTypes.number.isRequired,
valueRenderer: propTypes.func,
})
@connectStore(() => {
const label = createSelector(
createGetObject((_, props) => props.objectId),
@@ -82,6 +67,22 @@ const HORIZON_AREA_PATH_STYLE = {
return { label }
})
class XoWeekChart extends Component {
static propTypes = {
chartHeight: PropTypes.number,
chartWidth: PropTypes.number,
data: PropTypes.arrayOf(
PropTypes.shape({
date: PropTypes.number.isRequired,
value: PropTypes.number.isRequired,
})
).isRequired,
maxValue: PropTypes.number,
objectId: PropTypes.string.isRequired,
onTooltipChange: PropTypes.func.isRequired,
tooltipX: PropTypes.number.isRequired,
valueRenderer: PropTypes.func,
}
static defaultProps = {
chartHeight: 70,
chartWidth: 300,
@@ -307,22 +308,23 @@ class XoWeekChart extends Component {
// ===================================================================
@propTypes({
chartHeight: propTypes.number,
series: propTypes.arrayOf(
propTypes.shape({
data: propTypes.arrayOf(
propTypes.shape({
date: propTypes.number.isRequired,
value: propTypes.number.isRequired,
})
).isRequired,
objectId: propTypes.string.isRequired,
})
).isRequired,
valueRenderer: propTypes.func,
})
export default class XoWeekCharts extends Component {
static propTypes = {
chartHeight: PropTypes.number,
series: PropTypes.arrayOf(
PropTypes.shape({
data: PropTypes.arrayOf(
PropTypes.shape({
date: PropTypes.number.isRequired,
value: PropTypes.number.isRequired,
})
).isRequired,
objectId: PropTypes.string.isRequired,
})
).isRequired,
valueRenderer: PropTypes.func,
}
_handleResize = () => {
const { container } = this.refs
this.setState({

View File

@@ -1,3 +1,4 @@
import PropTypes from 'prop-types'
import React from 'react'
import forEach from 'lodash/forEach'
import map from 'lodash/map'
@@ -9,7 +10,6 @@ import { FormattedTime } from 'react-intl'
import _ from '../intl'
import Component from '../base-component'
import propTypes from '../prop-types-decorator'
import Tooltip from '../tooltip'
import styles from './index.css'
@@ -72,16 +72,17 @@ const computeMissingDays = days => {
// ===================================================================
@propTypes({
cellRenderer: propTypes.func,
data: propTypes.arrayOf(
propTypes.shape({
date: propTypes.number.isRequired,
value: propTypes.number.isRequired,
})
).isRequired,
})
export default class XoWeekHeatmap extends Component {
static propTypes = {
cellRenderer: PropTypes.func,
data: PropTypes.arrayOf(
PropTypes.shape({
date: PropTypes.number.isRequired,
value: PropTypes.number.isRequired,
})
).isRequired,
}
static defaultProps = {
cellRenderer: value => value,
}

View File

@@ -1,19 +1,20 @@
import keys from 'lodash/keys'
import PropTypes from 'prop-types'
import React from 'react'
import * as FormGrid from '../../form-grid'
import _ from '../../intl'
import Combobox from '../../combobox'
import Component from '../../base-component'
import propTypes from '../../prop-types-decorator'
import { createSelector } from '../../selectors'
@propTypes({
type: propTypes.string.isRequired,
user: propTypes.object.isRequired,
value: propTypes.string.isRequired,
})
export default class SaveNewUserFilterModalBody extends Component {
static propTypes = {
type: PropTypes.string.isRequired,
user: PropTypes.object.isRequired,
value: PropTypes.string.isRequired,
}
get value () {
return this.state.name || ''
}

View File

@@ -1,10 +1,10 @@
import Collapse from 'collapse'
import Component from 'base-component'
import PropTypes from 'prop-types'
import React from 'react'
import { map } from 'lodash'
import _ from '../../intl'
import propTypes from '../../prop-types-decorator'
import SingleLineRow from '../../single-line-row'
import { Container, Col } from 'grid'
import { isSrWritable } from 'xo'
@@ -22,23 +22,24 @@ const Collapsible = ({ collapsible, children, ...props }) =>
)
Collapsible.propTypes = {
collapsible: propTypes.bool.isRequired,
children: propTypes.node.isRequired,
collapsible: PropTypes.bool.isRequired,
children: PropTypes.node.isRequired,
}
@propTypes({
mainSrPredicate: propTypes.func,
onChange: propTypes.func.isRequired,
srPredicate: propTypes.func,
value: propTypes.objectOf(
propTypes.shape({
mainSr: propTypes.object,
mapVdisSrs: propTypes.object,
})
).isRequired,
vdis: propTypes.object.isRequired,
})
export default class ChooseSrForEachVdisModal extends Component {
static propTypes = {
mainSrPredicate: PropTypes.func,
onChange: PropTypes.func.isRequired,
srPredicate: PropTypes.func,
value: PropTypes.objectOf(
PropTypes.shape({
mainSr: PropTypes.object,
mapVdisSrs: PropTypes.object,
})
).isRequired,
vdis: PropTypes.object.isRequired,
}
_onChange = newValues => {
this.props.onChange({
...this.props.value,

View File

@@ -1,22 +1,16 @@
import PropTypes from 'prop-types'
import React from 'react'
import _ from './intl'
import Icon from './icon'
import Link from './link'
import propTypes from './prop-types-decorator'
import { Card, CardHeader, CardBlock } from './card'
import { connectStore, getXoaPlan } from './utils'
import { isAdmin } from 'selectors'
const Upgrade = propTypes({
available: propTypes.number,
place: propTypes.string.isRequired,
required: propTypes.number,
const Upgrade = connectStore({
isAdmin,
})(
connectStore({
isAdmin,
})
)(
({ available, children, isAdmin, place, required = available }) =>
process.env.XOA_PLAN < required ? (
<Card>
@@ -49,4 +43,10 @@ const Upgrade = propTypes({
)
)
Upgrade.propTypes = {
available: PropTypes.number,
place: PropTypes.string.isRequired,
required: PropTypes.number,
}
export { Upgrade as default }

View File

@@ -2,6 +2,7 @@ import _ from 'intl'
import ActionButton from 'action-button'
import addSubscriptions from 'add-subscriptions'
import Icon from 'icon'
import PropTypes from 'prop-types'
import React from 'react'
import SortedTable from 'sorted-table'
import StateButton from 'state-button'
@@ -149,7 +150,7 @@ const MODES = [
})
class JobsTable extends React.Component {
static contextTypes = {
router: React.PropTypes.object,
router: PropTypes.object,
}
static tableProps = {

View File

@@ -6,6 +6,7 @@ import Icon from 'icon'
import Link from 'link'
import LogList from '../../logs'
import NoObjects from 'no-objects'
import PropTypes from 'prop-types'
import React from 'react'
import SortedTable from 'sorted-table'
import StateButton from 'state-button'
@@ -155,7 +156,7 @@ const JOB_COLUMNS = [
})
export default class Overview extends Component {
static contextTypes = {
router: React.PropTypes.object,
router: PropTypes.object,
}
_getSchedules = createSelector(

View File

@@ -5,7 +5,7 @@ import Component from 'base-component'
import forEach from 'lodash/forEach'
import Icon from 'icon'
import map from 'lodash/map'
import propTypes from 'prop-types-decorator'
import PropTypes from 'prop-types'
import React from 'react'
import renderXoItem from 'render-xo-item'
import sortBy from 'lodash/sortBy'
@@ -159,9 +159,6 @@ const STATS_TYPE_TO_COMPUTE_FNC = {
memoryUsed: computeMemoryUsedMetric,
}
@propTypes({
onChange: propTypes.func.isRequired,
})
@connectStore(() => {
const getRunningHosts = createGetObjectsOfType('host')
.filter([runningObjectsPredicate])
@@ -176,6 +173,10 @@ const STATS_TYPE_TO_COMPUTE_FNC = {
}
})
class SelectMetric extends Component {
static propTypes = {
onChange: PropTypes.func.isRequired,
}
constructor (props) {
super(props)
this.state = {
@@ -351,11 +352,12 @@ class SelectMetric extends Component {
// ===================================================================
@propTypes({
metricRenderer: propTypes.func.isRequired,
title: propTypes.any.isRequired,
})
class MetricViewer extends Component {
static propTypes = {
metricRenderer: PropTypes.func.isRequired,
title: PropTypes.any.isRequired,
}
_handleSelectedMetric = (selectedMetric, objects) => {
this.setState({ selectedMetric, objects })
}

View File

@@ -12,7 +12,7 @@ import invoke from 'invoke'
import Link from 'link'
import Page from '../page'
import Pagination from 'pagination'
import propTypes from 'prop-types-decorator'
import PropTypes from 'prop-types'
import React from 'react'
import Shortcuts from 'shortcuts'
import Tooltip from 'tooltip'
@@ -301,12 +301,13 @@ const DEFAULT_TYPE = 'VM'
noServersConnected,
}
})
@propTypes({
isAdmin: propTypes.bool.isRequired,
isPoolAdmin: propTypes.bool.isRequired,
noResourceSets: propTypes.bool.isRequired,
})
class NoObjects_ extends Component {
static propTypes = {
isAdmin: PropTypes.bool.isRequired,
isPoolAdmin: PropTypes.bool.isRequired,
noResourceSets: PropTypes.bool.isRequired,
}
render () {
const {
areObjectsFetched,
@@ -453,7 +454,7 @@ class NoObjects_ extends Component {
})
export default class Home extends Component {
static contextTypes = {
router: React.PropTypes.object,
router: PropTypes.object,
}
state = {

View File

@@ -1,6 +1,6 @@
import Component from 'base-component'
import Icon from 'icon'
import propTypes from 'prop-types-decorator'
import PropTypes from 'prop-types'
import React from 'react'
import { Col, Row } from 'grid'
import {
@@ -18,10 +18,11 @@ const MINI_STATS_PROPS = {
width: 50,
}
@propTypes({
fetchStats: propTypes.func.isRequired,
})
export default class MiniStats extends Component {
static propTypes = {
fetchStats: PropTypes.func.isRequired,
}
_fetch = () => {
this.props.fetch().then(stats => {
this.setState({ stats })

View File

@@ -5,6 +5,7 @@ import Icon from 'icon'
import Link from 'link'
import { NavLink, NavTabs } from 'nav'
import Page from '../page'
import PropTypes from 'prop-types'
import React, { cloneElement, Component } from 'react'
import Tooltip from 'tooltip'
import { Text } from 'editable'
@@ -130,7 +131,7 @@ const isRunning = host => host && host.power_state === 'Running'
})
export default class Host extends Component {
static contextTypes = {
router: React.PropTypes.object,
router: PropTypes.object,
}
loop (host = this.props.host) {

View File

@@ -1,4 +1,5 @@
import _ from 'intl'
import PropTypes from 'prop-types'
import React, { Component } from 'react'
import SortedTable from 'sorted-table'
import TabButton from 'tab-button'
@@ -312,7 +313,7 @@ class XenServerPatches extends Component {
export default class TabPatches extends Component {
static contextTypes = {
router: React.PropTypes.object,
router: PropTypes.object,
}
_chooseActionPatch = async doInstall => {

View File

@@ -2,6 +2,7 @@ import _ from 'intl'
import Icon from 'icon'
import Link from 'link'
import LogList from '../../logs'
import PropTypes from 'prop-types'
import React, { Component } from 'react'
import SortedTable from 'sorted-table'
import StateButton from 'state-button'
@@ -108,7 +109,7 @@ const ACTIONS = [
})
export default class Overview extends Component {
static contextTypes = {
router: React.PropTypes.object,
router: PropTypes.object,
}
constructor (props) {

View File

@@ -4,7 +4,7 @@ import BaseComponent from 'base-component'
import classnames from 'classnames'
import Icon from 'icon'
import NoObjects from 'no-objects'
import propTypes from 'prop-types-decorator'
import PropTypes from 'prop-types'
import React, { Component } from 'react'
import renderXoItem from 'render-xo-item'
import Select from 'form/select'
@@ -427,10 +427,7 @@ const LOG_FILTERS = {
jobCallSkipped: '!hasErrors? callSkipped?',
}
export default [
propTypes({
jobKeys: propTypes.array,
}),
const Logs = [
addSubscriptions(({ jobKeys }) => ({
logs: cb =>
subscribeJobsLogs(rawLogs => {
@@ -531,3 +528,9 @@ export default [
</Card>
),
].reduceRight((value, decorator) => decorator(value))
Logs.propTypes = {
jobKeys: PropTypes.array,
}
export { Logs as default }

View File

@@ -9,7 +9,7 @@ import info, { error } from 'notification'
import isEmpty from 'lodash/isEmpty'
import map from 'lodash/map'
import Page from '../../page'
import propTypes from 'prop-types-decorator'
import PropTypes from 'prop-types'
import React from 'react'
import store from 'store'
import trim from 'lodash/trim'
@@ -46,11 +46,12 @@ import {
// ===================================================================
@propTypes({
onChange: propTypes.func.isRequired,
options: propTypes.array.isRequired,
})
class SelectScsiId extends Component {
static propTypes = {
onChange: PropTypes.func.isRequired,
options: PropTypes.array.isRequired,
}
_getOptions = createSelector(
() => this.props.options,
options =>
@@ -138,11 +139,12 @@ class SelectIqn extends Component {
}
}
@propTypes({
onChange: propTypes.func.isRequired,
options: propTypes.array.isRequired,
})
class SelectLun extends Component {
static propTypes = {
onChange: PropTypes.func.isRequired,
options: PropTypes.array.isRequired,
}
_getOptions = createSelector(
() => this.props.options,
options =>

View File

@@ -1,5 +1,6 @@
import { messages } from 'intl'
import DocumentTitle from 'react-document-title'
import PropTypes from 'prop-types'
import React from 'react'
import { injectIntl } from 'react-intl'
@@ -34,11 +35,11 @@ const Page = ({
}
Page.propTypes = {
children: React.PropTypes.node,
collapsedHeader: React.PropTypes.bool,
formatTitle: React.PropTypes.bool,
header: React.PropTypes.node,
title: React.PropTypes.string,
children: PropTypes.node,
collapsedHeader: PropTypes.bool,
formatTitle: PropTypes.bool,
header: PropTypes.node,
title: PropTypes.string,
}
export default injectIntl(Page)

View File

@@ -5,7 +5,7 @@ import includes from 'lodash/includes'
import intersection from 'lodash/intersection'
import keyBy from 'lodash/keyBy'
import map from 'lodash/map'
import propTypes from 'prop-types-decorator'
import PropTypes from 'prop-types'
import React, { Component } from 'react'
import reduce from 'lodash/reduce'
import renderXoItem from 'render-xo-item'
@@ -15,10 +15,11 @@ import { subscribeGroups, subscribeUsers } from 'xo'
// ===================================================================
@propTypes({
subjects: propTypes.array.isRequired,
})
export class Subjects extends Component {
static propTypes = {
subjects: PropTypes.array.isRequired,
}
constructor (props) {
super(props)
this.state = {

View File

@@ -5,7 +5,7 @@ import includes from 'lodash/includes'
import isEmpty from 'lodash/isEmpty'
import keyBy from 'lodash/keyBy'
import map from 'lodash/map'
import propTypes from 'prop-types-decorator'
import PropTypes from 'prop-types'
import React from 'react'
import size from 'lodash/size'
import SortedTable from 'sorted-table'
@@ -27,11 +27,12 @@ import {
@addSubscriptions({
users: cb => subscribeUsers(users => cb(keyBy(users, 'id'))),
})
@propTypes({
id: propTypes.string.isRequired, // user id
group: propTypes.object.isRequired, // group
})
class UserDisplay extends Component {
static propTypes = {
id: PropTypes.string.isRequired, // user id
group: PropTypes.object.isRequired, // group
}
_removeUser = () => {
const { id, group } = this.props
return removeUserFromGroup(id, group)

View File

@@ -6,7 +6,7 @@ import Component from 'base-component'
import copy from 'copy-to-clipboard'
import Icon from 'icon'
import Link from 'link'
import propTypes from 'prop-types-decorator'
import PropTypes from 'prop-types'
import React from 'react'
import renderXoItem from 'render-xo-item'
import SortedTable from 'sorted-table'
@@ -226,11 +226,12 @@ const FILTERS = {
// ===================================================================
@injectIntl
@propTypes({
onClose: propTypes.func,
sr: propTypes.object.isRequired,
})
class NewDisk extends Component {
static propTypes = {
onClose: PropTypes.func,
sr: PropTypes.object.isRequired,
}
_createDisk = () => {
const { sr, onClose = noop } = this.props
const { name, readOnly, size } = this.state

View File

@@ -4,7 +4,7 @@ import _, { messages } from 'intl'
import ActionButton from 'action-button'
import Component from 'base-component'
import Icon from 'icon'
import propTypes from 'prop-types-decorator'
import PropTypes from 'prop-types'
import React from 'react'
import SortedTable from 'sorted-table'
import { Text } from 'editable'
@@ -66,13 +66,14 @@ const getUserPreferences = user => user.preferences || {}
// ===================================================================
@propTypes({
customFilters: propTypes.object,
defaultFilter: propTypes.string.isRequired,
filters: propTypes.object.isRequired,
type: propTypes.string.isRequired,
})
class DefaultFilterPicker extends Component {
static propTypes = {
customFilters: PropTypes.object,
defaultFilter: PropTypes.string.isRequired,
filters: PropTypes.object.isRequired,
type: PropTypes.string.isRequired,
}
_computeOptions (props) {
const { customFilters, filters } = props
@@ -144,10 +145,11 @@ class DefaultFilterPicker extends Component {
// ===================================================================
@propTypes({
user: propTypes.object.isRequired,
})
class UserFilters extends Component {
static propTypes = {
user: PropTypes.object.isRequired,
}
_removeFilter = ({ name, type }) => removeCustomFilter(type, name)
render () {

View File

@@ -8,7 +8,7 @@ import Icon from 'icon'
import isEmpty from 'lodash/isEmpty'
import map from 'lodash/map'
import orderBy from 'lodash/orderBy'
import propTypes from 'prop-types-decorator'
import PropTypes from 'prop-types'
import React from 'react'
import { Container, Col, Row } from 'grid'
import { importVms, isSrWritable } from 'xo'
@@ -48,22 +48,6 @@ const HEADER = (
// ===================================================================
@propTypes({
descriptionLabel: propTypes.string,
disks: propTypes.objectOf(
propTypes.shape({
capacity: propTypes.number.isRequired,
descriptionLabel: propTypes.string.isRequired,
nameLabel: propTypes.string.isRequired,
path: propTypes.string.isRequired,
})
),
memory: propTypes.number,
nameLabel: propTypes.string,
nCpus: propTypes.number,
networks: propTypes.array,
pool: propTypes.object.isRequired,
})
@connectStore(
() => {
const getHostMaster = createGetObject((_, props) => props.pool.master)
@@ -82,6 +66,23 @@ const HEADER = (
{ withRef: true }
)
class VmData extends Component {
static propTypes = {
descriptionLabel: PropTypes.string,
disks: PropTypes.objectOf(
PropTypes.shape({
capacity: PropTypes.number.isRequired,
descriptionLabel: PropTypes.string.isRequired,
nameLabel: PropTypes.string.isRequired,
path: PropTypes.string.isRequired,
})
),
memory: PropTypes.number,
nameLabel: PropTypes.string,
nCpus: PropTypes.number,
networks: PropTypes.array,
pool: PropTypes.object.isRequired,
}
get value () {
const { props, refs } = this
return {

View File

@@ -5,6 +5,7 @@ import Icon from 'icon'
import Link from 'link'
import { NavLink, NavTabs } from 'nav'
import Page from '../page'
import PropTypes from 'prop-types'
import React, { cloneElement } from 'react'
import VmActionBar from './action-bar'
import { Select, Text } from 'editable'
@@ -88,7 +89,7 @@ import TabAdvanced from './tab-advanced'
})
export default class Vm extends BaseComponent {
static contextTypes = {
router: React.PropTypes.object,
router: PropTypes.object,
}
loop (vm = this.props.vm) {

View File

@@ -6,7 +6,7 @@ import HTML5Backend from 'react-dnd-html5-backend'
import Icon from 'icon'
import IsoDevice from 'iso-device'
import Link from 'link'
import propTypes from 'prop-types-decorator'
import PropTypes from 'prop-types'
import React from 'react'
import SingleLineRow from 'single-line-row'
import StateButton from 'state-button'
@@ -214,10 +214,6 @@ const parseBootOrder = bootOrder => {
}
@injectIntl
@propTypes({
onClose: propTypes.func,
vm: propTypes.object.isRequired,
})
@addSubscriptions({
resourceSets: subscribeResourceSets,
})
@@ -225,6 +221,11 @@ const parseBootOrder = bootOrder => {
isAdmin,
})
class NewDisk extends Component {
static propTypes = {
onClose: PropTypes.func,
vm: PropTypes.object.isRequired,
}
_createDisk = () => {
const { vm, onClose = noop } = this.props
const { bootable, name, readOnly, size, sr } = this.state
@@ -355,12 +356,13 @@ class NewDisk extends Component {
}
}
@propTypes({
onClose: propTypes.func,
vbds: propTypes.array.isRequired,
vm: propTypes.object.isRequired,
})
class AttachDisk extends Component {
static propTypes = {
onClose: PropTypes.func,
vbds: PropTypes.array.isRequired,
vm: PropTypes.object.isRequired,
}
_getVdiPredicate = createSelector(
() => {
const { vm } = this.props
@@ -466,16 +468,17 @@ const orderItemTarget = {
connectDragSource: connect.dragSource(),
isDragging: monitor.isDragging(),
}))
@propTypes({
connectDragSource: propTypes.func.isRequired,
connectDropTarget: propTypes.func.isRequired,
index: propTypes.number.isRequired,
isDragging: propTypes.bool.isRequired,
id: propTypes.any.isRequired,
item: propTypes.object.isRequired,
move: propTypes.func.isRequired,
})
class OrderItem extends Component {
static propTypes = {
connectDragSource: PropTypes.func.isRequired,
connectDropTarget: PropTypes.func.isRequired,
index: PropTypes.number.isRequired,
isDragging: PropTypes.bool.isRequired,
id: PropTypes.any.isRequired,
item: PropTypes.object.isRequired,
move: PropTypes.func.isRequired,
}
_toggle = checked => {
const { item } = this.props
item.active = checked
@@ -497,12 +500,13 @@ class OrderItem extends Component {
}
}
@propTypes({
onClose: propTypes.func,
vm: propTypes.object.isRequired,
})
@DragDropContext(HTML5Backend)
class BootOrder extends Component {
static propTypes = {
onClose: PropTypes.func,
vm: PropTypes.object.isRequired,
}
constructor (props) {
super(props)
const { vm } = props

View File

@@ -4,7 +4,7 @@ import ActionRowButton from 'action-row-button'
import BaseComponent from 'base-component'
import copy from 'copy-to-clipboard'
import Icon from 'icon'
import propTypes from 'prop-types-decorator'
import PropTypes from 'prop-types'
import React from 'react'
import SortedTable from 'sorted-table'
import StateButton from 'state-button'
@@ -368,10 +368,6 @@ const FILTERS = {
filterVifsOnlyDisconnected: '!attached?',
}
@propTypes({
onClose: propTypes.func,
vm: propTypes.object.isRequired,
})
@addSubscriptions({
resourceSets: subscribeResourceSets,
})
@@ -396,6 +392,11 @@ const FILTERS = {
})
@injectIntl
class NewVif extends BaseComponent {
static propTypes = {
onClose: PropTypes.func,
vm: PropTypes.object.isRequired,
}
componentWillMount () {
this._autoFill(this.props)
}

View File

@@ -1,7 +1,7 @@
import _ from 'intl'
import Component from 'base-component'
import Icon from 'icon'
import propTypes from 'prop-types-decorator'
import PropTypes from 'prop-types'
import React from 'react'
import { isInteger, map } from 'lodash'
@@ -93,12 +93,13 @@ const replicationGraph = (nSrs, redundancy, w, h) => {
return graph(nGroups, redundancy, w, h, redundancy - 1)
}
@propTypes({
layout: propTypes.string.isRequired,
redundancy: propTypes.number.isRequired,
nSrs: propTypes.number,
})
export default class Graph extends Component {
static propTypes = {
layout: PropTypes.string.isRequired,
redundancy: PropTypes.number.isRequired,
nSrs: PropTypes.number,
}
render () {
const { layout, redundancy, nSrs, width, height } = this.props