/* 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 . */ import React, { Component, PropTypes } from 'react'; import withStyles from 'isomorphic-style-loader/lib/withStyles'; import SearchBox from '../SearchBox'; import s from './WizardVms.scss'; import { itemsPerPage } from '../../config'; import ConnectionsActions from '../../actions/ConnectionsActions'; import LoadingIcon from '../LoadingIcon'; const title = 'Select instances to migrate'; const vmStatesConst = ["All", "RUNNING", "PAUSED", "STOPPED"] const searchTimeout = 1000; class WizardVms extends Component { static propTypes = { data: PropTypes.object, setWizardState: PropTypes.func } static contextTypes = { onSetTitle: PropTypes.func.isRequired, }; constructor(props) { super(props) let valid = false if (this.props.data.instances) { this.props.data.instances.forEach((vm) => { if (vm.selected) { valid = true } }) } this.retryLoadingInstances = this.retryLoadingInstances.bind(this) this.state = { valid, queryText: '', page: 0, filterStatus: 'All', filteredData: this.props.data.instances ? this.props.data.instances.slice(0, itemsPerPage) : [], nextStep: "WizardOptions" } } componentWillMount() { this.context.onSetTitle(title); this.props.setWizardState(this.state) } componentWillReceiveProps(newProps) { this.processProps(newProps) if (newProps.data.selectedInstances) { let valid = newProps.data.selectedInstances.length > 0 if (this.props.data.valid != valid) { this.props.setWizardState({ valid: valid }) } } } processProps(props) { if (props.data.instances) { this.setState({ filteredData: props.data.instances.slice( this.state.page * itemsPerPage, this.state.page * itemsPerPage + itemsPerPage) }) } } checkVm(e, item) { let instances = this.props.data.instances instances.forEach((vm) => { if (vm == item) { vm.selected = !vm.selected let selectedInstances = this.props.data.selectedInstances let index = -1 selectedInstances.forEach((instance, key) => { if (instance.name == item.name) { index = key } }) if (index == -1) { selectedInstances.push(item) } else { selectedInstances.splice(index, 1) } this.props.setWizardState({ selectedInstances: selectedInstances }) } }) this.props.setWizardState({ instances: instances }) } searchVm(queryText) { let queryResult = [] if (this.props.data.instances) { this.props.data.instances.forEach((vm) => { if ( (this.state.filterStatus === "All" || this.state.filterStatus === vm.status) ) { queryResult.push(vm) } }, this) } if (this.state.queryText != queryText) { if (this.timeout != null) { clearTimeout(this.timeout) } this.timeout = setTimeout(() => { this.setState({ page: 0, filteredData: null, queryText: queryText }, () => { this.props.setWizardState({ instances: null }) ConnectionsActions.loadInstances( { id: this.props.data.sourceCloud.credential.id }, this.state.page, queryText, false ) }) }, searchTimeout) } else { this.setState({ filteredData: queryResult }) } } instancesSelected() { let count = this.props.data.selectedInstances.length; return count; } filterStatus(e, status) { this.setState({ filterStatus: status }, () => { this.searchVm({ target: { value: this.state.queryText } }) }) } toTitleCase(str) { return str.replace(/\w\S*/g, (txt) => { // eslint-disable-line arrow-body-style return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase(); }); } isSelected(item) { let selected = false; this.props.data.selectedInstances.forEach(instance => { if (instance.name == item.name) { selected = true } }) return selected } nextPage() { if (this.state.filteredData && this.state.filteredData.length == itemsPerPage) { this.setState({ page: this.state.page + 1 }, () => { ConnectionsActions.loadInstances( { id: this.props.data.sourceCloud.credential.id }, this.state.page, this.state.queryText ) this.processProps({ data: { instances: this.props.data.instances } }) }) } } previousPage() { if (this.state.page > 0) { this.setState({ page: this.state.page + -1 }, () => { ConnectionsActions.loadInstances( { id: this.props.data.sourceCloud.credential.id }, this.state.page, this.state.queryText ) this.processProps({ data: { instances: this.props.data.instances } }) }) } } retryLoadingInstances() { ConnectionsActions.loadInstances( { id: this.props.data.sourceCloud.credential.id }, this.state.page, this.state.queryText, false ) } renderSearch() { let _this = this switch (this.props.data.instancesLoadState) { case "success": if (this.state.filteredData && this.state.filteredData.length) { let instances = this.state.filteredData.map((item, index) =>
_this.checkVm(e, item) }>
_this.checkVm(e, item)} className="checkbox-normal" />
{item.instance_name}
{item.num_cpu} vCPU | {item.memory_mb} MB RAM {item.flavor_name && (" | " + item.flavor_name)}
) return instances } else { return
Your search returned no results
} case "error": return (
An error occurred while searching for instances
) case "loading": return default: return } } render() { let _this = this let vmStates = vmStatesConst.map( (state, index) => _this.filterStatus(e, state)} key={"status_" + index} >{_this.toTitleCase(state)} ) return (
this.searchVm(e)} className={"searchBox" + (!(this.state.filteredData && this.state.filteredData.length) ? " hidden" : " ")} />
{vmStates}
{this.renderSearch()}
{this.instancesSelected()} instances selected
this.previousPage(e)} > {this.state.page + 1} this.nextPage(e)} >
); } } export default withStyles(WizardVms, s);