Source

components/InventoryTable/InventoryList.js

/* eslint-disable react/display-name */
import React, { useEffect, useRef } from 'react';
import { useSelector } from 'react-redux';
import InventoryEntityTable from './EntityTable';
import { Grid, GridItem } from '@patternfly/react-core';
import PropTypes from 'prop-types';
import './InventoryList.scss';
import isEqual from 'lodash/isEqual';
import AccessDenied from '../../Utilities/AccessDenied';

const convertItem = ({ children, isOpen, ...item }) => item;

/**
 * Component that works as a side channel for consumers to notify inventory of new data changes.
 *  @param props
 *  @param props.showHealth
 *  @param props.onRefreshData
 *  @param props.ignoreRefresh
 */
const ContextInventoryList = ({
  showHealth,
  onRefreshData,
  ignoreRefresh,
  ...props
}) => {
  const prevItems = useRef(props.items);
  const prevSortBy = useRef(props.sortBy);

  useEffect(() => {
    if (props.hasItems) {
      onRefreshData({}, ignoreRefresh);
    }
  }, []);

  /**
   * Function to calculate for new changes, this function limits re-renders by checking if previous items are
   * same as new items.
   * If items are not passed, it only checks for props sortBy.
   *  @param {*} prevProps previous props - items, hasItems, sortBy.
   */
  useEffect(() => {
    if (
      props.hasItems &&
      !isEqual(prevItems.current.map(convertItem), props.items.map(convertItem))
    ) {
      prevItems.current = props.items;
      onRefreshData({}, ignoreRefresh);
    }

    if (
      !props.hasItems &&
      props.loaded == true &&
      !isEqual(prevSortBy.current, props.sortBy)
    ) {
      prevSortBy.current = props.sortBy;
      onRefreshData({});
    }
  });

  return (
    <Grid
      gutter="sm"
      className="ins-inventory-list"
      data-testid="inventory-table-list"
    >
      <GridItem span={12}>
        <InventoryEntityTable {...props} onRefreshData={onRefreshData} />
      </GridItem>
    </Grid>
  );
};

/**
 * Component that consumes active filters and passes them down to component.
 */
const InventoryList = React.forwardRef(
  ({ hasAccess, onRefreshData, ...props }, ref) => {
    const activeFilters = useSelector(
      ({ entities: { activeFilters } }) => activeFilters,
    );

    if (ref) {
      ref.current = {
        onRefreshData: (params, disableRefresh = true, forceRefresh) =>
          onRefreshData(params, disableRefresh, forceRefresh),
      };
    }

    return !hasAccess ? (
      <div className="ins-c-inventory__no-access">
        <AccessDenied showReturnButton={false} />
      </div>
    ) : (
      <ContextInventoryList
        {...props}
        activeFilters={activeFilters}
        onRefreshData={onRefreshData}
      />
    );
  },
);

ContextInventoryList.propTypes = {
  ...InventoryList.propTypes,
  setRefresh: PropTypes.func,
  onRefreshData: PropTypes.func,
  ignoreRefresh: PropTypes.bool,
};
ContextInventoryList.defaultProps = {
  perPage: 50,
  page: 1,
  ignoreRefresh: true,
};
InventoryList.propTypes = {
  showTags: PropTypes.bool,
  filterEntities: PropTypes.func,
  loadEntities: PropTypes.func,
  showHealth: PropTypes.bool,
  page: PropTypes.number,
  perPage: PropTypes.number,
  sortBy: PropTypes.shape({
    key: PropTypes.string,
    direction: PropTypes.string,
  }),
  items: PropTypes.arrayOf(
    PropTypes.oneOfType([
      PropTypes.string,
      PropTypes.shape({
        id: PropTypes.string.isRequired,
      }),
      PropTypes.shape({
        account: PropTypes.any,
        isOpen: PropTypes.bool,
        title: PropTypes.node,
      }),
    ]),
  ),
  entities: PropTypes.arrayOf(PropTypes.any),
  customFilters: PropTypes.shape({
    tags: PropTypes.oneOfType([
      PropTypes.object,
      PropTypes.arrayOf(PropTypes.string),
    ]),
  }),
  getEntities: PropTypes.func,
  hideFilters: PropTypes.shape({
    tags: PropTypes.bool,
    name: PropTypes.bool,
    registeredWith: PropTypes.bool,
    stale: PropTypes.bool,
    operatingSystem: PropTypes.bool,
  }),
  onRefreshData: PropTypes.func,
};

InventoryList.defaultProps = {
  hasAccess: true,
};

export default InventoryList;