| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308 |
- /*
- 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 <http://www.gnu.org/licenses/>.
- */
- 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) =>
- <div className="item" key={ "vm_" + index } onClick={ (e) => _this.checkVm(e, item) }>
- <div className="checkbox-container">
- <input
- id={"vm_check_" + index}
- type="checkbox"
- checked={this.isSelected(item)}
- onChange={(e) => _this.checkVm(e, item)}
- className="checkbox-normal"
- />
- <label htmlFor={ "vm_check_" + index }></label>
- </div>
- <span className="cell cell-icon">
- <div className="icon vm"></div>
- <span className="details">
- {item.instance_name}
- </span>
- </span>
- <span className="cell">{item.num_cpu} vCPU | {item.memory_mb} MB RAM
- {item.flavor_name && (" | " + item.flavor_name)}</span>
- </div>
- )
- return instances
- } else {
- return <div className="no-results">Your search returned no results</div>
- }
- case "error":
- return (<div className="no-results">
- An error occurred while searching for instances <br />
- <button onClick={this.retryLoadingInstances}>Retry</button>
- </div>)
- case "loading":
- return <LoadingIcon padding={64} text="Loading instances.." />
- default:
- return <LoadingIcon padding={64} text="Loading instances.." />
- }
- }
- render() {
- let _this = this
- let vmStates = vmStatesConst.map(
- (state, index) =>
- <a
- className={_this.state.filterStatus == state || (_this.state.filterStatus == null && state == "All") ?
- "selected" : ""}
- onClick={(e) => _this.filterStatus(e, state)} key={"status_" + index}
- >{_this.toTitleCase(state)}</a>
- )
- return (
- <div className={s.root}>
- <div className={s.container}>
- <div className={s.topFilters}>
- <SearchBox
- placeholder="Search VMs"
- value={this.state.queryText}
- onChange={(e) => this.searchVm(e)}
- className={"searchBox" + (!(this.state.filteredData && this.state.filteredData.length) ? " hidden" : " ")}
- />
- <div className="category-filter hidden">
- {vmStates}
- </div>
- </div>
- <div className="items-list instances">
- {this.renderSearch()}
- </div>
- <div className={s.selectionCount +
- (!(this.state.filteredData && this.state.filteredData.length) ? " hidden" : " ")}
- >
- {this.instancesSelected()} instances selected
- </div>
- <div className={s.pagination +
- (!(this.state.filteredData && this.state.filteredData.length) ? " hidden" : " ")}
- >
- <span
- className={(this.state.page == 0 ? "disabled " : "") + s.prev}
- onClick={(e) => this.previousPage(e)}
- ></span>
- <span className={s.currentPage}>{this.state.page + 1}</span>
- <span
- className={(this.state.filteredData && this.state.filteredData.length == itemsPerPage ?
- " " : "disabled ") + s.next}
- onClick={(e) => this.nextPage(e)}
- ></span>
- </div>
- </div>
- </div>
- );
- }
- }
- export default withStyles(WizardVms, s);
|