diff --git a/CHANGELOG.md b/CHANGELOG.md
index 11023b28..af0ff12b 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -6,3 +6,4 @@
* [UIMARCAUTH-6](https://issues.folio.org/browse/UIMARCAUTH-6) Add View MARC authority record permission.
* [UIMARCAUTH-5](https://issues.folio.org/browse/UIMARCAUTH-5) Add Edit MARC authority record permission.
* [UIMARCAUTH-16](https://issues.folio.org/browse/UIMARCAUTH-16) Implement MARC Authorities Search Box.
+* [UIMARCAUTH-20](https://issues.folio.org/browse/UIMARCAUTH-20) Implement Results List Column Chooser.
diff --git a/package.json b/package.json
index 326678e4..4351abc2 100644
--- a/package.json
+++ b/package.json
@@ -40,6 +40,7 @@
"inflected": "^2.0.4",
"jest": "^26.6.3",
"jest-junit": "^12.0.0",
+ "lodash": "^4.17.4",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-intl": "^5.8.0",
diff --git a/src/components/SearchResultsList/SearchResultsList.js b/src/components/SearchResultsList/SearchResultsList.js
index b85f4a96..6ac6ca53 100644
--- a/src/components/SearchResultsList/SearchResultsList.js
+++ b/src/components/SearchResultsList/SearchResultsList.js
@@ -4,6 +4,7 @@ import { FormattedMessage } from 'react-intl';
import { MultiColumnList } from '@folio/stripes/components';
import { AuthorityShape } from '../../constants/shapes';
+import { searchResultListColumns } from '../../constants';
const propTypes = {
authorities: PropTypes.arrayOf(AuthorityShape).isRequired,
@@ -11,22 +12,18 @@ const propTypes = {
onNeedMoreData: PropTypes.func.isRequired,
pageSize: PropTypes.number.isRequired,
totalResults: PropTypes.number,
+ visibleColumns: PropTypes.arrayOf(PropTypes.string).isRequired,
};
const authRef = 'Auth/Ref';
-const searchResultListColumns = {
- AUTH_REF_TYPE: 'authRefType',
- HEADING_REF: 'headingRef',
- HEADING_TYPE: 'headingType',
-};
-
const SearchResultsList = ({
authorities,
totalResults,
loading,
pageSize,
onNeedMoreData,
+ visibleColumns,
}) => {
const columnMapping = {
[searchResultListColumns.AUTH_REF_TYPE]: ,
@@ -45,11 +42,6 @@ const SearchResultsList = ({
: authority.authRefType;
},
};
- const visibleColumns = [
- searchResultListColumns.AUTH_REF_TYPE,
- searchResultListColumns.HEADING_REF,
- searchResultListColumns.HEADING_TYPE,
- ];
return (
render(
{
expect(getAllByText('Twain, Mark')).toHaveLength(15);
});
+
+ it('should display 3 columns', () => {
+ const { getByText } = renderSearchResultsList();
+
+ expect(getByText('ui-marc-authorities.search-results-list.authRefType')).toBeDefined();
+ expect(getByText('ui-marc-authorities.search-results-list.headingRef')).toBeDefined();
+ expect(getByText('ui-marc-authorities.search-results-list.headingType')).toBeDefined();
+ });
+
+ describe('when show columns checkbox for "Type of Heading" is not checked', () => {
+ it('should display 2 columns', () => {
+ const { queryByText } = renderSearchResultsList({
+ visibleColumns: [
+ searchResultListColumns.AUTH_REF_TYPE,
+ searchResultListColumns.HEADING_REF,
+ ],
+ });
+
+ expect(queryByText('ui-marc-authorities.search-results-list.authRefType')).toBeDefined();
+ expect(queryByText('ui-marc-authorities.search-results-list.headingRef')).toBeDefined();
+ expect(queryByText('ui-marc-authorities.search-results-list.headingType')).toBeNull();
+ });
+ });
});
diff --git a/src/constants/index.js b/src/constants/index.js
index 6994aae6..4edb3e6d 100644
--- a/src/constants/index.js
+++ b/src/constants/index.js
@@ -1,3 +1,4 @@
export * from './searchableIndexesValues';
export * from './rawSearchableIndexes';
export * from './searchableIndexesMap';
+export * from './searchResultsListColumns';
diff --git a/src/constants/searchResultsListColumns.js b/src/constants/searchResultsListColumns.js
new file mode 100644
index 00000000..4df39454
--- /dev/null
+++ b/src/constants/searchResultsListColumns.js
@@ -0,0 +1,5 @@
+export const searchResultListColumns = {
+ AUTH_REF_TYPE: 'authRefType',
+ HEADING_REF: 'headingRef',
+ HEADING_TYPE: 'headingType',
+};
diff --git a/src/views/AuthoritiesSearch/AuthoritiesSearch.js b/src/views/AuthoritiesSearch/AuthoritiesSearch.js
index f6b9e3af..ad815b7c 100644
--- a/src/views/AuthoritiesSearch/AuthoritiesSearch.js
+++ b/src/views/AuthoritiesSearch/AuthoritiesSearch.js
@@ -6,7 +6,10 @@ import {
useHistory,
useLocation,
} from 'react-router-dom';
-import { useIntl } from 'react-intl';
+import {
+ FormattedMessage,
+ useIntl,
+} from 'react-intl';
import queryString from 'query-string';
import {
useLocalStorage,
@@ -24,6 +27,8 @@ import {
CollapseFilterPaneButton,
ExpandFilterPaneButton,
PersistedPaneset,
+ useColumnManager,
+ ColumnManagerMenu,
} from '@folio/stripes/smart-components';
import {
@@ -36,10 +41,15 @@ import {
SearchResultsList,
} from '../../components';
import { useAuthorities } from '../../hooks/useAuthorities';
-import { rawSearchableIndexes } from '../../constants';
+import {
+ rawSearchableIndexes,
+ searchResultListColumns,
+} from '../../constants';
import css from './AuthoritiesSearch.css';
+const prefix = 'authorities';
+
const AuthoritiesSearch = () => {
const intl = useIntl();
const [, getNamespace] = useNamespace();
@@ -55,6 +65,16 @@ const AuthoritiesSearch = () => {
const [searchDropdownValue, setSearchDropdownValue] = useState('');
const [searchIndex, setSearchIndex] = useState('');
+ const columnMapping = {
+ [searchResultListColumns.AUTH_REF_TYPE]: ,
+ [searchResultListColumns.HEADING_REF]: ,
+ [searchResultListColumns.HEADING_TYPE]: ,
+ };
+ const {
+ visibleColumns,
+ toggleColumn,
+ } = useColumnManager(prefix, columnMapping);
+
useEffect(() => {
const locationSearchParams = queryString.parse(location.search);
@@ -121,6 +141,18 @@ const AuthoritiesSearch = () => {
);
};
+ const renderActionMenu = () => {
+ return (
+
+ );
+ };
+
const searchableIndexes = rawSearchableIndexes.map(index => ({
label: intl.formatMessage({ id: index.label }),
value: index.value,
@@ -189,12 +221,14 @@ const AuthoritiesSearch = () => {
defaultWidth="fill"
paneTitle={intl.formatMessage({ id: 'ui-marc-authorities.meta.title' })}
firstMenu={renderResultsFirstMenu()}
+ actionMenu={renderActionMenu}
>
diff --git a/src/views/AuthoritiesSearch/AuthoritiesSearch.test.js b/src/views/AuthoritiesSearch/AuthoritiesSearch.test.js
index e5a930c8..784a6323 100644
--- a/src/views/AuthoritiesSearch/AuthoritiesSearch.test.js
+++ b/src/views/AuthoritiesSearch/AuthoritiesSearch.test.js
@@ -5,6 +5,7 @@ import {
fireEvent,
} from '@testing-library/react';
+import mockMapValues from 'lodash/mapValues';
import routeData from 'react-router';
import { createMemoryHistory } from 'history';
@@ -13,7 +14,10 @@ import '../../../test/jest/__mock__';
import Harness from '../../../test/jest/helpers/harness';
import AuthoritiesSearch from './AuthoritiesSearch';
-import { searchableIndexesValues } from '../../constants';
+import {
+ searchableIndexesValues,
+ searchResultListColumns,
+} from '../../constants';
const history = createMemoryHistory();
const historyReplaceSpy = jest.spyOn(history, 'replace');
@@ -22,6 +26,15 @@ jest.mock('../../hooks/useAuthorities', () => ({
useAuthorities: () => ({ authorities: [] }),
}));
+jest.mock('../../components', () => ({
+ ...jest.requireActual('../../components'),
+ SearchResultsList: (props) => {
+ const mapedProps = mockMapValues(props, (prop) => ((typeof prop === 'object') ? JSON.stringify(prop) : prop));
+
+ return ();
+ },
+}));
+
const renderAuthoritiesSearch = (props = {}) => render(
@@ -67,6 +80,12 @@ describe('Given AuthoritiesSearch', () => {
expect(getByRole('button', { name: 'stripes-smart-components.resetAll' })).toBeDefined();
});
+ it('display "Action" button', () => {
+ const { getByRole } = renderAuthoritiesSearch();
+
+ expect(getByRole('button', { name: 'stripes-components.paneMenuActionsToggleLabel' })).toBeDefined();
+ });
+
describe('when textarea is not empty and Reset all button is clicked', () => {
it('should clear textarea', () => {
const {
@@ -178,4 +197,52 @@ describe('Given AuthoritiesSearch', () => {
});
});
});
+
+ describe('when click on "Action" button', () => {
+ it('should display "Show columns" section', () => {
+ const {
+ getByRole,
+ getByText,
+ } = renderAuthoritiesSearch();
+
+ fireEvent.click(getByRole('button', { name: 'stripes-components.paneMenuActionsToggleLabel' }));
+
+ expect(getByText('stripes-smart-components.columnManager.showColumns')).toBeDefined();
+ });
+
+ it('should display "Authorized/Reference" and "Type of heading" checkboxes', () => {
+ const { getByRole } = renderAuthoritiesSearch();
+
+ fireEvent.click(getByRole('button', { name: 'stripes-components.paneMenuActionsToggleLabel' }));
+
+ expect(getByRole('checkbox', { name: 'ui-marc-authorities.search-results-list.authRefType' })).toBeDefined();
+ expect(getByRole('checkbox', { name: 'ui-marc-authorities.search-results-list.headingType' })).toBeDefined();
+ });
+
+ it('should be checked by the default', () => {
+ const { getByRole } = renderAuthoritiesSearch();
+
+ fireEvent.click(getByRole('button', { name: 'stripes-components.paneMenuActionsToggleLabel' }));
+
+ expect(getByRole('checkbox', { name: 'ui-marc-authorities.search-results-list.authRefType' })).toBeChecked();
+ expect(getByRole('checkbox', { name: 'ui-marc-authorities.search-results-list.headingType' })).toBeChecked();
+ });
+
+ describe('when click on "Type of Heading" checkbox', () => {
+ it('should hide "Type of Heading" column', () => {
+ const {
+ getByRole,
+ getByTestId,
+ } = renderAuthoritiesSearch();
+
+ fireEvent.click(getByRole('button', { name: 'stripes-components.paneMenuActionsToggleLabel' }));
+ fireEvent.click(getByRole('checkbox', { name: 'ui-marc-authorities.search-results-list.headingType' }));
+
+ expect(getByTestId('SearchResultsList')).toHaveAttribute('visibleColumns', JSON.stringify([
+ searchResultListColumns.AUTH_REF_TYPE,
+ searchResultListColumns.HEADING_REF,
+ ]));
+ });
+ });
+ });
});