/* Copyright (C) 2017 Cloudbase Solutions SRL This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ // @flow import React from 'react' import styled from 'styled-components' import { observer } from 'mobx-react' import Tooltip from '../../atoms/Tooltip' import StyleProps from '../../styleUtils/StyleProps' import ToggleButtonBar from '../../atoms/ToggleButtonBar' import WizardOptionsField from '../../molecules/WizardOptionsField' import StatusImage from '../../atoms/StatusImage' import type { Field } from '../../../types/Field' import type { Instance } from '../../../types/Instance' import { executionOptions } from '../../../config' const Wrapper = styled.div`` const Options = styled.div`` const Fields = styled.div` margin-top: 46px; display: flex; ` const OneColumn = styled.div`` const Column = styled.div` ${props => props.left ? 'margin-right: 160px;' : ''} ` const WizardOptionsFieldStyled = styled(WizardOptionsField)` width: ${StyleProps.inputSizes.wizard.width}px; justify-content: space-between; margin-bottom: 39px; ` const LoadingWrapper = styled.div` margin-top: 32px; display: flex; flex-direction: column; align-items: center; ` const LoadingText = styled.div` margin-top: 38px; font-size: 18px; ` type Props = { fields: Field[], selectedInstances: ?Instance[], data: ?{ [string]: mixed }, onChange: (field: Field, value: any) => void, useAdvancedOptions: boolean, onAdvancedOptionsToggle: (showAdvanced: boolean) => void, wizardType: string, loading: boolean, } @observer class WizardOptions extends React.Component { constructor() { super() // $FlowIssue this.handleResize = this.handleResize.bind(this) } componentDidMount() { window.addEventListener('resize', this.handleResize) } componentDidUpdate() { Tooltip.rebuild() } componentWillUnmount() { window.removeEventListener('resize', this.handleResize, false) } getFieldValue(fieldName: string, defaultValue: any) { if (!this.props.data || this.props.data[fieldName] === undefined) { return defaultValue } return this.props.data[fieldName] } getDefaultFieldsSchema() { let fieldsSchema = [ { name: 'description', type: 'string' }, ] if (this.props.wizardType === 'migration') { fieldsSchema.unshift({ name: 'skip_os_morphing', type: 'strict-boolean', default: false }) } if (this.props.selectedInstances && this.props.selectedInstances.length > 1) { fieldsSchema.unshift({ name: 'separate_vm', type: 'strict-boolean', default: true }) } if (this.props.wizardType === 'replica') { fieldsSchema.push({ name: 'execute_now', type: 'strict-boolean', default: true }) let executeNowValue = this.getFieldValue('execute_now', true) if (executeNowValue) { fieldsSchema = [ ...fieldsSchema, { name: 'execute_now_options', type: 'object', properties: executionOptions, }, ] } } return fieldsSchema } handleResize() { this.setState({}) } shouldRenderField(field: Field) { return (field.type !== 'array' || (field.enum && field.enum.length && field.enum.length > 0)) && (field.type !== 'integer' || (field.minimum && field.maximum)) && (field.type !== 'object' || field.properties) } renderOptionsField(field: Field) { let additionalProps if (field.type === 'object' && field.properties) { additionalProps = { valueCallback: f => this.getFieldValue(f.name, f.default), onChange: (f, value) => { this.props.onChange(f, value) }, properties: field.properties, } } else { additionalProps = { value: this.getFieldValue(field.name, field.default), onChange: value => { this.props.onChange(field, value) }, } } return ( ) } renderOptionsFields() { let fieldsSchema = this.getDefaultFieldsSchema() fieldsSchema = fieldsSchema.concat(this.props.fields.filter(f => f.required)) if (this.props.useAdvancedOptions) { fieldsSchema = fieldsSchema.concat(this.props.fields.filter(f => !f.required)) } let executeNowColumn let fields = fieldsSchema.filter(f => this.shouldRenderField(f)).map((field, i) => { let column = i % 2 === 0 ? 'left' : 'right' if (field.name === 'execute_now') { executeNowColumn = column } if (field.name === 'execute_now_options') { column = executeNowColumn } return { column, component: this.renderOptionsField(field), } }) if (fields.length * 96 < window.innerHeight - 450) { return ( {fields.map(f => f.component)} ) } return ( {fields.map(f => f.column === 'left' && f.component)} {fields.map(f => f.column === 'right' && f.component)} ) } renderLoading() { if (!this.props.loading) { return null } return ( Loading options... ) } renderOptions() { if (this.props.loading) { return null } return ( { this.props.onAdvancedOptionsToggle(item.value === 'advanced') }} /> {this.renderOptionsFields()} ) } render() { return ( {this.renderOptions()} {this.renderLoading()} ) } } export default WizardOptions