theforeman/foreman

View on GitHub
webpack/assets/javascripts/react_app/components/hosts/storage/vmware/index.js

Summary

Maintainability
C
1 day
Test Coverage
import { pick } from 'lodash';
import React from 'react';
import { Alert, Button } from 'patternfly-react';
import { connect } from 'react-redux';
import PropTypes from 'prop-types';

import Controller from './controller/';
import * as VmWareActions from '../../../../redux/actions/hosts/storage/vmware';
import { MaxDisksPerController } from './StorageContainer.consts';
import { translate as __ } from '../../../../../react_app/common/I18n';
import { noop } from '../../../../common/helpers';
import AlertBody from '../../../common/Alert/AlertBody';
import './StorageContainer.scss';
import { STATUS } from '../../../../constants';

const filterKeyFromVolume = volume => {
  // eslint-disable-next-line no-unused-vars
  const { key, ...volumeWithoutKey } = volume;
  return volumeWithoutKey;
};

export const controllersToJsonString = (controllers, volumes) =>
  JSON.stringify({
    scsiControllers: controllers,
    volumes: volumes.map(v => filterKeyFromVolume(v)),
  });

class StorageContainer extends React.Component {
  componentDidMount() {
    const {
      data: { config, controllers, volumes, cluster },
      initController,
    } = this.props;

    initController(config, cluster, controllers, volumes);
  }

  getDatastoresStatus() {
    const { datastoresLoading, datastoresError } = this.props;
    if (datastoresError) {
      return STATUS.ERROR;
    }
    if (datastoresLoading) {
      return STATUS.PENDING;
    }
    return STATUS.RESOLVED;
  }

  getStoragePodsStatus() {
    const { storagePodsLoading, storagePodsError } = this.props;
    if (storagePodsError) {
      return STATUS.ERROR;
    }
    if (storagePodsLoading) {
      return STATUS.PENDING;
    }
    return STATUS.RESOLVED;
  }

  renderControllers(controllers) {
    const {
      addDisk,
      updateController,
      removeDisk,
      updateDisk,
      removeController,
      config,
      volumes,
      datastores,
      datastoresError,
      storagePods,
      storagePodsError,
    } = this.props;

    return controllers.map((controller, idx) => {
      const controllerVolumes = volumes.filter(
        v => v.controllerKey === controller.key
      );

      return (
        <Controller
          key={controller.key}
          removeController={() => removeController(controller.key)}
          controller={controller}
          controllerVolumes={controllerVolumes}
          addDiskEnabled={controllerVolumes.length < MaxDisksPerController}
          addDisk={() => addDisk(controller.key)}
          updateDisk={updateDisk}
          removeDisk={removeDisk}
          updateController={newValues => updateController(idx, newValues)}
          config={config}
          datastores={datastores}
          datastoresError={datastoresError}
          datastoresStatus={this.getDatastoresStatus()}
          storagePods={storagePods}
          storagePodsError={storagePodsError}
          storagePodsStatus={this.getStoragePodsStatus()}
        />
      );
    });
  }

  render() {
    const { addController, controllers, volumes, cluster, config } = this.props;
    const paramsScope = config && config.paramsScope;
    const enableAddControllerBtn =
      config && config.addControllerEnabled && !config.vmExists;

    if (!cluster) {
      return (
        <Alert type="info">
          <AlertBody message={__('Please select a cluster')} />
        </Alert>
      );
    }

    return (
      <div className="row vmware-storage-container">
        <div className="storage-header">
          <div className="col-md-2 storage-title">{__('Storage')}</div>
          <div className="col-md-10 storage-controller-buttons">
            <Button
              className="btn-add-controller"
              onClick={() => addController()}
              disabled={!enableAddControllerBtn}
              bsStyle="primary"
            >
              {__('Add Controller')}
            </Button>
          </div>
        </div>
        <div className="storage-body">
          {this.renderControllers(controllers)}
          <input
            value={controllersToJsonString(controllers, volumes)}
            id="scsi_controller_hidden"
            name={paramsScope}
            type="hidden"
          />
        </div>
      </div>
    );
  }
}

StorageContainer.propTypes = {
  data: PropTypes.shape({
    config: PropTypes.object.isRequired,
    controllers: PropTypes.array.isRequired,
    volumes: PropTypes.array.isRequired,
    cluster: PropTypes.string,
  }).isRequired,
  controllers: PropTypes.array.isRequired,
  config: PropTypes.object,
  volumes: PropTypes.array,
  cluster: PropTypes.string,
  datastoresLoading: PropTypes.bool,
  datastores: PropTypes.arrayOf(
    PropTypes.shape({
      id: PropTypes.string,
      name: PropTypes.string,
      capacity: PropTypes.number,
      freespace: PropTypes.number,
      uncommitted: PropTypes.number,
    })
  ),
  datastoresError: PropTypes.string,
  storagePodsLoading: PropTypes.bool,
  storagePods: PropTypes.arrayOf(
    PropTypes.shape({
      id: PropTypes.string,
      name: PropTypes.string,
      capacity: PropTypes.number,
      freespace: PropTypes.number,
    })
  ),
  storagePodsError: PropTypes.string,
  addController: PropTypes.func,
  addDisk: PropTypes.func,
  updateController: PropTypes.func,
  removeDisk: PropTypes.func,
  updateDisk: PropTypes.func,
  removeController: PropTypes.func,
  initController: PropTypes.func,
};

StorageContainer.defaultProps = {
  config: {},
  cluster: '',
  volumes: [],
  datastoresLoading: false,
  storagePodsLoading: false,
  datastores: [],
  storagePods: [],
  datastoresError: undefined,
  storagePodsError: undefined,
  addController: noop,
  addDisk: noop,
  updateController: noop,
  removeDisk: noop,
  updateDisk: noop,
  removeController: noop,
  initController: noop,
};

const mapStateToProps = state =>
  pick(state.hosts.storage.vmware, [
    'controllers',
    'config',
    'cluster',
    'volumes',
    'datastores',
    'datastoresLoading',
    'datastoresError',
    'storagePods',
    'storagePodsLoading',
    'storagePodsError',
  ]);

export default connect(mapStateToProps, VmWareActions)(StorageContainer);