Skip to content

Commit

Permalink
feat(Clusters list table): filters edition modifies search params (#196)
Browse files Browse the repository at this point in the history
  • Loading branch information
gkarat authored Mar 29, 2022
1 parent da37e23 commit 8536160
Show file tree
Hide file tree
Showing 4 changed files with 130 additions and 22 deletions.
9 changes: 9 additions & 0 deletions src/AppConstants.js
Original file line number Diff line number Diff line change
Expand Up @@ -310,3 +310,12 @@ export const LIKELIHOOD_LABEL_LOWER = {
intlSettings
),
};
export const CLUSTERS_LIST_COLUMNS_KEYS = [
'name',
'recommendations',
'critical',
'important',
'moderate',
'low',
'last_seen',
];
54 changes: 49 additions & 5 deletions src/Components/ClustersListTable/ClustersListTable.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import React, { useEffect, useState } from 'react';
import PropTypes from 'prop-types';
import { useIntl } from 'react-intl';
import { useDispatch, useSelector } from 'react-redux';
import isEqual from 'lodash/isEqual';
import { useLocation } from 'react-router-dom';

import {
SortByDirection,
Expand All @@ -25,14 +27,18 @@ import {
} from '../../Services/Filters';
import {
CLUSTERS_LIST_COLUMNS,
CLUSTERS_LIST_COLUMNS_KEYS,
CLUSTER_FILTER_CATEGORIES,
CLUSTER_LAST_CHECKED_CELL,
CLUSTER_NAME_CELL,
} from '../../AppConstants';
import {
buildFilterChips,
mapClustersToRows,
paramParser,
passFiltersCluster,
translateSortParams,
updateSearchParams,
} from '../Common/Tables';
import Loading from '../Loading/Loading';
import messages from '../../Messages';
Expand All @@ -41,7 +47,6 @@ import {
NoMatchingClusters,
NoRecsForClusters,
} from '../MessageState/EmptyStates';
import isEqual from 'lodash/isEqual';

const ClustersListTable = ({
query: { isError, isUninitialized, isFetching, isSuccess, data, refetch },
Expand All @@ -57,6 +62,13 @@ const ClustersListTable = ({

const [filteredRows, setFilteredRows] = useState([]);
const [displayedRows, setDisplayedRows] = useState([]);
// helps to distinguish the state when the API data received but not yet filtered
const [rowsFiltered, setRowsFiltered] = useState(false);
const [filterBuilding, setFilterBuilding] = useState(true);
const { search } = useLocation();
const loadingState = isUninitialized || isFetching || !rowsFiltered;
const errorState = isError;
const successState = isSuccess;

useEffect(() => {
setDisplayedRows(
Expand All @@ -72,8 +84,40 @@ const ClustersListTable = ({

useEffect(() => {
setFilteredRows(buildFilteredRows(clusters, filters));
if (isSuccess && !rowsFiltered) {
setRowsFiltered(true);
}
}, [data, filters.hits, filters.text]);

useEffect(() => {
if (search && filterBuilding) {
const paramsObject = paramParser(search);

if (paramsObject.sort) {
const sortObj = translateSortParams(paramsObject.sort);
paramsObject.sortIndex = CLUSTERS_LIST_COLUMNS_KEYS.indexOf(
sortObj.name
);
paramsObject.sortDirection = sortObj.direction;
}
paramsObject.offset &&
(paramsObject.offset = Number(paramsObject.offset[0]));
paramsObject.limit &&
(paramsObject.limit = Number(paramsObject.limit[0]));
paramsObject.impacting &&
!Array.isArray(paramsObject.impacting) &&
(paramsObject.impacting = [`${paramsObject.impacting}`]);
updateFilters({ ...filters, ...paramsObject });
}
setFilterBuilding(false);
}, []);

useEffect(() => {
if (!filterBuilding) {
updateSearchParams(filters, CLUSTERS_LIST_COLUMNS_KEYS);
}
}, [filters, filterBuilding]);

const buildFilteredRows = (allRows, filters) =>
mapClustersToRows(
allRows.filter((cluster) => passFiltersCluster(cluster, filters))
Expand Down Expand Up @@ -184,7 +228,7 @@ const ClustersListTable = ({

return (
<>
{isUninitialized || isFetching ? (
{loadingState ? (
<Bullseye>
<Spinner />
</Bullseye>
Expand All @@ -210,15 +254,15 @@ const ClustersListTable = ({
filterConfig={{ items: filterConfigItems }}
activeFiltersConfig={activeFiltersConfig}
/>
{(isUninitialized || isFetching) && <Loading />}
{isError && (
{loadingState && <Loading />}
{errorState && (
<Card ouiaId="error-state">
<CardBody>
<ErrorState />
</CardBody>
</Card>
)}
{!(isUninitialized || isFetching) && isSuccess && (
{!loadingState && successState && (
<React.Fragment>
<Table
aria-label="Table of clusters"
Expand Down
87 changes: 70 additions & 17 deletions src/Components/ClustersListTable/ClustersListTable.spec.ct.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,15 @@ const TABLE_HEADERS = [
'Low',
'Last seen',
];
const TABLE_HEADERS_SORT_KEYS = {
Name: 'name',
Recommendations: 'recommendations',
Critical: 'critical',
Important: 'important',
Moderate: 'moderate',
Low: 'low',
'Last seen': 'last_seen',
};

function checkRowCounts(n) {
return cy
Expand Down Expand Up @@ -86,6 +95,8 @@ function itemsPerPage() {
return array;
}

// TODO: test pre-filled search parameters filtration

describe('data', () => {
it('has values', () => {
cy.wrap(data).its('length').should('be.gte', 1);
Expand Down Expand Up @@ -185,6 +196,7 @@ describe('clusters list table', () => {
.find('b')
.eq(0)
.should('have.text', '1 - 20');
expect(window.location.search).to.contain('limit=20');
});

it('can change page limit', () => {
Expand All @@ -196,7 +208,8 @@ describe('clusters list table', () => {
.find('ul[class=pf-c-options-menu__menu]')
.find(DROPDOWN_ITEM)
.contains(`${el}`)
.click();
.click()
.then(() => expect(window.location.search).to.contain(`limit=${el}`));
checkRowCounts(Math.min(el, data.length));
});
});
Expand All @@ -217,7 +230,11 @@ describe('clusters list table', () => {

it('can iterate over pages', () => {
cy.wrap(itemsPerPage()).each((el, index, list) => {
checkRowCounts(el);
checkRowCounts(el).then(() => {
expect(window.location.search).to.contain(
`offset=${DEFAULT_ROW_COUNT * index}`
);
});
cy.get(TOOLBAR)
.find(PAGINATION)
.find('button[data-action="next"]')
Expand All @@ -239,6 +256,7 @@ describe('clusters list table', () => {
.find('.pf-c-chip__text')
.should('have.length', 1)
.should('have.text', 'All clusters');
expect(window.location.search).to.contain(`hits=all`);
});

it('reset filters button is displayed', () => {
Expand All @@ -265,7 +283,8 @@ describe('clusters list table', () => {
.find('.pf-c-select__menu')
.find('input')
.eq(0)
.click();
.click()
.then(() => expect(window.location.search).to.not.contain(`hits=`));
// open pagination
cy.get(PAGINATION).eq(0).find('.pf-c-options-menu__toggle-button').click();
// set to 50 clusters per page
Expand All @@ -275,7 +294,8 @@ describe('clusters list table', () => {
.find('li')
.eq(2)
.find('button')
.click();
.click()
.then(() => expect(window.location.search).to.contain(`limit=50`));
cy.getTotalClusters().should('have.text', 26);
// check all shown clusters have recommendations > 0
cy.get('TBODY')
Expand All @@ -293,16 +313,20 @@ describe('clusters list table', () => {
.eq(1)
.click();
cy.get(TOOLBAR_FILTER).find('.pf-c-select__toggle').click();
// unflag "All clusters"
cy.get(TOOLBAR_FILTER)
.find('.pf-c-select__menu')
.find('input')
.eq(0)
.click();
.click()
.then(() => expect(window.location.search).to.not.contain(`hits=`));
// flag "Critical"
cy.get(TOOLBAR_FILTER)
.find('.pf-c-select__menu')
.find('input')
.eq(1)
.click();
.click()
.then(() => expect(window.location.search).to.contain(`hits=4`));
cy.get('.pf-c-table__sort').eq(2).click();
cy.getFirstRow().find('td[data-label=Critical]').should('have.text', 1);
cy.get('.pf-c-table__sort').eq(2).click();
Expand All @@ -321,12 +345,14 @@ describe('clusters list table', () => {
.find('.pf-c-select__menu')
.find('input')
.eq(0)
.click();
.click()
.then(() => expect(window.location.search).to.not.contain(`hits=`));
cy.get(TOOLBAR_FILTER)
.find('.pf-c-select__menu')
.find('input')
.eq(2)
.click();
.click()
.then(() => expect(window.location.search).to.contain(`hits=3`));
cy.get('.pf-c-table__sort').eq(3).click();
cy.getFirstRow().find('td[data-label=Important]').should('have.text', 1);
cy.get('.pf-c-table__sort').eq(3).click();
Expand All @@ -345,12 +371,14 @@ describe('clusters list table', () => {
.find('.pf-c-select__menu')
.find('input')
.eq(0)
.click();
.click()
.then(() => expect(window.location.search).to.not.contain(`hits=`));
cy.get(TOOLBAR_FILTER)
.find('.pf-c-select__menu')
.find('input')
.eq(3)
.click();
.click()
.then(() => expect(window.location.search).to.contain(`hits=2`));
cy.get('.pf-c-table__sort').eq(4).click();
cy.getFirstRow().find('td[data-label=Moderate]').should('have.text', 3);
cy.get('.pf-c-table__sort').eq(4).click();
Expand All @@ -369,12 +397,14 @@ describe('clusters list table', () => {
.find('.pf-c-select__menu')
.find('input')
.eq(0)
.click();
.click()
.then(() => expect(window.location.search).to.not.contain(`hits=`));
cy.get(TOOLBAR_FILTER)
.find('.pf-c-select__menu')
.find('input')
.eq(4)
.click();
.click()
.then(() => expect(window.location.search).to.contain(`hits=1`));
cy.get('.pf-c-table__sort').eq(5).click();
cy.getFirstRow().find('td[data-label=Low]').should('have.text', 1);
cy.get('.pf-c-table__sort').eq(5).click();
Expand All @@ -383,7 +413,10 @@ describe('clusters list table', () => {

it('can filter by name', () => {
// search by "cc" search input
cy.get(TOOLBAR_FILTER).find('.pf-c-form-control').type('cc');
cy.get(TOOLBAR_FILTER)
.find('.pf-c-form-control')
.type('cc')
.then(() => expect(window.location.search).to.contain(`text=cc`));
// should be 4 clusters left
cy.get(TBODY)
.children()
Expand All @@ -399,12 +432,20 @@ describe('clusters list table', () => {
.find('td[data-label=Name]')
.should('have.text', '947b8f15-cc44-47ca-9265-945085d4f3b8');
// click on the Name sorting button
cy.get('.pf-c-table__sort').eq(0).click();
cy.get('.pf-c-table__sort')
.eq(0)
.click()
.then(() => expect(window.location.search).to.contain(`sort=name`));
cy.getFirstRow()
.find('td[data-label=Name]')
.should('have.text', '1ghhxwjfoi 5b5hbyv07');
// click on the Recommendations sorting button
cy.get('.pf-c-table__sort').eq(1).click();
cy.get('.pf-c-table__sort')
.eq(1)
.click()
.then(() =>
expect(window.location.search).to.contain(`sort=recommendations`)
);
// the first cluster has 0 recommendations
cy.getFirstRow()
.find('td[data-label=Recommendations]')
Expand Down Expand Up @@ -433,7 +474,10 @@ describe('clusters list table', () => {
});

it('sorts N/A in last seen correctly', () => {
cy.get('.pf-c-table__sort').eq(6).click();
cy.get('.pf-c-table__sort')
.eq(6)
.click()
.then(() => expect(window.location.search).to.contain(`sort=last_seen`));
cy.getFirstRow().find('span').should('have.text', 'N/A');
cy.get('.pf-c-table__sort').eq(6).click();
cy.get(PAGINATION).eq(0).find('.pf-c-options-menu__toggle-button').click();
Expand Down Expand Up @@ -476,7 +520,16 @@ describe('clusters list table', () => {
Math.min(DEFAULT_ROW_COUNT, namedClusters.length)
);
if (order === 'ascending') {
cy.get(header).find('button').click();
cy.get(header)
.find('button')
.click()
.then(() =>
expect(window.location.search).to.contain(
`sort=${order === 'descending' ? '-' : ''}${
TABLE_HEADERS_SORT_KEYS[label]
}`
)
);
} else {
cy.get(header).find('button').dblclick();
}
Expand Down
2 changes: 2 additions & 0 deletions src/Components/Common/Tables.js
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,7 @@ export const buildFilterChips = (filters, categories) => {
const localFilters = cloneDeep(filters);
delete localFilters.sortIndex;
delete localFilters.sortDirection;
delete localFilters.sort;
delete localFilters.offset;
delete localFilters.limit;
localFilters?.hits &&
Expand Down Expand Up @@ -233,6 +234,7 @@ export const updateSearchParams = (filters = {}, columnMapping) => {
key !== 'sortDirection' &&
key !== 'sort' &&
value !== '' &&
!(Array.isArray(value) && value.length === 0) &&
url.searchParams.set(key, value)
);
});
Expand Down

0 comments on commit 8536160

Please sign in to comment.