ManageIQ/manageiq-ui-classic

View on GitHub
app/javascript/components/button-group/index.jsx

Summary

Maintainability
D
2 days
Test Coverage
import React, { useState, useEffect } from 'react';
import MiqFormRenderer, { useFormApi } from '@@ddf';
import { Button, Loading } from 'carbon-components-react';
import PropTypes from 'prop-types';
import { FormSpy } from '@data-driven-forms/react-form-renderer';
import createSchema from './group-form.schema';
import {
  formatButton, formatName, formatSetData, getButtonList,
} from './helper';
import miqRedirectBack from '../../helpers/miq-redirect-back';
import { API } from '../../http_api';

const GroupForm = ({
  recId, availableFields, fields, url, appliesToClass, appliesToId, isGenericObject,
}) => {
  const [{
    isLoading, initialValues, buttonIcon, options,
  }, setState] = useState({
    isLoading: true,
  });

  let iconChanged = false;
  const actionType = (recId ? 'group_update' : 'group_create');
  const buttonType = (recId ? 'save' : 'add');
  const cancelUrl = `${actionType}/${recId}?button=cancel`;
  const buttonOptions = formatButton(availableFields.concat(fields));

  const getInitialValues = (buttons = []) => {
    API.get(`/api/custom_button_sets/${recId}`)
      .then((initialValues) => {
        setState((state) => ({
          ...state,
          initialValues: { ...initialValues, name: formatName(initialValues.name) },
          buttonIcon: (initialValues && initialValues.set_data) ? initialValues.set_data.button_icon : '',
          options: isGenericObject || appliesToClass === 'ServiceTemplate' ? buttons : buttonOptions,
          isLoading: false,
        }));
      });
  };

  useEffect(() => {
    if (isGenericObject || appliesToClass === 'ServiceTemplate') {
      API.get(`/api/custom_buttons?expand=resources&filter[]=applies_to_class=${appliesToClass}&filter[]=applies_to_id=${appliesToId}`)
        .then((data) => {
          API.get(`/api/custom_button_sets?expand=resources&filter[]=owner_type=${appliesToClass}&filter[]=owner_id=${appliesToId}`)
            .then((buttonGroups) => {
              const buttons = getButtonList(buttonGroups, data, recId);
              if (recId) {
                getInitialValues(buttons);
              } else {
                setState((state) => ({
                  ...state,
                  options: buttons,
                  isLoading: false,
                }));
              }
            });
        });
    } else if (recId) {
      getInitialValues();
    } else {
      setState((state) => ({
        ...state,
        options: availableFields.length > 0 ? buttonOptions : [],
        isLoading: false,
      }));
    }
  }, []);

  iconChanged = (recId && initialValues && initialValues.set_data)
    ? (initialValues.set_data.button_icon !== buttonIcon)
    : false;

  /** When the api resquest is completed, an miqAjaxButton method is used to retain the current page.
   * While saving from 'services/catalogItem', if the redirect method is used, the current page will not be displayed.
  */
  const onSubmit = (values) => {
    miqSparkleOn();
    if (appliesToId) {
      values.owner_id = appliesToId;
    }
    values.owner_type = appliesToClass;
    const groupIndex = initialValues ? initialValues.set_data.group_index : undefined;
    values.set_data = formatSetData(values.set_data, buttonIcon, appliesToClass, appliesToId, groupIndex);
    if (values.set_data.display === undefined) {
      values.set_data.display = false;
    }

    const request = recId
      ? API.patch(`/api/custom_button_sets/${recId}`, values, { skipErrors: [400, 500] })
      : API.post('/api/custom_button_sets', values, { skipErrors: [400, 500] });
    request.then(({ results }) => {
      const saveMsg = recId ? sprintf(__(`Custom Button Group "%s" has been successfully saved.`), values.name)
        : sprintf(__(`Custom Button Group "%s" has been successfully added.`), values.name);
      if (isGenericObject) {
        miqRedirectBack(saveMsg, 'success', url);
        miqSparkleOff();
      } else {
        miqAjaxButton(`${actionType}/${recId || results[0].id}?button=${buttonType}`, values);
      }
    }).catch(({ data: { error: { message } } }) => {
      const errorMessage = message ? message.split(': ')[1] : __('Please try again');
      add_flash(errorMessage, 'error');
      miqSparkleOff();
    });
  };

  const onCancel = () => {
    if (isGenericObject) {
      if (recId) {
        miqRedirectBack(sprintf(__(`Edit of Custom Button Group "%s" was canceled by the user.`), initialValues.name), 'warn', url);
      } else {
        miqRedirectBack(__(`Creation of new Custom Button Group was canceled by the user.`), 'warn', url);
      }
    } else {
      miqAjaxButton(cancelUrl);
    }
  };

  const onFormReset = () => {
    setState((state) => ({
      ...state,
      buttonIcon: initialValues.set_data.button_icon,
      isLoading: false,
    }));
    add_flash(__('All changes have been reset'), 'warn');
  };

  if (isLoading || (options === undefined)) return <Loading className="export-spinner" withOverlay={false} small />;
  return (!isLoading && options) && (
    <div className="col-md-12 button-form">
      <MiqFormRenderer
        schema={createSchema(buttonIcon, options, url, setState)}
        initialValues={initialValues}
        FormTemplate={(props) => <FormTemplate {...props} recId={recId} modified={iconChanged} />}
        onSubmit={onSubmit}
        onCancel={onCancel}
        onReset={onFormReset}
      />
    </div>
  );
};

const FormTemplate = ({
  formFields, recId, modified,
}) => {
  const {
    handleSubmit, onReset, onCancel, getState,
  } = useFormApi();
  const { valid, pristine } = getState();
  const submitLabel = !!recId ? __('Save') : __('Add');
  return (
    <form onSubmit={handleSubmit}>
      {formFields}
      <FormSpy>
        {() => (
          <div className="custom-button-wrapper">
            <Button
              disabled={(!valid || !modified) && pristine}
              kind="primary"
              className="btnRight"
              type="submit"
              variant="contained"
            >
              {submitLabel}
            </Button>

            {!!recId
              ? (
                <Button
                  disabled={(!valid || !modified) && pristine}
                  kind="secondary"
                  className="btnRight"
                  variant="contained"
                  onClick={onReset}
                  type="button"
                >
                  { __('Reset')}
                </Button>
              ) : null}

            <Button variant="contained" type="button" onClick={onCancel} kind="secondary">
              { __('Cancel')}
            </Button>
          </div>
        )}
      </FormSpy>
    </form>
  );
};

GroupForm.propTypes = {
  recId: PropTypes.number,
  availableFields: PropTypes.arrayOf(PropTypes.any),
  fields: PropTypes.arrayOf(PropTypes.any),
  url: PropTypes.string,
  appliesToClass: PropTypes.string,
  appliesToId: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
  isGenericObject: PropTypes.bool,
};

GroupForm.defaultProps = {
  recId: undefined,
  availableFields: [],
  fields: [],
  url: '',
  appliesToClass: '',
  appliesToId: undefined,
  isGenericObject: false,
};

FormTemplate.propTypes = {
  recId: PropTypes.number,
  formFields: PropTypes.arrayOf(PropTypes.any),
  modified: PropTypes.bool,
};

FormTemplate.defaultProps = {
  recId: undefined,
  formFields: [],
  modified: false,
};

export default GroupForm;