18F/federalist

View on GitHub
frontend/components/site/SiteSettings/EnvironmentVariables.jsx

Summary

Maintainability
A
40 mins
Test Coverage
A
93%
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import {
  addUserEnvironmentVariable,
  deleteUserEnvironmentVariable,
  fetchUserEnvironmentVariables,
} from '../../../actions/userEnvironmentVariableActions';
import { siteUserEnvironmentVariables } from '../../../selectors/userEnvironmentVariable';
import { USER_ENVIRONMENT_VARIABLE } from '../../../propTypes';
import AlertBanner from '../../alertBanner';
import ExpandableArea from '../../ExpandableArea';
import LoadingIndicator from '../../LoadingIndicator';
import globals from '../../../globals';
import EnvironmentVariableForm from './EnvironmentVariableForm';
import EnvironmentVariableTable from './EnvironmentVariableTable';

const infoContent = (
  <>
    Certain environment variable names are reserved for
    {` ${globals.APP_NAME} `}
    use and will
    be ignored. Warnings for any ignored environment variables will be present
    in the build logs. See the default variables in
    {' '}
    <a
      href="https://cloud.gov/pages/documentation/env-vars-on-pages-builds"
      rel="noopener"
    >
      Environment Variables On
      {` ${globals.APP_NAME} `}
      Builds
    </a>
    {' '}
    for an up-to-date list.
  </>
);

const warningContent = (
  <>
    {` ${globals.APP_NAME} `}
    is a
    {' '}
    <b>
      FISMA Moderate
    </b>
    system, do NOT store variables for systems that are High, and
    only expose variables if it is safe to do so. You assume the risk if the
    values you add contain, or allow access to information that is not suitable
    for this categorization. See
    {' '}
    <a
      href="https://csrc.nist.gov/Projects/Risk-Management/Risk-Management-Framework-(RMF)-Overview/Security-Categorization"
      rel="noopener noreferrer"
    >
      FISMA Security Categorization
    </a>
    {' '}
    for more information on FISMA information categorization.
  </>
);

class EnvironmentVariables extends Component {
  componentDidMount() {
    const { siteId, actions } = this.props;
    actions.fetchUserEnvironmentVariables(siteId);
  }

  render() {
    const {
      siteId,
      userEnvironmentVariables: { isLoading, data },
      actions,
    } = this.props;

    const addUEV = params => actions.addUserEnvironmentVariable(siteId, params);
    const deleteUEV = uevId => actions.deleteUserEnvironmentVariable(siteId, uevId);
    const showTable = !isLoading && data.length > 0;

    return (
      <>
        <h3>Environment Variables</h3>
        <div className="well">
          <AlertBanner
            status="info"
            message={infoContent}
            alertRole={false}
          />
          <AlertBanner
            status="warning"
            message={warningContent}
            alertRole={false}
          />
          <br />
          { isLoading
            ? <LoadingIndicator />
            : (
              <>
                <ExpandableArea
                  bordered
                  title="Add a new environment variable"
                >
                  <div className="well">
                    <EnvironmentVariableForm onSubmit={params => addUEV(params)} />
                  </div>
                </ExpandableArea>
                { showTable
                && (
                <EnvironmentVariableTable uevs={data} onDelete={deleteUEV} />
                )}
              </>
            )}
        </div>
      </>
    );
  }
}

EnvironmentVariables.propTypes = {
  siteId: PropTypes.number.isRequired,
  actions: PropTypes.shape({
    fetchUserEnvironmentVariables: PropTypes.func.isRequired,
    addUserEnvironmentVariable: PropTypes.func.isRequired,
    deleteUserEnvironmentVariable: PropTypes.func.isRequired,
  }).isRequired,
  userEnvironmentVariables: PropTypes.shape({
    isLoading: PropTypes.bool.isRequired,
    data: PropTypes.arrayOf(USER_ENVIRONMENT_VARIABLE).isRequired,
  }).isRequired,
};

const mapStateToProps = ({ userEnvironmentVariables }, { siteId }) => ({
  userEnvironmentVariables: siteUserEnvironmentVariables(userEnvironmentVariables, siteId),
});

const mapDispatchToProps = dispatch => ({
  actions: bindActionCreators({
    addUserEnvironmentVariable,
    deleteUserEnvironmentVariable,
    fetchUserEnvironmentVariables,
  }, dispatch),
});

export { EnvironmentVariables };
export default connect(mapStateToProps, mapDispatchToProps)(EnvironmentVariables);