ManageIQ/manageiq-ui-classic

View on GitHub
app/javascript/components/reconfigure-vm-form/index.jsx

Summary

Maintainability
D
2 days
Test Coverage
import React, { useState, useEffect } from 'react';
import PropTypes from 'prop-types';
import { Loading } from 'carbon-components-react';
import componentMapper from '../../forms/mappers/componentMapper';
import MiqFormRenderer from '../../forms/data-driven-form';
import { createSchema } from './reconfigure-form.schema';
import { CellAction } from '../miq-data-table/helper';
import ReconfigureTable from './reconfigure-table';
import ReconfigureTemplate from './reconfigure-template';
import miqRedirectBack from '../../helpers/miq-redirect-back';
import {
  setInitialData,
  subFormSubmit,
  setButtonActions,
  reconfigureSubmitData,
  validateMemory,
  getFormSubmitStatus,
  validateCpu,
} from './helper';
import { TYPES, formsData } from './helpers/general';
import { validateDiskSize } from './helpers/disk';
import { setNetworkOptions } from './helpers/network';

const ReconfigureVmForm = ({
  recordId, requestId, roles, options, memory,
}) => {
  const [data, setData] = useState({
    initialValues: {},
    isLoading: true,
    form: {
      title: formsData.reconfigure.title,
      type: TYPES.RECONFIGURE,
      className: formsData.reconfigure.className,
      action: 'edit',
    },
    orchestration_stack_id: '',
    networkOptions: [],
    dataTable: {
      disks: [],
      networkAdapters: [],
      drives: [],
    },
    editingRow: [],
    submitParams: {
      disks: { add: [], resize: [], delete: [] },
      diskIds: {
        add: [], resize: [], delete: [], backup: [],
      },
      networks: { add: [], edit: [], delete: [] },
      networkIds: { add: [], edit: [], delete: [] },
      drives: { connect: [], disconnect: [] },
      driveIds: { connect: [], disconnect: [] },
    },
    changeCounter: 0,
    socket: '',
    cores: '',
    reset: 1,
  });

  useEffect(() => {
    setInitialData(recordId, requestId, data, setData, roles);
  }, [recordId, data.reset]);

  const onSubmit = (formsData) => {
    miqSparkleOn();
    if (data.form.type === TYPES.RECONFIGURE) {
      const URL = `/vm_infra/reconfigure_update/${requestId}?button=submit`;
      miqAjaxButton(URL, reconfigureSubmitData(recordId, data, formsData));
    } else {
      subFormSubmit(data, setData, formsData, roles);
    }
    miqSparkleOff();
  };

  const onCancel = () => {
    if (data.form.type === TYPES.RECONFIGURE) {
      miqSparkleOn();
      const returnURL = '/vm_infra/explorer/';
      const message = sprintf(__('VM Reconfigure Request was cancelled by the user'));
      miqRedirectBack(message, 'success', returnURL);
    } else {
      setData({
        ...data,
        isLoading: false,
        form: {
          title: __('Options'),
          type: TYPES.RECONFIGURE,
          className: 'reconfigureForm',
        },
      });
    }
  };

  const onReset = () => {
    if (data.form.type === TYPES.RECONFIGURE) {
      setData({
        ...data,
        editingRow: [],
        submitParams: {
          disks: { add: [], resize: [], delete: [] },
          diskIds: {
            add: [], resize: [], delete: [], backup: [],
          },
          networks: { add: [], edit: [], delete: [] },
          networkIds: { add: [], edit: [], delete: [] },
          drives: { connect: [], disconnect: [] },
          driveIds: { connect: [], disconnect: [] },
        },
        changeCounter: 0,
        reset: data.reset + 1,
      });
    }
  };

  /** Function to define the custom validation functions */
  const customValidatorMapper = {
    customRequired: ({ hideField }) => (value) => (!value && !hideField ? __('Required') : undefined),
    memoryCheck: () => (value, allValues) => (
      validateMemory(value, allValues.cb_memory, allValues.mem_type, memory) ? undefined : __('Memory value not in range or not a multiple of 4')
    ),
    cpuCheck: ({ field }) => (value, allValues) => (
      validateCpu(value, allValues, field, memory.max_cpu) ? undefined : __(`Total processors value larger than the maximum allowed value`)
    ),
    diskMemoryCheck: ({ size, unit }) => (value, allValues) => (
      validateDiskSize(value, allValues.unit, size, unit) ? undefined : __(`Disk size has to be greater than ${size}${unit}`)
    ),
  };

  /** Function to render the forms by setting form type.
   * return true for no render action.
   */
  // eslint-disable-next-line consistent-return
  const setRenderForm = (row, type, action) => {
    if (type === TYPES.DISK && action === 'edit') {
      return true;
    }
    if (type === TYPES.NETWORK || type === TYPES.EDITNETWORK) {
      if (action === 'edit') {
        const networks = data.submitParams.networkIds;
        if (networks.add.includes(row.id) || networks.edit.includes(row.id) || networks.delete.includes(row.id)) {
          return true;
        }
      }
      if (roles.isVmwareCloud) {
        setNetworkOptions(data.orchestration_stack_id, data, setData, type, action, row);
        return true;
      }
    }
    setData({
      ...data,
      isLoading: false,
      editingRow: row,
      form: {
        title: formsData[type].title,
        type,
        action,
        className: formsData[type].className,
      },
    });
  };

  /** Function to handle the button clicks of the datatable. */
  const setButtonClick = (item) => {
    if (item && item.callbackAction) {
      if (item.callbackAction === TYPES.EDITNETWORK) {
        setRenderForm(item, TYPES.EDITNETWORK, 'edit');
      } else if (item.callbackAction === 'connectDrives') {
        setRenderForm(item, TYPES.DRIVE, 'edit');
      } else if (item.callbackAction === 'resizeDisk') {
        setRenderForm(item, TYPES.RESIZE, TYPES.RESIZE);
      } else {
        setButtonActions(item, data, setData, roles);
      }
    }
  };

  /** Function to execute the click events of from the datables.
  * Like - row's click event  for resize and delete button click event.
  */
  const onCellClick = (selectedRow, cellType) => {
    if (cellType === CellAction.buttonCallback) {
      setButtonClick(selectedRow);
    }
    return true;
  };

  const tableComponentMapper = {
    ...componentMapper,
    'reconfigure-table': ReconfigureTable,
  };

  if (data.isLoading) return <Loading className="export-spinner" withOverlay={false} small />;
  return !data.isLoading && (
    <>
      <MiqFormRenderer
        componentMapper={tableComponentMapper}
        schema={createSchema(recordId, data, setData, roles, options, memory, onCellClick, setRenderForm)}
        FormTemplate={(props) => (
          <ReconfigureTemplate
            canSubmit={getFormSubmitStatus(data)}
            {...props}
          />
        )}
        initialValues={data.initialValues}
        onSubmit={onSubmit}
        onReset={onReset}
        onCancel={() => onCancel(data)}
        validatorMapper={customValidatorMapper}
        clearOnUnmount={data.form.type !== TYPES.RECONFIGURE}
      />
    </>
  );
};

ReconfigureVmForm.propTypes = {
  recordId: PropTypes.arrayOf(PropTypes.any).isRequired,
  requestId: PropTypes.oneOfType([PropTypes.number, PropTypes.string]).isRequired,
  roles: PropTypes.objectOf(PropTypes.any),
  options: PropTypes.objectOf(PropTypes.any),
  memory: PropTypes.objectOf(PropTypes.any),
};

ReconfigureVmForm.defaultProps = {
  roles: undefined,
  options: undefined,
  memory: undefined,
};

export default ReconfigureVmForm;