diff --git a/CHANGELOG.md b/CHANGELOG.md index 9102524b..4563b84b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ * COUNTER statistics: Show the COUNTER release version for reports in an additional column ([UIEUS-368](https://folio-org.atlassian.net/browse/UIEUS-368)) * Leverage `yarn.lock` ([UIEUS-377](https://folio-org.atlassian.net/browse/UIEUS-377)) * COUNTER 5.1 Support: Harvesting configuration for usage data providers ([UIEUS-357](https://folio-org.atlassian.net/browse/UIEUS-357)) +* Add filter for COUNTER report release ([UIEUS-374](https://folio-org.atlassian.net/browse/UIEUS-374)) ## [9.0.0](https://github.com/folio-org/ui-erm-usage/tree/v9.0.0) (2024-04-17) * *BREAKING* Use `multipart/form-data` to upload COUNTER reports ([UIEUS-353](https://folio-org.atlassian.net/browse/UIEUS-353)) diff --git a/src/components/UDPFilters/UDPFilters.js b/src/components/UDPFilters/UDPFilters.js index 00d26ec4..fabc0dc6 100644 --- a/src/components/UDPFilters/UDPFilters.js +++ b/src/components/UDPFilters/UDPFilters.js @@ -30,6 +30,7 @@ const UDPFilters = ({ tags: [], errorCodes: [], reportTypes: [], + reportReleases: [], }); const isFilterDefinedLocally = filter => { @@ -134,94 +135,31 @@ const UDPFilters = ({ ); }; - const renderTagsFilter = () => { - const tagFilters = activeFilters.tags || []; - - return ( - 0} - header={FilterAccordionHeader} - label={} - onClearFilter={() => { - filterHandlers.clearGroup('tags'); - }} - separator={false} - > - filterHandlers.state({ - ...activeFilters, - tags: e.values - }) - } - selectedValues={tagFilters} - /> - - ); - }; - - const renderErrorCodesFilter = () => { - const errorCodesFilters = activeFilters.errorCodes || []; - - return ( - 0} - header={FilterAccordionHeader} - label={} - onClearFilter={() => { - filterHandlers.clearGroup('errorCodes'); - }} - separator={false} - > - filterHandlers.state({ - ...activeFilters, - errorCodes: e.values - }) - } - selectedValues={errorCodesFilters} - /> - - ); - }; - - const renderReportTypesFiler = () => { - const reportTypesFilters = activeFilters.reportTypes || []; + const renderMultiSelectionFilter = (key, closedByDefault = true) => { + const groupFilters = activeFilters[key] || []; return ( 0} + closedByDefault={closedByDefault} + displayClearButton={groupFilters.length > 0} header={FilterAccordionHeader} - label={} - onClearFilter={() => { - filterHandlers.clearGroup('reportTypes'); - }} + id={`filter-accordion-${key}`} + label={} + onClearFilter={() => { filterHandlers.clearGroup(key); }} separator={false} > filterHandlers.state({ - ...activeFilters, - reportTypes: e.values - }) - } - selectedValues={reportTypesFilters} + ariaLabelledBy={`clickable-filter-${key}`} + dataOptions={filterState[key]} + id={`filter-${key}`} + name={key} + onChange={group => { + filterHandlers.state({ + ...activeFilters, + [group.name]: group.values + }); + }} + selectedValues={groupFilters} /> ); @@ -232,10 +170,11 @@ const UDPFilters = ({ {renderCheckboxFilter('harvestingStatus')} {renderCheckboxFilter('harvestVia')} {renderCheckboxFilter('aggregators', true)} - {renderReportTypesFiler()} + {renderMultiSelectionFilter('reportTypes')} + {renderMultiSelectionFilter('reportReleases')} {renderCheckboxFilter('hasFailedReport', true)} - {renderTagsFilter()} - {renderErrorCodesFilter()} + {renderMultiSelectionFilter('tags')} + {renderMultiSelectionFilter('errorCodes')} ); }; diff --git a/src/components/views/UDPs.test.js b/src/components/views/UDPs.test.js index 9dbca2bb..c2f16122 100644 --- a/src/components/views/UDPs.test.js +++ b/src/components/views/UDPs.test.js @@ -1,4 +1,4 @@ -import { screen } from '@folio/jest-config-stripes/testing-library/react'; +import { screen, within } from '@folio/jest-config-stripes/testing-library/react'; import userEvent from '@folio/jest-config-stripes/testing-library/user-event'; import { MemoryRouter } from 'react-router-dom'; @@ -32,6 +32,7 @@ const renderUDPs = (stripes, props, udpsData, rerender) => renderWithIntl( tags: [], errorCodes: ['3030', '3031', 'other'], reportTypes: ['BR', 'TR'], + reportReleases: ['5.0', '4'], }} selectedRecordId="" onNeedMoreData={jest.fn()} @@ -136,28 +137,36 @@ describe('UDPs SASQ View', () => { }); describe('check filters', () => { - it('harvesting status filter should be present', () => { - expect(document.querySelector('#filter-accordion-harvestingStatus')).toBeInTheDocument(); + it('should be present the harvesting status filter', () => { + expect(screen.getByRole('button', { name: 'Harvesting status filter list' })).toBeInTheDocument(); }); - it('harvestVia filter should be present', () => { - expect(document.querySelector('#filter-accordion-harvestVia')).toBeInTheDocument(); + it('should be present the harvestVia filter', () => { + expect(screen.getByRole('button', { name: 'Harvest via filter list' })).toBeInTheDocument(); }); - it('aggregators filter should be present', () => { - expect(document.querySelector('#filter-accordion-aggregators')).toBeInTheDocument(); + it('should be present the aggregators filter', () => { + expect(screen.getByRole('button', { name: 'Aggregators filter list' })).toBeInTheDocument(); }); - it('report types filter should be present', () => { - expect(document.querySelector('#clickable-report-types-filter')).toBeInTheDocument(); + it('should be present the report types filter', () => { + expect(screen.getByRole('button', { name: 'Report types filter list' })).toBeInTheDocument(); }); - it('has failed reports filter should be present', () => { - expect(document.querySelector('#filter-accordion-hasFailedReport')).toBeInTheDocument(); + it('should be present the report releases filter', () => { + expect(screen.getByRole('button', { name: 'Report releases filter list' })).toBeInTheDocument(); }); - it('error codes filter should be present', () => { - expect(document.querySelector('#clickable-error-codes-filter')).toBeInTheDocument(); + it('should be present the has failed reports filter', () => { + expect(screen.getByRole('button', { name: 'Has failed report(s) filter list' })).toBeInTheDocument(); + }); + + it('should be present the tags filter', () => { + expect(screen.getByRole('button', { name: 'Tags filter list' })).toBeInTheDocument(); + }); + + it('should be present the error codes filter', () => { + expect(screen.getByRole('button', { name: 'Error codes filter list' })).toBeInTheDocument(); }); it('reset all button should be present', () => { @@ -172,6 +181,35 @@ describe('UDPs SASQ View', () => { expect(document.querySelector('#clickable-search-udps')).toBeInTheDocument(); }); + test('select and clear report release filter values', async () => { + const reportReleaseAccordion = screen.getByRole('button', { name: 'Report releases filter list' }); + expect(reportReleaseAccordion).toBeInTheDocument(); + await userEvent.click(reportReleaseAccordion); + + const multiselects = screen.getAllByLabelText('open menu'); + const multiselectReportReleases = multiselects.find(btn => btn.getAttribute('aria-controls') === 'multiselect-option-list-filter-reportReleases'); + expect(multiselectReportReleases).toBeInTheDocument(); + await userEvent.click(multiselectReportReleases); + + const listboxes = screen.getAllByRole('listbox'); + const reportReleasesList = listboxes.find(ul => ul.getAttribute('id') === 'multiselect-option-list-filter-reportReleases'); + expect(within(reportReleasesList).getByRole('option', { name: /5.0/ })).toBeInTheDocument(); + expect(within(reportReleasesList).getByRole('option', { name: /4/ })).toBeInTheDocument(); + await userEvent.click(within(reportReleasesList).getByRole('option', { name: /4/ })); + + const searchboxes = screen.getAllByRole('searchbox'); + const searchboxReportReleases = searchboxes.find(btn => btn.getAttribute('aria-describedby') === 'multi-describe-control-filter-reportReleases'); + expect(searchboxReportReleases).toBeInTheDocument(); + expect(within(searchboxReportReleases).getByText('4')).toBeInTheDocument(); + expect(within(searchboxReportReleases).queryByText('5.0')).not.toBeInTheDocument(); + + const clearReportReleasesButton = screen.getByRole('button', { name: /Clear selected Report releases filters/i }); + expect(clearReportReleasesButton).toBeInTheDocument(); + await userEvent.click(clearReportReleasesButton); + + expect(within(searchboxReportReleases).queryByText('4')).not.toBeInTheDocument(); + }); + it('columns of MCL should be present', async () => { const searchFieldInput = document.querySelector('#input-udp-search'); expect(searchFieldInput).toBeInTheDocument(); diff --git a/src/routes/UDPsRoute.js b/src/routes/UDPsRoute.js index f0de70ca..85a8e8e8 100644 --- a/src/routes/UDPsRoute.js +++ b/src/routes/UDPsRoute.js @@ -62,6 +62,11 @@ class UDPsRoute extends React.Component { path: 'counter-reports/reports/types', records: 'reportTypes' }, + reportReleases: { + type: 'okapi', + path: 'counter-reports/reports/releases', + records: 'reportReleases' + }, numFiltersLoaded: { initialValue: 1 }, // will be incremented as each filter loads initializedFilterConfig: { initialValue: false }, query: { @@ -193,7 +198,8 @@ class UDPsRoute extends React.Component { aggregators: get(resources, 'aggregatorSettings.records', []), tags: get(resources, 'tags.records', []), errorCodes: get(resources, 'errorCodes.records', []), - reportTypes: get(resources, 'reportTypes.records', []) + reportTypes: get(resources, 'reportTypes.records', []), + reportReleases: get(resources, 'reportReleases.records', []), }} selectedRecordId={match.params.id} onNeedMoreData={this.handleNeedMoreData} diff --git a/src/util/data/filterGroups.js b/src/util/data/filterGroups.js index 54937d3f..8a11313b 100644 --- a/src/util/data/filterGroups.js +++ b/src/util/data/filterGroups.js @@ -55,6 +55,13 @@ const filterGroups = [ cql: 'reportTypes', operator: '=', values: [], + }, + { + label: 'Report Releases', + name: 'reportReleases', + cql: 'reportReleases', + operator: '=', + values: [], } ]; diff --git a/translations/ui-erm-usage/en.json b/translations/ui-erm-usage/en.json index b5615f55..88fdce07 100644 --- a/translations/ui-erm-usage/en.json +++ b/translations/ui-erm-usage/en.json @@ -35,6 +35,7 @@ "general.tags": "Tags", "general.errorCodes": "Error codes", "general.reportTypes": "Report types", + "general.reportReleases": "Report releases", "general.edit": "Edit", "general.note": "Note", "general.year": "Year",