/*
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);