Skip to content

Commit

Permalink
feat(inventoryList): issues/410 activate column sorting (#433)
Browse files Browse the repository at this point in the history
* inventoryList, apply onColumnSort callback
* inventoryListHelpers, expand isSortable filter for table component
* openshiftView, apply isSortable, clear inventory query
* rhelView, apply isSortable, clear inventory query
* table, expand sorting, active column, direction
* toolbar, clear inventory query
* viewReducer, queryTypes, clear inventory query
* rhsmApiTypes, sort, direction types
  • Loading branch information
cdcabrera committed Oct 8, 2020
1 parent 6a881bb commit 5da946c
Show file tree
Hide file tree
Showing 22 changed files with 946 additions and 100 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,53 @@ exports[`InventoryList Component should handle expandable guests data: number of
/>
`;

exports[`InventoryList Component should handle updating sorting through redux state: dispatch filter 1`] = `
Array [
Array [
Array [
Object {
"dir": "asc",
"type": "SET_QUERY_RHSM_dir",
"viewId": "lorem",
},
Object {
"sort": "sockets",
"type": "SET_QUERY_RHSM_sort",
"viewId": "lorem",
},
],
],
Array [
Array [
Object {
"dir": "desc",
"type": "SET_QUERY_RHSM_dir",
"viewId": "lorem",
},
Object {
"sort": "sockets",
"type": "SET_QUERY_RHSM_sort",
"viewId": "lorem",
},
],
],
Array [
Array [
Object {
"dir": "asc",
"type": "SET_QUERY_RHSM_dir",
"viewId": "lorem",
},
Object {
"sort": "sockets",
"type": "SET_QUERY_RHSM_sort",
"viewId": "lorem",
},
],
],
]
`;

exports[`InventoryList Component should handle variations in data: filtered data 1`] = `
<Card
className="curiosity-inventory-card"
Expand Down Expand Up @@ -294,3 +341,5 @@ exports[`InventoryList Component should render a non-connected component: non-co
</CardFooter>
</Card>
`;

exports[`InventoryList Component should return an empty render when disabled: disabled component 1`] = `""`;
Original file line number Diff line number Diff line change
@@ -1,5 +1,66 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`InventoryListHelpers applySortFilters should apply and return updated filters for table sorting: NOT sortable 1`] = `
Object {
"id": "lorem",
"isSortable": false,
}
`;

exports[`InventoryListHelpers applySortFilters should apply and return updated filters for table sorting: sortable 1`] = `
Object {
"id": "lorem",
"isSortable": true,
"onSort": [Function],
}
`;

exports[`InventoryListHelpers applySortFilters should apply and return updated filters for table sorting: sortable, active column 1`] = `
Object {
"id": "lorem",
"isSortable": true,
"onSort": [Function],
"sortActive": true,
"sortDirection": "asc",
}
`;

exports[`InventoryListHelpers applySortFilters should apply and return updated filters for table sorting: sortable, direction 1`] = `
Object {
"ascending": Object {
"id": "lorem",
"isSortable": true,
"onSort": [Function],
"sortDirection": "asc",
},
"descending": Object {
"id": "lorem",
"isSortable": true,
"onSort": [Function],
"sortDirection": "desc",
},
}
`;

exports[`InventoryListHelpers parseInventoryFilters should parse and return updated filters for table cells: NOT sortable 1`] = `
Array [
Object {
"id": "lorem",
"isSortable": false,
},
]
`;

exports[`InventoryListHelpers parseInventoryFilters should parse and return updated filters for table cells: sortable 1`] = `
Array [
Object {
"id": "lorem",
"isSortable": true,
"onSort": [Function],
},
]
`;

exports[`InventoryListHelpers parseRowCellsListData should parse and return formatted/filtered table cells.: basic cell data 1`] = `
Object {
"cells": Array [
Expand Down Expand Up @@ -119,6 +180,8 @@ Object {

exports[`InventoryListHelpers should have specific functions: inventoryListHelpers 1`] = `
Object {
"applySortFilters": [Function],
"parseInventoryFilters": [Function],
"parseRowCellsListData": [Function],
}
`;
53 changes: 53 additions & 0 deletions src/components/inventoryList/__tests__/inventoryList.test.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,22 @@
import React from 'react';
import { shallow } from 'enzyme';
import { SortByDirection } from '@patternfly/react-table';
import Table from '../../table/table';
import { InventoryList } from '../inventoryList';
import { store } from '../../../redux';
import { RHSM_API_QUERY_TYPES } from '../../../types/rhsmApiTypes';

describe('InventoryList Component', () => {
let mockDispatch;

beforeEach(() => {
mockDispatch = jest.spyOn(store, 'dispatch').mockImplementation((type, data) => ({ type, data }));
});

afterEach(() => {
jest.clearAllMocks();
});

it('should render a non-connected component', () => {
const props = {
query: {
Expand All @@ -18,6 +30,24 @@ describe('InventoryList Component', () => {
expect(component).toMatchSnapshot('non-connected');
});

it('should return an empty render when disabled', () => {
const props = {
query: {
[RHSM_API_QUERY_TYPES.LIMIT]: 10,
[RHSM_API_QUERY_TYPES.OFFSET]: 0
},
productId: 'lorem',
listData: [
{ lorem: 'ipsum', dolor: 'sit' },
{ lorem: 'sit', dolor: 'amet' }
],
isDisabled: true
};
const component = shallow(<InventoryList {...props} />);

expect(component).toMatchSnapshot('disabled component');
});

it('should handle variations in data', () => {
const props = {
query: {
Expand Down Expand Up @@ -61,4 +91,27 @@ describe('InventoryList Component', () => {

expect(component.find(Table)).toMatchSnapshot('number of guests, and id');
});

it('should handle updating sorting through redux state', () => {
const props = {
query: {
[RHSM_API_QUERY_TYPES.LIMIT]: 10,
[RHSM_API_QUERY_TYPES.OFFSET]: 0
},
productId: 'lorem',
listData: [
{ lorem: 'ipsum', dolor: 'sit' },
{ lorem: 'sit', dolor: 'amet' }
]
};

const component = shallow(<InventoryList {...props} />);
const componentInstance = component.instance();

componentInstance.onColumnSort({}, { direction: SortByDirection.asc, id: 'sockets' });
componentInstance.onColumnSort({}, { direction: SortByDirection.desc, id: 'sockets' });
componentInstance.onColumnSort({}, { direction: SortByDirection.asc, id: 'sockets' });

expect(mockDispatch.mock.calls).toMatchSnapshot('dispatch filter');
});
});
Original file line number Diff line number Diff line change
@@ -1,4 +1,13 @@
import { inventoryListHelpers, parseRowCellsListData } from '../inventoryListHelpers';
import {
inventoryListHelpers,
applySortFilters,
parseInventoryFilters,
parseRowCellsListData
} from '../inventoryListHelpers';
import {
RHSM_API_QUERY_SORT_DIRECTION_TYPES as SORT_DIRECTION_TYPES,
RHSM_API_QUERY_TYPES
} from '../../../types/rhsmApiTypes';

describe('InventoryListHelpers', () => {
it('should have specific functions', () => {
Expand Down Expand Up @@ -47,4 +56,54 @@ describe('InventoryListHelpers', () => {

expect(parseRowCellsListData({ filters, cellData })).toMatchSnapshot('custom callback data');
});

it('parseInventoryFilters should parse and return updated filters for table cells', () => {
const filters = [
{
id: 'lorem',
isSortable: false
}
];

expect(parseInventoryFilters({ filters, onSort: () => {} })).toMatchSnapshot('NOT sortable');

filters[0].isSortable = true;
expect(parseInventoryFilters({ filters, onSort: () => {} })).toMatchSnapshot('sortable');
});

it('applySortFilters should apply and return updated filters for table sorting', () => {
const filter = {
id: 'lorem',
isSortable: false
};

expect(applySortFilters({ filter, onSort: undefined })).toMatchSnapshot('NOT sortable');

filter.isSortable = true;
expect(applySortFilters({ filter, onSort: () => {} })).toMatchSnapshot('sortable');

expect({
ascending: applySortFilters({
filter,
onSort: () => {},
query: { [RHSM_API_QUERY_TYPES.DIRECTION]: SORT_DIRECTION_TYPES.ASCENDING }
}),
descending: applySortFilters({
filter,
onSort: () => {},
query: { [RHSM_API_QUERY_TYPES.DIRECTION]: SORT_DIRECTION_TYPES.DESCENDING }
})
}).toMatchSnapshot('sortable, direction');

expect(
applySortFilters({
filter,
onSort: () => {},
query: {
[RHSM_API_QUERY_TYPES.DIRECTION]: SORT_DIRECTION_TYPES.ASCENDING,
[RHSM_API_QUERY_TYPES.SORT]: 'lorem'
}
})
).toMatchSnapshot('sortable, active column');
});
});
58 changes: 52 additions & 6 deletions src/components/inventoryList/inventoryList.js
Original file line number Diff line number Diff line change
@@ -1,22 +1,28 @@
import React from 'react';
import PropTypes from 'prop-types';
import _isEqual from 'lodash/isEqual';
import { TableVariant } from '@patternfly/react-table';
import { SortByDirection, TableVariant } from '@patternfly/react-table';
import { Card, CardActions, CardBody, CardFooter, CardHeader, CardTitle, Title } from '@patternfly/react-core';
import { TableToolbar } from '@redhat-cloud-services/frontend-components/components/cjs/TableToolbar';
import _camelCase from 'lodash/camelCase';
import { helpers } from '../../common';
import { connect, reduxActions, reduxSelectors } from '../../redux';
import { connect, reduxActions, reduxSelectors, reduxTypes, store } from '../../redux';
import Table from '../table/table';
import { Loader } from '../loader/loader';
import GuestsList from '../guestsList/guestsList';
import { inventoryListHelpers } from './inventoryListHelpers';
import Pagination from '../pagination/pagination';
import { RHSM_API_QUERY_TYPES } from '../../types/rhsmApiTypes';
import {
RHSM_API_QUERY_SORT_DIRECTION_TYPES as SORT_DIRECTION_TYPES,
RHSM_API_QUERY_SORT_TYPES as SORT_TYPES,
RHSM_API_QUERY_TYPES
} from '../../types/rhsmApiTypes';

/**
* A system inventory component.
*
* @augments React.Component
* @fires onColumnSort
* @fires onUpdateInventoryData
*/
class InventoryList extends React.Component {
Expand All @@ -32,6 +38,43 @@ class InventoryList extends React.Component {
}
}

/**
* On column sort update state.
*
* @event onColumnSort
* @param {object} data pass-through inventory data.
* @param {object} sortParams
* @param {string} sortParams.direction
* @param {string} sortParams.id column identifier
*/
onColumnSort = (data, { direction, id }) => {
const { productId } = this.props;
const updatedSortColumn = Object.values(SORT_TYPES).find(value => _camelCase(value) === id);
let updatedDirection;

switch (direction) {
case SortByDirection.desc:
updatedDirection = SORT_DIRECTION_TYPES.DESCENDING;
break;
default:
updatedDirection = SORT_DIRECTION_TYPES.ASCENDING;
break;
}

store.dispatch([
{
type: reduxTypes.query.SET_QUERY_RHSM_TYPES[RHSM_API_QUERY_TYPES.DIRECTION],
viewId: productId,
[RHSM_API_QUERY_TYPES.DIRECTION]: updatedDirection
},
{
type: reduxTypes.query.SET_QUERY_RHSM_TYPES[RHSM_API_QUERY_TYPES.SORT],
viewId: productId,
[RHSM_API_QUERY_TYPES.SORT]: updatedSortColumn
}
]);
};

/**
* Call the RHSM APIs, apply filters.
*
Expand All @@ -56,7 +99,11 @@ class InventoryList extends React.Component {

const updatedRows = listData.map(({ ...cellData }) => {
const { columnHeaders, cells } = inventoryListHelpers.parseRowCellsListData({
filters: filterInventoryData,
filters: inventoryListHelpers.parseInventoryFilters({
filters: filterInventoryData,
onSort: this.onColumnSort,
query
}),
cellData
});

Expand Down Expand Up @@ -114,7 +161,6 @@ class InventoryList extends React.Component {
}

const updatedPerPage = query?.[RHSM_API_QUERY_TYPES.LIMIT] || perPageDefault;
const loaderPerPage = updatedPerPage / 2;

return (
<Card className="curiosity-inventory-card">
Expand Down Expand Up @@ -143,7 +189,7 @@ class InventoryList extends React.Component {
tableProps={{
className: 'curiosity-inventory-list',
colCount: filterInventoryData?.length || (listData?.[0] && Object.keys(listData[0]).length) || 1,
rowCount: listData?.length || loaderPerPage,
rowCount: listData?.length || updatedPerPage,
variant: TableVariant.compact
}}
/>
Expand Down
Loading

0 comments on commit 5da946c

Please sign in to comment.